I am using the ResetsPasswords trait by laravel to implement password reset. What I would like to achieve is to send the email using queue. Digging through the code I found the line below in function postEmail():
$response = Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
});
Digging further I notice that sendResetLink() function is implemented in a PasswordBroker class which in turn calls the function emailResetLink(). emailResetLink function returns the following:
return $this->mailer->send($view, compact('token', 'user'), function ($m) use ($user, $token, $callback) {
$m->to($user->getEmailForPasswordReset());
which I can simply change mailer->send
to mailer->queue
. Is they some better way to do it without modifying this non-project file?
This is where the Laravel container comes to the rescue. If you don't like the functionality of a core component then you can go ahead and override it fairly painlessly.
First things first you will need to create your own PasswordBroker:
namespace App\Auth\Passwords;
use Illuminate\Auth\Passwords\PasswordBroker as IlluminatePasswordBroker;
class PasswordBroker extends IlluminatePasswordBroker
{
public function emailResetLink()
{
$view = $this->emailView;
return $this->mailer->queue($view, compact('token', 'user'), function ($m) use ($user, $token, $callback) {
$m->to($user->getEmailForPasswordReset());
if (! is_null($callback)) {
call_user_func($callback, $m, $user, $token);
}
});
}
}
Change your namespace to whatever you want if you want to place it elsewhere in your app.
Since the service provider registering the service is a deferred service provider you will need to create your own provider to replace it. Probably the easiest way to do this is extend Illuminate\Auth\Passwords\PasswordResetServiceProvider
with something like the following:
namespace App\Providers;
use App\Auth\Passwords\PasswordBroker;
class PasswordResetServiceProvider extends \Illuminate\Auth\Passwords\PasswordResetServiceProvider
{
protected function registerPasswordBroker()
{
$this->app->singleton('auth.password', function ($app) {
$tokens = $app['auth.password.tokens'];
$users = $app['auth']->driver()->getProvider();
$view = $app['config']['auth.password.email'];
return new PasswordBroker(
$tokens, $users, $app['mailer'], $view
);
});
}
}
Finally in your config/app.php
file remove Illuminate\Auth\Passwords\PasswordResetServiceProvider::class
and add App\Providers\PasswordResetServiceProvider::class
to your 'providers'
array.
Laravel will now use your implementation of the PasswordBroker rather than the stock framework one and you don't have to worry about modifying framework code.
I know this has been answered but I found another way to queue password reset notification which I found much simpler. I've tested it on Laravel 5.3.
By default, password reset notification is implemented by Illuminate\Auth\Notifications\ResetPassword
class. This class is instantiated in your User
model in sendPasswordResetNotification
method and passed to notify
method of Illuminate\Notifications\Notifiable
trait.
So, to queue password reset notification you can simply create new ResetPassword
notification class via artisan make:notification ResetPassword
and replace it's code with this:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
class ResetPassword extends ResetPasswordNotification implements ShouldQueue
{
use Queueable;
}
And now just override sendPasswordResetNotification
method in your App\User
class:
<?php
...
use App\Notifications\ResetPassword as ResetPasswordNotification;
...
/**
* Send the password reset notification.
*
* @param string $token
* @return void
*/
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
In case you get "Call to a member function onQueue() on null" after trying to specify queue fakemeta's solution just specify the the queue you are targeting in the constructor of your class.
<?php
namespace App;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
class ResetPasswordNotification extends ResetPassword implements ShouldQueue
{
use Queueable;
public function __construct()
{
$this->queue = "authentication";
}
}
then use the notification facade to send your mail in the overriding method. The notify method also works
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\ResetPasswordNotification;
class User extends Authenticatable
{
public function sendPasswordResetNotification($token)
{
// either of the two work
// $this->notify(new ResetPasswordNotification($token));
\Notification::send($this, new ResetPasswordNotification($token));
}
}