2013-08-27 8 views
6

Sto sollevando un evento Yii su beforeSave del modello, che deve essere attivato solo se viene modificata una proprietà specifica del modello.Yii all'aggiornamento, rileva se una proprietà AR specifica è stata modificata su beforeSave()

L'unico modo in cui posso pensare a come farlo al momento è creando un nuovo oggetto AR e interrogando il DB per il vecchio modello usando il PK corrente, ma questo non è ottimizzato molto bene.

Ecco quello che ho in questo momento (si noti che il mio tavolo non dispone di un PK, è per questo che interrogo da tutti gli attributi, oltre a quello che sto paragonando contro - da qui la funzione unset):

public function beforeSave() 
{ 
    if(!$this->isNewRecord){ // only when a record is modified 
     $newAttributes = $this->attributes; 
     unset($newAttributes['level']); 
     $oldModel = self::model()->findByAttributes($newAttributes); 

     if($oldModel->level != $this->level) 
      // Raising event here 
    } 
    return parent::beforeSave(); 
} 

Esiste un approccio migliore? Forse memorizzare le vecchie proprietà in una nuova proprietà locale in afterFind()?

risposta

12

È necessario memorizzare i vecchi attributi in una proprietà locale nella classe AR in modo da poter confrontare gli attributi correnti con quelli vecchi in qualsiasi momento.

Passaggio 1. Aggiungere una nuova proprietà alla classe AR:

// Stores old attributes on afterFind() so we can compare 
// against them before/after save 
protected $oldAttributes; 

Fase 2. Sostituire Yii afterFind() e memorizzare gli attributi originali immediatamente dopo che sono stati recuperati.

public function afterFind(){ 
    $this->oldAttributes = $this->attributes; 
    return parent::afterFind(); 
} 

Fase 3. Confronta gli attributi vecchi e nuovi in ​​beforeSave/afterSave o in qualsiasi altro posto che desideri all'interno della classe AR. Nell'esempio sotto stiamo controllando se la proprietà chiamata 'level' è cambiata.

public function beforeSave() 
{ 
    if(isset($this->oldAttributes['level']) && $this->level != $this->oldAttributes['level']){ 

      // The attribute is changed. Do something here... 

    } 

    return parent::beforeSave(); 
} 
+1

Questo è davvero l'unico modo "pulito" per farlo in Yii. Quello che ho fatto è stato implementare un ActiveRecord derivato che ha incorporato quella funzionalità e lo rende disponibile per tutti i miei modelli. Molto più facile che farlo di nuovo ogni volta. Ho anche dato metodi come "getIsChanged()" e "getChangedProperties()" e così via. – Blizz

0

È possibile memorizzare le vecchie proprietà con campi nascosti all'interno del modulo di aggiornamento invece di caricare nuovamente il modello.

0

Proprio in una linea

$ changedArray = array_diff_assoc ($ this-> attributi, $ this-> oldAttributes);

foreach($changedArray as $key => $value){ 

    //What ever you want 
    //For attribute use $key 
    //For value use $value 

} 

Nel tuo caso si desidera utilizzare if ($ == chiave 'livello') all'interno del foreach