4

I'm trying to send broadcast notification to users when data changes. But every time I try to send a notification, I get this error:

array_key_exists(): The first argument should be either a string or an integer.

Here is my notification:

class MyNotification extends Notification
{
    use Queueable;

    public $games;

    public $title;
    public $summary;
    public $url;

    public function __construct($games)
    {
        $this->games = $games;

        $this->title = "Your games";
        $this->summary = "Games for {$games[0]->team}";
        $this->url = "/some/url";
    }

    public function via($notifiable)
    {
        return ['mail','broadcast','database'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->subject($this->title)
            ->line($this->summary);
    }

    /**
     * Get the voice representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return PushMessage
     */
    public function toPush($notifiable)
    {
        // ...
    }

    public function toBroadcast($notifiable)
    {
        return new BroadcastMessage($this->toArray($notifiable));
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            'icon' => 'fa fa-calendar',
            'text' => $this->summary,
            'title' => $this->title,
            'url' => $this->url
        ];
    }
}

When I remove 'broadcast' from the via array, everything works fine. I don't know what I'm doing wrong! Can someone help please? Thanks!

EDIT Here is my complete stack trace

Stack trace:
  1. ErrorException->() /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:321
  2. array_key_exists() /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php:321
  3. Illuminate\Database\Eloquent\Model->getAttribute() /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1396
  4. Illuminate\Database\Eloquent\Model->getKey() /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1406
  5. Illuminate\Database\Eloquent\Model->getQueueableId() /var/www/html/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php:60
  6. Illuminate\Support\HigherOrderCollectionProxy->Illuminate\Support\{closure}() [internal]:0
  7. array_map() /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Collection.php:638
  8. Illuminate\Support\Collection->map() /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Collection.php:254
  9. Illuminate\Database\Eloquent\Collection->map() /var/www/html/vendor/laravel/framework/src/Illuminate/Support/HigherOrderCollectionProxy.php:61
 10. Illuminate\Support\HigherOrderCollectionProxy->__call() /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Collection.php:549
 11. Illuminate\Database\Eloquent\Collection->getQueueableIds() /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php:25
 12. Illuminate\Notifications\Notification->getSerializedPropertyValue() /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/SerializesModels.php:23
 13. Illuminate\Notifications\Notification->__sleep() [internal]:0
 14. serialize() /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:139
 15. Illuminate\Queue\Queue->createObjectPayload() /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:110
 16. Illuminate\Queue\Queue->createPayloadArray() /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:88
 17. Illuminate\Queue\Queue->createPayload() /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/SyncQueue.php:40
 18. Illuminate\Queue\SyncQueue->push() /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:44
 19. Illuminate\Queue\Queue->pushOn() /var/www/html/vendor/laravel/framework/src/Illuminate/Broadcasting/BroadcastManager.php:127
 20. Illuminate\Broadcasting\BroadcastManager->queue() /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php:267
 21. Illuminate\Events\Dispatcher->broadcastEvent() /var/www/html/vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php:190
 22. Illuminate\Events\Dispatcher->dispatch() /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/Channels/BroadcastChannel.php:51
 23. Illuminate\Notifications\Channels\BroadcastChannel->send() /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php:146
 24. Illuminate\Notifications\NotificationSender->sendToNotifiable() /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php:105
 25. Illuminate\Notifications\NotificationSender->Illuminate\Notifications\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Traits/Localizable.php:19
 26. Illuminate\Notifications\NotificationSender->withLocale() /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php:107
 27. Illuminate\Notifications\NotificationSender->sendNow() /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php:79
 28. Illuminate\Notifications\NotificationSender->send() /var/www/html/vendor/laravel/framework/src/Illuminate/Notifications/ChannelManager.php:39
 29. Illuminate\Notifications\ChannelManager->send() /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:261
 30. Illuminate\Support\Facades\Facade->__callStatic() /var/www/html/app/Http/Controllers/Basketball/BasketballGameController.php:458
 31. App\Http\Controllers\Basketball\BasketballGameController->updateJudges() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
 32. call_user_func_array() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54
 33. Illuminate\Routing\Controller->callAction() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:45
 34. Illuminate\Routing\ControllerDispatcher->dispatch() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php:219
 35. Illuminate\Routing\Route->runController() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php:176
 36. Illuminate\Routing\Route->run() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:681
 37. Illuminate\Routing\Router->Illuminate\Routing\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:130
 38. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php:43
 39. Illuminate\Auth\Middleware\Authenticate->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 40. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/barryvdh/laravel-cors/src/HandleCors.php:58
 41. Barryvdh\Cors\HandleCors->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 42. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php:41
 43. Illuminate\Routing\Middleware\SubstituteBindings->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 44. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php:59
 45. Illuminate\Routing\Middleware\ThrottleRequests->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 46. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:105
 47. Illuminate\Pipeline\Pipeline->then() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:683
 48. Illuminate\Routing\Router->runRouteWithinStack() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:658
 49. Illuminate\Routing\Router->runRoute() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:624
 50. Illuminate\Routing\Router->dispatchToRoute() /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php:613
 51. Illuminate\Routing\Router->dispatch() /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:170
 52. Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:130
 53. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/fideloper/proxy/src/TrustProxies.php:57
 54. Fideloper\Proxy\TrustProxies->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 55. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:21
 56. Illuminate\Foundation\Http\Middleware\TransformsRequest->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 57. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php:27
 58. Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 59. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php:62
 60. Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 61. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/barryvdh/laravel-cors/src/HandleCors.php:58
 62. Barryvdh\Cors\HandleCors->handle() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:171
 63. Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}() /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:105
 64. Illuminate\Pipeline\Pipeline->then() /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:145
 65. Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter() /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:110
 66. Illuminate\Foundation\Http\Kernel->handle() /var/www/html/public/index.php:55

EDIT 2

In my constructor of my notification, I have a model that uses a composite key. As soon as when I delete this line: $this->games = $games;, and edit $this->summary to some string - it works! $gamesis a collection of the Model Game.

But I don't know why this happens?!

Mike_NotGuilty
  • 2,253
  • 5
  • 32
  • 64
  • 1
    The error message tells you what line the error occurs on, and provides a backtrace to the point in user code where the error occurs. – miken32 Mar 04 '20 at 19:32
  • @miken32 no because I want to return the same array like `toArray()` – Mike_NotGuilty Mar 04 '20 at 22:14
  • Pls share your complete error stack – Sehdev Mar 05 '20 at 02:06
  • @Sehdev See my edit. Thank you! – Mike_NotGuilty Mar 05 '20 at 16:06
  • Try getting rid of `use Queueable;` and see if that clears things up any. At the very least it should make the trace shorter. If you're copying this from an exception report on your browser, it should also show you parameters that were passed to `array_key_exists` which might help you figure out the problem. – miken32 Mar 05 '20 at 23:20
  • @miken32 where can I find the parameters? Deleting `use Queueable`had no effect. Still the same error with the same stack trace! – Mike_NotGuilty Mar 06 '20 at 15:41
  • I forgot that Ignition doesn't show function arguments any more, but if you're still on Laravel 5, the Whoops error page should show a list of arguments below the code. If your notification wasn't queued, I wouldn't expect to see `Illuminate\Queue\Queue` objects in the stack trace. – miken32 Mar 06 '20 at 16:42
  • I removed `use Queueable`, but it still shows it in the stack trace. Is there another place where I have to remove it? I'm on Laravel 6.0 - my error page looks like this (example): https://i.stack.imgur.com/YDQcV.png - but I can't find the parameters – Mike_NotGuilty Mar 06 '20 at 17:14
  • The argument in that example would be listed under "Arguments" and is the string "You do not have permissions...". If you can see what the argument to `Illuminate\Database\Eloquent\Model->getAttribute()` was, you might figure out what the problem is. – miken32 Mar 06 '20 at 20:19
  • Ok I found the reason for the error, but I don't know why this happens! Please See my edit! – Mike_NotGuilty Mar 07 '20 at 08:45
  • @miken32 - I found a fix for my problem by converting my `Collection` to an array before passing it to the Notification. But isn't it possible to fix it without converting the `Collection`? – Mike_NotGuilty Mar 07 '20 at 09:12

2 Answers2

5

If i understand this correctly, The reason is simply because your model uses a composite key which is not supported by eloquent.

So here's what i think is actually happening with my limited knowledge on the whole notification/broadcasting module.

  1. You try to send your notification which the dispatcher then passes your notification on to a broadcast manager since you specified to broadcast it in your via method
  2. The broadcast manager will then try to push your MyNotification event into the queue
  3. To push the event into a queue, it will attempt to create the payload of your notification class which tries to serialize it
  4. The Notification base class that you are extending from actually implements the Illuminate\Queue\SerializesModels trait and so will automatically try to serialize all the model in your notification class's attributes
  5. While trying to serialize your eloquent collection of Game objects, the collection then tries to call getQueueableId on every one of your model in the collection, which then fails because it tries to retrieve the attribute based on your composite key

As for the solution i would say try to remove your composite key on the model since it seems like it wouldn't work as intended when using eloquent.

// in Game model
protected $primaryKey = 'id';

According to this documentation on queues, you can also try to add a broadcastWith method on your MyNotification Class, although i'm not sure if this will bypass the serialize method of SerializeModels trait.

// in MyNotification
public function broadcastWith()
{
    return ['id' => $this->id];
}

Or as per your own trial and error, instead of initializing $this->games with a collection, you can cast it into an array. After all, in the end, your toBroadcast method is the one that actually controls the broadcast.

$this->games = $games->toArray();

And your final option is to override the getQueueableId() method of your Game Model.

// in Game Model
public function getQueueableId()
{
    return $this->id; 

    // or if you still want to utilize your composite keys. UNTESTED
    return $this->key_one.$this->key_two;
}
Helioarch
  • 1,158
  • 5
  • 18
  • Thank you for the `getQueueableId()` tip... that saved me work to rewrite everything to `->toArray()` – Mike_NotGuilty Mar 13 '20 at 15:15
  • Hi @Mike_NotGuilty did you have to override any other methods besides `getQueueableId()`? And what does you `$primaryKey` on `Game` look like? Is it still an array of column names? – Daniel Jan 07 '21 at 09:46
  • 1
    @Daniel Not sure if it's of any interest to you, but I work with composite primary keys in Eloquent quite a lot. See my answer to this question. – cartbeforehorse Nov 22 '21 at 13:36
1

I know I'm a bit late to the party, but I work with Laravel/Eloquent composite keys quite a lot.

Not that it's an exhaustive/complete repository at all, but I a do maintain a Git repository to help me deal with some of Eloquent's shortcomings (as well as add some additional functionality).

In particular, I've created a trait that overrides some of Eloquent's functions, which exist specifically to deal with Laravel's stubborn denial of the fact that RDBMSs can't all be built on top of fake ID primary-key fields.

I won't write all of the overriding functions in their complete forms here, because they tend to evolve over time as I find new situations that I need to cater for. Nevertheless, the function names that I currently override in my trait are as follows:

public function getKeyName();
public function getKey();
public function setKeysForSaveQuery();
public function getKeyForSaveQuery();

In my tests, my trait does remedy the (what I think is a) bug reported by the OP.

If anyone has any interest in helping maintain such a repository, let me know! Collaboration is always appreciated.

cartbeforehorse
  • 3,045
  • 1
  • 34
  • 49