cybercog / laravel-love

Add Social Reactions to Laravel Eloquent Models. It lets people express how they feel about the content. Fully customizable Weighted Reaction System & Reaction Type System with Like, Dislike and any other custom emotion types. Do you react?
https://komarev.com/sources/laravel-love
MIT License
1.16k stars 71 forks source link

Concept: Configurable behavior on event dispatching #145

Closed antonkomarev closed 4 years ago

antonkomarev commented 4 years ago

How could we override what will happen on Love event will be dispatched?

This question was raised many times before. Each time I've returned to it a new ideas come into my mind but all of them have their pros and cons. Finally I've got all pieces together and ready to share with my vision.

Thanks to Pavel Volkov @volkv for helping me out with better solution.

First, we should encapsulate increment & decrement logic in jobs. Because we will be able to run those jobs from any place in any time without dispatching an event (which may be listened by many listeners at moment). Listeners will become very simple and synchronous but they will dispatch queued jobs.

Second, we should have more control over the queue. Because developers should be able to choose if they want to use stock package behavior or they want to modify it to their application requirements.

I've designed 4 different implementations of the second part. Each implementation will be described in separate comment.

Spoiler: 4th solution will be implemented https://github.com/cybercog/laravel-love/issues/145#issuecomment-583730266

antonkomarev commented 4 years ago

1. Love global jobs connection

Add love.jobs_connection config value which will affect on all jobs.

return [
    // ...other config fields

    'jobs_connection' => null,
];

Right now its fine because we have only 2 listeners, but later it might be an issue when only some jobs will require to work synchronously.

Pros:

Cons:

antonkomarev commented 4 years ago

2. Queue options in config

Add love.jobs config array where we could define jobs queue options specific for each job.

return [
    // ...other config fields
    'jobs' => [
        Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob => [
            'connection' => 'custom_connection_name',
            'queue' => 'custom_queue_name',
            'timeout' => 60,
            'delay' => 90,
        ],
        Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob => [
            'connection' => 'custom_connection_name',
            'queue' => 'custom_queue_name',
            'timeout' => 60,
            'delay' => 90,
        ],
    ],
];

Pros:

Cons:

antonkomarev commented 4 years ago

3. Love jobs config registry

Add love.jobs config array which will work as service locator.

return  [
    // ...other config fields

    'jobs' => [
        Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob::class => App\Jobs\Love\ReactantIncrementAggregatesJob,
        Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob::class => App\Jobs\Love\ReactantDecrementAggregatesJob,
    ],
]

or

return  [
    // ...other config fields

    'jobs' => [
        'reactant_increment_aggregates' => Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob::class,
        'reactant_decrement_aggregates' => Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob::class,
    ],
]

or

return  [
    // ...other config fields

    'jobs' => [
        'reactant' => [
            'increment_aggregates' => Cog\Laravel\Love\Reactant\Jobs\IncrementAggregatesJob::class,
            'decrement_aggregates' => Cog\Laravel\Love\Reactant\Jobs\DecrementAggregatesJob::class,
        ],
    ],
]

Pros:

Cons:

antonkomarev commented 4 years ago

4. Love event service provider

Introduce LoveEventServiceProvider class which will be responsible for registering Event Listeners only.

final class LoveEventServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Event::listen(ReactionHasBeenAdded::class, IncrementAggregates::class);
        Event::listen(ReactionHasBeenRemoved::class, DecrementAggregates::class);
    }
}

For example if you want to update reactant counters synchronously you could follow 3 easy steps.

  1. You will need to opt-out package discovery:

    "extra": {
    "laravel": {
        "dont-discover": [
            "cybercog/laravel-love"
        ]
    }
    },
  2. Register only core LoveServiceProvider provider in your application's AppServiceProvider:

    $this->app->register(\Cog\Laravel\Love\LoveServiceProvider::class);
  3. Finally, register any custom event listeners in your EventServiceProvider. To not reinvent the wheel you could just make a copy of stock Love's listeners and dispatch jobs introduced in #146 on sync connection:

    IncrementAggregatesJob::dispatch()->onConnection('sync');

Pros:

Cons:

antonkomarev commented 4 years ago

This concept has been implemented in these PRs: #146 #147