DavidHyogo
DavidHyogo

Reputation: 2898

Laravel Eloquent Model Observer deleted method throws an exception. What is wrong?

Can you see what I'm doing wrong with the following code?

 /**
 * Listen to the AdministerRole deleted event.
 * @param  AdministerRole $role
 * @return void
 */
public function deleted(AdministerRole $role)
{
    //This works
    $arg_list = func_get_args();
    event(new BroadcastingModelEvent($arg_list, 'deleted'));
    //This throws an exception
    //event(new BroadcastingModelEvent($role, 'deleted'));
    //No query results for model [App\Models\AdministerRole].
    
}

When I delete an AdministerRole model and pass the parameter $role to my BroadcastingModelEvent, an exception is thrown suggesting that perhaps the model can't be found because it's already deleted: No query results for model [App\Models\AdministerRole]].

However, if I use func_get_args to get the parameters which were passed to the function, and pass the resulting array to BroadcastingModelEvent, I can see a JSON representation of the model collected by Pusher on the client side. What on earth is the difference that's causing this exception?

Upvotes: 1

Views: 1550

Answers (1)

DavidHyogo
DavidHyogo

Reputation: 2898

I got the clue to this problem from this SerializesModels with recently deleted models discussion on the Laravel GitHub page.

My BroadcastingModelEvent's constructor is expecting an Eloquent Model. If I use the SerializesModels trait, it throws an No query results for model exception as discussed in the GitHub page if the event is deleted. The argument seems to be that if the model is already deleted it shouldn't be serializable - or something. The logic escapes me because the deleted event receives the model which has just been deleted and that model is accessible within the deleted event handler, and furthermore, you can call toArray() or toJson() to serialise it! That's my solution. The observer deleted method calls toArray() on the model passed to it and sends that array to the BroadcastingModelEvent constructor. I simply commented out SerializesModels and pre-serialised my model in the observer. If you can explain and justify that seeming inconsistency I'll bake you some shortbread.

public function deleted(AdministerRole $role)
{
    event(new BroadcastingModelEvent($role->toArray(), 'deleted'));        
}

And BroadcastingModelEvent handles it

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Database\Eloquent\Model as Model;

/**
 * https://github.com/laravel/framework/issues/10733
 */
class BroadcastingModelEvent implements ShouldBroadcast {

    use Dispatchable,
        InteractsWithSockets;
    //Throws an exception after the deleted event.
        //SerializesModels;

    public $modelArray;
    public $eventType;

    public function __construct($modelArray, $eventType) {
        $this->modelArray = $modelArray;
        $this->eventType = $eventType;
    }

    public function broadcastOn() {
        return new Channel('MyObservers');
    }

    public function broadcastAs() {
        return 'MyBroadcastEvent';
    }

}

Upvotes: 1

Related Questions