Laravels 'Should Queue" resets mail text to default - laravel

i have a problem woth combining notifications and queue in laravel...
if i dont use queue and write notification like this
namespace App\Notifications;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class InterestingOfferPosted extends Notification
{
public $offer;
public function __construct($offer)
{
$this->offer = $offer;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->subject('New Offer')
->line("You have new offer: ".$this->offer->name }
}
this works fine, i get correct text at the end, however if i get this class to implement "Illuminate\Contracts\Queue\ShouldQueue" class and use "Illuminate\Bus\Queueable" trait users are receiving default laravels "The introduction to the notification." mail.
queues are working nice in any other cases, so i think i got that right, but in this particular case it alters final result.
Any ideas?

I think you are not implementing queue interface here
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class InterestingOfferPosted extends Notification implements ShouldQueue{
use Queueable;

Related

Laravel Events Listeners on multiple servers via Redis

I deploy my Laravel project on multiple servers, and my balancer distributes visitors between them.
I want to organize broadcast Events via Redis (queue) and listen to Events on all servers (servers have a common redis db).
I have Event class:
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class BaseRedisEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public string $connection = 'redis';
public string $queue = 'default';
public string $channel = 'default';
public function broadcastOn(): Channel
{
return new Channel($this->channel);
}
}
And class Listener
use App\Events\Bitcoin\Address\CreatedEvent;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
class BaseRedisListener
{
public function __construct()
{
}
public function handle(BaseRedisEvent $event)
{
Log::debug('New Event in Redis ' . var_export($event, true));
}
}
After sending the event, I want the listener to work on all servers.
BaseRedisEvent::dispatch();
An entry is added to the logs only for the server that sent the event. I want for all servers. Can you help me?
No way with logging in files. You should use add custom driver to handle the logs in /config/logging.php. Keep in mind that you should implement your custom class for this. Some example and tutorial https://cylab.be/blog/144/laravel-custom-logging
Please google about laravel custom log driver.

Laravel 8 jobs not dispatching

I have this Job
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Http\Traits\CreateTrait;
class CreateJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, CreateTrait;
protected $contactForm;
public function __construct($contactForm)
{
$this->contactForm = $contactForm;
}
public function handle()
{
//This connects to SSH and takes 5-10s
$this->CreateOnetime($this->contactForm->room_id, $this->contactForm->company_id, $this->contactForm->id);
}
}
Then I try in controller
use App\Jobs\CreateJob;
class ContactFormController extends Controller
{
public function save(StoreContactFormRequest $request, $cid, $rid){
$validated = $request->validated();
$validated['room_id'] = $rid;
$validated['company_id'] = $cid;
$contactForm = ContactForm::create($validated);
CreateJob::dispatch($contactForm);
return back();
}
}
Nothing written in the DB, though I have QUEUE_DRIVER=database in the .env file.
The function runs synchronously, so it does not create the Job somehow, just runs it.
Problem was I had QUEUE_CONNECTION=sync somewhere after QUEUE_DRIVER=database

Laravel: Passing a class name from a Controller to a Job

I'm trying to pass a certain class name from the controller to a job file through
Job::dispatch($className);
I've tried passing it as a string and passing it as a ClassName::class but none of these methods work
The code in the Job file looks something along the lines of this:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class BreakUpArraysJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $products;
protected $jobName;
public function __construct($products, $jobName)
{
$this->products = $products;
$this->jobName = $jobName;
}
/**
* Execute the jobName.
*
* #return void
*/
public function handle()
{
$productArrays = array_chunk($this->products, 5000);
foreach($productArrays as $productArray){
$this->jobName::dispatch($productArray);
}
}
}
the $jobname variable is the className I'm trying to pass.
I also need to note that I'm passing the classname of a different Job from the Controller, by which I mean the job handler is supposed to call another Job through the variable.
I do not think your syntax is working, an alternative approach would be to do it like this.
dispatch(new $this->jobName($productArray));
in your job construct add class Name that your var is instance of before $product like this:
public function __construct(Product $products, $jobName)
{
$this->products = $products;
$this->jobName = $jobName;
}

How to queue Laravel 5.7 "email verification" email sending

Laravel 5.7 included "email verification" feature works well but not async email sending (during user register or resend link page) is not ideal.
Is there any way to send the email verification email through a queue without rewrite whole email verification in Laravel 5.7 ?
There is no built in way, but you can do it easily by extending and overriding.
First, create a new notification that extends the built-in notification, and also implements the ShouldQueue contract (to enable queuing). The following class assumes you create a notification at app/Notifications/VerifyEmailQueued.php:
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Auth\Notifications\VerifyEmail;
class VerifyEmailQueued extends VerifyEmail implements ShouldQueue
{
use Queueable;
// Nothing else needs to go here unless you want to customize
// the notification in any way.
}
Now you need to tell the framework to use your custom notification instead of the default one. You do this by overriding the sendEmailVerificationNotification() on your User model. This simply changes which notification gets sent out.
public function sendEmailVerificationNotification()
{
$this->notify(new \App\Notifications\VerifyEmailQueued);
}
Yes! It's possible. And to do that you will have to rewrite the sendEmailVerificationNotification in your App\User. This method is provided by the Illuminate\Auth\MustVerfiyEmail trait. The method sendEmailVerificationNotification notifies the created user by sending an Email as defined in the Illuminate\Auth\Notifications\VerifyEmail Notification class.
// This is the code defined in the sendEmailVerificationNotification
public function sendEmailVerificationNotification()
{
$this->notify(new Notifications\VerifyEmail);
}
You can change this method to not notify directly the user. You will have to define a Job which you will dispath in the sendEmailVerificationNotification method instead of notifying the created user.
In the Job class you will create a handle method where you can send the email to the user, but you must provide the $user to the Job which can be performed by passing it as a parameter to the dispatch method like this:
public function sendEmailVerificationNotification()
{
VerifyEmail::dispatch($this);
}
$this represents the created user and the App\Jobs\VerififyEmail job (which you will create) will receive all the parameters passed to the dispatch in its __construct
The code of the VerifyEmail will look like this:
namespace App\Jobs;
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\Auth\Notifications\VerifyEmail;
class VerifyEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function handle()
{
// Here the email verification will be sent to the user
$this->user->notify(new VerifyEmail);
}
}
My solution is for if you gonna register a user manually in the controller.
Laravel already created the Registered event and its listener SendEmailVerificationNotification.
-first configure queue in application
in .env file update QUEUE_CONNECTION=database.
for more queue documentation read https://laravel.com/docs/6.x/queues
publish queue table by php artisan queue:table
php artisan migrate
php artisan make:job EmailVerificationJob
in EmailVerificationJob.php add public variable
public $user;
in EmailVerificationJob.php constructor
public function __construct(User $user)
{
$this->user = $user;
}
in EmailVerificationJob.php handle function write event(new Registered($this->user)).
in your controller if user created successfully add this code for job to work.
EmailVerificationJob::dispatch($user)
->delay(now()->addSeconds(5));
here job delay for 5 seconds.
at the end you must start queue worker php artisan queue:work --tries=3 . here tries means how many times queue should try the job.
Update#1
this solution I used in Laravel 8.
first create SendEmailVerificationNotification notification class
php artisan make:notification SendEmailVerificationNotification
app/Notifications/SendEmailVerificationNotification.php file content will be this one. here we are going to extend Laravel default SendEmailVerificationNotification class and implement should queue
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class SendEmailVerificationNotification extends \Illuminate\Auth\Listeners\SendEmailVerificationNotification implements ShouldQueue
{
use Queueable;
}
the last step is editing EventServiceProvider class $listen array. Comment out default notification of Registered event and add custom notification which we have created.
use App\Notifications\SendEmailVerificationNotification as QueuedSendEmailVerificationNotification;
use Illuminate\Auth\Events\Registered;
//use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
protected $listen = [
Registered::class => [
// SendEmailVerificationNotification::class,
QueuedSendEmailVerificationNotification::class
],
];
The solution is pretty simple:
Steps:
Configure Queue Driver
Go To --> Illuminate\Auth\Notifications\VerifyEmail
Implement 'ShouldQueue' interface and add a trait 'Queueable' on above mentioned class i.e. 'VerifyEmail' like this:
class VerifyEmail extends Notification implements ShouldQueue{
use Queueable;
....
....
...
}
3.That's it
Path of interface & trait:
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Bus\Queueable;
Please check the docs too:
https://laravel.com/docs/5.7/notifications#queueing-notifications

Laravel custom event not being triggered by eloquent event when model update run as scheduled task

I have a custom event being triggerred by the updated Eloquent model event. This custom event is working when an update is done manually, (ie outside a Scheduled Task) but not when the update is done via a Scheduled Task
Model code
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Location extends Model {
self::updated(function ($location) {
event(new LocationRefresh($location));
});
}
Here's the event listener:
<?php namespace App\Events;
use App\Events\Event;
use App\Models\Location;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class LocationRefresh extends Event implements ShouldBroadcast
{
use SerializesModels;
public $id;
public $closed;
public $closed_until;
public function __construct(Location $location)
{
$this->id = $location->id;
$this->closed = $location->closed;
$this->closed_until = $location->closed_until;
}
public function broadcastOn()
{
return [
'private-location-'.$this->id
];
}
}
Any ideas?

Resources