I'm firing event and passing object with array like this:
$event = new App\Events\SendMessage;
$event->msg = [ 'sender_id'=>'191',
'recepient_id'=>'190',
'text'=>'some text',
];
Event::fire($event);
Is it possible to make this call a bit shorter and fire event in one line like this?
Event::fire(new App\Events\SendMessage([
'sender_id'=>'191',
'recepient_id'=>'190',
'text'=>'some text',
]));
You would just need to make sure your event constructor is setup to populate that field.
See: http://laravel.com/docs/5.1/events#defining-events
<?php
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class SendMessage extends Event
{
use SerializesModels;
public $msg;
public function __construct($msg)
{
$this->msg = $msg;
}
}
Yep. Just pass the data in the __construct()
class SendMessage extends Event
{
protected $data;
public function __construct(array $data)
{
$this->data = $data;
}
}
In your App\Events\SendMessage you need to define a constructor method for example:
namespace App\Events;
class SendMessage {
protected $data = null;
public function __construct(Array $data)
{
$this->data = $data;
}
}
you can fire event like this in laravel
just put the code into your controller
event(new App\Events\EventClassName());
if your Event has parameters then
event(new App\Events\EventClassName(['first' => 'value','second' => 'value']));
Related
I have an event that would dispatch information on multiple channels:
A channel for members
A channel for managers
I wrote this:
<?php
class ModelUpdated implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $model;
public function __construct(Model $model)
{
$this->model = $model;
}
public function broadcastWith($who)
{
if ($who == "model.{$this->model->id}")
return [$this->model->id];
else if ($who == "model.{$this->model->id}.managers")
return [$this->model];
else
return [];
}
public function broadcastOn()
{
return [
new PrivateChannel("model.{$this->model->id}"),
new PrivateChannel("model.{$this->model->id}.managers")
];
}
}
Unfortunately, the broadcastWith doesn't work with my $who magic. Is there an alternative way of doing it?
I would like to avoid having different events because mine is triggered in the model:
class MyModel extends Model
{
use Notifiable;
protected $dispatchesEvents = [
'saved' => ModelUpdated::class,
'updated' => ModelUpdated::class,
];
}
As far as I know broadcastWith does not accept any parameter, Laravel 8.x.
You need to pass all your data through the constructor, then, make decision on what you need to return as event's payload.
Make sure to return an array from the broadcastWith() method.
So I am trying to implement a command that notifies all users that are subscribes to an event with command that does an check every day. I was reading Laravel mail docs 7.x so there example is about order system where they send the mail with this peace of code
foreach (['taylor#example.com', 'dries#example.com'] as $recipient) {
Mail::to($recipient)->send(new OrderShipped($order));
}
what as it looks takes the email of of the loop and then send an email toward that adress.
So I made a mail class php artisan make:mail NotifyUserOfEvents
and where I made this code
<?php
namespace App\Mail;
use App\Event;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class NotifyUserOfEvents extends Mailable
{
use Queueable, SerializesModels;
protected $event;
public function __construct(Event $event)
{
$this->event = $event;
}
public function build()
{
return $this->view('mails.NotifyUserOfEvents')
->with([
'name' => $this->event->name,
'date' => $this->event->settings->start_date,
]);
}
}
but when I try to call this class with this function
<?php
namespace App\Console\Commands;
use App\Event;
use App\RegistrationEvents;
use App\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
class NotifyUsersForEvents extends Command
{
protected $signature = 'NotifyUsersForEvents';
protected $description = 'Notify the user for the event. test run with -> php artisan schedule:run';
public function __construct()
{
parent::__construct();
}
public function handle()
{
Log::debug('this works every minute');
$events = Event::query()
->with('settings')
->has('settings')
->get();
foreach ($events as $event) {
$week = Carbon::now()->addWeek();
$sixDays = $week->copy()->subDay();
if (Carbon::create($event->settings->date_start)->between($week, $sixDays)) {
$subscriptions = RegistrationEvents::query()
->where('event_id', $event->id)
->get();
foreach ($subscriptions as $subscription) {
var_dump($subscription->user_id);
$user = User::findOrFail($subscription->user_id);
Mail::to($user->email)->send($event);
var_dump($user->email);
}
}
}
}
}
it returns this error: Argument 1 passed to Illuminate\Database\Eloquent\Model::__construct() must be of the type array, object given, called in so do I need to change the way I call the mail class or do I need to add something to the Event Model?
also the event.php
use Illuminate\Contracts\Mail\Mailable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Event extends Model implements Mailable
{
use SoftDeletes;
public function settings(){
return $this->hasOne('App\EventSettings', 'event_id');
}
}
You must pass to send function an object of your NotifyUserOfEvents, not an Event object.
Try this:
Mail::to($user->email)->send(new NotifyUserOfEvents($event));
Referring to this line:
Mail::to($user->email)->send(new Event($event));
you are creating a new Event passing to the constructor another Event... you probably never define a constructor that accept as first parameter an Event...
But despite that, what's the sense of doing this? To Mail::send you have to pass a Mailable, not an event, and i'm pretty sure you don't need a new event, so i believe you would want to do something like this:
use App\Mail\NotifyUserOfEvents; // or whatever namespace you have to the mail
Mail::to($user->email)->send(new NotifyUserOfEvents($event));
$user = User::find($id);
$email = $user->email;
if(Helper::isValidEmail($email))
{
Mail::send('emails.applicant_reference',
$emailParameters, function($message) use ($email, $name, $subject){
$message->to($email, $name)
->subject($subject);
});
$applicantName = null;
$subject = " Application received for ".$applicantName;
$emailParameters = ["applicantName" => $applicantName, "proposerName" => $proposerName, "seconderName" => $seconderName];
try
{
Mail::send('emails.application', $emailParameters, function($message) use ($applicantName, $subject){
$message->to(['test#gmail.com','test#gamil.com'], " Test Email Function ")
->subject($subject);
});
} catch (Exception $ex){ Log::error("UserController".$ex->getMessage());
}
So I have event and listener classes defined as well as having them registered in the $listen array in EventServiceProvider.php. Here is the code:
use App\Events\EpisodeCreated;
use App\Listeners\NewEpisodeListener;
use Event;
class EventServiceProvider extends ServiceProvider {
protected $listen = [
EpisodeCreated::class => [
NewEpisodeListener::class
]
];
}
and then in EventServiceProvider's boot method I have the following:
public function boot() {
Episode::created(function($episode) {
Event::fire(new EpisodeCreated($episode));
});
}
here is the EpisodeCreated event class:
namespace App\Events;
use App\Models\Episode;
class EpisodeCreated extends Event {
public $episode;
public function __construct(Episode $episode) {
$this->episode = $episode;
}
}
and finally the listener:
namespace App\Listeners;
use App\Events\EpisodeCreated;
use App\Facades\EventHandler;
use App\Http\Resources\ShowResource;
class NewEpisodeListener {
public function __construct() {
}
public function handle(EpisodeCreated $event) {
EventHandler::sendNewEpisode((new ShowResource($event->episode->show))->toArray());
}
}
Lastly, I wrote the following unit test to make sure that the event is firing. It doesn't seem to be:
public function testNewEpisodeEventFiredOff() {
Event::fake();
$show = factory(Show::class)->create();
$episode = factory(Episode::class)->create(['show_id' => $show->id]);
Event::assertDispatched(EpisodeCreated::class);
}
I get an error saying that the event never got dispatched when I run phpunit. Also I added echo debug statements and while the EpisodeCreated object is being created, the NewEpisodeListener is not being fired off. Any help you guys can give would be greatly appreciated.
Well, my problem seems to be that I defined the boot method in EventServiceProvider without calling parent::boot(). Since I refactored my code to not use the boot method at all, I removed it and it seems to be working better now.
I had the issue and could solve this. You should add below code to your EventServiceProvider class:
public function register()
{
$this->boot();
}
It seems boot method is not called when it is run by UnitTest or Command-line command I don't know why.
I try to catch an event, when job is completed
Test code:
class MyTest extends TestCase {
public function testJobsEvents ()
{
Queue::after(function (JobProcessed $event) {
// if ( $job is 'MyJob1' ) then do test
dump($event->job->payload());
$event->job->payload()
});
$response = $this->post('/api/user', [ 'test' => 'data' ], $this->headers);
$response->assertSuccessful($response->isOk());
}
}
method in UserController:
public function userAction (Request $request) {
MyJob1::dispatch($request->toArray());
MyJob2::dispatch($request->toArray());
return response(null, 200);
}
My job:
class Job1 implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $data = [];
public function __construct($data)
{
$this->data= $data;
}
public function handle()
{
// Process uploaded
}
}
I need to check some data after job is complete but I get serialized data from
$event->job->payload() in Queue::after And I don't understand how to check job ?
Well, to test the logic inside handle method you just need to instantiate the job class & invoke the handle method.
public function testJobsEvents()
{
$job = new \App\Jobs\YourJob;
$job->handle();
// Assert the side effect of your job...
}
Remember, a job is just a class after all.
Laravel version ^5 || ^7
Synchronous Dispatching
If you would like to dispatch a job immediately (synchronously), you may use the dispatchNow method. When using this method, the job will not be queued and will be run immediately within the current process:
Job::dispatchNow()
Laravel 8 update
<?php
namespace Tests\Feature;
use App\Jobs\ShipOrder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Support\Facades\Bus;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_orders_can_be_shipped()
{
Bus::fake();
// Perform order shipping...
// Assert that a job was dispatched...
Bus::assertDispatched(ShipOrder::class);
// Assert a job was not dispatched...
Bus::assertNotDispatched(AnotherJob::class);
}
}
This my generic method, using a route
Route::get('job-tester/{job}', function ($job) {
if(env('APP_ENV') == 'local'){
$j = "\\App\Jobs\\".$job;
$j::dispatch();
}
});
Im developing a task system and i want to mark as viewed a task and do other things when a user request the task
I wrote a Task Event Subscriber like this
<?php namespace Athena\Events;
class TaskEventSubscriber {
public function onCreate($event)
{
// Here we can send a lot of emails
}
public function onUpdate($event)
{
\Log::info('This is some useful information.');
}
public function onShow($event)
{
\Log::info('The view event is now triggerd ');
}
public function subscribe($events)
{
$events->listen('user.create', 'Athena\Events\TaskEventSubscriber#onCreate');
$events->listen('user.update', 'Athena\Events\TaskEventSubscriber#onUpdate');
$events->listen('task.show', 'Athena\Events\TaskEventSubscriber#onShow');
}
}
And my controller I fire the event like this:
public function show($id)
{
$canView = $this->canView($id);
if($canView !== true)
{
return $canView;
}
$task = $this->task->byId($id);
// We fire the showed event
$this->events->fire('task.show', $this->task);
return View::make('tasks.show')
->with('task', $task);
}
But i dont know how can I or I should catch a parameter to be used inside of the event
By the way my Task Event subscriber is register on this Service Provider
class AthenaServiceProvider extends ServiceProvider {
public function register()
{
// A lot of stuffs
}
public function boot()
{
\Event::subscribe('Athena\Events\UserEventSubscriber');
\Event::subscribe('Athena\Events\TaskEventSubscriber');
}
}
If you need more information just let me know, Thnks in advance
You will need to declare an Event object like this
<?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class TriggerShowTask extends Event {
use SerializesModels;
public $task;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($task)
{
$this->task = $task;
}
}
When you trigger the event with
\Event::fire(TriggerShowTask, $this->task);
The $taskobject will be passed to the event
You can then access it in the subscriber with
public function onShow($event)
{
$event->task; // A Task object
\Log::info('The view event is now triggerd ');
}
I dont know how to feel already...
I am passing the values what i need to my event there are on $event variable of each function
Note: if you need to send more than one value just put them into an array and set your event function to catch them like parameters