YiiWheels
  • Package
  • Class
  • Tree

Packages

  • yiiwheels
    • behaviors
    • widgets
    • widgets
      • ace
      • box
      • datepicker
      • daterangepicker
      • datetimepicker
      • detail
      • editable
      • fileupload
      • fileuploader
      • formhelpers
      • gallery
      • google
      • grid
        • behaviors
        • operations
      • highcharts
      • maskInput
      • maskmoney
      • modal
      • multiselect
      • rangeslider
      • redactor
      • select2
      • sparklines
      • switch
      • timeago
      • timepicker
      • toggle
      • typeahead

Classes

  • WhEditable
  • WhEditableColumn
  • WhEditableDetailView
  • WhEditableField
  • WhEditableSaver
  1 <?php
  2 /**
  3  * WhEditableColumn class
  4  *
  5  * Helps to update model by editable widget submit request.
  6  *
  7  * @author Antonio Ramirez <amigo.cobos@gmail.com>
  8  * @copyright Copyright &copy; 2amigos.us 2013-
  9  * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 10  * @package YiiWheels.widgets.editable
 11  *
 12  * @author Vitaliy Potapov <noginsk@rambler.ru>
 13  * @link https://github.com/vitalets/x-editable-yii
 14  * @copyright Copyright &copy; Vitaliy Potapov 2012
 15  * @version 1.3.1
 16  */
 17 class WhEditableSaver extends CComponent
 18 {
 19     /**
 20      * scenario used in model for update. Can be taken from `scenario` POST param
 21      *
 22      * @var mixed
 23      */
 24     public $scenario;
 25 
 26     /**
 27      * name of model
 28      *
 29      * @var mixed
 30      */
 31     public $modelClass;
 32 
 33     /**
 34      * primaryKey value
 35      *
 36      * @var mixed
 37      */
 38     public $primaryKey;
 39 
 40     /**
 41      * name of attribute to be updated
 42      *
 43      * @var mixed
 44      */
 45     public $attribute;
 46 
 47     /**
 48      * model instance
 49      *
 50      * @var CActiveRecord
 51      */
 52     public $model;
 53 
 54     /**
 55      * @var mixed new value of attribute
 56      */
 57     public $value;
 58 
 59     /**
 60      * http status code returned in case of error
 61      */
 62     public $errorHttpCode = 400;
 63 
 64     /**
 65      * name of changed attributes. Used when saving model
 66      *
 67      * @var mixed
 68      */
 69     protected $changedAttributes = array();
 70 
 71     /**
 72      * Constructor
 73      *
 74      * @param mixed $modelName
 75      * @return EditableBackend
 76      */
 77     public function __construct($modelClass)
 78     {
 79         if (empty($modelClass)) {
 80             throw new CException(Yii::t('EditableSaver.editable', 'You should provide modelClass in constructor of EditableSaver.'));
 81         }
 82 
 83         $this->modelClass = $modelClass;
 84 
 85         //for non-namespaced models do ucfirst (for backwards compability)
 86         //see https://github.com/vitalets/x-editable-yii/issues/9
 87         if(strpos($this->modelClass, '\\') === false) {
 88             $this->modelClass = ucfirst($this->modelClass);
 89         }
 90     }
 91 
 92     /**
 93      * main function called to update column in database
 94      *
 95      */
 96     public function update()
 97     {
 98         //get params from request
 99         $this->primaryKey = yii::app()->request->getParam('pk');
100         $this->attribute = yii::app()->request->getParam('name');
101         $this->value = yii::app()->request->getParam('value');
102         $this->scenario = yii::app()->request->getParam('scenario');
103 
104         //checking params
105         if (empty($this->attribute)) {
106             throw new CException(Yii::t('EditableSaver.editable','Property "attribute" should be defined.'));
107         }
108         
109         $this->model = new $this->modelClass();
110         
111         $isFormModel = $this->model instanceOf CFormModel;
112         $isMongo = EditableField::isMongo($this->model);
113         
114         if (empty($this->primaryKey) && !$isFormModel) {
115             throw new CException(Yii::t('EditableSaver.editable','Property "primaryKey" should be defined.'));
116         }
117         
118         //loading model
119         if($isMongo) {
120             $this->model = $this->model->findByPk(new MongoID($this->primaryKey));
121         } elseif(!$isFormModel) {
122             $this->model = $this->model->findByPk($this->primaryKey);
123         }
124         
125         if (!$this->model) {
126             throw new CException(Yii::t('EditableSaver.editable', 'Model {class} not found by primary key "{pk}"', array(
127                '{class}'=>get_class($this->model), '{pk}' => is_array($this->primaryKey) ? CJSON::encode($this->primaryKey) : $this->primaryKey)));
128         }
129         
130         //keep parent model for mongo
131         $originalModel = $this->model;
132         
133         //resolve model only for mongo! we should check attribute safety
134         if($isMongo) {
135             $resolved = EditableField::resolveModels($this->model, $this->attribute);
136             $this->model = $resolved['model']; //can be related model now
137             $this->attribute = $resolved['attribute'];
138             $staticModel = $resolved['staticModel'];                
139         } else {
140             $staticModel = $this->model;
141         }
142 
143         //set scenario for main model
144         if($this->scenario) {
145             $originalModel->setScenario($this->scenario);
146         }
147 
148         //is attribute safe
149         if (!$this->model->isAttributeSafe($this->attribute)) {
150             throw new CException(Yii::t('editable', 'Model {class} rules do not allow to update attribute "{attr}"', array(
151                     '{class}'=>get_class($this->model), '{attr}'=>$this->attribute)));
152         }
153 
154         //setting new value
155         $this->setAttribute($this->attribute, $this->value);
156 
157         //validate attribute
158         $this->model->validate(array($this->attribute));
159         $this->checkErrors();
160 
161         //trigger beforeUpdate event
162         $this->beforeUpdate();
163         $this->checkErrors();
164         
165         //remove virtual attributes (which NOT in DB table)
166         if(!$isMongo) {
167             $this->changedAttributes = array_intersect($this->changedAttributes, $originalModel->attributeNames()); 
168             if(count($this->changedAttributes) == 0) {
169                 //can not pass empty array in model->save() method!
170                 $this->changedAttributes = null;
171             }
172         }
173         
174         //saving (no validation, only changed attributes) note: for mongo save all!
175         if($isMongo) {
176             $result = $originalModel->save(false, null);
177         } elseif(!$isFormModel) {
178             $result = $originalModel->save(false, $this->changedAttributes);
179         } else {
180             $result = true;
181         } 
182         if ($result) {
183             $this->afterUpdate();
184         } else {
185             $this->error(Yii::t('EditableSaver.editable', 'Error while saving record!'));
186         }
187     }
188 
189     /**
190      * errors as CHttpException
191      * @param $msg
192      * @throws CHttpException
193      */
194     public function checkErrors()
195     {
196         if ($this->model->hasErrors()) {
197             $msg = array();
198             foreach($this->model->getErrors() as $attribute => $errors) {
199                $msg = array_merge($msg, $errors);
200             }
201             //todo: show several messages. should be checked in x-editable js
202             //$this->error(join("\n", $msg));
203             $this->error($msg[0]);
204         }
205     }
206 
207     /**
208      * errors as CHttpException
209      * @param $msg
210      * @throws CHttpException
211      */
212     public function error($msg)
213     {
214         throw new CHttpException($this->errorHttpCode, $msg);
215     }
216 
217     /**
218     * setting new value of attribute.
219     * Attrubute name also stored in array to save only changed attributes
220     *
221     * @param mixed $name
222     * @param mixed $value
223     */
224     public function setAttribute($name, $value)
225     {
226          $this->model->$name = $value;
227          if(!in_array($name, $this->changedAttributes)) {
228              $this->changedAttributes[] = $name;
229          }
230     }
231 
232     /**
233      * This event is raised before the update is performed.
234      * @param CModelEvent $event the event parameter
235      */
236     public function onBeforeUpdate($event)
237     {
238         $this->raiseEvent('onBeforeUpdate', $event);
239     }
240 
241     /**
242      * This event is raised after the update is performed.
243      * @param CEvent $event the event parameter
244      */
245     public function onAfterUpdate($event)
246     {
247         $this->raiseEvent('onAfterUpdate', $event);
248     }
249 
250     /**
251      * beforeUpdate
252      *
253      */
254     protected function beforeUpdate()
255     {
256         $this->onBeforeUpdate(new CEvent($this));
257     }
258 
259     /**
260      * afterUpdate
261      *
262      */
263     protected function afterUpdate()
264     {
265         $this->onAfterUpdate(new CEvent($this));
266     }
267 }
268 
YiiWheels API documentation generated by ApiGen 2.8.0