Home » Php » php – laravel hook into Eloquent pre and post save for every model

php – laravel hook into Eloquent pre and post save for every model

Posted by: admin July 12, 2020 Leave a comment

Questions:

I’m new to Laravel and ORM’s in general. How could i hook into Eloquent to fire code before and after a save of any model? I know i can do the following for specific models but i’m looking at figuring out how to do this for every model.

class Page extends Eloquent {

   public function save()
   {
      // before save code 
      parent::save();
      // after save code
   }
}
How to&Answers:

You can create a BaseModel class that extends eloquent and then have all your models extend BaseModel. Here’s an example:

abstract class Elegant extends Eloquent{

/* Save ****************************/
public function preNew() {}
public function postNew() {}
public function preSave() { return true; }
public function postSave() {}
public function save($validate=true, $preSave=null, $postSave=null)
{
    $newRecord = !$this->exists;
    if ($validate)
        if (!$this->valid()) return false;
    if($newRecord)
        $this->preNew();

    $before = is_null($preSave) ? $this->preSave() : $preSave($this);
      // check before & valid, then pass to parent
    $success = ($before) ? parent::save() : false;
    if ($success)
        is_null($postSave) ? $this->postSave() : $postSave($this);
    if($newRecord)
        $this->postNew();
    return $success;
}
public function onForceSave(){}
public function forceSave($validate=true, $rules=array(), $messages=array(), $onForceSave=null)
{
    if ($validate)
        $this->valid($rules, $messages);
     $before = is_null($onForceSave) ? $this->onForceSave() : $onForceSave($this);  // execute onForceSave
     return $before ? parent::save() : false; // save regardless of the result of validation
}

/** Soft Delete ****************************/
public function preSoftDelete() {  return true;  }
public function postSoftDelete()  { }
public function softDelete($val = true, $preSoftDelete=null, $postSoftDelete=null)
{
    if ($this->exists)
    {
        $before = is_null($preSoftDelete) ? $this->preSoftDelete() : $preSoftDelete($this);
        $success = null;
        if($before) {
            $this->set_attribute(static::$softDelete, $val);
            $success = $this->save(false);
        }
        else
            $success = false;
        if ($success)
        {
            is_null($postSoftDelete) ? $this->postSoftDelete() : $postSoftDelete($this);
         }
        return $success;
    }
}

/** Hard Delete ****************************/
public function preDelete()  { return true;}
public function postDelete(){}
public function delete( $preDelete=null, $postDelete=null)
{
    if ($this->exists)
    {
        $before = is_null($preDelete) ? $this->preDelete() : $preDelete($this);
        $success = ($before) ? parent::delete() : false;
        if ($success)
        {
            is_null($postDelete) ? $this->postDelete() : $postDelete($this);
         }
        return $success;
    }
}
}

Answer:

There’s even a better way of accomplishing this! Create an observer for, lets say a model called House:

class HouseObserver {

    public function saving(House $house) {
        // Code before save
    }

    public function saved(House $house) {
        // Code after save
    }

}

Now register the observer with the House model by adding the line House::observe(new HouseObserver) somewhere. The line can be added in the boot method of the model:

class House extends Eloquent {

    // Lots of model code

    public static function boot() {
        parent::boot();
        self::observe(new HouseObserver);
    }

}

More info can be found here.

Answer:

Using laravel models own life cycle events may solve this easy

/**
 * model life cycle event listeners
 */
public static function boot(){
    parent::boot();

    static::creating(function ($instance){
        //
    });

    static::created(function ($instance){
        //
    });
}