Magento 2 - Event being triggered multiple times in one request - magento

I have created an Observer to monitor this event in Magento 2 newsletter_subscriber_save_after. I am lost and not sure how to proceed with this because this event is getting fired 3 times.
The purpose of the observer is to connect to an API and send an email when a user is added to the newsletter. Since the event is firing 3 times, so will the observer. This means 3 calls are made to the API and the only workaround was to create a stop at the API to prevent 3 emails being sent out. That is not the best solution.
Why is Magento 3 firing 3 events for one request? Is there a workaround?
Another awful issue is that if a user is unsubscribing the first two event firing has the user as Subscribed and only the 3rd event the user is then set to Unsubscribed? I am confused. I am have read about using a Plugin instead, but I really want to concentrate this module around Observers. Is Observer this unreliable?
I am new to Magento, but this makes me wonder if I am looking at it the wrong way.

Related

Best practice to solve Livewire UI Not updating until after API call

I am using Laravel Livewire, I currently have a form that captures a user's address information, then it needs to submit that to a 3rd party API (it's for billing information).
The issue that I am facing is that the UI doesnt update / livewire doesnt call render until after the entire method has run - which looks on the frontend like the UI is frozen / system isnt doing anything as the API is slow and takes a few seconds (15 - 20) to give a response.
I want to be able to trigger a browser event to display an alert saying the request is processing / show an alert banner on the page that it is processing before making the API request, process the API request, then display the results.
Currently I have identified the following ways to make this happen:
make the updates on the frontend, fire off an event with the data needed. Laravel event listener handles the API call, and emits a result event that the livewire component listens for, then the livewire component updates the page with the results.
make the updates on the frontend, dispatch a job to run in a queue worker, emit an event that the livewire component listens for, update the page with the results.
emit an event from the livewire component to itself, the livewire component then listens for that event and processes the API request, then updates the frontend with the results.
emit an event from the livewire component to itself to update the UI with processing info, while it still runs the API process in the original method call, and then updates the UI once the API gets a response
My thoughts are, what would be best practice here? All the above solutions require a different amount of work to get running, and solution 1 and 2 looks like complete overkill for such a simple process.
Does this come down to preference? Or is there actually a best practice way to do this in livewire?
And additionally, is there another way / simpler way to do this that I havnt mentioned above?
Your feedback is appreciated.
I would probably create a job and then return a response to the user. Then instigate Livewire polling that can check for the job being complete. If the API takes 15-20 seconds then polling once per second should be fine.
You might want to store the state in the database so that the job and the livewire component can communicate with each other. If you don't need to keep the data, using the cache to communicate between job and component would be a good alternative.

Save data through the controller after an event has been fired in laravel

I'm allowing a user to upload a post which includes an image and some related information as well as select the promotion fee[bronze,silver or gold].In my /post controller i'm validating the request and then sending a request to another API[third party api for performing payments].The API takes the user phone number and the promotion fee selected and does the payment transaction.So i made the Transaction model[used to save details concerning the completed transaction]to dispatch a created event since i want to save the other post related information only if the payment is successful.
I've tried to create the listener for the TransactionCreatedEvent but i can't find a way to pass the post related data into the listener in order to save them. I also tried to use the closure by calling the listen method on the Event Facade inside the post controller to no avail.
Mh, i'm not quite sure if i undestood you question correctly, but in you case, you could either relate the Transaction with the post, or pass the Transaction and the Post Model to any event or to a job, and then do whatever you want with the data in the event handler or job

Laravel mail automation

I'm developing an invoicing system in order to collect payments from customers. Once I create an invoice, an email including invoice details will be sent to the customers with payment link. I want to re-generate payment token(once it expires) and send renewed payment link to the customers, and want to automate the process.
I created a Job called renewingInvoiceLinks and inside the handle method, I wrote code to retrieve all invoices with expired links and create new token and send new link. In App->Console->Kernel.php scheduled the job as following. I referred Laravel Docs but did not get the flow properly to dispatch the Job.
protected function schedule(Schedule $schedule)
{
$schedule->job(new renewingInvoiceLinks, 'renewingInvoiceLinks')->daily();
}
Things I want to get clear.
Whether using Job to do the requirement is correct or not? If not what is the perfect way to do it.
How to dispatch the Job? (Where I need to call the dispatch method?)
I think the question is quite subjective and opinionated, but here is how I'd do it:
Whenever the payment link is updated, I would fire a custom PaymentLinkUpdated event. You can either fire this event in the place(s) where you update the link, or you listen for the saving event on the affected model and fire the PaymentLinkUpdated event only when the original value is different from the updated one.
A custom event listener will listen for the update of payment links and will send out the email containing the payment details and link. This event listener should be a queued one so that emails are sent in the background and do not block the UI.
A scheduled job will check for expired payment links and will update the affected records, casting a PaymentLinkUpdated event where necessary. This will trigger step 2 (which is automatically queued again).
This way, you'd have all the logic implemented only once and sending mails would not be duplicated. If you have to send a different mail when the payment link is renewed, you can either do so in the event listener or you have to change your strategy entirely.

How to add a dynamic results section to Laravel

I made a laravel app which uses an index method that delivers a collection of the client's available appointments (think hairdresser) to the page (as an api), which I then display using vue/vuetify.
The client is saying they would like the appointments on the page to be dynamic/live eg if someone books an appointment, then all other logged in users will see that appointment disappear from the list on their screen.
I have no idea how I would do this, although I have had one idea - I somehow incorporate node/non-blocking on the server, like a chat room, but only for this part of the app.
Or is there a way to do this with laravel/nginx?
Thanks in advance - I don't know what to search for!
I believe you are looking for Broadcasting (Documentation Link). You would need to:
Configure your broadcasting driver (you could give pusher a try for quick setup and tinkering)
Configure your Laravel backend to dispatch a new event whenever a new appointment is made, (e.g. event(new AppointmentCreated($appointment)) where AppointmentCreated implements the ShouldBroadcast interface. You can combine this with Model Events
Update your frontend to receive your broadcast (Check Laravel Echo). Once you receive a broadcast, update the UI to mark this appointment as unavailable i.e, make it disappear

Slack logon trigger

I want to create something in Slack that sends a message (starting by calling someone with '#') to a channel when specific users login. I've checked ifttt and zapier. I also checked the slack api to create something myself, but I couldn't really find anything usefull.
Anyone has any ideas?
Slack does not track user login or logoff in a traditional sense. Instead, users are always always "logged in" and available to receive messages once they have joined a team / channel.
There also is the concept of "presence", which is related, but not the same thing. User presence can change multiple times during a few minutes, e.g. if the user is on a mobile. I am guessing you would not want to send the user your message that often.
Still you can poll the presence information of a user with the API users.getPresence , which could be used to implement a script that polls this information on a regular basis and send your message. You also want to filter out presence changes below a certain duration threshold.
Keep in mind though that the rate limit for API methods is 1 per second. So depending on how many users you have in your workspace there will be a significant delay between the user becoming "present" and your script being able to send the message.
There is a workaround for that to have a google sheet as a database for the users and you can trigger by day once and timestamp it.
So the best trigger is a private message or public and you can use filter when mentioning or signin or signout it depends on the trigger word then you pass the filter since zapier won't count your zaps if you used fiter as a second step.

Resources