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?

Home Page:https://komarev.com/sources/laravel-love

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to delete all reactions made by the User (unreactAll)?

wimil opened this issue · comments

commented

There is some method to erase all the reactions that a reacter has reacted to.

example something like unreactTo but all would be unreactAll

Could you provide a use-case for this feature, please?

Reacter's unreactTo method just trying to find reaction from the Reacter related to Reactant model and then deletes it. So you can do it manually in a pretty trivial way:

$reactions = $user->viaLoveReacter()->getReactions();
foreach ($reactions as $reaction) {
    $reaction->delete();
}

If you will delete reactions directly from the database using plain SQL query - then Laravel Eloquent model events wouldn't be fired and reaction counters will be un-synced.

commented

I am using Facebook reactions, a user can react with a "pisses me off", but he can change his reaction to a "like".
How could I do that? If the only way is to eliminate the reaction, and save the new reaction, now the unreactTo method only eliminates by type of reaction, then I would have to bring the reaction to get the type, and then eliminate. what occurred to me was to eliminate all the reactions and then add the new reaction, so I created a method called unreactAll, but it does not update the total and count of the reactions

public function unreactAll(ReactantContract $reactant): void
{
    if ($reactant->isNull()) {
        throw ReactantInvalid::notExists();
    }

    $this->reactions()
        ->where('reactant_id', $reactant->getId())->delete();
}

Ah, now I see your requirement.

That happens because you are calling delete method of the Query Builder instead of the Eloquent Model. Fetch all reactions first and then delete each.

$reactions = $this->reactions()->where('reactant_id', $reactant->getId())->get();
foreach ($reactions as $reaction) {
    $reaction->delete();
}

Or use some Laravel magic if you like:

$reactions = $this->reactions()->where('reactant_id', $reactant->getId())->get();
$reactions->each->delete();

Sadly, there is no way to listen Query Builder requests by event listeners so we cannot execute recounting.

commented

Thanks for the help, I created a method called "unreactFirst" that brings the first result and eliminates it, so use the eloquent and activate the events

public function unreactFirst(ReactantContract $reactant): void
    {
        if ($reactant->isNull()) {
            throw ReactantInvalid::notExists();
        }
        $this
            ->reactions()
            ->where('reactant_id', $reactant->getId())
            ->first()
            ->delete();
    }

With this I have solved the problem and now the user can react and change his reaction.

If user is allowed to create only one reaction, that should work.

If your method located in application's User model, I'd recommend you to rely on Cog\Contracts\Love\Reactable\Models\Reactable contract instead of Cog\Contracts\Love\Reactant\Models\Reactant. Then your application logic will be less coupled with Love package implementation.

use Cog\Contracts\Love\Reactable\Models\Reactable as ReactableContract;

public function unreactFirst(ReactableContract $reactable): void
{
    $reactant = $reactable->getLoveReactant();

    if ($reactant->isNull()) {
        throw ReactantInvalid::notExists();
    }

    $this
        ->getLoveReacter()
        ->reactions()
        ->where('reactant_id', $reactant->getId())
        ->first()
        ->delete();
}

Instead of:

$user->unreactFirst($comment->getLoveReactant());

You will write:

$user->unreactFirst($comment);

You can see how better your code looks like by using Reacter Facade & Reactant Facade.

commented

thank you very much for the advice and help