Laravel 5 Event Handler Not Firing - php

So I'm trying out the new Laravel 5 Event methodology.
In my repository, I'm firing the event "KitchenStored" as so:
// Events
use App\Events\KitchenStored;
class EloquentKitchen implements KitchenInterface {
public function store($input) {
$kitchen = new $this->kitchen;
$kitchen->name = $input['name'];
$kitchen->save();
\Event::fire(new KitchenStored($kitchen));
return $kitchen;
}
Which successfully fires this event:
<?php namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class KitchenStored extends Event {
use SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($kitchen)
{
$this->kitchen = $kitchen;
}
}
However, it doesn't link up to this handler:
<?php namespace App\Handlers\Events;
use App\Events\KitchenStored;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
class AttachCurrentUserToKitchen {
/**
* Create the event handler.
*
* #return void
*/
public function __construct()
{
dd('handler');
}
/**
* Handle the event.
*
* #param KitchenStored $event
* #return void
*/
public function handle(KitchenStored $event)
{
//
}
}
which I know because the dd('handler'); isn't fired during the request lifecycle.
I have registered the event with its listener here:
<?php namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider {
/**
* The event handler mappings for the application.
*
* #var array
*/
protected $listen = [
App\Events\KitchenStored::class => [
App\Handlers\Events\AttachCurrentUserToKitchen::class
]
];
/**
* Register any other events for your application.
*
* #param \Illuminate\Contracts\Events\Dispatcher $events
* #return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
Event::listen('App\Events\KitchenStored',
'App\Handlers\Events\AttachCurrentUserToKitchen');
}
}
Can anyone explain this process better so I can keep going with the cleanest code I have to date?
Many thanks

In EventServiceProvider.php, include the leading \ when referencing a class using the ::class notation:
protected $listener = [
\App\Events\KitchenStored::class => [
\App\Handlers\Events\AttachCurrentUserToKitchen::class,
],
];
You could also add use statements and keep your listener mappings short:
use App\Events\KitchenStored;
use App\Handlers\Events\AttachCurrentUserToKitchen;
...
protected $listener = [
KitchenStored::class => [
AttachCurrentUserToKitchen:class,
],
];
Or just use the string notation:
protected $listener = [
'App\Events\KitchenStored' => [
'App\Handlers\Events\AttachCurrentUserToKitchen',
],
];

If you run php artisan optimize, your event handlers should start listening.
Credit to mattstauffer from the larachat slack channel for that one.

I ran
composer dumpautoload
followed by
php artisan clear-compiled
Then my events began firing.

Don't be like me and cache your events locally to test something, then forget to clear that cache 😅
php artisan event:clear

Make sure your EventServiceProvider is calling the parent register function.
public function register() {
parent::register():
}

I had a similar issue and I fixed it by deleting the vendor\compiled.php file. Then I run "composer update" again and now the handler is firing as expected.

For me, I had the issue where I had multiple listeners for a single event. In that case, the listeners are executed in order. However, if one of the listeners return false, then all of the others listeners are not executed.

This is an older question, but I came across this same issue and for me, it was because I'd added my new Event to the service provider but crucially I had not imported it. For anyone in 2020 with this issue, check that you have imported the event.

Related

Have no idea why the listener is not being called in Laravel

Heres the event:
<?php
namespace App\Modules\Clinicians\Events;
use Illuminate\Queue\SerializesModels;
class CreateHealthCareProviderEvent
{
use SerializesModels;
public $data;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(array $data)
{
$this->data = $data;
}
}
The event gets called just fine. But the listener:
<?php
namespace App\Modules\Clinicians\Listeners;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Modules\Clinicians\Events\CreateHealthCareProviderEvent;
use App\Modules\Clinicians\Events\EmailClinicAdminsEvent;
use App\Modules\Users\Services\RegisterUserService;
class CreateHealthCareProviderListener
{
private $registerUserService;
/**
* Create the event listener.
*
* #return void
*/
public function __construct(RegisterUserService $registerUserService)
{
$this->registerUserService = $registerUserService;
}
/**
* Handle the event.
*
* #param object $event
* #return void
*/
public function handle(CreateHealthCareProviderEvent $event)
{
$user = $this->registerUserService->setRequestData($event->data)->registerUser(Clinic::find($event->data['clinic_id']));
$user->clinician()->create([
'user_id' => $user->id,
]);
$user->clinician->clinics()->attach($event->data['clinic_id']);
event(new EmailClinicAdminsEvent($user, $event->data['clinic_id']));
}
}
Never gets called. Ever. So how am I registering these?
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
// When a new health care provider registers:
CreateHealthCareProviderEvent::class => [
CreateHealthCareProviderListener::class,
],
// Email the Clinic admins when a healthcare provider registers:
// Called in the CreateHealthCareProviderListener handler method.
EmailClinicAdminsEvent::class => [
EmailClinicAdminsListener::class,
],
];
...
}
I have never had an issue registering events and listeners like this before. They always work. But for some reason the listener will not fire for this event. The event fires just fine. But not the listener. What am I missing?
I have tried:
php artisan optimize
composer dump-autoload
Nothing.
Its called as such:
// Create the health care provider user:
event(new CreateHealthCareProviderEvent($request->all()));
Any ideas? I checked spelling and namespaces and everything seems correct. What am I missing?
There are no errors, nothing. The tests still pass (I dont fake events) and the test coverage shows the event gets called, but the test coverage shows the listener does not get called. When I try this out in the browser, no user is created - which is done by the listener.
All my other events and their associated listeners are called just fine.
What is going on?
So I am retarded and will take the downvotes on this one but for future reference, make sure your use statements are proper. because Laravel won't tell you when registering events:
use App\Modules\Clinicians\CreateHealthCareProviderEvent;
use App\Modules\Clinicians\EmailClinicAdminsEvent;
use App\Modules\Clinicians\CreateHealthCareProviderListener;
use App\Modules\Clinicians\EmailClinicAdminsListener;
What do you think is missing here? let me tell you:
use App\Modules\Clinicians\Events\CreateHealthCareProviderEvent;
use App\Modules\Clinicians\Events\EmailClinicAdminsEvent;
use App\Modules\Clinicians\Listeners\CreateHealthCareProviderListener;
use App\Modules\Clinicians\Listeners\EmailClinicAdminsListener;
This is why the event was being called but not the listener. In the controller class where the event in question was being called, I imported the event properly, but in the event service provider I did not.

Capturing rows affected by query with Event

I am trying to write an event that will display how many rows were affected by a query.
I found the Illuminate\Database\Events\QueryExecuted Event. I have added a listener for the event and registered it in Event service Provider:
EventServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
'Illuminate\Database\Events\QueryExecuted' => [
'App\Listeners\QueryExecutedListener#handle'
],
];
/**
* Register any other events for your application.
*
* #param \Illuminate\Contracts\Events\Dispatcher $events
* #return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
//
}
}
and in my handle method I can see the queries being run:
public function handle(QueryExecuted $event)
{
var_dump($event);
}
However, I can't find a way to see how many rows were updated/deleted by the query run.
I'd appreciate any advice.
The EventServiceProvider included with your Laravel application provides a convenient place to register all of your application's event listeners.
https://laravel.com/docs/5.4/events

How to listen for an event in Laravel 5.2?

I have a Laravel package that fires an event which is located in the vendor folder.
The event's class that is being fired is Mikea\Kicker\Events\Interviews\SurveyWasCompleted
I need to listen in for that event and then die and dump the event's object.
I added the following code in my routes.php file
Event::listen('Mikea\Kicker\Events\Interviews\SurveyWasCompleted', function($event){
dd($event);
});
However, nothing is displayed on the screen. I know for sure that the SurveyWasCompleted event is called because when I die and dump from inside the event I get the data.
How can I correctly listen for an event to be fired?
You need to register the event in EventServiceProvider
protected $listen = [
'Mikea\Kicker\Events\Interviews\SurveyWasCompleted' => [
'Mikea\Kicker\Listeners\SurveyWasCompletedListener',
]
];
Then you need to create a Listener SurveyWasCompletedListener
namespace Mikea\Kicker\Listeners;
use Mikea\Kicker\Events\Interviews\SurveyWasCompleted;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SurveyWasCompletedListener
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param SurveyWasCompleted $event
* #return void
*/
public function handle(SurveyWasCompleted $event)
{
//do something
}
}
Obviously you need to fire the event using
Event::fire(new SurveyWasCompleted($data));
You might need to register it in the EventServiceProvider rather than the routes.php file.
https://laravel.com/docs/5.2/events#registering-events-and-listeners

auth.register Event in Laravel

I am currently trying to add events for when a user registers in Laravel 5.1. I have managed to add 2 event handlers that work perfectly, however when I build out another event using:
php artisan handler:event UserVotesAfterRegister
This does not get called, at all. I read on the Laravel website that you can have as many event handlers as you like so really not sure why this is not getting fired.
Here is my listen events stored in EventServiceProvider:
protected $listen = [
'App\Events\SomeEvent' => [
'App\Listeners\EventListener',
],
'SocialiteProviders\Manager\SocialiteWasCalled' => [
// add your listeners (aka providers) here
'SocialiteProviders\Tumblr\TumblrExtendSocialite#handle'
],
'auth.login' => [
'App\Handlers\Events\UserVotesAfterLogin',
'App\Handlers\Events\AddInteractionLog',
'App\Handlers\Events\PageInteractionTracking',
],
'auth.register' => [
'App\Handlers\Events\UserVotesAfterRegister',
'App\Handlers\Events\AddInteractionLog',
'App\Handlers\Events\PageInteractionTracking',
],
'auth.password' => [
'App\Handlers\Events\AddInteractionLog',
'App\Handlers\Events\PageInteractionTracking',
],
'auth.logout' => [
'App\Handlers\Events\AddInteractionLog',
],
];
And here is my event handler that was built from the artisan make command:
namespace App\Handlers\Events;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
class UserVotesAfterRegister
{
/**
* Create the event handler.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param Events $event
* #return void
*/
public function handle()
{
//
dd("DIE");
}
}
Any help would be appreciated.
I have tried to clear all caches using:
composer dumpautoload
composer dump-autoload
php artisan clear-compiled
php artisan optimize
php artisan cache:clear
...but to no avail
namespace App\Handlers\Events;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
class UserVotesAfterRegister
{
/**
* Create the event handler.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param Events $event
* #return void
*/
public function handle(SomeEventHandler $event)
{
// The $event is missing here. Please consider it first and try again.
dd("DIE");
}
}
Right,
Think I have figured this out. Basically, there is no auth.register event. When you register a new user the auth.login event gets called for both registration and login.
The website says:
When the attempt method is called, the auth.attempt event will be fired. If the authentication attempt is successful and the user is logged in, the auth.login event will be fired as well.
This indicates that even when a user registers the auth.login event is called.

login event handling in laravel 5

i am trying to hook to the login even in my L5 app to set last login time and IP address. i can make it work with the following:
Event::listen('auth.login', function($event)
{
Auth::user()->last_login = new DateTime;
Auth::user()->last_login_ip = Request::getClientIp();
Auth::user()->save();
});
however, i am wondering what the best way to do this in L5 is with the event handler object. i tried creating an event handler and adding auth.login as an array key in the events service provider, however that didnt work. im not sure if that is possible or not with the auth.login event. if it isnt, where is the most appropriate place to put the above code. for testing, i put it in my routes.php file, but i know that isnt where it should be.
In laravel 5.2; auth.login won't work... the following will have to be used:
protected $listen = [
'Illuminate\Auth\Events\Attempting' => [
'App\Listeners\LogAuthenticationAttempt',
],
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\LogSuccessfulLogout',
],
'Illuminate\Auth\Events\Lockout' => [
'App\Listeners\LogLockout',
],
];
As stated in the documentation here
EDIT: this only works in 5.0.* and 5.1.*.
For the 5.2.* solution see JuLiAnc response below.
after working with both proposed answers, and some more research i finally figured out how to do this the way i was trying at first.
i ran the following artisan command
$ php artisan handler:event AuthLoginEventHandler
Then i altered the generated class removing the import of the Event class and and imported the user model. I also passed User $user and $remember to the handle method since when the auth.login event is fired, thats what is passed.
<?php namespace App\Handlers\Events;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
use App\User;
class AuthLoginEventHandler {
/**
* Create the event handler.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param User $user
* #param $remember
* #return void
*/
public function handle(User $user, $remember)
{
dd("login fired and handled by class with User instance and remember variable");
}
}
now i opened EventServiceProvided.php and modified the $listen array as follows:
protected $listen = [
'auth.login' => [
'App\Handlers\Events\AuthLoginEventHandler',
],
];
i realized if this doesn't work at first, you may need to
$ php artisan clear-compiled
There we go! we can now respond to the user logging in via the auth.login event using an event handler class!
Be careful about asking what the best way to do X is, because Laravel, in particular, provides many ways of accomplishing the same task -- some are better than others in certain situations.
Taking a look at the Laravel documentation, personally I would go with the "Basic Usage" as it seems to match the use case you have stated.
If we run the following Artisan command we can generate a template for the UserLoggedIn event.
$ php artisan make:event UserLoggedIn
(note the past tense, because events happen, and then the subscribers are notified of the event having taken place)
(note 2: the app string in namespaces is what Laravel uses out of the box, it is likely different for you if you have executed the php artisan app:name command)
The following class is generated for us:
<?php namespace app\Events;
use app\Events\Event;
use Illuminate\Queue\SerializesModels;
class UserLoggedIn extends Event {
use SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
//
}
}
If we add a userId parameter to the constructor, then the event doesn't need to know about the Auth Facade/Guard Contract. This means our UserLoggedIn event code is not tightly coupled to Eloquent or which ever authentication framework you decide to utilize in your app. Anyways, let's add that userId parameter.
<?php namespace app\Events;
use app\Events\Event;
use app\User;
use Illuminate\Queue\SerializesModels;
class UserLoggedIn extends Event {
use SerializesModels;
public $userId;
/**
* Create a new event instance.
*
* #param int userId the primary key of the user who was just authenticated.
*
* #return void
*/
public function __construct($userId)
{
$this->userId = $userId;
}
}
Now you're probably wondering, well that's great and all, but how to we act on this event? Great question! We need to create an event handler to handle when this event is fired. Let's do that now using Artisan:
$ php artisan handler:event UpdateUserMetaData --event=UserLoggedIn
We name our new event handler UpdateUserMetaData and tell Artisan that the event we want to handle is the UserLoggedIn event.
Now we have some code that looks like this inside of app/Handlers/Events/UpdateUserMetaData.php:
<?php namespace app\Handlers\Events;
use app\Events\UserLoggedIn;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;
class UpdateUserMetaData {
/**
* Create the event handler.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param UserLoggedIn $event
* #return void
*/
public function handle(UserLoggedIn $event)
{
//
}
}
We can update the handle method to be able to handle this event like you specified above quite easily:
<?php namespace app\Handlers\Events;
use app\Events\UserLoggedIn;
use Illuminate\Http\Request;
class UpdateUserMetaData {
protected $request;
/**
* Create the event handler.
*
* #param Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Handle the event.
*
* #param UserLoggedIn $event
*/
public function handle(UserLoggedIn $event)
{
$user = User::find($event->userId); // find the user associated with this event
$user->last_login = new DateTime;
$user->last_login_ip = $this->request->getClientIp();
$user->save();
}
}
As a side note, if you're not familiar with Carbon, you might want to look into using it so you can take advantage of its fantastic API like you can with Eloquent's created_at and updated_at timestamp fields on most models. Here's a link for how to tell Eloquent which fields should be used with Carbon: http://laravel.com/docs/master/eloquent#date-mutators.
There are two final steps we have to perform before this code will work in your Laravel app.
We need to map the event to the event handler in the EventServiceProvider class under the app/Providers directory.
We need to fire the event after login.
To complete the first step, we just need to add our event classes to the $listeners property in app/Providers/EventServiceProvder.php like so:
UserLoggedIn::class => [
UpdateUserMetaData::class
]
The above will work provided you import the classes inside the EventServiceProvider class, and you are using PHP 5.5. If you're using a lower PHP version, you'll need to provide the full path to each class as a string like this: 'app/Events/UserLoggedIn' and 'app/Handlers/Events/UpdateUserMetaData'.
The $listeners array maps events to their respective handlers.
Okay, now for the final step! In your code base, find the place where the user is authenticated and add the following:
event(new \app\Events\UserLoggedIn(Auth::user()->id));
And we're done! I tested this code as I wrote this answer, feel free to ask follow up questions if you have any.
For 5.2 something like this
in Listeners:
use Carbon\Carbon;
use Illuminate\Auth\Events\Login;
class UpdateLastLoginWithIp
{
public function handle(Login $event)
{
$event->user->last_login_at = Carbon::now();
$event->user->last_login_ip = Request::getClientIp()
$event->user->save();
}
}
In EventServiceProvider.php :
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'City\Listeners\UpdateLastLoginWithIp',
],
];
Usually you can achieve by doing like this step by step for User Login Logs
first, you should have Auth Scaffolding
use this as event,
'Illuminate\Auth\Events\Login' for Login Event
'Illuminate\Auth\Events\Logout' for Logout Event
located the login and logout event at :
vendor\laravel\framework\src\Illuminate\Auth\Events
EventServiceProvider.php
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LoginLogs',
],
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\LogoutLogs',
],
];
public function boot()
{
parent::boot();
}
then after you get done for EventServiceProvider, do this next step
type this artisan command php artisan event:generate
look for folder Listener inside App folder, check if contains php files both LoginLogs and LogoutLogs
create your migration and model
command: php artisan make:migration create_UserLoginHistory
Migration File
public function up()
{
Schema::create('tbl_user_login_history', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id');
$table->datetime('login_at')->nullable();
$table->datetime('logout_at')->nullable();
$table->string('login_ip')->nullable();
$table->string('role');
$table->string('session_id');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('tbl_user_login_history');
}
then your Model : UserLoginHistory
public $timestamps = false;
protected $table = 'tbl_user_login_history';
protected $fillable = ['user_id','login_at','logout_at','login_ip','role','session_id'];
public function setLogOutLog(){
$this->where('session_id',request()->session()->getId())->update([
'logout_at' =>Carbon::now(),
]);
}
public function setLogInLog(){
$this->insert(
['user_id' => Auth::user()->id,'login_at' =>Carbon::now(),
'login_ip'=>request()->getClientIp(),'role' =>Auth::user()->role,
'session_id'=>request()->session()->getId()
]);
}
4.after the migration and model creation procedure, let's assume that you have already in roles in users table
the listener part
Listener : LoginLogs Class
use App\UserLoginHistory;
private $UserLoginHistory;
public function __construct(UserLoginHistory $UserLoginHistory)
{
// the initialization of private $UserLoginHistory;
$this->UserLoginHistory = $UserLoginHistory;
}
public function handle(Login $event)
{
// from model UserLoginHistory
$this->UserLoginHistory->setLogInLog();
}
Listener : LogoutLogs Class
private $UserLogoutHistory;
public function __construct(UserLoginHistory $UserLoginHistory)
{
// the initialization of private $UserLogoutHistory;
$this->UserLogoutHistory = $UserLoginHistory;
}
public function handle(Logout $event)
{
// from model UserLoginHistory
$this->UserLogoutHistory->setLogOutLog();
}
after you do this all steps , try to login with Auth
here is my approach:
I have done for making an event handler when user logged in using:
Laravel 5.8
1) Run the following artian command
php artisan make:listener Auth/UserLoggedIn --event='Illuminate\Auth\Events\Login'*
It will make a Listener: UserLoggedIn in folder app\Listeners\Auth\
2) Then you need to add this listener into your EventServiceProvider:**
...
protected $listen = [
...
'Illuminate\Auth\Events\Login' => [
'App\Listeners\Auth\UserLoggedIn',
],
];
Finaly you can do log when user logged in in handle function located at UserLoggedIn Listener:
public function handle(Login $event)
{
//you have access to user object by using : $event->user
}
you can use all other Auth events, here is the possible events:
'Illuminate\Auth\Events\Registered',
'Illuminate\Auth\Events\Attempting',
'Illuminate\Auth\Events\Authenticated',
'Illuminate\Auth\Events\Login',
'Illuminate\Auth\Events\Failed',
'Illuminate\Auth\Events\Logout',
'Illuminate\Auth\Events\Lockout',
**You can use all these events in your EventServiceProvider:
https://laravel.com/docs/5.8/authentication#events
Open up EventServiceProvider.php and in boot method you can listen for 'auth.login' event via callback.
public function boot(DispatcherContract $events)
{
parent::boot($events);
$events->listen('auth.login', function()
{
dd('logged in event');
});
}
You may want to create listener so you move callback function somewhere else. Do that following this http://laravel.com/docs/4.2/events#using-classes-as-listeners
just did it this way
<?php
namespace App\Providers;
use App\User;
use Auth;
use DB;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
];
/**
* Register any other events for your application.
*
* #param \Illuminate\Contracts\Events\Dispatcher $events
* #return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
$events->listen('auth.login', function()
{
DB::table('users')
-> where('id', Auth::id())
-> update(array(
'last_login' => date('Y-m-d H:i:s')
));
});
//
}
}

Categories