LaravelPackages.net
Acme Inc.
Toggle sidebar
artificertech/laravel-relationship-events

Missing relationship events for Laravel

18.800
12
v0.2.1
About artificertech/laravel-relationship-events

artificertech/laravel-relationship-events is a Laravel package for missing relationship events for laravel. It currently has 12 GitHub stars and 18.800 downloads on Packagist (latest version v0.2.1). Install it with composer require artificertech/laravel-relationship-events. Discover more Laravel packages by artificertech or browse all Laravel packages to compare alternatives.

Last updated

Laravel Relationship Events

Missing relationship events for Laravel

This package was intitally forked from https://github.com/chelout/laravel-relationship-events which is not being actively developed. This package is a different take on the original idea that allows relationship event listeners to be created on a per-relationship basis

This package is still in development. Feel free to contribute by submitting a pull request

Build Status Total Downloads Latest Stable Version License

Install

  1. Install package with composer

Latest Release:

Currently there are no releases for this project as it is still in development.

composer require artificertech/laravel-relationship-events

Development branch:

composer require artificertech/laravel-relationship-events:dev-master
  1. Add the HasRelationshipEvents trait to your model

use Artificertech\RelationshipEvents\Concerns\HasRelationshipEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasRelationshipEvents;

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

        /**
         * hasOne
         */
        static::hasOneSaved('profile', function ($user, $profile) {
            dump('hasOneSaved', $user, $profile);
        });
    }

    public function profile()
    {
        return $this->hasOne(Profile::class)->withEvents();
    }

}

For all saving, attaching, creating, etc events that are fired before the operation takes place you may return false from the event listener to cancel the operation


use Artificertech\RelationshipEvents\Concerns\HasRelationshipEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasRelationshipEvents;

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

        /**
         * hasMany
         */
        static::hasManyCreating('posts', function ($user, $post) {
            if ($post->name == 'badName') return false;
        });
    }

    public function posts()
    {
        return $this->hasMany(Post::class)->withEvents();
    }

}
  1. Dispatchable relationship events. It is possible to fire event classes via $dispatchesEvents properties

use Artificertech\RelationshipEvents\Concerns\HasRelationshipEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasRelationshipEvents;

    protected $dispatchesEvents = [
        'postsCreating' => UserPostsCreating::class,
        'postsCreated' => UserPostsCreated::class,
        'postsSaving' => UserPostsSaving::class,
        'postsSaved' => UserPostsSaved::class,
    ];

    public function posts()
    {
        return $this->hasMany(Post::class)->withEvents();
    }

}

Observers

It is possible to use relationship events in Laravel observers classes Usage is very simple. Define observer class:

namespace App\Observer;

class UserObserver
{
    /**
     * Handle the User "postsCreating" event.
     *
     * @param \App\Models\User $user
     * @param \App\Models\Post $post
     *
     * @return void
     */
    public function postsCreating(User $user, Post $post)
    {
        Log::info("Creating post: {$post->name} for user {$user->name}.");
    }

    /**
     * Handle the User "postsCreated" event.
     *
     * @param \App\Models\User $user
     * @param \App\Models\Post $post
     *
     * @return void
     */
    public function postsCreated(User $user, Post $post)
    {
        Log::info("Post: {$post->name} for user: {$user->name} has been created.");
    }

    /**
     * Handle the User "postsCreating" event.
     *
     * @param \App\Models\User $user
     * @param \App\Models\Post $post
     *
     * @return void
     */
    public function postsSaving(User $user, Post $post)
    {
        Log::info("Saving post: {$post->name} for user {$user->name}.");
    }

    /**
     * Handle the User "postsCreated" event.
     *
     * @param \App\Models\User $user
     * @param \App\Models\Post $post
     *
     * @return void
     */
    public function postsSaved(User $user, Post $post)
    {
        Log::info("Post: {$post->name} for user: {$user->name} has been saved.");
    }
}

Detecting observable events

the laravel-relationship-events package cannot automatically detect relationship events that you want to observe. Please define them in your model class like so:

class User extends Model
{
    use HasRelationshipEvents;

    /**
     * User exposed observable events.
     *
     * These are extra user-defined events observers may subscribe to.
     *
     * @var array
     */
    protected $observables = [
        'postsCreating',
        'postsCreated',
        'postsSaving',
        'postsSaved',
    ];

    public function posts()
    {
        return $this->hasMany(Post::class)->withEvents();
    }

}

Don't forget to register an observer in the boot method of your AppServiceProvider:

namespace App\Providers;

use App\Models\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
// ...
    public function boot()
    {
        User::observe(UserObserver::class);
    }
// ...
}

And now just create profile for user:

// ...
$user = factory(User::class)->create([
    'name' => 'John Smith',
]);

// Create profile and assosiate it with user
// This will fire two events hasOneCreating, hasOneCreated
$user->post()->create([
    'name' => 'My first post!',
]);
// ...

Customizing the event name

By default the relationship event name is equal to the relationship function name with the action taking place in camel case. For example if you have a HasOne relationship "profile" then the event names would be "profileCreating", "profileCreated", "profileSaving", "profileSaved".

You may customize the event name by passing the relationship name into the withEvents() function as a string. For example:

class User extends Model
{
    use HasRelationshipEvents;

    public function posts()
    {
        return $this->hasMany(Post::class)->withEvents('userPost');
    }

}

will fire "userPostCreating", "userPostCreated", "userPostSaving", "userPostSaved" events

Relationship Specific info

Each relationship as slightly different events. For example the belongsTo relationship fires {relationship}Associating, {relationship}Associated, {relationship}Dissociating, and {relationship}Dissociated events

Todo

  • Fix Automated Tests
  • Add documentation for ManyToMany type events (these events can be handled by the built in pivot models and do not need this package)
  • Non-Default event name tests
  • Event Dispatcher Tests
  • Event Listener Exception Tests
  • HasOneThrough & HasManyThrough
  • New HasOneOfMany relationship?
Comments