laravel model callbacks after save, before save, etc
Actually, Laravel has real callback before|after save|update|create some model. check this:
https://github.com/laravel/laravel/blob/3.0/laravel/database/eloquent/model.php#L362
the EventListener like saved and saving are the real callbacks
$this->fire_event('saving');
$this->fire_event('saved');
how can we work with that? just assign it to this eventListener example:
\Laravel\Event::listen('eloquent.saving: User', function($user){
$user->saving();//your event or model function
});
Laravel: how to create a function After or Before save|update
Inside your model, you can add a boot() method which will allow you to manage these events.
For example, having User.php model:
class User extends Model
{
public static function boot()
{
parent::boot();
self::creating(function($model){
// ... code here
});
self::created(function($model){
// ... code here
});
self::updating(function($model){
// ... code here
});
self::updated(function($model){
// ... code here
});
self::deleting(function($model){
// ... code here
});
self::deleted(function($model){
// ... code here
});
}
}
You can review all available events over here: https://laravel.com/docs/5.2/eloquent#events
how to know if laravel model values changed on save callback
You can use the isDirty()
method which returns a bool
and getDirty()
which returns an array
with the changed values.
public function save(array $options = array())
{
$changed = $this->isDirty() ? $this->getDirty() : false;
// before save code
parent::save();
// Do stuff here
if($changed)
{
foreach($changed as $attr)
{
// My logic
}
}
}
What's the most reliable way to catch saves and deletes in Laravel 5.2?
The three methods and 4th referred by @joko. There may be more as well but lets focus on the 4 methods.
Let me describe you them one by one:
1) Override the save and delete methods on the model
In this method you are using OOPD method overriding. You are overriding Laravel's interal save
method and adding your additional code by defining your own save
method on top of it. This should be avoided as Laravel keep evolving and it may happen that thing start to fail if major change is done like Suppose in future laravel replace save
method with any other method to save the records. Then again you will have to create another method to override that new method. Also writing code here may grow your model class file. You model may keep handling things like he shouldn't handle(Example: Sending Email). This method should be avoided.
2) Add creating/updating/deleting callbacks in the boot method
Here you are defining code on the Boot method of the Model. This method should only be used if there is much little code/things that you need to handle on event. The drawback of this method is that it make code more complicated and cluttered as you may write all logic in one like like functional programming. Suppose if you have to do some stuff on before creating and after created. You boot
method will grow.
3) Bind an observer in the boot method
This method is pretty good. You create one observer class which handles such stuff that what should happen on Laravel events. It makes code more cleaner and easy to maintain.
Example: Suppose you have to write code in creating
, saving
, saved
, deleting
in these methods. In this case, method 1) and method 2) won't be good practice because in
Method 1: We will have to create this 4 methods and override them as well and support them in future releases of Laravel. In this case, code in your Model will also grow because of overriding this methods
Method 2: In this case your boot
method will grow as well so you Model file will become a junk of code.
In method 1 and 2 also remember that its not responsibility of your Model to do many of the stuff that you going to write. Like sending email when user is created. These codes you may end up writing in created
method.
Suppose now you have scenario where you need to send email to user on created
event as well as you need to make user's entry log user in customer CRM. then you will have to write code for both in same method. Probably, you may not following single responsibility principle there. What should we do in the case? See method 4.
4) Other method suggested by @joko
The scenario that i suggested in method 4's end. You may send email to user and log him in Customer CRM whenever it is created. Then your method will do 2 things(Sending email and logging in CRM). It may not following single responsibility principle. What if better we can decouple both of them. Then comes this method.
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'eloquent.saved: App\User' => 'App\Listeners\SendWelcomeEmailToUser'
'eloquent.saved: App\User' => 'App\Listeners\LogUserInCRM'
];
}
Create two listener classes:
class SendWelcomeEmailToUser
{
public function handle(User $user){
// Write code to send email
}
}
class LogUserInCRM
{
public function handle(User $user){
// Write code to log
}
}
Through this you can separate out codes and make them more cleaner.
I generally prefer this method its mode clean. It also gives you much better idea that what actually happen when event happens. It becomes one single point for Event to Listener mapping.
How to access model attribute from an overrided eloquent save() method? (converting empty input to null)
You should be able to access it using $this:
class Page extends Eloquent {
public function save()
{
$this->sanitize();
parent::save();
}
public function sanitize()
{
foreach($this->getAttributes() as $key => $value)
{
if ( ! $value)
{
$this->{$key} = null;
}
}
}
}
This is untested code, but should work.
Laravel Update Eloquent Field automatically on save
So i think i have the answer here. it is two folds:
- in the event callback you need to update the field in question using the $model->setAttribute($field, $value); function.
- in my generateSku function i was relying on the models relationships to get names etc from child relationships; however on the even the models relationships had not updated at this time, thus the function was using old relationships. Changing this to use the data from the model/table that was being updated rather than its relationships had the desired effect.
All in all the event code now looks like this:
static::saving(function ($model) {
CustomLog::debug(__CLASS__, __FUNCTION__, __LINE__, 'saving model fired');
$model->setAttribute('sku', static::generateSku($model));
});
Ignore the updated event when an Eloquent model is restored
The trait HasLogs
adds a Boolean attribute to the Model
named loggableIsBeingRestored
set to false
by default.
The trait also registers a new listener for restoring
which sets loggableIsBeingRestored
to true
at the begging of the described actions.
Then the updated
listener checks for loggableIsBeingRestored
before proceeding with its actions.
trait HasLogs
{
public bool $loggableIsBeingRestored = false;
public static function bootHasLogs(): void
{
// ...
self::updated(callback: function ($model) {
if (isset($model->loggableIsBeingRestored) && $model->loggableIsBeingRestored) {
// This is a restored event so don't log!
return;
}
self::log($model, 'updated');
});
// ...
self::restored(callback: function ($model) {
self::log($model, 'restored');
$model->loggableIsBeingRestored = false;
});
self::restoring(callback: function ($model) {
$model->loggableIsBeingRestored = true;
});
}
// ...
}
How to save NOW() to the same field in my Laravel Eloquent model every time I save?
You can accomplish this in the saving
event, for which you can register a callback in you model's boot
method:
class User extends Eloquent {
public static function boot()
{
static::saving(function($user)
{
$user->modified = DB::raw('NOW()');
// Alternatively, you can use this:
$user->modified = Carbon\Carbon::now();
});
parent::boot();
}
}
Related Topics
Pass Array Literal to Postgresql Function
How to Override Built-In PHP Function(S)
Algorithm for Generating a Random Number
How to Prevent from Printscreen of My Webpage
How to Remove 'Index.Php' from Url in Codeigniter
Get_Result() Doesn't Work Even MySQLnd Is Enabled
Convert Exponential Number to Decimal in PHP
How to Properly Handle Session and Access Token with Facebook PHP Sdk 3.0
Convert Lat/Longs to X/Y Co-Ordinates
How to Validate a Domain Name Using Regex & PHP
Composer Cannot Download Files
How to Get User Timezone Using Jquery
How to Send Emails with Arabic Content via PHP's Mail Function
Can't Set PHP Cookie on the Same Page