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

Controller Bloat Problem0:00

Now, for this next Monstrous Code episode, we're going to move our focus over to controllers, and we'll figure out how to deal with some of the bloat that can come from that over the lifetime of a project. So you know what? Let's just dig into it. Let me show you an example here. So imagine that we have, maybe I'll show you a couple examples. So imagine that we have this concept of a flight. So we'll have a FlightsController, maybe like an airport, okay, a dumbed-down version of that.

RESTful Controller Basics0:22

So we'll have a FlightsController, maybe like an airport, okay, a dumbed-down version of that. So if we think about REST, what would you use to fetch all flights? Well, maybe a GET request to /flights will give you all flights. All right, well, what if we want to edit an existing flight? Okay, well, we could update flights/{id}, and then update the flight. You know, this is basic REST in action with Laravel and resources. And as you know, we have about seven or six or seven, right? So we have INDEX, CREATE, SHOW, EDIT, STORE, UPDATE, and DESTROY. So give me all flights, give me a form to create a new flight, show an existing flight,

Adding Filters and Custom Actions0:58

So we have INDEX, CREATE, SHOW, EDIT, STORE, UPDATE, and DESTROY. So give me all flights, give me a form to create a new flight, show an existing flight, give me a form to edit a flight, store a new flight in the database, update an existing flight in the database, and destroy an existing flight. Okay, so this is all fine, but in reality, you're going to end up with nested resources, and it gets a little tricky for how you go about organizing that and labeling it, and where do you put the method and things like that. So imagine that, yes, we have all flights, but we also have a filter to display canceled flights or scheduled flights or something like that. Now you can do this in a couple ways.

flights or scheduled flights or something like that. Now you can do this in a couple ways. You could always just do flights and then $canceled equals 1 or true, you know, something like that. And then the controller method would simply check, well, does the request have canceled? So I need to do this query, otherwise that query. And that works to some extent, but it might eventually get kind of tricky, especially if you start combining filters and things of that nature. But now even beyond the URI, so for example, like you could do flights/canceled, even though that's not entirely restful, you know, who cares?

But now even beyond the URI, so for example, like you could do flights/canceled, even though that's not entirely restful, you know, who cares? You're an adult, you can decide. You could do, I don't know, canceled flights. You just turn that into a top-level resource. So either way, no matter what URI you choose, where do we store this new method? So let's think. A typical resourceful controller will have index, show, create, store, edit, update, and then finally destroy, right? So these are your seven common methods for a resourceful controller.

and then finally destroy, right? So these are your seven common methods for a resourceful controller. And in fact, a little trick here you may not know about, when you create a controller, you can also pass this resource option here. And what that's going to do is give you the boilerplate for all of those methods. Kind of cool, right? You have all of that ready to go, which is really useful, especially if right from the get-go you know you're going to need these. If you just know you want index and show, then typically I don't bother. But if you know you'll have a full lifecycle for this resource, then add that option.

If you just know you want index and show, then typically I don't bother. But if you know you'll have a full lifecycle for this resource, then add that option. We have these seven methods, but now we want cancelled flights. So I guess we're just going to add a new method here, cancelled, right? So now you add a new method, cancelled, and now you display all cancelled flights. But then you're going to have another one maybe for scheduled. And you're not using filters, so you're going to have different methods for this. So you add it again, and now you add another method, scheduled. So as we're doing this, we're getting further and further away from the initial seven resourceful methods.

So as we're doing this, we're getting further and further away from the initial seven resourceful methods. And as you can imagine, as the project grows, this continues and continues. So I would say if you just have one, you know, it doesn't matter that much whether you add this here. You know, as always, this is kind of contingent upon the project and how your team works. But here's one thing to consider. As you continue adding more and more methods to your controller, it's going to grow and grow. And trust me, you'll get to a point where you keep adding more of these.

Extracting Actions into Controllers4:10

grow. And trust me, you'll get to a point where you keep adding more of these. You'll add three, four, five of these, and then it gets to the point where your controller is pretty gross to look at, and it feels gross. And you do the squint test, and you're not happy with yourself, and you can't respect yourself when you go to sleep at night, right? Probably not. But anyways, one option you have is to extract these custom names into their own controllers. So anytime you find yourself wanting to create an action that is not one of these initial seven RESTful actions, in those cases, consider creating a brand new controller and naming

So anytime you find yourself wanting to create an action that is not one of these initial seven RESTful actions, in those cases, consider creating a brand new controller and naming it this very thing. So in our case for Canceled, you might consider a FlightsController, and then a second controller called CanceledFlightsController. And now within there, do we call it Canceled? No. You go right back to the RESTful methods. So what we're trying to do here, to the best of our ability, is adhere to these seven RESTful method names as much as possible.

So what we're trying to do here, to the best of our ability, is adhere to these seven RESTful method names as much as possible. So when you find yourself feeling like you need to creep away and use these custom names to show only canceled flights, instead what you consider doing is you remove the method entirely, you then create a new controller with that exact name, and then you return to the appropriate RESTful name. In this case, to fetch all canceled flights, you would use an index method. And the same thing might possibly be true for ScheduledFlightsController. So yeah, you don't want to take this to the ends of the earth. You don't want to just do it for every possible thing.

Subscription Feature Example5:37

So yeah, you don't want to take this to the ends of the earth. You don't want to just do it for every possible thing. But as always, if it makes sense, if it feels better, if you find yourself thinking, you know what, this would be easier if I just gave it its own controller, then that is exactly what you should do. Okay, so there's your first example. Let's write code for a second example. So we're going to go back to this idea of a form, since I have that at Lerikas, and I'm very familiar with that domain, so to speak. So we have this concept of form threads.

I'm very familiar with that domain, so to speak. So we have this concept of form threads. Most people call them threads. I use this term conversations. So as you can imagine, for a resource, well, index would display all convos. show would display one conversation, right? edit would edit the conversation. store would store a new convo in the database. create would display a form to create a new conversation. update would update an existing conversation in the database.

Create would display a form to create a new Conversation. Update would update an existing Conversation in the database. People sometimes get confused, beginners sometimes get confused at the difference between these. Edit is going to display the form, and then when you submit the form, you hit the update method, and that is what updates the database. And then finally, what do we have? Destroy will delete the Conversation from the database. But now, what about something as simple as a User asking to be informed when a Conversation is updated? I have this exact same thing at Lerikas.

is updated? I have this exact same thing at Lerikas. So a User wants to be notified when a Conversation is updated or when it receives a new reply. Okay, so what would our URI look like? How is this going to work? Well, let's see. We're going to have /conversations, so that would give us all Conversations. But now, maybe I want to post somewhere. So POST to /conversations/subscribe. You know, if you're not following REST, I've seen stuff like this before, kind of weird.

So post to conversations/subscribe. You know, if you're not following REST, I've seen stuff like this before, kind of weird. And maybe we have the ID of the conversation as part of that. So like if you post to conversations/1/subscribe, well, then that's going to hit a method called subscribe on the controller. You know, these are the things people end up worrying about quite a bit, where it's just simple, how do I name this? What is the URI going to be? Where do I put this file? How do I name this method?

So if we want to protect ourselves against this, we can consider, that doesn't mean you have to do it. It means you consider doing it and you determine if your application got better from doing it or if it got worse, you know. So in our particular case, we might be missing something here. So if we want to put this on its own controller, yeah, maybe we could have a conversation SubscriptionsController, something like that. Or maybe we elevate this to sort of its own thing. So a full SubscriptionsController can manage all of this. Now I might not use that term because I think of sort of like a paying subscriber.

So a full SubscriptionsController can manage all of this. Now I might not use that term because I think of sort of like a paying subscriber. But if your entire application is just a forum, then subscriptions would make perfect sense. This is sort of the representative controller for any subscribing actions that could take place. So now, what would happen here? What's the method we want? Well, once again, we go back to the original seven methods. So if we want to post to register a new subscription, then you might use the store method here. So notice we hunt down the action that is not part of our initial seven.

So if we want to post to register a new subscription, then you might use the store method here. So notice we hunt down the action that is not part of our initial seven. We remove it. We create a new controller with that name, SubscriptionsController or ThreadSubscriptionsController if it's more direct for you. And then you create a new method and you return to the original seven. And which one just depends upon what action you're doing here. In this case, we want to create a new record, so to speak. So the store method in this case would make good sense. And now further, rather than using this verb, you know, as always, make up your own mind.

So the store method in this case would make good sense. And now further, rather than using this verb, you know, as always, make up your own mind and decide on a per case basis. But if we want to stick with rest, a verb here doesn't quite make sense. Instead, you might say post to conversations, the ID of the conversation and then subscriptions. Or like I said, if you want to upgrade it to its own top level thing, you might post to subscriptions. And then as part of the request, you would give the thing to which the user is subscribing. So that would include the conversation ID as part of the request. But yeah, now think about it.

So that would include the conversation ID as part of the request. But yeah, now think about it. You got the offending method out of your ConversationsController. So now your ConversationsController can stay very simple. You next created a new controller and returned to your core method names and your core resourceful names. And then further, in your URI itself, you were able to get rid of the verb, subscribeTo, and elevate that to its own resource and its own thing, sort of like a first class citizen. So subscribeTo just becomes a POST to /subscriptions.

Implementing with Routes12:15

the point that I try to stay away from that. But yeah, your views may differ. So anyways, let's see this in action. We are going to have a php artisan make:controller ConversationsController. This is a resourceful controller. So now here, all of our methods are good. Let's go back to our web.php routes file, Route::resource for conversations, and we'll use ConversationsController for that. All right, so let's do this, php artisan route:list and zoom out just a bit. Yeah, so we have all of the associated methods for that.

All right, so let's do this, php artisan route:list and zoom out just a bit. Yeah, so we have all of the associated methods for that. Next we're going to have a new one. So Route::post, not to conversations/{id}/subscribe, and then ConversationsController::addSubscriber. You know, that's maybe what you have right now, right? So if we run it, our controller is now that much more complex. Nope. Instead, we're going to create a new controller, SubscriptionsController or ConversationSubscriptionsController.

Instead, we're going to create a new controller, SubscriptionsController or ConversationSubscriptionsController. And in this case, we don't need all of those methods. We only need a single method. And that's okay. It's not like a controller with one method in it is the worst thing in the world. In reality, you might have one or two or three, but it's okay. You're not breaking any rules if you create a controller with just one method in it. Anyways, if we go to SubscriptionsController, now you'll have your store method. And here is where you register a new subscription or subscriber for the conversation.

Anyways, if we go to SubscriptionsController, now you'll have your store method. And here is where you register a new subscription or subscriber for the conversation. And maybe that would accept this here. And then you would do something like auth user subscribe to conversation and then return back or some kind of response. So now this is clean and simple. Your ConversationsController remains clean and simple. And now your routes file, once again, can return to either this or this, in which case the destination would be SubscriptionsController at store. So cool.

the destination would be SubscriptionsController at store. So cool. Something to think about for sure. Don't feel like you have to do this, that you're breaking the law if you create a method that's not one of those initial seven. As always, make up your own mind. Sometimes it's perfectly fine, but other times if you feel, if you're starting to feel gross about that controller, this is one good solution.

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