laravel job/notification failing - laravel

I am trying to set up a contact form on my site whereby when someone clicks send, then a job is run and in that job, a notification is sent to all admin users. I keep getting this error in my failed jobs table though:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\Contact]. in /var/www/html/leonsegal/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:412
I have been all over my code and I can't see what I have done wrong. Would anyone be able to help please?
Here is my controller:
<?php
namespace App\Http\Controllers;
use App\Contact;
use App\Jobs\SendContactJob;
class ContactController extends Controller
{
/**
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function create()
{
return view('contact');
}
public function store()
{
request()->validate([
'name' => 'required|max:255',
'email' => 'required|email|unique:contacts|max:255',
'message' => 'required|max:2000',
]);
$contact = Contact::create(
request()->only([
'name',
'email',
'message',
])
);
SendContactJob::dispatch($contact);
return back()->with('success', 'Thank you, I will be in touch as soon as I can');
}
}
my job:
<?php
namespace App\Jobs;
use App\Contact;
use App\Notifications\SendContactNotification;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Notification;
class SendContactJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $contact;
/**
* Create a new job instance.
*
* #param Contact $contact
*/
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$users = User::all()
->where('admin', 1)
->where('approved', 1);
Notification::send($users, new SendContactNotification($this->contact));
}
}
my notification:
<?php
namespace App\Notifications;
use App\Contact;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class SendContactNotification extends Notification implements ShouldQueue
{
use Queueable;
protected $contact;
/**
* Create a new notification instance.
*
* #param $contact
*/
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line($this->contact->name)
->line($this->contact->email)
->line($this->contact->message);
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
The weird thing is that when I run a die dump in the handle method of the job, it never fires, but the artisan queue worker says it was processed correctly but the subsequent notification is where it is failing. I am not sure why that handle method in the job wouldn't be firing.
I have set my .env file to database queue driver.
I thought it might be that I didn't import the contact model, but you can see I have.
Any help would be appreciated.

Could be that because both the job and the notification are queued, the contact could be getting 'lost in transit' so to speak. try making the job non queueable, and only queue the notification (or the other way around). Or scrap the job altogether and just send the notification from the controller.

Did you check on your model path? Coz for newer laravel the path should be
use App\Models\Contact;

Related

Laravel 9 - How to get resolved instance of task in Queue::before event?

I have a multi-tenant project with multiple databases and a single queue. I need to switch between databases before running the job.
Here's the code I have:
Queue::before(function (JobProcessing $event) {
$costumer = DB::table('costumers')
->select('db_password', 'id')
->where('id', 11)
->first();
DB::disconnect('mysql');
config(
[
'database.connections.mysql.database' => 'costumer_'.$costumer->id.'_db',
'database.connections.mysql.username' => 'costumer_'.$costumer->id,
'database.connections.mysql.password' => Crypt::decryptString($costumer->db_password),
'costumer.code' => $costumer->id,
]
);
DB::reconnect('mysql');
});
It's working, but in the where clause, the id must be dynamically set.
So I pass the id in the Job::dispatch() method, but here's the problem: how do I get the job instance to return the data inside it?
I saw in another question the $event->job->instance and $event->job->getResolvedJob().
The first option is a protected property, so it doesn't work (it worked in Laravel 5). The second returns null.
You can set public property or getter in your job, so you can retrieve your id from the job instance, like here in getPodcastId:
<?php
namespace App\Jobs;
use App\Models\Podcast;
use App\Services\AudioProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The podcast instance.
*
* #var \App\Models\Podcast
*/
protected $podcast;
/**
* Create a new job instance.
*
* #param App\Models\Podcast $podcast
* #return void
*/
public function __construct(Podcast $podcast)
{
$this->podcast = $podcast;
}
public function getPodcastId()
{
return $this->podcast?->id;
}
/**
* Execute the job.
*
* #param App\Services\AudioProcessor $processor
* #return void
*/
public function handle(AudioProcessor $processor)
{
// Process uploaded podcast...
}
}
But, to be honest, I think this is not really safe to change config on the go. The better solution would be to initialize another database connection inside your job and use it in your job dirrectly:
use Illuminate\Database\Connectors\ConnectionFactory;
// ...
public function __construct()
{
$factory = app(ConnectionFactory::class);
return $this->db = $factory->make(/* Config */);
}

Laravel. How to get id of database notification?

I use database notifications, in notification code I have method toDatabase:
public function toDatabase($notifiable)
{
$user = \App\SomeUsers::where('id', $notifiable->id)->first();
return [
'message' => $message,
];
}
it returns data array which is being sent to database channel mentioned in via method of current notification:
public function via($notifiable)
{
return ['database'];
}
Everything is as usual, BUT... The problem is I need id of notification in database here in current notification file so that I could broadcast message (from current notification file) to frontend which contains id of notificaion in db (so I could somehow identify it to mark as read). How to get it?
P.S. Moreover, database notification may be queueable, so... it seems that I can't get id...
P.P.S Another words I need broadcast message which contains ["id" => "id of just added corresponding database notification"].
<?php
namespace App\Notifications;
use App\Channels\SocketChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Redis;
class MyCustomNotification extends Notification implements ShouldQueue
{
use Queueable;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($param)
{
$this->param = $param;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
$channels = ['database'];
return $channels;
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toDatabase($notifiable)
{
info("This is the current notification ID, it's generated right here before inserting to database");
info($this->id);
return [
'id' => **$this->id**,
'message' => 'Notification message',
];
}
}
$this->id solves the problem.
https://laracasts.com/discuss/channels/laravel/get-database-notification-id-in-push-notification
P.S. I want to draw attention to one fact. When I posted this question, I knew about $this->id, but I couldn't make it work. The reason was: when I dive deeper to my target code from the top level I made changes to code, but they didn't apply. The reason is queues. You need to restart laravel worker to apply settings as Laravel caches logic or you need temporarily delete those: implements ShouldQueue and use Queueable.
In order to retrieve the actual ID of the notifications table in Laravel, you need to cast the ID column to string. First, you need to create a new model called, Notification.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Notification extends Model
{
/**
* Cast variables to specified data types
*
* #var array
*/
protected $casts = [
'data' => 'array',
'id' => 'string'
];
}
This way, if you retrieve the model, it will give you the actual ID of the table.
{
"id": "212829d6-5579-449f-a8e5-e86f0a08e0f9",
"type": "App\\Notifications\\CronFailureNotification",
....
}
The accepted answer did not provide a solution for me in Laravel 8. To properly get the id of the notification, listen for the NotificationSent event and retrieve the id there. Example code:
EventServiceProvider.php
protected $listen = [
NotificationSent::class => [
DispatchBroadcastNotification::class
]
];
DispatchBroadcastNotification.php
<?php
namespace App\Listeners;
use App\Notifications\BroadcastNotification;
use Illuminate\Notifications\Events\NotificationSent;
class DispatchBroadcastNotification
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param NotificationSent $event
* #return void
*/
public function handle(NotificationSent $event)
{
$event->notifiable->notify(
new BroadcastNotification($event->notification->id)
);
}
}
BroadcastNotification.php
<?php
namespace App\Notifications;
use App\Models\Tenant\User;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Notification;
class BroadcastNotification extends Notification implements ShouldBroadcast
{
public $notificationId;
public function __construct($notificationId)
{
$this->notificationId = $notificationId;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via(User $notifiable): array
{
return ['broadcast'];
}
public function toBroadcast(User $notifiable)
{
return new BroadcastMessage([
'notificationId' => $this->notificationId
]);
}
}

Laravel 5.7 Queue function but not send email

i have created a notification with ShouldQueue and my "job" table is populated but, when i launch a command: "php artisan queue:listen" the rows in table are processed but not send the email.
If don't use the queue all code function and email are send to destination.
I use the markdown for send email.
Command:
namespace App\Console\Commands;
use Illuminate\Console\Command;
//
use Notification;
use App\Notifications\Listini\NotifyListinoUpdate;
class StoreListinoOil extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'command:storelistinooil';
/**
* The console command description.
*
* #var string
*/
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$details = array(
'day_listino' => 'today',
'email' => 'email#email.com'
);
Notification::send($details, new NotifyListinoUpdate($details));
dd('OK');
}
}
Notification -> NotifyListinoUpdate
namespace App\Notifications\Listini;
// use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
// use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
//
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class NotifyListinoUpdate extends Notification implements ShouldQueue
{
// use Queueable;
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $details;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($details)
{
$this->details = $details;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Notifica - '.$this->details['day_listino'])
->markdown('mail.admin.listino_update',['details'=> $this->details]);
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
You have to run the Queue worker using following command:
php artisan queue:work
Check the documentation on:
Running Queue Workers

Map Eloquent event to a dedicated classes and get the ID of the logged in user

I'm trying to find out how I could access the logged in users ID in the handle method of the listener.
This is how the listener looks like:
namespace App\Listeners;
use App\Events\ProjectWasDeleted;
class DeleteUserProjectMapping
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param ProjectWasDeleted $event
* #return void
*/
public function handle(ProjectWasDeleted $event)
{
$project = $event->project->toArray();
var_dump($project['id']); // This is working.
}
}
This is how the event:
namespace App\Events;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
class ProjectWasDeleted
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $project;
/**
* Create a new event instance.
*
* #param $project
*/
public function __construct($project)
{
$this->project = $project;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
The user id is necessary as I would like to delete in a pivot table a record that requires the user id & the project id.
You can access current user instance globally with:
auth()->user()
And get ID with:
auth()->id()
Or:
auth()->user()->id

Laravel 5.2 not broadcasting events

I've tried to broadcast event with pusher. But after a long hours of debugging I am still without a working solution.
Pusher works great, it's getting events from the debug console. Laravel is also firing the event. I also set up the queue and broadcasting configuration, but I noticed that my queue listener never getting any response.
This is my event listener:
<?php
namespace App\Listeners;
use App\Events\SomeEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
class EventListener implements ShouldQueue
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
}
/**
* Handle the event.
*
* #param SomeEvent $event
* #return void
*/
public function handle(SomeEvent $event)
{
//dd($event);
}
}
Routes:
Route::get('event', function () {
event(new App\Events\SomeEvent());
return "event fired";
});
Event file:
<?php
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class SomeEvent extends Event implements ShouldBroadcast
{
use SerializesModels;
public $data;
public $x = 1111;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
$this->data = array(
'power'=> '10'
);
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
return ['test_channel'];
}
}
Edit:
i reinstalled laravel and now the queue seems to respond and create row in the job table. but the pusher still dont recive any events from laravel.
Your App\Providers\EventServiceProvider needs to be made aware of the events and listeners.
protected $listen = [
App\Events\SomeEvent::class => [
App\Listeners\SomeListener::class,
],
];
These can be automatically populated by running php artisan event:generate.

Resources