تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Messy Controller Example0:00

Now, another option you have when cleaning up a very muddy, messy controller is to, of course, fire domain events. Maybe something like this. So let's say, route when we post to, how about, users that will hit a UserController at store. All right? But now in this case, just to make it easy for us to hit it in the browser, I'll switch that to a get. All right, so let me create that. php artisan make:controller UserController.

All right, so let me create that. php artisan make:controller UserController. And if we switch over there, I will create a method called store and reformat. Okay, so here's what I mean, just as a quick demonstration. So you might, you might build up a new User, right? And then you set the user's name to myself, the user's email to jeffrey@larikes.com. The user's password, of course, would be bcrypt(pass). You get the idea, right? And then you save it. All right, so that's sort of the core job.

And then you save it. All right, so that's sort of the core job. You have to create the User and persist them. But then there's also these related things that often need to be done as well. So for example, when you register a User, well, you also need to send them a welcome email. And you don't want to see me write this out, so I will paste it in. But yeah, pretty basic stuff that you've seen a hundred times over. Use this view, pass the User object to the view. And then for the message itself, we will send it to the User's email address and set a subject.

Use this view, pass the $user object to the view. And then for the message itself, we will send it to the user's email address and set a subject. Okay, so that's one thing. They've registered, they now have an account, they're in the database. We've fired off a welcome email. But then yeah, maybe there's something else, like you use CampaignMonitor, and you have a newsletter list. And you want to add their email address to that list, so that whenever you fire off your monthly newsletter, they receive it, right? Okay, well, that would look like something else.

very rarely reflect real life. So yeah, in a tutorial or documentation, you see something simple, and then you redirect, and then you're done, right? But that's not the reality. And the reality is, for a lot of these tasks, you need to do 10 different things in response. And figuring out where to put all that information is kind of one of those hurdles you have to get through when learning how to code well. So in episode one of this series, we reviewed form objects. That's a great choice, especially when there's not too much logic going on. So yeah, a handful of methods for each action, and you're good to go.

Firing Events from Model4:12

Now, where exactly do you do that? Well, once again, you could do it in the controller. So you could do it right here. You could say events, and then just pass a string, user registered. That's fine in a lot of cases. Generally, I sort of prefer to put these events within the model itself. So if you can think of a single method you will call to perform an action, then that method is where I will fire the event. For example, in this case, rather than newing up a User, we're really registering a User. So maybe I could create a static constructor like this, and then just pass my attributes.

For example, in this case, rather than newing up a User, we're really registering a User. So maybe I could create a static constructor like this, and then just pass my attributes to it. So in this case, let me paste this in, like so. And then up here, we could remove all of that stuff entirely. And now notice the comment here, it's redundant, and that's a good sign. Next, yeah, you know what, for the password, you might want to set a custom setter so that we will, no matter what, always encrypt the password. And you don't end up with any situation where you might accidentally have a password in clear text in your database.

And you don't end up with any situation where you might accidentally have a password in clear text in your database. But anyways, this is fine enough for the demonstration. So if we were to create that method right here in our User class, that has the attributes. And yeah, some people would pass it through individually. So they would do name, email, password. And once again, really great for slides, really great for documentation. But what about when the form has 20 different fields, right? That's where it starts to break down. So yeah, more often than not, I have no problem with an array of attributes, in which case

That's where it starts to break down. So yeah, more often than not, I have no problem with an array of attributes, in which case you could say return static create attributes. But now I just got done saying that I would like to fire the event from the main model method that performs the action. So in that case, yeah, maybe I could say User, and then here, fire the event. NewUserRegistered. And then finally, return that created User. But now what about creating this event? How do we do that?

Creating Events and Listeners6:11

But now what about creating this event? How do we do that? And you have a couple choices. One, you could say php artisan, and you'll see that we have a few make commands. So make an event, and then also make a companion listener. So remember, an event is a container, nothing more than that. It's a single class that holds the data relevant to the event that just occurred. But now a listener is sort of the companion to that. So a listener listens for the event and does an action in response. So you very well could have a listener class called SendWelcomeEmail.

So a listener listens for the event and does an action in response. So you very well could have a listener class called SendWelcomeEmail. No problem there whatsoever. So it's true, you could run both of these commands one after the other. But then you would also need to go to your EventServiceProvider, and this is within your app/Providers directory. And then here, yeah, this is a container where we register each event in a list of listeners associated with that event. Think of this as your way to tell Laravel, when we fire this event, here's a list of listener classes that I want you to trigger.

Think of this as your way to tell Laravel, when we fire this event, here's a list of listener classes that I want you to trigger. Now check this out. A lot of people don't know about this. If our event is userRegistered, and actually a quick note on that, notice that we use past tense. This is a common convention. An event reflects something that is done, it has taken place. So we reference it in the past tense, userRegistered, or userHasRegistered if you prefer.

So we reference it in the past tense, User registered, or User has registered if you prefer. Okay, next, this array, one or more, will be a list of listeners. So if we have, well let's go back to UserController. This first one, sendWelcomeEmail. So there's our class. SendWelcomeEmail. Okay, so here's the trick I was going to tell you about. We can have Laravel read this array and automatically create any events or listeners for you. Like this, php artisan event:generate.

Generating via event:generate7:57

We can have Laravel read this array and automatically create any events or listeners for you. Like this, php artisan event:generate. Okay, now take a look. If I open the sidebar, you'll now see in my events folder, there's UserRegistered. And notice if you want, you can even broadcast this using WebSockets. Cool stuff, we've already covered that at Laracasts. And that won't be applicable in this lesson. So I will reformat that to remove the imports. And that means I can also get rid of the broadcastOn method. Anyways, it created that class, but it also created the companion listener.

And that means I can also get rid of the broadcastOn method. Anyways, it created that class, but it also created the companion listener. And if we take a look further, notice that the handle method accepts the event that you fired. So now anything that is stored within this UserRegistered class, like as a public property, may be the $user in this case. Let me initialize that. And then also import my User. Now in this case, it's private. Honestly, I'm totally okay with making it public.

Now in this case, it's private. Honestly, I'm totally okay with making it public. Developers disagree. Some people really like to make that a dangerous thing where you should always use a getter method instead. It's fine if that's what you want to do. I personally stick with making it public and never once had a problem with it. And it's also less verbose. Okay, but anyways, we can now see that a particular event that can take place in our system is this, when a User registers.

Okay, but anyways, we can now see that a particular event that can take place in our system is this, when a User registers. And we can see that this class encapsulates that particular event and all of the data associated with it. Next, if we go back to our service provider, we can see that when a User registers, right now only one listener, SendWelcomeEmail. This class now has exactly one responsibility, fire off a welcome specific email. And now once again, yeah, you can queue it up. I'm going to get rid of all of that. So why don't we do this?

Wiring Listener Actions9:54

I'm going to get rid of all of that. So why don't we do this? Why don't we simulate it? Why don't we say var_dump sending a welcome email to, and then I will say event $user ->email. Now if I did have a dependency, for example, maybe you decide you don't want to use Laravel's Mail facade, but you instead want to inject the Mailer contract, that's fine if you want to do that. Okay, let me initialize this. And now the important thing to know is that, yeah, like your controllers, you get full dependency injection, or I should say automatic dependency injection.

And now the important thing to know is that, yeah, like your controllers, you get full dependency injection, or I should say automatic dependency injection. So in other words, Laravel will instantly inject the mailer for you without you having to do a thing. All right, let's go back to UserController and go over this. Before, our controller method was getting larger and larger and larger. For small stuff, keep it simple. Keep it in the controller. But yeah, as you feel it grow and you start to feel a little gross about yourself, that's usually your hint that maybe I should consider something else.

But yeah, as you feel it grow and you start to feel a little gross about yourself, that's usually your hint that maybe I should consider something else. All right? So that means I can get rid of this entirely and instead use my event. Next, we don't have to fire this from the controller. That's being done from the register method, which is a more appropriate place. Now in this case, I do need to import the class. So at the top, app\Events\UserRegistered. And then finally, don't forget to pass through the data associated with that event. So in our case, we've decided that the important thing for this particular event is the User.

And then finally, don't forget to pass through the data associated with that event. So in our case, we've decided that the important thing for this particular event is the User in question. So let me pass that through. And that looks good to me. So when we register a User, we provide an array of attributes. We pass that to essentially User::create. Next, we make an announcement. It's sort of like holding up a bullhorn and making a big announcement to your entire application. Hey, a User has registered.

It's sort of like holding up a bullhorn and making a big announcement to your entire application. Hey, a User has registered. If anyone cares, do whatever you need to do. And as it turns out, parts of our application do care. We've said that this listener in particular wants to know when a User has registered. So we reference it there. And then finally, we send the email, or in our case, stub it out with a var_dump. Okay, so I think we are ready to try this out. Real quick, I don't have a CampaignMonitor class, so I will comment that out. Anyways, if we switch over to the browser and refresh the page, sure enough, we have

Real quick, I don't have a CampaignMonitor class, so I will comment that out. Anyways, if we switch over to the browser and refresh the page, sure enough, we have created a User. That register method did fire an event, which we listened for, and then fired off a welcome email. So now we can get rid of this next section. We have something related to CampaignMonitor. And what does this do? We add the User to a newsletter list. So let's do that.

Adding Newsletter Listener12:36

We add the User to a newsletter list. So let's do that. Back to EventServiceProvider. And we now have a second action we want to take, app, listeners, and maybe add User to default newsletter list, or something like that. All right, once again, php artisan event:generate. All right, now in this case, we don't have to create the event class. That's already done. So it only needed to generate the single listener. All right, let me format.

So it only needed to generate the single listener. All right, let me format. I don't have any dependencies in this case. So I can just say, once again, to stub it out, use campaign monitor, or whatever you want, to add event user email to the main newsletter list. Oh, and by the way, remember, you can organize these however you want. So if you want a listeners directory that corresponds to the event itself, then create it. It's fine. Whatever you want to do there.

It's fine. Whatever you want to do there. Now, before we try this out, I do need to clear out the user. Because of course, if I refresh, we already have a user with that email. So yeah, very quickly, I'll say user::truncate(). Okay, if I give it a refresh now, we register the user, we persist them, we fire an event, the SendWelcomeEmail listener has the opportunity to respond to it. And now the CampaignMonitor listener also has the chance to respond. So this is what I mean when I say it offers a nice, clean way to take a particular action or event in your system, like a user registering, and then have the opportunity to respond to

So this is what I mean when I say it offers a nice, clean way to take a particular action or event in your system, like a User registering, and then have the opportunity to respond to that event in any number of ways. And like I said, this is good for more complex things. So if the reality is a User creates an account and you fire off one email and you're done, don't instantly make this more complicated. You can keep it in your controller and you can call a method on your model if you want. Keep it simple. But when you start to feel it kind of grow beyond your comfort level, and it feels kind of wrong to you, we all pick up on that where you're not exactly sure what's wrong, but

Tradeoffs and Annotations14:37

But when you start to feel it kind of grow beyond your comfort level, and it feels kind of wrong to you, we all pick up on that where you're not exactly sure what's wrong, but something isn't right, you're missing something. That's the point when you might fire a domain event. Now if you're wondering what is the downside to this, the undeniable downside is it's a bit more difficult to take in the system, so to speak. So for example, before in your UsersController, for better or worse, you could look at this one method and immediately understand what happens. Now in this case, I just see that we're registering a User and then we may not remember this six months from now, but yeah, then at some point an event will fire and then other classes

Now in this case, I just see that we're registering a User and then we may not remember this six months from now, but yeah, then at some point an event will fire and then other classes listen for that and then they respond. So it's more difficult to debug and kind of understand at a glance. So here's what I would recommend. There's nothing wrong with adding a custom annotation. So for example, if I were to say register a User, yeah, you might do something like event::fire and then say App\Events\UserRegistered. I almost think of this like the throws annotation. Now I feel like there should be an official annotation for this, whether it's event or

I almost think of this like the throws annotation. Now I feel like there should be an official annotation for this, whether it's event or something else, but to the best of my knowledge, there isn't one. And personally, I think this is kind of a good way to go about it. It gives you just that extra bit of information when you come back a year from now. When you see this, you can look, oh, it looks like this UserRegistered event will fire. And then at that point, you can go to your ServiceProvider and get a good glance at what exactly does happen in response to that event.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟