Questions about Laravel Notifications - laravel

I have configured it to send notifications to users who can be members or non-members.
Notifications are sent via email, database, and broadcast.
At this time, if the user is a member, he will receive a notification through e-mail, database, and broadcast, and if the user is a non-member, the user will receive a notification through e-mail.
If the user is a member, the code below is called.
User::find($userId)->notify($notificationInstance);
If the user is a non-member, the code below is called.
Notification::route('mail', $emailAddress)->notify($notificationInstance);
If the user is a member, it works as expected.
However, for non-members, it is transmitted through e-mail and broadcast. Why does broadcast work? Also, why are databases excluded?

...
public function via($notifiable)
{
if ($notifiable instanceof AnonymousNotifiable) {
if (Arr::exists($notifiable->routes, 'mail')) {
$via[] = 'mail';
}
if (...) {
$via[] = '...';
}
return $via;
}
}
...
Solved. Here my code.

Related

when we send email with job and queue error occur

[when send emails shows these error][1]ReflectionException Method App\Mail\Newsletter::__invoke() does not exist
these is my controlledispatch(new Newsletter($emailSubject,$emailBody,$arrayEmails));
these is my email classpublic function build() { return $this->view('emails.newsletter')->subject($this->emailSubject)->with(['msg'=> $this->emailBody]); }
these is my jobs public function handle() { $email = new Newsletter($this->emailSubject,$this->emailBody,$this->arrayEmails); Mail::to($this->arrayEmails)->send($email); }
As I understand, you create a job that in turn create and send the email object.
However, in the controller, you are not dispatching the job, you are dispatch the email object. And the email object doesn't contain either a handle or __invoke method so you see the error message.
The solution is to dispatch the job instead of the email.
This design is indeed unnecessary. Pls have a look at Mailables, create a queued mailable, and just send it.

Laravel echo send data when joining channel

How do I receive data when the client initially joins a channel?
Something like this:
Echo.channel('channel-name')
.onjoin(function (data) {
console.log(data) // Data received from server
})
As soon when the client joins, the server should respond with data, preferably with PHP.
Presence channels return information about the users in the channel at the time the client subscribes.
If you require other data from your server then you could send a post request to your server to get the information. You could invoke this in a pusher:subscription_succeeded binding so it occurs as soon as the subscription is established.
Edit:
.here will display the data per user connected, which is not what I want.
I thought presence channel was what I was looking for. https://laravel.com/docs/8.x/broadcasting#presence-channels
// Define channel
Broadcast::channel('channel-name', function () {
if (/* Condition if user is allowed to join channel */) {
return ['data' => 'your Data'];
}
});
// Join channel
Echo.join('channel-name')
.here(function(data) {
console.log(data)
})
// Event
class Event implements ShouldBroadcast
{
public function broadcastOn()
{
return new PresenceChannel('channel-name');
}
}

Laravel schedule push notification and cancel it if necessary

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.

Change SMTP user according to the user in Laravel 5

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!

How to send an email after finishing a chain of queued jobs (Laravel 5.5)?

What would be the best approach to send an email notification to a user after my chain of jobs are finished ?
I am using Laravel 5.5 & horizon queues.
My method where user is being validated and a chain of jobs are being fired:
public function activateUser($token)
{
if ($user = $this->activationService->activateUser($token)) {
CheckIfDown::withChain([
(new ScanOne($user))->onQueue('new-user'),
(new ScanTwo($user))->onQueue('new-user'),
(new ScanThree($user))->onQueue('new-user'),
(new FirstScanFinished($user))->onQueue('new-user') // What I've tried - this job should send an email from it's handle() method.
])->dispatch($user)->onQueue('new-user');
return redirect('/login')->with('message', 'You have successfully completed the registration process!');
// return redirect($this->redirectPath());
}
abort(404);
}
These specific chain of jobs are only fired once the user validates his email address. Email should be sent only once.
FirstScanFinished handle method
public function handle()
{
$message = (new FirstScanFinished($this->user));
$email = $this->user->email;
Mail::to($email)
->send($message);
}
All the jobs appears to be successfully fired, but I don't get any email in my mailtrap(just to note all my smtp settings are good and emails in other places are firing of without any problems). I also don't get any error in my logs. How should I approach this ?

Resources