When I try to send reset password notification, this error occurs
Attempt to read property "view" on null
this is the code line on which this error occurs
$this->notify(new ResetPasswordNotification($token));
this is my code inside notification class
You need this method in User model:
public function sendPasswordResetNotification($token): void
{
$this->notify(new ResetPassword($token, $this));
}
You must pass user with token
You need to return the MailMessage in toMail like so:
return $this->buildMailMessage($this->resetUrl($notification));
Related
I noticed that when an email verification token expires in Laravel, it shows an error page which says
403 | Invalid Signature
I don't think its a good user experience for users, because the information is not clear to the user and they don't know what to do next.
Is it possible to redirect to /email/verify
or customize the error message?
If you still wanted to keep that behavior of what the trait is providing but you want to catch that exception and do something specific instead you can define your own verify method and aliasing the verify method from the trait so you can still use it:
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Auth\VerifiesEmails;
use Illuminate\Http\Request;
class VerificationController extends Controller
{
use VerifiesEmails {
verify as verifyTrait;
}
...
public function verify(Request $request)
{
try {
return $this->verifyTrait($request);
} catch (AuthorizationException $e) {
return ; // what ever you would like to do on failure
}
}
}
In my app with Laravel on back-end users can send messages to each other.
I want to send push notification to app users on new inbox message, but I need to send messages only if user hadn't already read this message.
So I see it that way
On every message sended I need to schedule Laravel notification after 1 minute
if user already received this message I need to cancel this notification
How can dismiss scheduled notification in Laravel? Is this approach fine and actual now?
Class extends Notification
public function via($notifiable)
{
if($this->dontSend($notifiable)) {
return [];
}
return ['mail'];
}
public function dontSend($notifiable)
{
return $this->appointment->status === 'cancelled';
}
Maybe there is more convenient way to handle it? For example, to send push every time but somehow dismiss it showing from app if it's already launched?
One way to do it would be something like this;
Before you trigger your notification create a unique identifier(sha1 could be an option) with the combination of user_id. Let's say it is SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C. Send it to the notification. Both notification and message will be send at the same time, but notification will have one minute delay.
$identifier = Str::random(64);
$delay = now()->addMinute();
$user->notify((new MyNotification($identifier))->delay($delay));
// send a request that contains identifier.
You set this to the Redis with TTL of 2 minutes. It will be gone if there is no action.
Redis::set('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C', 1, 120);
While sending a message to the user, attach this identifier to the message. When user read that message, you make a request to your /read endpoint with all the parameters + the identifier.
When you receive the request, delete the key from Redis. (user received the message)
Redis::del('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C');
In your Notification class, implement a small method to check whether the key exists in Redis.
Redis::exists('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C');
class MyNotification extends BaseNotification
{
use Queueable;
private $identifier;
public function __construct($identifier)
{
$this->identifier = $identifier;
}
public function via()
{
return $this->isValid() ? ['mail'] : [];
}
public function isValid()
{
return Redis::exists($this->identifier);
}
public function toMail()
{
// details..
}
}
It doesn't have to be Redis but it is a perfect match for these kind of key/value structure.
I have a Season Resource model with a field named active.
The requirement is to disable deletion for a season with an active status.
I have created an Observer for the season model to watch deleting an event. From this function, I can block the delete in case active is true.
But the issue is with the error message; is there any way to add an error message to session flash from the Observer class?
<?php
public function deleting(Season $season)
{
if($season->active_season)
{
Log::info('Sorry, this season can`t be deleted.
There must be at least one active season.');
}
return false;
}
This is not tested but I was able to achieve something like that in a previous project:
use Illuminate\Validation\ValidationException;
class AbcObserver
{
public function creating(Abc $abc)
{
if ($abc->details != 'test') {
throw ValidationException::withMessages(['details' => 'This is not valid.']);
}
}
}
You can use the Exception class. I tested it in a Nova action and it throws the toast error notification.
use Exception;
throw new Exception('Error message here ...');
// Or
throw_if(
$validator->fails(), // or any true boolean
Exception::class,
'Error message here ...'
);
I don't know how to flash the error message.
But since the requirement is to disable deletion for a season with an active status, I'm suggesting to use policy which won't display the delete icon when doesn't match the condition.
class SeasonPolicy {
...
public function delete(User $user, Season $season) {
if($season->active_season) {
return false;
}
return true;
}
}
and register the policy in AuthServiceProvider.
Note:
Undefined Policy Methods
If a policy exists but is missing a method for a particular action,
the user will not be allowed to perform that action. So, if you have
defined a policy, don't forget to define all of its relevant
authorization methods.
I want to assign different SMTP hosts to different authenticated users so that the privileged users can send mails faster through a dedicated SMTP server.
I can change the host in the service provider like:
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->extend('swift.transport', function ($transportManager, $app) {
$app->make('config')->set('mail.host', 'just.testing.com');
return new TransportManager($app);
});
}
}
However since I need the authenticated user I created a listener listening to "Authenticated" event and moved the code there like:
class ChangeSmtpServer
{
public function handle($event)
{
app()->extend('swift.transport', function ($transportManager, $app) use ($event) {
$app->make('config')->set('mail.host', $event->user->smtp_server);
return new TransportManager($app);
});
}
}
The host is not changed this time... So inside the service provider I can overwrite the setting but not inside the listener.
Any ideas why?
Your code works on my setup just fine. Actually it should still work if you keep it in AppServiceProvider because Laravel will only resolve bindings when they are relevant. So the code pertaining to Mail driver configuration will not be run until you actually try to send a Mail. By that point your user will already be authenticated. However...
This will only work when you send your mail synchronously. When you want to send from a Queue worker, there won't be any authenticated user and the Authenticated event will never be called. You need a way to keep track of which user is sending the e-mail.
Here is my solution:
Add a sender argument to your Mail class constructor (the one in App\Mail) that takes in the User object that's sending the e-mail.
public $sender;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $sender)
{
$this->sender = $sender;
}
Then add this method that configures your SwiftMailer instance
private function usingSendersSmtp()
{
$mailTransport = app()->make('mailer')
->getSwiftMailer()
->getTransport();
if ($mailTransport instanceof \Swift_SmtpTransport) {
/** #var \Swift_SmtpTransport $mailTransport */
$mailTransport->setHost($this->sender->smtp_host);
$mailTransport->setUsername($this->sender->smtp_username);
$mailTransport->setPassword($this->sender->smtp_password);
// Port and authentication can also be configured... You get the picture
}
return $this;
}
And finally call it inside your build method:
public function build()
{
return $this->usingSendersSmtp()
->view('test');
}
When sending the mail, instantiate your class like new YourMailClass(auth()->user()) and then send it or queue it with the Mail facade to whomever you like. It also might be a good idea to create an abstract class that inherits Illuminate\Mail\Mailable and move these extra stuff over there so you won't have to duplicate this in every other mail class. Hope this helps!
I have a custom Request Class on Laravel 5 which handles form inputs (POST). the thing is, I want to use the same request class for a GET method but instead of redirecting the user back to the original request URL (which causes an infinite) loop I want to throw an exception (if the request is not valid), how is that possible?
In your custom Request class, you can override the failedValidation method that is defined in the FormRequest class.
I.e. place this method in your Request class:
protected function failedValidation(\Illuminate\Validation\Validator $validator) {
throw new \Exception('Error processing request');
}
Overriding the response() method can also be used to return a preferred response, personally I have used this to return the errors in JSON form, all that was required to do this was to return a JsonResponse with the errors and response code:
public function response(array $errors)
{
return new JsonResponse($errors, 422);
}
You can add something like this in your request method:
if (Request::isMethod('get'))
{
//Here you can add your custom exception.
}
You can see the documentation for more info about this: http://laravel.com/docs/5.0/requests#other-request-information