IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

aka Esdeveniments Laravel o també Application Hooks. Documentació oficial:

https://laravel.com/docs/master/events

Introducció

Els esdeveniments Laravel proporcionen un implementació simple del patró de disseny observer permeten la subscripció i escolta d'esdeveniments a la nostra aplicació

Per què utilitzar esdeveniments

Pot ser molt útil per crear codi més DRY per exemple:

https://laracasts.com/lessons/use-events

On veiem com evitem codi repetit als controladors i també evitem que els controladors tinguin més responsabilitats de les que pertoquen (vegeu Single Responsability Principle).

Un altre exemple típic, les accions a executar un cop s'ha logat un usuari:

Event::listen('user.login', function($user)
{
    $user->last_login = new DateTime;
    $user->save();
});

$event = Event::fire('user.login', array($user));

Executant "només":

$event = Event::fire('user.login', array($user));

Al controlador complim tan el Single Responsability Principle com Open Closed ja que no haurem de modificar el controlador cada cop que decidim realitzar una tasca adicional durant el login de l'usuari.

En aquest sentit és molt interessant el vídeo:

https://laracasts.com/series/whip-monstrous-code-into-shape/episodes/3

I tota la sèrie a la que pertany que tracta sobre com evitar objectes God, és a dir objectes que tenen molt codi i el que es pitjor moltes responsabilitats. En aquest cas s'utilitzen els esdeveniments com una opció possible.

Registre

El registre dels event listeners es realitza al fitxer EventServiceProvider al array listen:

/**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'App\Events\EventName' => [
            'App\Listeners\EventListener',
        ],
    ];

Cada element de l'array associatiu representa un parell de valors esdeveniment/listener:

  • Esdeveniments: són la clau de l'array associatiu. Una classe de tipus esdeveniment és simplement un contenidor de dades que emmagatzema la informació relacionada amb l'esdeveniment. En cap cas l'esdeveniment executa accions/mètodes. És el típic objecte contenidor semblant als objecte POJO de Java sense lògica d'aplicació. A partir de Laravel 5 els esdeveniments es guarden a la carpeta app/Events
  • Listeners: són els valor de l'array associatiu. A partir de Laravel 5 els esdeveniments es guarden a la carpeta app/Listeners. Els listeners tenen una classe handle que és l'encarregada d'executar la lògica/acció relacionada amb l'esdeveniment.

Creació

Artisan ens ofereix múltiples generadors de codi relacionats amb els esdeveniments de Laravel:

$ php artisan | grep event          
event
 event:generate      Generate the missing events and listeners based on registration
 make:event          Create a new event class
 make:listener       Create a new event listener class

Com podeu observar tenim tres comandes:

$ php artisan make:event MyEvent

Crea a partir d'un stub/plantilla un esdeveniment a la carpeta app/Events amb el nom de fitxer i classe MyEvent

$ php artisan make:listener MyListener

Crea a partir d'un stub/plantilla un listener a la carpeta app/Listeners amb el nom de fitxer i classe MyListener.

Amb

$ php artisan event:generate 

es creen tant els esdeviments com els listeners a partit del declarat a l'array $listen del provider EventServiceProvider.

Esdeveniments

Una event class (classe esdeveniment) és simplement un contenidor de dades que conté la informació de l'esdeveniment. Vegeu un exemple:

  • Esdeveniment PodcastWasPurchased que és l'esdeveniment que es dispara quan un usuari compra un podcast

Amb Laravel un cop hem executat:

$ php artisan make:event PodcastWasPurchased

L'esdeveniment pot ser similar a:

<?php

namespace App\Events;

use App\Podcast;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;

class PodcastWasPurchased extends Event
{
    use SerializesModels;

    public $podcast;

    /**
     * Create a new event instance.
     *
     * @param  Podcast  $podcast
     * @return void
     */
    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast;
    }
}

Com podeu veure l'objecte no conté cap lògica i simplement mitjançant la injecció de dependències conté un Model Eloquent amb el podcast que s'ha comprat. El trait SerializesModels facilita la serialització (persistència temporal de l'objecte) de l'objecte.

Listeners

Amb:

$ php artisan make:listener

podem crear l'esquelet d'un listener. Continuant amb l'exemple de la compra d'un podcast:

<?php

namespace App\Listeners;

use App\Events\PodcastWasPurchased;

class EmailPurchaseConfirmation
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  PodcastWasPurchased  $event
     * @return void
     */
    public function handle(PodcastWasPurchased $event)
    {
        // Access the podcast using $event->podcast...
    }
}

Com podeu veure ha de contenir un mètode handler que serà el mètode que s'executarà al ocorre l'esdeveniment (el que es coneix com un event handler). Observeu com es passa l'objecte esdeveniment com una injecció de dependències per mètode type-hinted

Per aturar la propagació d'un esdeveniment cal tornar false al mètode handler.

Executar els handlers amb una cua

Simplement cal implementar la interfície ShouldQueue. Un exemple:

<?php

namespace App\Listeners;

use App\Events\PodcastWasPurchased;
use Illuminate\Contracts\Queue\ShouldQueue;

class EmailPurchaseConfirmation implements ShouldQueue
{
    //
}

Amb això Laravel ja s'encarregarà d'executar el handler de l'esdeveniment en segon terme.

Disparant esdeveniments

https://laravel.com/docs/master/events#firing-events

3 opcions:

  • Utilitzar facade Event i executar el mètode fire
  • Injectar dependència objecte event i executar esdeveniment fire
  • Utilitzar el Laravel Helper event

Un exemple:

<?php

namespace App\Http\Controllers;

use Event;
use App\Podcast;
use App\Events\PodcastWasPurchased;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $userId
     * @param  int  $podcastId
     * @return Response
     */
    public function purchasePodcast($userId, $podcastId)
    {
        $podcast = Podcast::findOrFail($podcastId);

        // Purchase podcast logic...

        Event::fire(new PodcastWasPurchased($podcast));
    }
}

Amb helper:

event(new PodcastWasPurchased($podcast));


I finalment podeu veure un exemple de com Injectar dependència objecte event i executar esdeveniment fire a:

TODO

Broadcasting Events

Vegeu Laravel Broadcasting Events

Facades

Un exemple de juguet de com fer-ho tot al fitxer routes.php i només amb Facades:

Event:fire('listen', function() {
       //Event handler here
});

Event:fire('event');

Recursos:

Tutorials i documentació externa

  • Screencast de Taylor Otwell a Laracast:
  • Exemple amb Laravel 4 però explicant quan utilitzar Events:
  • Un altre screencast sobre com utilitzar els Esdeveniments:

Vegeu també

Enllaços externs