How to hook into Spark Events on Register - laravel

I know that spark has events that can be listened to when user has registered but I'm totally new to laravel and Events, are there examples that I can make use of to access the events? My goal is to listen to the user created event and send a welcome email to the user.

Finally, here i came up with solution.
Basically, Events call listeners that is defined in the EventServiceProvider class that is store in the providers inside the app folder of the application.
In the EventServiceProvider.php find
'Laravel\Spark\Events\Auth\UserRegistered' => [
'Laravel\Spark\Listeners\Subscription\CreateTrialEndingNotification',
],
it will be store in the $listen of the EventServiceProvider class, this means that the UserRegistered event will call the CreateTrialEndingNotification listener, so we need to create a listerner and attach here , creating listener is easy just create a new
file with name HookRegisteredUser(or your choice) some thing like below in app/Listeners sand add its path into the $listen of the "Laravel\Spark\Events\Auth\UserRegistered"
namespace App\Listeners;
use Laravel\Spark\Events\Auth\UserRegistered;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class HookRegisteredUser
{
/**
* Handle the event.
*
* #param UserRegistered $event
* #return void
*/
public function handle(UserRegistered $event)
{
//your code goes here
}
}
After this add HookRegisteredUser listener in EventServiceProvider.php as follows,
'Laravel\Spark\Events\Auth\UserRegistered' => [
'Laravel\Spark\Listeners\Subscription\CreateTrialEndingNotification',
'App\Listeners\HookRegisteredUser',
],
Now the UserRegistered event will call two listeners i.e CreateTrialEndingNotification , HookRegisteredUser and the method handle will get executed on call to listeners and thats it!

Related

Laravel broadcasting - use job ID as an 'order' property

I want to send some sort of (unique, auto-incrementing) number as part of the payload of an event - so that the consumer can, for example, know it should ignore an 'updated' event if the event is older than a previous 'update' event it received.
I see I can add a broadcastWith method to my event, where I could add such a number, which I'm storing in some table.
But, I don't really need to create a new number. The ID of the job in the jobs table will work just fine. So, how can I make Laravel automatically add a property, say order, to this event before it is broadcast and make the value of order to id column from the jobs table? Is there a way to get it in the broadcastWith method?
I had previously thought of using a timestamp as the 'order' but of course that won't help me or the consumer when two events have been created in a short-a timeframe as a computer can create two events.
UPDATE
Looks like I haven't worded it well and people are confused as to what I'm looking for. In hindsight, I shouldn't of added the criteria that it must be the job id that gets included in the payload. The main thing I'm after is a unique, auto-incrementing ID in each broadcast event. For example, I have an UserUpdated event. Say the a user is updated twice - my SPA that is consuming the events needs to know which event is the newer one, otherwise the SPA might display outdated info. If the events are delivered sequentially, then this problem won't happen. But, especially as I'm relying on a third-party service (Pusher) to deliver the events to the SPA, I don't want to assume / trust that the events will always be delivered in the same order they were sent to Pusher.
Hi such a nice requirement, i have been working on a POCO and here are some snippets, you do not need broadcast at all. Of course you need to have the queue worker up and running
Running The Queue Worker
On your order controller, i guess you need the update method to dispatch the job before commiting.
function update(Request $req)
{
$data= Order::find($req->id);
$data->amount=$req->amount; //example field
PostUpdateOrderJob::dispatch($data)->beforeCommit();
$data->save();
}
Important: Why before commit and not after commit: Setting the after_commit configuration option to true will also cause any queued event listeners, mailables, notifications, and broadcast events to be dispatched after all open database transactions have been committed.
Your PostUpdateOrderJob class
?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Order;
use Throwable;
class PostUpdateOrderJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The number of times the job may be attempted.
*
* #var int
*/
public $tries = 25;
/**
* The maximum number of unhandled exceptions to allow before failing.
*
* #var int
*/
public $maxExceptions = 3;
protected $order;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct(Order $order)
{
$this->order=$order;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$this->order->update(['jobid'=>$this->job->getJobId()]);
}
public function failed(Throwable $exception)
{
// Send user notification of failure, etc...
//Several options on link below
//https://laravel.com/docs/9.x/queues#dealing-with-failed-jobs
}
}
Well php has a function called time() which returns the current unix time in seconds, so you can just use that in your broadcast event.
In your broadcast event, you can add this time to the public class properties, which would then be available through the event payload:
class MyBroadcastEvent implements ShouldBroadcast
{
public $time;
public function __construct()
{
$this->time = time();
}
}
I'm not sure if this is exactly what you need, your question is kind of confusing to be honest.

Where do I run code after successful login in Laravel 8?

I want to register a user log in immediately after successful login. I found a suggestion that I can use EventServiceProvider to listen to LOGIN event like this:
public function boot(DispatcherContract $events)
{
parent::boot($events);
// Fired on successful logins...
$events->listen('auth.login', function ($user, $remember) {
//
});
}
However, that throws this error:
Declaration of App\Providers\EventServiceProvider::boot(App\Providers\DispatcherContract $events) must be compatible with Illuminate\Foundation\Support\Providers\EventServiceProvider::boot()
So, where is the approriate place to register Log immediately after user Logs in in Laravel 8? or how do I format the above code to work for Laravel 8?
You can create a listener using php artisan make:listener and define your logic in the handle method of that listener class. Then bind listener class to the event in $listen property of EventServiceProvider
protected $listen = [
\Illuminate\Auth\Events\Login::class=>[
\App\Listener\YourCustomListener::class
]
];

Integrating stripe webhook in laravel with redis queue driver

I've been implemented stripe webhook in laravel 7 using library https://github.com/spatie/laravel-stripe-webhooks
The goal is to subscribe my users to plan created in stripe and generate an invoice on charge succeeded webhook request. Now to achieve this I created a cron script that dispatches the job to subscribe users. Also, set up a webhook endpoint in stripe. All setup is done and configuration in environment variables. It works perfectly when set the queue connection to "sync". However, when setting the queue connection to Redis it doesn't work.
Here's the code inside my config/stripe-webhooks.php
<?php
return [
/*
* Stripe will sign each webhook using a secret. You can find the used secret at the
* webhook configuration settings: https://dashboard.stripe.com/account/webhooks.
*/
'signing_secret' => env('STRIPE_WEBHOOK_SECRET'),
/*
* You can define the job that should be run when a certain webhook hits your application
* here. The key is the name of the Stripe event type with the `.` replaced by a `_`.
*
* You can find a list of Stripe webhook types here:
* https://stripe.com/docs/api#event_types.
*/
'jobs' => [
'charge_succeeded' => \App\Jobs\StripeWebhooks\ChargeSucceededJob::class,
// 'source_chargeable' => \App\Jobs\StripeWebhooks\HandleChargeableSource::class,
// 'charge_failed' => \App\Jobs\StripeWebhooks\HandleFailedCharge::class,
],
/*
* The classname of the model to be used. The class should equal or extend
* Spatie\StripeWebhooks\ProcessStripeWebhookJob.
*/
'model' => \Spatie\StripeWebhooks\ProcessStripeWebhookJob::class,
];
And inside the command that dispatches SubscribeCustomerJob:
$subscribed = 0;
$users = User::role('admin')->where(function ($q) {
$q->where('stripe_id', '!=', null)->where('verified_employees', '>=', 5);
})->get();
foreach ($users as $user) {
if ( $user->subscribed('default') && now()->format('Y-m-d') >= $user->trial_ends_at->format('Y-m-d')) {
SubscribeCustomerJob::dispatch($user)->onQueue('api');
$subscribed++;
}
}
Handling webhook requests using jobs
<?php
namespace App\Jobs\StripeWebhooks;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Spatie\WebhookClient\Models\WebhookCall;
class HandleChargeableSource implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
/** #var \Spatie\WebhookClient\Models\WebhookCall */
public $webhookCall;
public function __construct(WebhookCall $webhookCall)
{
$this->webhookCall = $webhookCall;
}
public function handle()
{
// At this point, I store data to Payments table,
// generate invoice and send email notification to subscribed user.
}
}
The output inside the logs of job:
[2021-04-14 07:53:46][Nr84GbvR3kxqnBGRrrWHtkTj34XRYsGv] Processing: App\Jobs\SubscribeCustomerJob
[2021-04-14 07:53:53][Nr84GbvR3kxqnBGRrrWHtkTj34XRYsGv] Processed: App\Jobs\SubscribeCustomerJob
Inside table in webhook_calls:
webhook_calls table click to see it
All thigs works well with queue connection set to sync. However, the problem is when I set queue connection to "redis".
I know webhook call works because there's data inside webhook_calls table but I guess fails to reach the job.
Any idea with stripe webhook and laravel using redis as queue driver, please add your comment below and thanks in advance.
I've fixed this issue it's my bad that I accidentally put an invalid queue name in my queue worker setup in supervisor.
[program:queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work --queue=api,notification
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile=/var/www/html/worker.log

How to listen to events fired by dispatcher

I’m using a package that fires an event using Illuminate\Contracts\Events\Dispatcher.
It fires an event like this:
public function __construct(Dispatcher $events)
{
$this->events = $events;
}
And then
$this->events->fire('cart.added', $content);
My question is how I can listen to that event using a Listener or an event subscriber. I’m used to events being defined as App\Events\ExampleEvent and then using that to listen to them.
In your EventServiceProvider, register a listener:
protected $listen = [
"cart.added" => [
Your listener::class
]
];
The key in the listeners array is a string. Often this is the class names of an event, but it can also be a string like above, and it can hold wildcards.

Yii2 session event before close/destroy

I want to run some code every time before user session is being destroyed for any reason. I haven't found any events binded to session in official documentation. Has anyone found a workaround about this?
There are no events out of the box for Session component.
You can solve this problem with overriding core yii\web\Session component.
1) Override yii\web\Session component:
<?php
namespace app\components;
use yii\web\Session as BaseSession
class Session extends BaseSession
{
/**
* Event name for close event
*/
const EVENT_CLOSE = 'close';
/**
* #inheritdoc
*/
public function close()
{
$this->trigger(self::EVENT_CLOSE); // Triggering our custom event first;
parent::close(); // Calling parent implementation
}
}
2) Apply your custom component to application config:
'session' => [
'class' => 'app\components\Session' // Passing our custom component instead of core one
],
3) Attach handler with one of available methods:
use app\components\Session;
use yii\base\Event;
Event::on(Session::className(), Session::EVENT_OPEN, function ($event) {
// Insert your event processing code here
});
Alternatively you can specify handler as method of some class, check official docs.
As an alternative to this approach, take a look at this extension. I personally didn't test it. The Yii way to do it I think will be overriding with adding and triggering custom events as I described above.

Resources