Handling Push Events0:00
Let's start pushing. I think a great place to start will be our service worker. Because ultimately, it's the service worker that is going to essentially handle the push event, and then it's going to display the notification inside of our operating system. This gives us the opportunity to also test to make sure that that part works before we move on and actually implement the push notification on the server. Just like with everything else,
actually implement the push notification on the server. Just like with everything else, we want to handle the event, which unsurprisingly is called push. I think I called it push just a second ago, didn't I? Well, anyway, we are going to handle this event, and this is going to give us an opportunity to check the data of that event. Now, not every push event is going to have this data property, in which case, we need to check to see if we have data to work with.
Now, not every push event is going to have this data property, in which case, we need to check to see if we have data to work with. But this data can be, well, it can be really anything. It can be adjacent structure. It can be just a simple text message. It really doesn't matter what it is because we have the tools that we need to get the information that we need. So I'm going to do this. We're going to create a data object because
So I'm going to do this. We're going to create a data object because eventually what we will want to do is call eWaitUntil. We've seen this before, in which case, we are going to call self.registration. That is the registration of our service worker, and it has a method called showNotification. We need to pass two things to it. We need to pass a title, and then we need to pass an options object.
Parsing Push Payload1:44
We need to pass a title, and then we need to pass an options object. This options object has a variety of things that give us some control over how the notification looks. So this options object, we are going to build based upon whatever data that we get from the event. So we want to try here because if we don't receive a JSON structure, then we're going to run into an error whenever we try to convert that into an object. So this data object has a JSON method. Now, this is very different from something like fetch.
So this data object has a JSON method. Now, this is very different from something like fetch. With fetch, we get the response body and we can only use that response body once. If we want to read the response body, then we have to create a copy of it so that we can work with the copy. That's not the case here. We can call this JSON method as often as we want. It really doesn't matter. Of course, we only need to do it once. If this works, then great.
Of course, we only need to do it once. If this works, then great. But if it fails, then we need to take that into account. Because it could be, as I mentioned, just a simple text message. So we could do something like this to where we would then build a data object that we could say that we would have a title property, which would be field logger or whatever we wanted to call it. Since this is the name of our application, it makes sense to use this as a title. And then we would have the body of the message or the body of the notification. In which case, we would call data.text because it would be treated
And then we would have the body of the message or the body of the notification. In which case, we would call data.text because it would be treated as nothing more than text. So either way, we are going to end up with a data object that, well, it's gonna have some structure. So the overall structure of this data object is completely dependent upon us. So if we send an object with our push notification, we would want it to have a title and a body property. Because we already assume that that's what we are working with inside of the service worker.
Building Notification Options3:44
Because we already assume that that's what we are working with inside of the service worker. It's up to us, it's arbitrary. Just decide what you're gonna do and stick with it. So after this, we're gonna have a data object. In which case, we will need to get a title, which we would have that from our data object that we built ourselves. But then we would have our options object. And this is where we would have all of the options about the notification. So the first thing would be the body that we want to display in that notification.
And this is where we would have all of the options about the notification. So the first thing would be the body that we want to display in that notification. So that would be data.body. You can see why I chose body here, just so that there's this similar link between the two. But we can also do this, we could have an icon. And our icon can be anything. Because remember, this is part of the service worker, and our service worker can have a cache. One of those caches is our icons.
our service worker can have a cache. One of those caches is our icons. So we could have icons slash, and then, what do we call it? Field, logger, and then the size, let's take a look. Let's go to icons, yes, field, underscore, logger, underscore, 192. So that is gonna be fine. That's gonna be an icon that's going to also appear within our notification. And there's some other things. If we had a URL, which if we are sending a push notification from the server, we could include that URL if we wanted to, in which case,
Testing Browser Notifications5:02
If we had a URL, which if we are sending a push notification from the server, we could include that URL if we wanted to, in which case, we could provide the URL there. We aren't going to do that just yet. For right now, we're just going to stick with this simple stuff. And really, that's all that we need to display a notification. So let's test it out in the browser. So inside of the browser, let's first of all unregister our service worker. Let's do a hard refresh, so that it's loaded. And inside of the application tab, we see that there's this push.
Let's do a hard refresh, so that it's loaded. And inside of the application tab, we see that there's this push. And here's a text box. This is just a message that we can include with the push notification, and then the push button. So if we click this, we should see a notification, and we do. We see the site, field-logger.test. Now, we do see the Laravel icon, because that is the favicon for this particular website. If we had our own favicon, that would appear here.
because that is the favicon for this particular website. If we had our own favicon, that would appear here. Ideally, we would have that. But we do see the icon that we have. We have the title that we specified, field-logger. And then the text, test push message from DevTools. That is exactly the text that was included here. So there's no JSON there. We simply took the text of that notification and displayed it. And we can see that this works.
Creating Push Service6:18
We simply took the text of that notification and displayed it. And we can see that this works. So all we need to do now is implement this on the server side. And I want to start that by creating a service. So inside of the app directory, I want a new file. That did not go where I wanted it to go. Let's create a new file. There we go. I will call it services slash push notification service.php. And our namespace, app slash services.
I will call it services slash push notification service.php. And our namespace, app slash services. And then we have our class, class, not clash, class of push notification services. Now, this notification service is going to make use of the Minishlink library that we downloaded several episodes ago. And basically what we want to do is create a protected web push object, which is going to do all of the pushing for our notifications. And this web push object is going to have all of the vapid information. So it's gonna have the subject, the public key, and the private key.
And this web push object is going to have all of the vapid information. So it's gonna have the subject, the public key, and the private key. And it needs those things in order to send our push notifications. So let's build that inside of our constructor. And thankfully, everything is inside of our config. So this is going to be very easy to do. We'll just call the web push constructor. This will have a key called simply vapid, which is going to be an array of keys and values. The first key, and of course, the order in which these keys are, it doesn't matter.
which is going to be an array of keys and values. The first key, and of course, the order in which these keys are, it doesn't matter. I'm just gonna go with subject. That comes from our config, which is push.vapid, and then subject. I love IntelliSense. I love IntelliSense when it works. And then we need the public key, which of course is going to come from our config. Once again, push.vapid, public key. Then finally, we will have the private key, which you guessed it, comes from our push.vapid.
Then finally, we will have the private key, which you guessed it, comes from our push.vapid. Now, why is that not working? Well, private key, okay. So we build this web push object that we will then use to send our push notifications. And we can do that with a method, which we'll just call it sendToUser. That's essentially what we are going to do. We are going to have a user, and we are going to have a payload that we will then send to each one of these subscriptions for that user. Now, remember that a user can have multiple subscriptions.
then send to each one of these subscriptions for that user. Now, remember that a user can have multiple subscriptions. So let's get those subscriptions by using user and then push subscriptions. And we want to iterate over all of these push subscriptions. Because if we are going to notify a user, we want to notify that user for all of their subscriptions. So we will have forEach, subscriptions, as, subscription. And then in order to send a notification using these subscriptions, we essentially need to wrap these subscriptions inside of, well, a subscription object.
we essentially need to wrap these subscriptions inside of, well, a subscription object. And we get that from minishlink, webpush, subscription. But I don't want to confuse this subscription with our other subscription. So let's call this as webpush, subscription. So that as we iterate over our subscriptions that we have in the database, we will wrap that with this webpush, subscription, we'll call create. And then this is essentially going to have the same structure as the subscription object that came from the browser whenever we stored it inside of the database. So it starts with that endpoint,
object that came from the browser whenever we stored it inside of the database. So it starts with that endpoint, which is of course going to be our subscription endpoint. But then we have that keys key to where we have the P256DH, not DN. Made that mistake once, DH, which is going to be the value of subscription. And then P256DH, and then we have that auth key, which again comes from that subscription object and the auth attribute. And that's it, so we are taking that data from the database. We are wrapping it using this webpush, subscription. Well, it's not webpush, subscription.
We are wrapping it using this webpush, subscription. Well, it's not webpush, subscription. It's this subscription class, but we're calling it webpush, subscription. So that then we can queue that with our webpush object. It has a method called queueNotification where we have the webpush, subscription, and then the payload that we want to include with this notification. In which case, we will JSON encode the payload. And then we want to send everything. And we will do that, once again, with the webpush object. And we have this flush method.
And we will do that, once again, with the webpush object. And we have this flush method. This flushes the notifications and triggers sending those requests. And we are going to get a report for every one of those requests. We can get the status code from the report. We want to get the response. And then we want to hopefully get the status code. Then we'll check if the report is not successful. And we will check if I'll get the ampersand right. If the status code is not 404 or 410,
And we will check if I'll get the ampersand right. If the status code is not 404 or 410, then we're going to delete the subscription. The idea being that if we attempted to send this notification and it doesn't exist, and it's not because of a network issue. It's because it doesn't exist. What's the point of having it? So we need to get the endpoint. We can get the report, getRequest, and then getUri. And then from there, we can say push subscription where the endpoint
We can get the report, getRequest, and then getUri. And then from there, we can say push subscription where the endpoint is the same as endpoint, and then we will delete. So that is our sendToUser method. We get our subscriptions. We iterate over those subscriptions, wrapping the data that we have in the database with these subscription objects. So that then we can queue up the subscription, and then we send those notifications. If it fails because of a 404 or it's not found,
Adding Test Controller12:52
then we send those notifications. If it fails because of a 404 or it's not found, then we delete the subscription. I think that's perfectly fine. So now that we have this service, we need something that we can use to send the notification. So let's create a controller. We'll use Artisan to make a controller. We'll call it TestPushController. Let's make this invocable because all we are going to do is
We'll call it TestPushController. Let's make this invocable because all we are going to do is use it to test our push notifications. So let's open up our TestPushController. We want the request, but we also want our push notifications service. And let's just call it notifier. And of course, we will use this to send to our currently signed in users. So we will call request user that will give us our user object. But we should check that if the user doesn't have any push subscriptions, then there's nothing to do.
But we should check that if the user doesn't have any push subscriptions, then there's nothing to do. But I also want some kind of indication as to knowing that there's nothing to do. So let's return response, which will be JSON. And we can have a status that says no subscriptions. And then we would have a message that says you have no push subscriptions. Okay, so that'll work. But of course, if we do have subscriptions for this user, we want to send them. So we will use our notifier to send to the user. And then we would have a payload of, well, what do we need?
So we will use our notifier to send to the user. And then we would have a payload of, well, what do we need? We need the title, which would be Field Logger Push Notification Test. I want something very different than what we saw with the test. And then the body could be something else, rather unique. Like this is a test push notification. And then of course, if we have this, we need to open up our routes. And ideally, this would be a POST request. But I'm gonna make it a GET request. And let's just call it test notification.
But I'm gonna make it a GET request. And let's just call it test notification. That way, we don't have to put something into the page or anything like that. Yes, absolutely, we would want something as a POST request. I'm not denying that. I'm just trying to make things easier for me. So that's the test push controller class. Let's give this a name of test push. You know what, I'm gonna change that URL so that it's just test push because that's a lot easier to type.
You know what, I'm gonna change that URL so that it's just test push because that's a lot easier to type. So inside of the browser, we first of all need to re-enable our notifications. Because we have unregistered and re-registered the service worker. Therefore, all of the subscriptions that the service worker is aware of are now gone. So we need to try again to subscribe. Looks like that worked. And let's duplicate our tab here. So that then we can just go to test push. And hopefully, we will get a push notification.
So that then we can just go to test push. And hopefully, we will get a push notification. There it is. Our title, Field Logger Push Notification Test. It's rather a long thing, but we know that that's what we put. That's why it was so specific. And then this is a test push notification. So we have push notifications all set up and ready to go, at least for the most part. Because by itself, it's just a notification. But what happens if we tap on or click on that notification?
Because by itself, it's just a notification. But what happens if we tap on or click on that notification? Well, currently nothing. But ideally, it would take us to a certain web page so that the user could actually look at the detail of that notification. And we will implement that in the next episode.
