In laravel 9 app I use queues with redis and for that in notifications which must be queued I wrote :
class CurrencyRatesImportRunNotification extends Notification implements ShouldQueue // IT IS QUEUED
{
use Queueable;
public function __construct(
) {
...
}
public function via($notifiable)
{
return ['mail'];
}
and these emails are sent at the moment when I run in console :
php artisan queue:work
But I also have different notifications, which must be sent at immediately and event must be broadcasted to notify in the app with pusher-js, so
this notification has :
class ContactUsCreatedNotification extends Notification // IT HAS NO ShouldQueue here
{
use Queueable;
public function __construct(string $title, string $content_message, int $user_id)
{
...
}
public function via($notifiable)
{
return ['mail', 'broadcast'];
}
as in .env file I have :
QUEUE_CONNECTION=redis
REDIS_CLIENT=predis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
BROADCAST_DRIVER=log // later I will replace it with pusher
CACHE_DRIVER=file
FILESYSTEM_DISK=local
SESSION_DRIVER=database
SESSION_LIFETIME=120
I expected to see Broadcasting events in log but it does not happen.
In phpRedisAdmin I see these Broadcasting events and only after I run
php artisan queue:work
I see in logs files lines like :
[2022-05-13 06:51:10] local.INFO: Broadcasting [Illuminate\Notifications\Events\BroadcastNotificationCreated] on channels [private-App.Models.User.1] with payload:
{
"title": "Contact us and we will review your message",
"content_message": "Contact us and we will review your message",
"user_id": 1,
"id": "ea1c4896-9460-495c-bc9a-6a8fd0547fd3",
"type": "App\\Notifications\\ContactUsCreatedNotification",
"socket": null
}
for any event.
Why ContactUsCreatedNotification is queued in redis? as i has no implements ShouldQueue ?
"laravel/framework": "^v9.6.0",
"predis/predis": "^1.1",
"pusher/pusher-php-server": "^7.0",
"pusher-js": "^7.1.0-beta",
Thanks!
Remove the Queueable trait from ContactUsCreatedNotification and everything will be ok.
Related
What's the secret of testing a mailable was sent from a notification?
Testing the notification:
it('does send notification when model is deleted', function() {
Notification::fake();
$this->model->delete();
Notification::assertSentTo($this->model->user, MyModelDeletedNotification::class);
});
Passes.
Testing the mailable:
it('does send email when model is deleted', function() {
Mail::fake();
$this->model->delete();
Mail::assertQueued(MyModelDeletedMail::class, 1);
});
Fails. No mails queued.
When a model is deleted a observer method is triggered:
public function deleted(MyModel $model)
{
if ($model->isForceDeleting()) {
return;
}
$model->user->notify(new MyModelDeletedNotification($model));
}
Notification:
class MyModelDeleted extends Notification implements ShouldQueue
{
use Queueable;
...
public function via($notifiable)
{
return ['mail', 'database'];
}
public function toMail($notifiable)
{
return (new MyModelDeletedMail($this->model))->to($notifiable->email);
}
...
}
Mailable:
class ConsultationDeleted extends Mailable
{
use Queueable, SerializesModels;
...
public function build()
{
...
}
}
When I dump("foobar") inside the mailables constructor or build method, the message is appearing in the log. However the test fails. What am I missing here?
Regarding using Mail:fake in the context of notifications:
It is not a very good way to test because it catches only mails sent
using the Mail facade (doesn't intercept mails sent through a
notification or using a mailer retrieved via dependency injection).
Make sure you have set
<server name="MAIL_MAILER" value="array"/>
phpunit.xml. In your test:
it('does send email', function() {
// business logic
$emails = app()->make('mailer')->getSwiftMailer()->getTransport()->messages();
assertCount(1, $emails);
assertEquals([$this->user->email], array_keys($emails[0]->getTo()));
});
This worked for me using laravel 8.
Reference: https://laracasts.com/discuss/channels/testing/testing-if-email-was-sent-with-out-sending-it?page=1&replyId=402801
In my laravel.log i can see the event is broadcasting on the channel i.e.
[2018-08-30 13:41:27] local.INFO: Broadcasting [App\Events\NewRating] on channels [rating] with payload:
{
"music": {
"id": 42,
"name": "1535368873_admin.mp3",
"path": "public\/music\/1535368873_admin.mp3",
"rating": 53,
"user_id": 4,
"created_at": "2018-08-27 11:21:13",
"updated_at": "2018-08-27 11:21:13",
"is_last_played": 1,
"is_now_playing": 0,
"location_id": 1
},
"socket": null
}
As of i know i have done everything according to requirement.my redis server is running.laravel-echo-server is running and it is joining my channel i.e.
[18:41:24] - VX9bkHqs-QHRv3MvAAAC joined channel: rating
This is where i am subscribing to the channel and listening to the event
window.app = new Vue({
el: '#app',
beforeMount: function () {
alert("asdas");
this.joinPublicChatChannel();
},
methods: {
joinPublicChatChannel: function () {
Echo.channel('rating').listen('App\\Events\\NewRating', (event) => {
console.log("Event fired!"); //This doesnt work
});
}
}
});
and this is my event class
class NewRating implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $music;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Music $music)
{
$this->music=$music;
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new Channel('rating');
}
}
and this is my env file
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=laravel_restaurant
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=redis
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=
Dont know the reason behind :/
UPDATE
Just cleared all the caches, Now im getting this in laravel-echo-server console
Channel: rating
Event: App\Events\NewRating
Channel: rating
Event: App\Events\NewRating
Channel: rating
Event: App\Events\NewRating
you can use this in your event file :
public function broadcastAs()
{
return 'NewRating';
}
Never Mind, I got this running :). just cleared the caches and in
Echo.channel('rating').listen('App\\Events\\NewRating', (event) => {
console.log("Event fired!"); //This doesnt work
});
I used NewRating instead of App\\Events\\NewRating
I'm using laravel 5.5. I set my BROADCAST_DRIVER to log but when i access the link to fire the event, nothing happen. The laravel.log file still empty. I already uncomment BroadcastServiceProvider on config/app.php. This is my code
.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myDatabase
DB_USERNAME=root
DB_PASSWORD=numberPassword
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=database
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
config/app.php
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
app/Events/ReloadTableEvent.php
class ReloadTableEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
protected $coinData;
public function __construct($coinData)
{
$this->coinData = $coinData;
}
public function broadcastWith()
{
return ['coin' => $this->coinData];
}
public function broadcastAs()
{
return 'reload-event';
}
public function broadcastOn()
{
return new Channel('reload-channel');
}
}
app/Http/Controllers/ReloadTableController.php
public function reloadTable()
{
$coin = Coin::take(50)->get();
$event = new ReloadTableEvent($coin);
event($event);
}
I already do this
php artisan config:clear
php artisan cache:clear
php artisan optimize
php artisan clear-compiled
composer update
composer dump-autoload
Still nothing. What should i do?
UPDATE 1
I'm not using listener yet. When i create new project, and set the same option with my current project, it works.
storage/log/laravel.log
[2018-01-08 06:24:02] local.INFO: Broadcasting [reload-event] on channels [reload-channel] with payload:
{
"coin": {
"name": "Test"
},
"socket": null
}
You should listen to the events by php artisan queue:work
I am using an inbuilt code in Laravel to send Email Notification. Code is below. I am using smtp to send email
class RegisterNotification extends Notification
{
use Queueable;
public function __construct($token)
{
$this->token = $token;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line('hi');
}
public function toArray($notifiable)
{
return [
//
];
}
}
Here the problem is, it takes around 5 seconds to complete the process and control does not come back. I am assuming that if it come back and do the email sending work in background...it would save a lot of time.
Is there any inbuilt work to do the same? I meant, control should come back and should say email sent...and then it should do the work in background.
Email Sending code in Controller
class apiRegisterController extends Controller
{
public function Register(RegisterRequest $request) {
$RegisterNotification = new RegisterNotification($Token);
$User->notify($RegisterNotification);
}
}
Code for Queue
Controller Code
$job = (new SendForgotPasswordEmail($Data))->onConnection('database');
dispatch($job);
Job
class SendForgotPasswordEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $Data;
public $tries = 5;
public function __construct($Data)
{
$this->Data = $Data;
}
public function handle()
{
$Token = $this->Data["Token"];
$User = $this->Data["User"];
$RegisterNotification = new RegisterNotification($Token);
$User->notify($RegisterNotification);
}
}
Step 1: Change class RegisterNotification extends Notification to class RegisterNotification extends Notification implements ShouldQueue
Step 2: Implement a queue driver. In your config/queue.php make sure your driver is not set to sync like so: 'default' => env('QUEUE_DRIVER', 'sync'), and make sure your .env doesnt have QUEUE_DRIVER=sync. You can look at the Laravel documentation for queues to choose an appropriate queue driver
You can use the build-in API.
$user = User::findOrFail($id);
Mail::queue('emails.welcome', $data, function ($message) use ($user){
$message->from('hello#app.com', 'Your Application');
$message->to($user->email, $user->name)->subject('Your Reminder!');
});
But first you have to configure the queues.
Add in your .env file the line QUEUE_DRIVER=sync and then write on the terminal php artisan queue:listen.
If you want the queue to run forever on the server use Supervisor. Queues documentation explains how you can use it.
you can use laravel job queue https://laravel.com/docs/5.4/queues
Mail::queue(
I'm trying to use redis as a default broadcaster in laravel here is my .env fille
QUEUE_DRIVER=sync
APP_ENV=local
APP_DEBUG=true
APP_KEY=***********
DB_HOST=***************
DB_PORT=******************
DB_DATABASE=***************
DB_USERNAME=***********
DB_PASSWORD=*************
CACHE_DRIVER=file
SESSION_DRIVER=file
BROADCAST_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
I'm using this event class to broadcast
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
use Log ;
class SomeEvent extends Event implements ShouldBroadcast
{
use SerializesModels;
public $data;
public function __construct($room, $data)
{
Log::debug($room);
Log::debug($data);
$this->data = array(
'room' => $room,
'data' => $data
);
}
public function broadcastOn()
{
Log::debug('in channel!!!');
return ['test-channel'];
}
}
when i fire the event inside a controller using
event(new SomeEvent("test room", "test message"));
I get the following error
[2016-02-29 19:17:38] local.ERROR: exception 'Symfony\Component\Debug\Exception\FatalErrorException' with message 'Class 'Pusher' not found' in C:\xampp\htdocs\TechInsights\vendor\laravel\framework\src\Illuminate\Broadcasting\BroadcastManager.php:132
Stack trace:
The most strange thing is when i change the method createPusherDriver inside the BroadcastManager.php
from
protected function createPusherDriver(array $config)
{
return new PusherBroadcaster(
new Pusher($config['key'], $config['secret'], $config['app_id'], Arr::get($config, 'options', []))
);
}
to
protected function createPusherDriver(array $config)
{
return new RedisBroadcaster(
$this->app->make('redis'), Arr::get($config, 'connection')
);
}
the event broadcasts in redis without any issue ! any ideas ? Why laravel using pusher even if i configured it to use redis ? what i'm missing ?
Have you tried clearing your config cache?
php artisan config:clear