zss61890 zss61890 - 5 days ago 5
PHP Question

Using Model Events Listener in Laravel 5

I would like to make sure that I correctly used model events listeners in Laravel 5 and I didn't messed up nothing (listener vs handler?). My solution works fine, but I wonder if I developed according to concept and convention of Laravel 5.

Goal:
Always set $issue->status_id on some value when model is saving.

In app\Providers\EventServiceProvider.php

<?php namespace App\Providers;

...

class EventServiceProvider extends ServiceProvider {

...

public function boot(DispatcherContract $events)
{
parent::boot($events);

Issue::saving('App\Handlers\Events\SetIssueStatus');
}

}


In app\Handlers\Events\SetIssueStatus.php

<?php namespace App\Handlers\Events;

...

class SetIssueStatus {

...

public function handle(Issue $issue)
{
if (something)
{
$issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
}
else
{
$issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
}

// issue_status() is One-to-One relations with IssueType (belongsTo)
$issue->issue_status()->associate($issueStatus);
}

}


Thank you for your time.

Answer

As you said you have a working version and it's a valid one, now that's up to you to figure out if it's ok for you.

Just to clarify I'm not saying that these are better solutions, they are just a valid different way.

Since what you are doing is specific to the Issue model or at least it doesn't seem to be a generic event, you could set it up on your model directly

<?php namespace App;

use Illuminate\Database\Eloquent\Model;
use IssueStatus;

class Issue extends Model {


    protected static function boot()
    {
        parent::boot();

        static::saving(function($issue){
            if (something)
            {   
                $issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
            }
            else 
            {
                $issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
            }

            // issue_status() is One-to-One relations with IssueType (belongsTo)
            $issue->issue_status()->associate($issueStatus);

        });
    }
}

but if your event is indeed a generic one and you want to use it across multiple Models, you could achieve the same thing. You just need to extract the code from the model and use traits (like you do with soft deletes)

First we create our trait(in this case we created on the root of our App) and extract the code, I wrote before, from the model:

<?php namespace App

use IssueStatus;

trait IssueStatusSetter
{
    protected static function boot()
    {
        parent::boot();

        static::saving(function($model){
            if (something)
            {   
                $issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
            }
            else 
            {
                $issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
            }

            // issue_status() is One-to-One relations with IssueType (belongsTo)
            $model->issue_status()->associate($issueStatus);

        });
    }
}

Now on the models where you want to use it, you just import the trait and declare it's use:

<?php namespace App;

use Illuminate\Database\Eloquent\Model;
use IssueStatusSetter;

class Issue extends Model {

    use IssueStatusSetter;

}

Now this last option I showed you it's a generic option you have that you could apply to every Model by just declaring it's use on the top of your model.

Comments