Monday, April 3, 2017

Event fails when using serialization in laravel 5.4

I have different models, which describe different tables in database.

I use this trait for these classes

trait ApplicationModelTrait
 {
     protected static $_currentModel = null;

     protected $currentModel;

     public static function setCurrentModel(ApplicationModel $model) {
         static::$_currentModel = $model;
     }   

     public function __construct(array $attributes = [], ApplicationModel $model = null) {
         parent::__construct($attributes);

         $this->currentModel = $model !== null ? $model : static::$_currentModel;

         if($this->currentModel === null) throw new \InvalidArgumentException('No model passed');
     }   
 }

All models are similar. The only difference is what fields exist in database for every model, so I describe these fields in separate config and main model class ApplicationModel has some methods to work with different tables. For example

public function getInstanceTable() {
     return 'application_model_instances_' . $this->name;
}

public function getCommentsTable() {
    return 'application_model_instance_' . $this->name . '_comments';
}

Where application_model_instances_{name} contains (obviously) instances of this model and application_model_instance_{name}_comments contains comments for instances of this model.

Everything works fine except events.

When I add comment to model instance, I pass as argument current model

$comment = new ApplicationModelInstanceComment([], $this->currentModel);
$comment->text = $request->input('comment');
// etc.

After comment has been saved I want it to be instantly delivered to user browser via websocket

event(new CommentCreated($comment, $this)); // this represents model instance class

And, finally, the event

namespace App\Events;

use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\Models\Application\ApplicationModelInstanceComment;
use App\Models\Application\ApplicationModelInstance;

class CommentCreated implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;
    public $comment;
    public $instance;

    public function __construct(ApplicationModelInstanceComment $comment, ApplicationModelInstance $instance)
    {
        $this->comment = $comment;
        $this->instance = $instance;
    }

    public function broadcastOn() {
        $notifiableUsers = $this->instance->getNotifiableUsers(); // this method is used to fetch list of users who must get this comment in their browser
        $channels = [];
        foreach($notifiableUsers as $user) {
            $channels[] = new PrivateChannel('user.' . $user->id);
        }
        return $channels;
    }
}

But when I add comment Laravel my code throws an exception (this is what I see in network tab in Google Chrome because request is done via ajax:

Whoops, looks like something went wrong.

1/1 InvalidArgumentException in ApplicationModelTrait.php line 20: No model passed

in ApplicationModelTrait.php line 20
at ApplicationModelInstanceComment->__construct() in SerializesAndRestoresModelIdentifiers.php line 45
at CommentCreated->getRestoredPropertyValue(object(ModelIdentifier)) in SerializesModels.php line 41
at CommentCreated->__wakeup()
at unserialize('O:38:"Illuminate\\Broadcasting\\BroadcastEvent":4:{s:5:"event";O:25:"App\\Events\\CommentCreated":3:{s:7:"comment";O:45:"Illuminate\\Contracts\\Database\\ModelIdentifier":2:{s:5:"class";s:54:"App\\Models\\Application\\ApplicationModelInstanceComment";s:2:"id";i:68;}s:8:"instance";O:45:"Illuminate\\Contracts\\Database\\ModelIdentifier":2:{s:5:"class";s:47:"App\\Models\\Application\\ApplicationModelInstance";s:2:"id";i:11;}s:6:"socket";N;}s:10:"connection";N;s:5:"queue";N;s:5:"delay";N;}') in CallQueuedHandler.php line 95
at CallQueuedHandler->failed(array('commandName' => 'Illuminate\\Broadcasting\\BroadcastEvent', 'command' => 'O:38:"Illuminate\\Broadcasting\\BroadcastEvent":4:{s:5:"event";O:25:"App\\Events\\CommentCreated":3:{s:7:"comment";O:45:"Illuminate\\Contracts\\Database\\ModelIdentifier":2:{s:5:"class";s:54:"App\\Models\\Application\\ApplicationModelInstanceComment";s:2:"id";i:68;}s:8:"instance";O:45:"Illuminate\\Contracts\\Database\\ModelIdentifier":2:{s:5:"class";s:47:"App\\Models\\Application\\ApplicationModelInstance";s:2:"id";i:11;}s:6:"socket";N;}s:10:"connection";N;s:5:"queue";N;s:5:"delay";N;}'), object(InvalidArgumentException)) in Job.php line 158
at Job->failed(object(InvalidArgumentException)) in FailingJob.php line 33

I've passed model into ApplicationModelInstanceComment upon creation of comment, so everything is fine here. There is some problem with deserialization, but I do not know how to deal with this problem.



via Jackson J

Advertisement