Code Monkey home page Code Monkey logo

laravel-relationship-events's Introduction

Laravel Relationship Events

Missing relationship events for Laravel

Build Status Total Downloads Latest Stable Version License

Install

  1. Install package with composer

Stable branch:

composer require chelout/laravel-relationship-events

Development branch:

composer require chelout/laravel-relationship-events:dev-master
  1. Use necessary trait in your model.

Available traits:

  • HasOneEvents
  • HasBelongsToEvents
  • HasManyEvents
  • HasBelongsToManyEvents
  • HasMorphOneEvents
  • HasMorphToEvents
  • HasMorphManyEvents
  • HasMorphToManyEvents
  • HasMorphedByManyEvents
use Chelout\RelationshipEvents\Concerns\HasOneEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasOneEvents;

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

        /**
         * One To One Relationship Events
         */
        static::hasOneSaved(function ($parent, $related) {
            dump('hasOneSaved', $parent, $related);
        });

        static::hasOneUpdated(function ($parent, $related) {
            dump('hasOneUpdated', $parent, $related);
        });
    }

}
use Chelout\RelationshipEvents\Concerns\HasMorphToManyEvents;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasMorphToManyEvents;

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

        /**
         * Many To Many Polymorphic Relations Events.
         */
        static::morphToManyAttached(function ($relation, $parent, $ids, $attributes) {
            dump('morphToManyAttached', $relation, $parent, $ids, $attributes);
        });

        static::morphToManyDetached(function ($relation, $parent, $ids) {
            dump('morphToManyDetached', $relation, $parent, $ids);
        });
    }

    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }

}
  1. Dispatchable relationship events. It is possible to fire event classes via $dispatchesEvents properties and adding HasDispatchableEvents trait:
use Chelout\RelationshipEvents\Concerns\HasOneEvents;
use Chelout\RelationshipEvents\Traits\HasDispatchableEvents;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasDispatchableEvents;
    use HasOneEvents;

    protected $dispatchesEvents = [
        'hasOneSaved' => HasOneSaved::class,
    ];

}

Relationships

Observers

Starting from v0.4 it is possible to use relationship events in Laravel observers classes Usage is very simple. Let's take User and Profile classes from One To One Relations, add HasRelationshipObservables trait to User class. Define observer class:

namespace App\Observer;

class UserObserver
{
    /**
     * Handle the User "hasOneCreating" event.
     *
     * @param \App\Models\User $user
     * @param \Illuminate\Database\Eloquent\Model $related
     *
     * @return void
     */
    public function hasOneCreating(User $user, Model $related)
    {
        Log::info("Creating profile for user {$related->name}.");
    }

    /**
     * Handle the User "hasOneCreated" event.
     *
     * @param \App\Models\User $user
     * @param \Illuminate\Database\Eloquent\Model $related
     *
     * @return void
     */
    public function hasOneCreated(User $user, Model $related)
    {
        Log::info("Profile for user {$related->name} has been created.");
    }
}

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->profile()->create([
    'phone' => '8-800-123-45-67',
    'email' => '[email protected]',
    'address' => 'One Infinite Loop Cupertino, CA 95014',
]);
// ...

Todo

  • Tests, tests, tests

laravel-relationship-events's People

Contributors

alvin-nt avatar chelout avatar giekus avatar laravel-shift avatar nhedger avatar saleem-hadad avatar waltoncon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-relationship-events's Issues

Problem with modify data before updating hasOne model.

Hello, I have a problem with package, i don't know, maybe I'm doing something wrong.

I have bootable trait bootConvertable with HasOneUpdating with anonymous function and two parameters, $parent and $model like in your documentation. When I dumping $model, everything is ok, working, but after change some values in model, this is not saved to the database (with laravel creating/updating etc. is ok). Example:

Method in trait which is used in User model:

protected static function bootConvertable()
{
    static::hasOneUpdating(function ($parent, $model) {
        $model->account_to_pay = '21122121221212121212121221';
    });
}

Parent is User model with relation HasOne to UserProfile model. account_to_pay (is column in UserProfile) is not changed/saved to the database.

Could someone help with that? I don't know if problem is with other relations, I'm trying this relation for now.

Events do not fire when Nova UI is used.

This package is great, does everything we need, except in Laravel Nova. When I use the Attach or Detach buttons on the Nova UI for any of my belongsToMany relationships, nothing fires, no events.

The same relationships with no code changes work great outside of Nova, and I get my events in my observer class for. In jobs running on the schedule, and even down in tinker on the command line. The events fire.

public function belongsToManyAttached($relation, Website $website, $ids)

and

public function belongsToManyDetached($relation, Website $website, $ids)

Website is the class I am observing.

Using HasRelationshipObservables trait in multiple models causes double events to be fired in tests

When adding the HasRelationshipObservables trait to multiple models, the tests often fail, because of observers receiving the event twice.

For eg. a user and a group model with HasRelationshipObservables. With two observers that subscribe to belongsToManyAttached both.

trait HasRelationshipObservables
{
    /**
     * @var array
     */
    protected static $relationshipObservables = [];

    /**
     * Initialize relationship observables.
     *
     * @return void
     */
    public static function bootHasRelationshipObservables()
    {
         ......gets the methods

        static::mergeRelationshipObservables($methods);
    }

Static properties will most of the time in tests never be reset, because of how PHPUnit works. When booting HasRelationshipObservables, then it merges the $methods with the static $relationshipObservables. This causes the observer to be fire multiple times in tests where the static property is never reset.

A solution would be to set $relationshipObservables to an empty array in the bootHasRelationshipObservables. Anyone expiring the same issues?

distinguishing multiple relationships in same model

Hello,

i have a model with 2 belongsToMany relationships, so this code :

static::belongsToManyDetached(function($relation,$parent,$ids){ });

catch the 2 relationships when detached and i can't figure how to distinguish which one fired the event.

EDIT:

i was expecting $relation to return the class name of the target model, but in my case i get "insertUpdateData" .
Now i think this is the name of a function from a CMS i use that update relationship data directly so the event is not aware of the target model.
So this can be an issue of the CMS.

New package to replace this one

I recently needed the functionality of this package but with some adjustments. I decided to fork and the rewrite this package with a different set of functionality since this package no longer seems to be under active development.

The main benefit of this new package is that it allows you to fire a different set of events per relationship or not fire events at all for specific events.

For example lets say you have a User model which hasMany Posts and hasMany Comments. With my package you can fire postsCreating, postsCreated, postsSaving, and postsSaved events and not fire any events on the comments relationship.

The package is still in development so I haven't made any official releases of it but I have tested the existing functionality.

Please check it out here: https://github.com/artificertech/laravel-relationship-events

Also big thanks to @chelout and everyone else who contributed to the existing package. I have made sure to mention you as the original package creator in the README

Fire detach without ids

Hello, this package is useful for my project. But, I have a problem in detach function.
I call detach() without any parameter to detach large number of ids, which will over 65535 of PDO limit, and want to record their events.
I think $result = parent::detach($ids, $touch) this can be modified by check the parameters which user pass, like:

public function detach($ids = null, $touch = true)
  {
      // Check parameters
      $sendIds = (! empty($ids));
      ....
      if ($result = parent::detach(($sendIds) ? $ids : null, $touch)) {
          ....

If there are any further information or solution, please kindly to tell me. Thank you.

When the primary key is UUID, not ID

Hello, I have a problem with package,When the primary key is UUID, not ID,This can lead to bugs
public function detach($ids = null, $touch = true)
{
// Get detached ids to pass them to event
$ids = $ids ?? $this->parent->{$this->getRelationName()}->pluck('id');
......
return $result;
}

Using Observer needs to define extra events observables

I spent an hour to find out that when using Observer you need to define extra observable events to the model so that the observer class can listen to those custom events like so:

/**
 * These are extra user-defined events observers may subscribe to.
 *
 * @var array
 */
protected $observables = [
    'belongsToManyAttaching',
    'belongsToManyAttached',
    'belongsToManyDetaching',
    'belongsToManyDetached',
];

Please update the docs.

model in morphToManyAttached is not updated

I am setting up audit logging and want to record old and new relations of a model:

        // Record old values
        static::morphToManyAttaching(function($relation, Model $model) {
            dump($model->{$relation}->pluck('name')->toArray());
        });

        // Store activity
        static::morphToManyAttached(function($relation, Model $model) {
            dump($model->{$relation}->pluck('name')->toArray());            
        }

The relations returned from the model in morphToManyAttached are identical to those returned from the model in morphToManyAttaching.

Multi tenant support

Hi,

Thank you for the package... I tried to use it with a multi tenant package and as soon as I do

static::hasManySaved(function ($parent, $related) { dd('hello'); });

I can't even run migrations anymore, it says my database is not configured.

Any idea that can help me to figure out the problem?

Telescope compatible

I just recently installed Telescope and got an error when inserting belongsToMany relation.

get_class() expects parameter 1 to be object, string given

Stacktrace:

../vendor/laravel/telescope/src/Watchers/ModelWatcher.php:35
--
../vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php:357
../vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php:209
../vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php:169
../vendor/chelout/laravel-relationship-events/src/Concerns/HasBelongsToManyEvents.php:187
../vendor/chelout/laravel-relationship-events/src/BelongsToMany.php:47

Is there any chance to get this package compatible with telescope?

Event by "Dispatchable relationship events" receives only 1 argument

Hi,

When I detach a related model my event only receives 1 argument.

$form->>fields()->detach($id);

my event is called, but the constuctor only receives one argument, the Form class.

use Chelout\RelationshipEvents\Concerns\HasBelongsToManyEvents;
use Illuminate\Database\Eloquent\Model;

class Form extends Model
{
    use HasBelongsToManyEvents;

    protected $dispatchesEvents = [
            'belongsToManyDetached' => EventDetached::class
    ];

    public function fields()
          return $this->belongsToMany(Fields::class): 
}

What I'm doing wrong? I tried to set the dispatchable event on the Field class, but it's never called from there.

HasOneEvents not firing when defined inside observer

i have an issue with defining hasOneCreating method in an observer it is working fine if defined in the boot method of the parent class

Class:

class Payment extends Model
{
    use HasOneEvents;

    public function transaction()
    {
        return $this->hasOne(Transaction::class);
    }
}

Observer:

class PaymentObserver
{
    /**
     * Handle the User "hasOneCreating" event.
     *
     * @param Payment $payment
     * @param Transaction $transaction
     * @return void
     */
    public function hasOneCreating(Payment $payment, Transaction $transaction)
    {
        dump($transaction);
    }
}

AppServiceProvider:

public function boot()
    {
        Payment::observe(PaymentObserver::class);
    }

Laravel version: 7.8.1
package version: 1.2.1

HasMorphToManyEvents and HasMorphedByManyEvents in the same model

When trying to use:

use Chelout\RelationshipEvents\Concerns\HasMorphedByManyEvents;
use Chelout\RelationshipEvents\Concerns\HasMorphToManyEvents;

class Demo extends Model
{
  use HasMorphToManyEvents;
  use HasMorphedByManyEvents;
}

tells me Trait method 'newMorphToMany' will not be applied because it collides with 'HasMorphToManyEvents'.

Is there an easy work around for this?

Observer for ManyToMany

Hands up this will totally be my issue but I can't quite work out why. (new to Laravel).

I've setup both traits on my BookingFamilyMember Model:

    use HasBelongsToManyEvents;
    use HasRelationshipObservables;

And set the boot on the model as described

        static::belongsToManyAttaching(function ($relation, $parent, $ids) {
            Log::debug("Attaching  to member {$parent->name}. ");
        });

And in my BookingFamilyMemberObserver I have this:

    public function belongsToManyAttaching($relation,BookingFamilyMember $member,$ids)
    {
        dump($relation);
    }

Now in your example you show $relation being tied to Model.. however if I do that it fails.. My relation return "journeys"
Which is how it's being attached:

$member->journeys()->attach(1);

Is that all good - or am I missing something by loosely attaching it like this for a ManytoMany?
It works.. I just didn't want to miss something obvious if it should be tied to a Model.

Thank you!

Attached event's $parent (model) is doesn't include attachments.

Hi,

I have a User and Permission classes.

User has the Trait: HasMorphToManyEvents.

I added the attached event under boot:

static::morphToManyAttached(function ($relation, $model, $ids, $attributes = []) {
    print_r($ids); // includes the added permission
    print_r($model->permissions->pluck('id')->toArray()); / doesn't include the permission
});

I think the updated model should be sent to the Event (e.g. static::find($model->id)) instead of passing $model.

Or did I miss anything?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.