AnatolyRugalev / yii-insertDelayedBehavior

1 stars 1 forks source link

Fix beforeSave() call #2

Open shoaibi opened 11 years ago

shoaibi commented 11 years ago

Context: (YF Forum PM conversation):

Me:

When using this behavior in combination with EEnsureNull (git@github.com:yiiext/ensure-null-behavior.git) I get an error:

PHP warning

Missing argument 1 for EEnsureNullBehavior::beforeSave()

/home/shoaibi/public_html/www.project.com/protected/extensions/behaviours/ensure-null-behavior/EEnsureNullBehavior.php(17)

05 * Ensures no empty AR property value is written to DB if property's default is `NULL`.
06 *
07 * @version 1.0.1
08 * @author creocoder <creocoder@gmail.com>
09 */
10 class EEnsureNullBehavior extends CActiveRecordBehavior
11 {
12     /**
13     * @var bool Ensure nulls on update
14     */
15     public $useOnUpdate=true;
16 
17     public function beforeSave($event)
18     {
19         $owner=$this->getOwner();
20 
21         if($owner->getIsNewRecord() || $this->useOnUpdate)
22         {
23             foreach($owner->getTableSchema()->columns as $column)
24             {
25                 if($column->allowNull && trim($owner->getAttribute($column->name))==='')
26                     $owner->setAttribute($column->name,null);
27             }
28         }
29     }

Stack Trace

#0      
 unknown(0): EEnsureNullBehavior->beforeSave()

#1      
–  /home/shoaibi/public_html/yii-1.1.12.b600af/framework/base/CComponent.php(261): call_user_func_array(array(EEnsureNullBehavior, "beforeSave"), array())
256         if($this->_m!==null)
257         {
258             foreach($this->_m as $object)
259             {
260                 if($object->getEnabled() && method_exists($object,$name))
261                     return call_user_func_array(array($object,$name),$parameters);
262             }
263         }
264         if(class_exists('Closure', false) && $this->canGetProperty($name) && $this->$name instanceof Closure)
265             return call_user_func_array($this->$name, $parameters);
266         throw new CException(Yii::t('yii','{class} and its behaviors do not have a method or closure named "{name}".',

#2      
+  /home/shoaibi/public_html/yii-1.1.12.b600af/framework/db/ar/CActiveRecord.php(226): CComponent->__call("beforeSave", array())

#3      
–  /home/shoaibi/public_html/www.project.com/protected/extensions/behaviours/insert-delayed/InsertDelayedBehavior.php(34): CActiveRecord->__call("beforeSave", array())
29 
30     public function insertDelayed($attributes)
31     {
32         if(!$this->owner->getIsNewRecord())
33             throw new CDbException(Yii::t('yii','The active record cannot be inserted to database because it is not new.'));
34         if(is_null($this->beforeSaveFunction) || $this->owner->{$this->beforeSaveFunction}())
35         {
36             Yii::trace(get_class($this->owner).'.insertDelayed()','application.behaviors.InsertDelayedBehavior');
37             $builder=$this->owner->getCommandBuilder();
38             $table=$this->owner->getMetaData()->tableSchema;
39             $command=$builder->createInsertCommand($table,$this->owner->getAttributes());

#4      
–  /home/shoaibi/public_html/www.project.com/protected/extensions/behaviours/insert-delayed/InsertDelayedBehavior.php(34): Notification->beforeSave()
29 
30     public function insertDelayed($attributes)
31     {
32         if(!$this->owner->getIsNewRecord())
33             throw new CDbException(Yii::t('yii','The active record cannot be inserted to database because it is not new.'));
34         if(is_null($this->beforeSaveFunction) || $this->owner->{$this->beforeSaveFunction}())
35         {
36             Yii::trace(get_class($this->owner).'.insertDelayed()','application.behaviors.InsertDelayedBehavior');
37             $builder=$this->owner->getCommandBuilder();
38             $table=$this->owner->getMetaData()->tableSchema;
39             $command=$builder->createInsertCommand($table,$this->owner->getAttributes());

#5      
–  /home/shoaibi/public_html/www.project.com/protected/extensions/behaviours/insert-delayed/InsertDelayedBehavior.php(25): InsertDelayedBehavior->insertDelayed(null)
20     public $onFailSimpleInsert = true;
21 
22     public function saveDelayed($runValidation=true,$attributes=null)
23     {
24         if(!$runValidation || $this->owner->validate($attributes))
25             return $this->owner->getIsNewRecord() ? $this->insertDelayed($attributes) : $this->owner->update($attributes);
26         else
27             return false;
28     }
29 
30     public function insertDelayed($attributes)

#6      
 unknown(0): InsertDelayedBehavior->saveDelayed()

#7      
–  /home/shoaibi/public_html/yii-1.1.12.b600af/framework/base/CComponent.php(261): call_user_func_array(array(InsertDelayedBehavior, "saveDelayed"), array())
256         if($this->_m!==null)
257         {
258             foreach($this->_m as $object)
259             {
260                 if($object->getEnabled() && method_exists($object,$name))
261                     return call_user_func_array(array($object,$name),$parameters);
262             }
263         }
264         if(class_exists('Closure', false) && $this->canGetProperty($name) && $this->$name instanceof Closure)
265             return call_user_func_array($this->$name, $parameters);
266         throw new CException(Yii::t('yii','{class} and its behaviors do not have a method or closure named "{name}".',

#8      
–  /home/shoaibi/public_html/yii-1.1.12.b600af/framework/db/ar/CActiveRecord.php(226): CComponent->__call("saveDelayed", array())
221         {
222             $this->getDbCriteria()->mergeWith($scopes[$name]);
223             return $this;
224         }
225 
226         return parent::__call($name,$parameters);
227     }
228 
229     /**
230      * Returns the related record(s).
231      * This method will return the related record(s) of the current record.

Setting beforeSave of this behavior to null results in:
2012/12/10 04:09:54 [error] [app.C:Ticket.F:add.L:116.S:/home/shoaibi/public_html/www.project.com/protected/controllers/TicketController.php] Exception when saving data: 
Message:
'Notification and its behaviors do not have a method or closure named \"afterInsertDelayed\".'

Trace:
'#0 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/db/ar/CActiveRecord.php(226): CComponent->__call(\'afterInsertDela...\', Array)
#1 /home/shoaibi/public_html/www.project.com/protected/extensions/behaviours/insert-delayed/InsertDelayedBehavior.php(65): CActiveRecord->__call(\'afterInsertDela...\', Array)
#2 /home/shoaibi/public_html/www.project.com/protected/extensions/behaviours/insert-delayed/InsertDelayedBehavior.php(65): Notification->afterInsertDelayed()
#3 /home/shoaibi/public_html/www.project.com/protected/extensions/behaviours/insert-delayed/InsertDelayedBehavior.php(25): InsertDelayedBehavior->insertDelayed(NULL)
#4 [internal function]: InsertDelayedBehavior->saveDelayed()
#5 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/base/CComponent.php(261): call_user_func_array(Array, Array)
#6 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/db/ar/CActiveRecord.php(226): CComponent->__call(\'saveDelayed\', Array)
#7 /home/shoaibi/public_html/www.project.com/protected/models/Notification.php(308): CActiveRecord->__call(\'saveDelayed\', Array)
#8 /home/shoaibi/public_html/www.project.com/protected/models/Notification.php(308): Notification->saveDelayed()
#9 /home/shoaibi/public_html/www.project.com/protected/models/Notification.php(321): Notification::add(\'notice\', \'<a href=\"https:...\', NULL, NULL, \'2\', NULL, NULL, NULL)
#10 /home/shoaibi/public_html/www.project.com/protected/models/Ticket.php(748): Notification::addForSupportTeam(\'notice\', \'<a href=\"https:...\', \'2\')
#11 /home/shoaibi/public_html/www.project.com/protected/models/Ticket.php(286): Ticket::_notify(\'89\', Object(Ticket), \'new\')
#12 /home/shoaibi/public_html/www.project.com/protected/controllers/TicketController.php(116): Ticket::add(Object(CreateOrUpdateTicketForm))
#13 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/actions/CInlineAction.php(50): TicketController->actionCreate()
#14 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/CController.php(309): CInlineAction->runWithParams(Array)
#15 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/filters/CFilterChain.php(134): CController->runAction(Object(CInlineAction))
#16 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/widgets/CFilterWidget.php(71): CFilterChain->run()
#17 /home/shoaibi/public_html/www.project.com/protected/filters/RbacFilter.php(11): CFilterWidget->filter(Object(CFilterChain))
#18 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/filters/CFilterChain.php(131): RbacFilter->filter(Object(CFilterChain))
#19 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/CController.php(292): CFilterChain->run()
#20 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/CController.php(266): CController->runActionWithFilters(Object(CInlineAction), Array)
#21 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/CWebApplication.php(283): CController->run(\'create\')
#22 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/web/CWebApplication.php(142): CWebApplication->runController(\'ticket/create\')
#23 /home/shoaibi/public_html/yii-1.1.12.b600af/framework/base/CApplication.php(162): CWebApplication->processRequest()
#24 /home/shoaibi/public_html/www.project.com/content/index.php(14): CApplication->run()
#25 {main}'
in /home/shoaibi/public_html/www.project.com/protected/helpers/SLog.php (20)
in /home/shoaibi/public_html/www.project.com/protected/models/Ticket.php (301)
in /home/shoaibi/public_html/www.project.com/protected/controllers/TicketController.php (116)
in /home/shoaibi/public_html/www.project.com/protected/filters/RbacFilter.php (11)
in /home/shoaibi/public_html/www.project.com/content/index.php (14)

If possible, i would really like to still use EnsureNull behavior too.

Anatoly:

As you see, CActiveRecord's beforeSave does not require any params: Class reference[ http://www.yiiframework.com/doc/api/1.1/CActiveRecord#beforeSave-detail ] If you need to pass something into other behavior, you can set another name for beforeSaveFunction property and call from this function.

Me:

You are right on your argument however all behaviors must extend CBehavior and the ensure null behavior extends CActiveRecordBehavior which has a different signature for beforeSave: http://www.yiiframew...foreSave-detail

I could ofcourse create a new function and just pass a new CEvent object to parent::beforeSave() to resolve this but won't that be hackish? Is there a way to counter this?

You extend from CBehavior instead of CActiveRecordBehavior. Is there another reason for that except being able to override the save() function by delayed method?

Anatoly:

I agree with you about CActiveRecordBehavior. I will fix it

AnatolyRugalev commented 11 years ago

Tried to fix it in commit https://github.com/AnatolyRugalev/yii-insertDelayedBehavior/commit/e25fa06f0212a7202164206c61cb088563245927

Check this out with EnsureNullBehavior

shoaibi commented 11 years ago

This seems to be fixed as I no longer get the error mentioned before but i can't do extensive testing as i only have innodb used througout my projects. May be keep it open for few weeks and close if no one else complains?

AnatolyRugalev commented 11 years ago

Ok. Maybe I will check it myself if I have some time