So I've started using Queued Events in L5 for handling some logic and I was wondering if it was possible to tell laravel what tube to use when pushing the events onto Beanstalkd.
I couldn't see anything in the documentation about it.
After digging through the Event Dispatcher code.
I found that if there is a queue method on your event handler laravel will pass the arguments through to that method and let you call the push method manually.
So if you have a SendEmail event handler you can do something like this:
<?php namespace App\Handlers\Events;
use App\Events\UserWasCreated;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
class SendEmail implements ShouldBeQueued {
use InteractsWithQueue;
public function __construct()
{
}
public function queue($queue, $job, $args)
{
// Manually call push
$queue->push($job, $args, 'TubeNameHere');
// Or pushOn
$queue->pushOn('TubeNameHere', $job, $args);
}
public function handle(UserWasCreated $event)
{
// Handle the event here
}
}
Related
Here's a simplified version of my Command which attempts to fire an event (obviously there's much more logic in the original).
The event is not being fired. Any idea what I've missed?
<?php namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Events\StackEvent;
class StackCommand extends Command
{
public function handle()
{
event(new StackEvent());
}
}
Thanks
The Laravel SSE(server sent event) is a great solution to push the changes to frontend, however, on the server side, we need to have an efficient way to keep track of the updated record(s) before sending notification to frontend. however, the SSE requires a controller to work with, problem is how can the controller capture the Laravel events?
class HomeController extends Controller
{
public function sse(SSE $sse)
{
// how to add the Laravel event listener here?
return $sse->createResponse();
}
}
Laravel provides with events, listeners, broadcasting and channels to communicate with front end via events. You don't need to do that in controllers. You can define broadcast routes in
routes/channels.php
you can then define events that by default include broadcast method in scaffolding.
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
Bind listeners to event and implement "shouldque" interface to that these run as async jobs. You can also use laravel notifications to provide live notification. laravel broadcasting
If you still want to grab event in controller you can specify in EventServiceProvider as
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
DownloadFile::class => [
CompanyDashboardController::class,
],
];
public function boot()
{
parent::boot();
}
}
your event will look like
class DownloadFile
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $process_id;
public function __construct($process_id)
{
$this->process_id = $file;
}
}
Finally you can grab this event in you controller as like:
class CompanyDashboardController extends Controller
{
public function __construct()
{
//constructor
}
public function handle(DownloadFile $event)
{
if($event->process_id == 1)
{
return "something";
}
}
}
If you meant to some Javascript event instead of Laravel read
Use Server-Sent Events to push messages to browser
In an event listener, I send a notification to a dog owner like this:
$event->dogowner->notify(new DogWasWalkedNotification);
The issue is since there are two channels database/mail set in the Notification below, they both get added as queued jobs on the 'notifications' queue, set in the constructor. Instead, I want to add the mail channel below to an emails queue instead of the default one set in the constructor of 'notifications'.
Any idea how to have the following notification only add the mail channel MailMessage to an emails queue without adding the database channel to a queue at all? (even if that means removing the constructor onQueue)
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use App\Events\DogWasWalked;
class DogWasWalkedNotification extends Notification implements ShouldQueue
{
use Queueable;
protected $event;
public function __construct(DogWasWalked $event) {
$this->event = $event;
// This is what creates 2 queued jobs (one per channel)
$this->onQueue('notifications');
}
public function via($notifiable) {
return ['database', 'mail'];
}
public function toArray($notifiable) {
return [
'activity' => 'Dog was walked!',
'walkername' => $this->event->walkername
];
}
public function toMail($notifiable) {
// How to set the queue name for
// this channel to 'emails'
return (new MailMessage)
->line('Dog was walked!');
}
}
Problem
I can confirm that Pusher API is receiving the message. I saw in Debug console of Pusher website. But listen callback is not working at all.
I am following this tutorial to implement Pusher in Laravel 5.4
Below were the step by step things done.
composer require pusher/pusher-php-server
npm install --save laravel-echo pusher-js
instantiated the Echo instance in your resources/assets/js/bootstrap.js
Initialized the pusher key in env and in bootstrap.js file.
Finally, I wrote below code in blade.
<script>
window.Echo.channel('SendMessageChannel.1')
.listen('App.Events.SendMessageEvent', (e) => {
console.log(e);
});
</script>
Controller Code
broadcast(new SendMessageEvent("Hi"))->toOthers();
Event Code
class SendMessageEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $Message;
public function __construct($message)
{
$this->Message = $message;
}
public function broadcastOn()
{
return new PrivateChannel('SendMessageChannel.2');
}
}
Am I missing anything?
You have to listen to: SendMessageEvent without the namespace.
when you listen to a private channel, you need to to listen to private-SendmessageChannel or you use Echo.private('SendmessageChannel')
Because we fixxed the issue via teamspeak at some parts it's difficult to explain it in this answer in full detail.
One problem was also that the event was fired before the client started to listen to it. The best way is to debug with the pusher console and to fire custom events.
I have been using Laravel 5.4 events quite efficiently since 6 months with a project. I had same trouble when I was doing initial setup. Let me guide you with whatever I have done to get it working.
I can see you have controller to initiate an Event, SendMessageEvent to send message content to pusherjs. You need to check following stuff to get it going.
Check 1:
But you have not mentioned if you have an Eventhandler defined. Event handler works as a bridge between the SendMessageEvent and its actual broadcaster.
So define an Eventhandler create one folders like app / Handlers / Events /. (here Handlers and Events are folders. where Events is inside Handlers)
create one file inside this Events folder with a name e.g.
HandleMyMessage.php
And put this code in it:
<?php
namespace App\Handlers\Events;
use App\Events\SendMessageEvent; // This should be your event class..
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class HandleMyMessage{
protected $name;
public function __construct() {
//
}
public function handle(Message $event) {
// No need to write anything here
}
}
Check 2:
There should be one provider at app / Providers / EventServiceProvider.php location, and put following code in EventServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
'App\Events\SendMessageEvent' => [
'App\Handlers\Events\EventServiceProvider',
],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
parent::boot();
}
}
Check 3:
And you should change syntax of sending event message in your controller like this:
$broadcast_data['first_name'] = 'John';
$broadcast_data['last_name'] = 'Doe';
$return_socket['data'] = $broadcast_data;
Event::fire(new Message($return_socket)); // Sending message to pusherjs via Laravel Event.
More on this, you also need Redis installed on your system and run it.
Hope this helps. If you need more information for any of above, just comment. I am posting a reference link for the same.
Happy coding!!! :-)
I got it working. Below is the correct code. I hope this will be useful to others for sending real time messaging.
Js Work
<script>
window.Echo.channel('private-SendMessageChannel.{!! \Auth::user()->UserID !!}')
.listen('SendMessageEvent', (e) => {
console.log(e);
});
</script>
Controller Code
broadcast(new SendMessageEvent("Hi", 1))->toOthers();
//Here 1 is recepient ID
Event Code
class SendMessageEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $Message;
private $UserID;
public function __construct($message, $RecepientID)
{
$this->Message = $message;
$this->UserID = $RecepientID;
}
public function broadcastOn()
{
return new PrivateChannel('SendMessageChannel.' . $UserID);
}
}
In my case, I had used:
public function broadcastAs()
{
return 'message';
}
If you've set the broadcast name, you must use that name in the listener differently.
For those who have done the same mistake as I did:
If you customize the broadcast name using the broadcastAs method, you should make sure to register your listener with a leading . character. This will instruct Echo to not prepend the application's namespace to the event:
https://laravel.com/docs/9.x/broadcasting#broadcast-name
Job
class DataFormFields extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $fieldList = [
'name' => 'Tom',
'age' => '20',
];
public function handle()
{
$fields = $this->fieldList;
return $fields;
}
}
controller
public function create()
{
$data = $this->dispatch(new DataFormFields());
return view('create', $data);
}
I try to dd($data); print 0
the code can work in laravel5.1 ,but in 5.2 it's not ok.help
Laravel5.2 the class will implement the Illuminate\Contracts\Queue\ShouldQueue interface, indicating to Laravel that the job should be pushed onto the queue instead of run synchronously.
So you should make job like php artisan make:job fooJob --sync
I don't think you want to rely on the return from dispatch(), as queued jobs can have their execution delayed by an arbitrary amount of time, depending on your implementation. You probably want to consider using Events or a callback.
https://laravel.com/docs/5.2/queues#job-events
Or, at the end of the handle function you could do something like:
call_user_func(['FormFieldsHandler', 'dataFormFieldsCallback'], $data]);
Getting a list of fields like that isn't really the use case for a Job, as the return value of the handle() method is never returned to the calling scope through the dispatch() method.
It seems like something best left to a Service, or a model even.
Here's how you might implement this with a service.
<?php
namespace App\Services;
class DataFieldService
{
protected $fields = ['field_one', 'field_two'];
public function getFields()
{
return $this->fields;
}
}
And in the controller...
<?php
namespace App\Http\Controllers;
use App\Services\DataFieldService;
class MyController
{
// in Laravel, the IoC container will inject DataFieldService
// for you automagically if you type hint it
public function create(DataFieldService $dataFieldService)
{
$fields = $dataFieldService->getFields();
return view('create', compact('fields'));
}
}
And, obviously, you can flesh out the DataFieldService to get the fields from a database or something. Hope that helps!
Yes you can. Simply return the value. Instead of calling dispatch, you can call the job's handle like this.
public function handle()
{
$a = "return value";
return $a;
}
}
Now instead of calling $this->dispatch(new ExampleJob) in your controller. You can do this instead.
$exampleJob = new ExampleJob();
$retval = $exampleJob->handle();
echo $retval; //return value
Please note that only works if you do not intend to queue the job.
You can't get result from async job . when you implements from ShouldQueue interface it means that you tend exec job Async . you must remove ShouldQueue to exec sync job to get result