Creating Notifications Table0:52
Okay, so what this will do, it's not going to fire off an email. It's not going to send a text message. It's going to throw the information of the notification into a database table. So that means we need to manually create that table first. Now, if we switch to the documentation, yeah, you'll see that the docs give you a quick little bit of schema to run. Okay, so let's try it. Make me a migration called create_notifications_table. All right, and if I switch over to that, yeah, we can just take all of this and paste it in. Okay, so take a look. Our table is called notifications. The ID will be a unique ID, a UUID that Laravel will fill for you. The type is going to be basically the name of the notification class. So notification subscription canceled.
The type is going to be basically the name of the notification class. So at notifications.subscriptionCanceled. Next, the type that will be usually the User and the ID. And then the data will be an encoded version of any data related to the notification. So if the User canceled, maybe it can be when they canceled or something like that. Okay, and finally, this read Boolean, well, that indicates have they seen the notification or not. And then we have some indexes. All right, so let's go ahead and migrate our database. We have the users, the password_resets that comes out of the box. Lessons, you don't need to worry about that.
Triggering Database Notification2:10
We have the users, the password resets that comes out of the box. Lessons, you don't need to worry about that. It's just to give us something to notify the user about. And now we have our notifications table. Okay, so let's try it. Back to my routes file, we're going to find some user. So let's do this. Auth::loginUsingId using ID. Let's just assume that the user with an ID of one is the person who is signed in for our example. So I'm quickly going to build up a factory and persist that. Just give me a dummy user in the database.
So I'm quickly going to build up a factory and persist that. Just give me a dummy User in the database. Okay, this will be our signed in User. So now, yeah, I can say auth user, notify them based on something that took place. Maybe this is directly when they cancel their account or when we deactivate their account, this fires it off. I don't know. Anyways, we'll say subscription canceled, and I will use that at the top. All right, so comment this out. And does this all make sense? It should be pretty familiar to you at this point.
And does this all make sense? It should be pretty familiar to you at this point. We have set up a new notification. But yeah, now it's not going to call toMail because we didn't use the mail channel. So by default, it will use toArray. Or if you have a method called toDatabase, it will call that instead. And generally, that's the way it works. The channel name, well, it's going to look for a to and then the name of the channel. So toDatabase or toMail. Or toArray is kind of the fallback, and it's also used for the broadcast driver.
So toDatabase or toMail. Or toArray is kind of the fallback, and it's also used for the broadcast driver. So maybe, yeah, in this particular case, there's not too much we would need to store there. Maybe, I don't know, subscriptionEnded would be Carbon now. Or, you know, anything that would be appropriate for the user to see with the notification. If the notification was that a new lesson has been published, then here I might include the Idea of the lesson or the title of the lesson or a link to it. Anything there. Or sometimes, yeah, you can just cast whatever the appropriate model is to an array. So maybe you could do something like that if that's appropriate.
Or sometimes, yeah, you can just cast whatever the appropriate model is to an array. So maybe you could do something like that if that's appropriate. You know, you get the basic idea. All right, so we're going to try this out. When I hit the home page, I'm going to notify the authenticated user that their subscription has, in fact, canceled. So let's do it. Laravel53.def. And we didn't return anything, but I bet we'll see it here. php artisan tinker. In my notifications table, give me everything there. And there we go.
In my notifications table, give me everything there. And there we go. There's the notification that we just submitted. So it has our UUID. The type is a subscription canceled. This is the User that it applies to. And for the data, yeah, it encodes that all up for us. And, of course, read would be set to false. Now, we are using the query builder to fetch the notifications here, but we can also fetch them directly off of the User.
Exploring Notifiable Relationship4:55
Now, we are using the query builder to fetch the notifications here, but we can also fetch them directly off of the User. So, for example, the authenticated User we have is Allison here. So I can even do this. I can reference that relationship directly off of the User object. And the reason why I can do that is because on my User model, we use the Notifiable trait. And remember, you can use this trait on any model you want. So like I said in the last episode, if you want to say Post notifications or Post notify, you can do that. Let's take a look at that. Notifiable, well, that just pulls in two other traits.
Let's take a look at that. Notifiable, well, that just pulls in two other traits. Let's do hasDatabaseNotifications. Okay, so here's the relationship that we just referenced here. It's a simple one-to-many, but it's a polymorphic one-to-many. So we use morphMany. Now, the model itself for the notification table, Laravel already has one. It's called DatabaseNotification. So Illuminate\Notifications\DatabaseNotification. So here is the Eloquent model for that table.
So Illuminate\Notifications\DatabaseNotification. So here is the Eloquent model for that table. And if we take a look at it, we can find, well, if you want to figure out the User associated with that, you could say notifiable, and that will be your User instance. So the User associated with the notification. And then we also have one important method for you to see here called markAsRead. So this, yeah, all you want to do is cycle through the notifications and then call markAsRead on each. And all that's going to do is update the read status to true. All right, but yeah, anyways, that's good to know, right? And we can also fetch unread notifications specifically.
All right, but yeah, anyways, that's good to know, right? And we can also fetch unread notifications specifically. The only difference, of course, is we are limiting the results to those where the read status is false. So chances are high that often this will be the one you want. So if we run it again, unread notifications. Yeah, we're going to get the same thing in this particular case. But once that gets read, we will get an empty Collection. So let's try this now. We have now notified the User, so I will comment that out. In real life, that would be in some kind of controller method.
Displaying Unread Notifications6:55
We have now notified the User, so I will comment that out. In real life, that would be in some kind of controller method. But let's imagine in our welcome view, we just want to display it, you know, in some kind of sidebar or in the nav bar or some kind of dropdown. I'm just going to put it here for now. And then I will say for each, give me my authenticated User's unread notifications. And then, I don't know, to be very quick, we'll just say notificationType. And let's see this in the browser. Okay, so the User has exactly one notification that their subscription has canceled. Yeah, in real life, they may have a dozen different notifications.
Okay, so the User has exactly one Notification that their subscription has canceled. Yeah, in real life, they may have a dozen different Notifications depending upon how long it has been since they signed in. Now further, what you can do is, well, you have notification data, right? And remember that was the encoded version of any of the data associated with it. So essentially, it's going to be this. Well, yes, in the database table, it's encoded. However, it will automatically be cast to an array. And the reason why that's the case, let's go to the model. Yeah, here we go.
And the reason why that's the case, let's go to the model. Yeah, here we go. So when we try to access that data column, so when we try to access this right here, it will automatically be cast to an array. So that means here I could say notificationData subscriptionEnded. So yeah, it's encoded and decoded automatically for you behind the scenes. And then we'll get the date here, I guess, because I used Carbon there. Anyways, if we come back, yeah, we can see this was exactly when their subscription ended. Or you could even do some kind of cool polymorphic stuff where you know the type, right? So if the type is appNotificationsSubscriptionCanceled,
Rendering Per-Type Views8:30
Or you could even do some kind of cool polymorphic stuff where you know the type, right? So if the type is app.notifications.subscriptionCanceled, yeah, we could do a cool thing here where basically you figure out what the type of notification it is and then you load a specific unique view for only that type. So now every different notification type would have its own view where you can define the presentation. And that's good if it's vast or unique enough where it would make sense. And if you ever find yourself doing like switch statements or lots of if notificationType is this, then I want to display this. Or if it's that, then I want to display that. Or if it's that, then I, you know, whenever you end up with that,
Or if it's that, then I want to display that. Or if it's that, then I, you know, whenever you end up with that, usually you can use polymorphism in such a way to make it easier. So in our case, maybe we could say class BaseName NotificationType. Now, this is a helper that's basically going to give us this right here. And then, well, that would be fine. But also maybe we ultimately want it to be subscriptionCanceled, right? Well, we can run that through snkCase. These are just little helper functions that Laravel offers. So now, yeah, we could say loadNotifications.
These are just little helper functions that Laravel offers. So now, yeah, we could say loadNotifications. And then in this case, it would be subscriptionCanceled. So now every notification type can have its own view. And if we were to create that, resources/views/notifications/subscriptionCanceled.blade.php, we could say your subscription was canceled. Come back to Chrome, give it a refresh, and now we're loading that specific view. And of course, we can style that however we want and reference the notification. Notification, data, subscriptionEnded, give me the date, whatever format it happens to be in. Come back, give it a refresh, and now that works.
Adding LessonUpdated Notification10:51
and we'll send through the lesson that corresponds to that notification. This is the lesson that has been updated. All right, so php artisan, make me a notification called LessonUpdated. Let's update this. It's going to accept a Lesson, and I'll use a macro really quickly to fill that up. Now here, once again, we're going to use the database driver, and toArray is fine. All we're going to do here is return this lesson toArray. Okay, so does that look good to you? Let's get rid of that. So when we notify the user in some part of our application that a Lesson was updated,
Let's get rid of that. So when we notify the User in some part of our application that a Lesson was updated, we've specified that we're going to use the database channel to perform that notification, and the data associated with it is just an array version of the data. So if we go to Laravel 5.3, ah, lesson updated not found. Let me import this, like so. All right, that should have done the trick. So once again, app\User::first(), and give me their notifications, and here we go. So they have one notification for their subscription canceled, but then here's the one that we just added.
So they have one notification for their subscription canceled, but then here's the one that we just added. So they have a new notification that a lesson they are interested in has been updated, and here's their data associated with it. So that's what I mean when I say you may not always want to cast it to an array. You may just want to grab only the relevant information and then throw that into the table. Yeah, as a general rule of thumb, keep it as minimal as you can, only what the user would actually require for the notification. So now if we come back, reload our view. This should not work, right?
So now if we come back, reload our view. This should not work, right? And that's because, well, we're still trying to use that polymorphism, but it's trying to load a notification view that does not exist. So that's where you would create that or set up a default or check to see if the view exists, but very likely you can just make sure that you have one view per notification. So lesson updated.blade.php, and a lesson you are watching has been updated. Come back, give that a refresh, and now, yeah, we're referencing two different views to load those notifications. And then once again you could say notification, data, and give me the title maybe.
Marking Notifications Read14:09
You can set this up however you want. So now you have some kind of button, and now ready. I'm sorry about that, read. So, yeah, that's fine for an AJAX request, or if you're just going to use server side, of course we can't submit a delete request. So we would PATCH that, and then we would do our method field here to basically tell the server what kind we want. And then what else we would want a CSRF field to. Anyways, give that a refresh. That will submit to the server.
Anyways, give that a refresh. That will submit to the server. The server now hit this, where we mapped over the User's notifications, and we marked them as read. And really, you'd probably want to do unread notifications because we're only interested in updating unread notifications, not read ones. And then we would redirect back, at which point there are no unread notifications, so we don't see any here. Which we could say right up at the top, if countAuthUserUnreadNotifications. So as long as they have some, we will display this,
Which we could say right up at the top, if countAuthUserUnreadNotifications. So as long as they have some, we will display this, but otherwise we're not going to bother with any of that junk. Okay, so now my site, refresh, and they don't see any notifications because they've all been read. However, if we notify the authenticated user, let's do a new one, AuthUserNotify, that we have a new app notifications lesson published. Once again, let's just grab the first lesson there. And I guess we don't have that. What was it? Lesson updated?
