come fare l'update di un attributo settato automaticamente?

Oggi mi sono imbattuto in questo problema. Mettete il caso di avere un modello con attributi settati automaticamente in beforeSave




  /**

   * This is invoked before the record is saved.

   * @return boolean whether the record should be saved.

   */

  protected function beforeSave() {

	if (parent::beforeSave()) {

  	if ($this->isNewRecord) {

    	$this->create_time = date('Y-m-d H:i:s', time());

  	}

  	$this->update_time = date('Y-m-d H:i:s', time());

  	$this->updater_id = Yii::app()->user->id;

  	return true;

	} else return false;

  }

Ora, quando nella nostra app andremo a fare un $model->update(array(…), quegli attributi non verranno salvati se non li specificheremo nell’array. E’ molto scomodo doverli includere sempre, d’altro canto mi sembra peggio ancora scrivere una cosa del genere




  /**

   * This is invoked before the record is saved.

   * @return boolean whether the record should be saved.

   */

  protected function beforeSave() {

	if (parent::beforeSave()) {

  	$this->update_time = date('Y-m-d H:i:s', time());

  	$this->updater_id = Yii::app()->user->id;

  	if ($this->isNewRecord) {

    	$this->create_time = date('Y-m-d H:i:s', time());

  	} else $this->update(array('update_time', 'updater_id'));

  	return true;

	} else return false;

  }

L’esempio qui sopra non funziona perché manda in loop Yii.

Se Yii avesse un attributo contenente le opzioni che si stanno salvando dovrei semplicemente aggiungerle, una cosa del genere intendo




  /**

   * This is invoked before the record is saved.

   * @return boolean whether the record should be saved.

   */

  protected function beforeSave() {

	if (parent::beforeSave()) {

  	if ($this->isNewRecord) {

    	$this->create_time = date('Y-m-d H:i:s', time());

  	}

  	$this->update_time = date('Y-m-d H:i:s', time());

   	$this->updater_id = Yii::app()->user->id;

  	array_push($this->updateAttributes, array('update_time', 'updater_id'));

  	return true;

	} else return false;

  }

Insomma, il problema è inserire in corso di update altri attributes oltre a quelli chiamati esplicitamente.

Che ne dite? Voi come risolvereste?

Mmmm in attesa di altre soluzioni, potresti aggiungere tu stesso quel metodo al model attuale.

Non è possibile modificando solo il model, dovrei modificare CActiveRecord per fare in modo che vada a pescare eventuali “aggiunte” agli attributes prima di fare l’update… in pratica servirebbe un parametro dove specificare i parametri aggiuntivi da salvare automaticamente e che venisse pescato prima di chiamare la updatebypk oppure nella getattributes




	public function update($attributes=null)

	{

		if($this->getIsNewRecord())

			throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));

		if($this->beforeSave())

		{

			Yii::trace(get_class($this).'.update()','system.db.ar.CActiveRecord');

			if($this->_pk===null)

				$this->_pk=$this->getPrimaryKey();

			$this->updateByPk($this->getOldPrimaryKey(),$this->getAttributes($attributes));

			$this->_pk=$this->getPrimaryKey();

			$this->afterSave();

			return true;

		}

		else

			return false;

	}


	public function getAttributes($names=true)

	{

		$attributes=$this->_attributes;

		foreach($this->getMetaData()->columns as $name=>$column)

		{

			if(property_exists($this,$name))

				$attributes[$name]=$this->$name;

			else if($names===true && !isset($attributes[$name]))

				$attributes[$name]=null;

		}

		if(is_array($names))

		{

			$attrs=array();

			foreach($names as $name)

			{

				if(property_exists($this,$name))

					$attrs[$name]=$this->$name;

				else

					$attrs[$name]=isset($attributes[$name])?$attributes[$name]:null;

			}

			return $attrs;

		}

		else

			return $attributes;

	}



quindi tutto potrebbe diventare:

nel model:


  protected function beforeSave() {

        if (parent::beforeSave()) {

        if ($this->isNewRecord) {

          $this->create_time = date('Y-m-d H:i:s', time());

        }

        $this->update_time = date('Y-m-d H:i:s', time());

        $this->updater_id = Yii::app()->user->id;

        $this->autoUpdateAttributes = array('update_time', 'updater_id') ;

        return true;

        } else return false;

  }

nel controller o dove ci serve un update qualsiasi:


$model->content = $something;

$model->published = true;

$model->update(array('content', 'published'));

e CActiveRecord sarebbe così:


   public function update($attributes=null)

	{

		if($this->getIsNewRecord())

			throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));

		if($this->beforeSave())

		{

			Yii::trace(get_class($this).'.update()','system.db.ar.CActiveRecord');

			if($this->_pk===null)

				$this->_pk=$this->getPrimaryKey();

			$saveAttributes = CMap::mergeArray( $attributes, $this->autoUpdateAttributes );

$this->updateByPk($this->getOldPrimaryKey(), $this->getAttributes($saveAttributes));

			$this->_pk=$this->getPrimaryKey();

			$this->afterSave();

			return true;

		}

		else

			return false;

	}



col risultato di salvare sia array(‘content’, ‘published’) che array(‘update_time’, ‘updater_id’) ;

Spero di essermi stato spiegato! ;D