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

Introducing Use Cases0:00

Alright, we're moving on to the second option you have when wrangling monstrous code into shape, and that's called a use case. But as you'll find a bit later, it really has a bunch of names, depending upon the community. Okay, so let's clear all of this out and make a new controller. We'll use an example from the Laravel documentation for purchasing a podcast. I always like this example because when you think about it, who has ever actually purchased a podcast before? But anyways, we might have, I don't know, maybe when we have, you post to purchases, or maybe you have some kind of cart. In reality, the URI doesn't matter one bit in this lesson.

Creating Purchases Controller0:33

or maybe you have some kind of cart. In reality, the URI doesn't matter one bit in this lesson. So to keep it simple, we're going to use a get request. And yeah, we'll just call it purchases, and that'll take us to PurchasesController at store. Alright, so let's do that, php artisan make:controller PurchasesController. And if we visit that file, we now have a method called store, right? And I'll clean this up. Now imagine that within here, you have a bunch of different operations for how you go about purchasing the podcast in this example.

Building Use Case Class4:35

And again, I'm going to show you just like the last video, two different ways to go about this. First, a manual custom approach that would work with even php. And then second, we'll see if Laravel provides anything that might help with this. Okay, so before I do that, let's go ahead and within our app directory, yeah, let's create a new directory there called use_cases, or honestly, you can put it anywhere you want. So if you have different directories that represent the different components or pieces of your application, then you can put each of these use cases within there. Okay, but anyways, let's go ahead and create that class. I'm going to put it within app/use_cases.

Okay, but anyways, let's go ahead and create that class. I'm going to put it within app/use cases. And yeah, the namespace will be app/use cases in this example. So we know that we had a static method, right, called perform. And this would accept any of your arguments. In our case, we won't have any. Now this is a static method, it's just going to be a bit of sugar that will new up a class. So think of it like a named constructor. Ultimately, we will return a new instance. And then maybe in the process, we will call a more Laravel friendly method, usually it's

Ultimately, we will return a new instance. And then maybe in the process, we will call a more Laravel friendly method, usually it's called handle. Okay, let's go ahead and create that method. So yeah, once again, this allows you to do something like this, purchasePodcast perform, perform that use case. And ultimately, that's just sugar for saying, $p equals a new PurchasePodcast, and then $p->handle(). Not quite as enjoyable to write. And this describes what you want to do a bit more, perform the following use case.

Not quite as enjoyable to write. And this describes what you want to do a bit more, perform the following use case. So now here is where you would delegate to handle this process. So if you need to send an email, then you would defer to that here. If you need to prepare the purchase itself, then you would do that there. All of these steps can be defined in their own methods. And that way your handle method can just simply delegate to them. So when you think about it, what's really nice about this is, if anyone wants to know what the workflow is for purchasing a podcast, all they have to do is open up the single file and look at the handle method.

what the workflow is for purchasing a podcast, all they have to do is open up the single file and look at the handle method. And then they can see, okay, well, that workflow consists of preparing the purchase, sending an email, printing out a receipt, blah, blah, blah, right? Now for each of the steps, yeah, you give them their own private methods. And so let's do this. Let's just say var_dump preparing the purchase since we don't have a real app. And then return this. In our example, I'm making this fluent, but you don't have to. You can call them one by one.

Calling Use Case in Controller7:01

In our example, I'm making this fluent, but you don't have to. You can call them one by one. Anyways, Vardomp send an email with their invoice or what have you. And that should return this as well. All right, so an incredibly simple use case here called PurchasePodcast. Now let's switch back to our controller and see if it works. So I will import this app, use cases, PurchasePodcast, and then we will call a perform method. We now know that that's simply going to new up the class and call a handle method. The handle method then describes each step of that process, in our case, preparing a purchase and sending an email.

The handle method then describes each step of that process, in our case, preparing a purchase and sending an email. And that's all there is to it. So why don't we try this out in the browser and see what we get. In this case, I'm just going to return done. Okay, so if we view this in the browser, sure enough, it worked. So we're var_dumping in this case, but once again, that's just to illustrate the different steps you would need to take in your own project. And what's nice is, assuming your controller had gotten really gross with all of this stuff, now you've reduced and isolated it to a single class with a good name.

And what's nice is, assuming your controller had gotten really gross with all of this stuff, now you've reduced and isolated it to a single class with a good name. Even better, when future developers are browsing your system and they're curious about the particular use cases for this app, well, you'll have a nice list of class names that show all of the important use cases that can take place. But again, I can't stress this enough, do not go overboard with this technique. So for that example again, like if you want to publish a Post, don't do stuff like this unless it's really complicated. If you try to translate every possible response to a form into a use case, trust me, it's not going to go well for you.

Abstract UseCase Base8:35

If you try to translate every possible response to a form into a use case, trust me, it's not going to go well for you. It may seem fun at first, but six months down the line, you're not going to like the application you've built. Save this for the things that are truly worthy of the name use case. Okay, so before we move on to step two, can we clean this up, can we give it an interface, make it a bit more simple? Sure. Why don't we create an abstract parent class, and that way we can take this perform method, which will be the same in every single class, and yeah, we can get it out of these subclasses.

Why don't we create an abstract parent class, and that way we can take this perform method, which will be the same in every single class, and yeah, we can get it out of these subclasses and into the parent. So let's do that now. I'm going to create a new class, and we'll just call it UseCase, but I am going to make it abstract because you should never instantiate this on your own. Okay, so if we come back, so yeah, let's have this extend UseCase, and then push this perform method up, like so. All right, so let's go to the parent. We now have an abstract parent class called UseCase.

All right, so let's go to the parent. We now have an abstract parent class called UseCase. It has a single static method, which is a named constructor called perform, and in this case it's squawking. Let's go ahead and make this an abstract public function. So any child class must implement a handle method, and again, just as a reminder, that's where they put the logic for how this UseCase is implemented, and we'll make that public now. So there we go. A little bit cleaner, right?

So there we go. A little bit cleaner, right? And of course, if we refresh, we're going to get the exact same thing. So now if you're asking, well, how do you go about testing this, I wouldn't recommend for use cases like this. Don't unit test it. Some people subscribe to an Idea that if it's not perfectly unit testable, it's terrible code. Honestly, I don't agree with that. In this scenario, this is a perfect use case, for lack of better words, for writing an integration.

Using Laravel Jobs Instead10:17

Honestly, I don't agree with that. In this scenario, this is a perfect use case, for lack of better words, for writing an integration test, and luckily Laravel makes that really simple for you. Okay, so this is cool stuff, but we also use Laravel, and we've heard of this similar thing called a job. So let's try it out. So if I were to say php artisan make:job, and we tried PurchasePodcast, let's see what that looks like. I'm going to open up that file now, and it looks a little bit more scary, but we still have the same class name.

I'm going to open up that file now, and it looks a little bit more scary, but we still have the same class name. It extends Job, but that almost sounds like UseCase. There's a little bit of overlap there. And then once again, we have a handle method for how we execute the job or execute the use case. But now we do see that by default, a job implements ShouldQueue. So typically, yeah, your Laravel jobs are your queueable jobs. So anything that you want to do in the background, and the most common example of this is sending an email or two.

So anything that you want to do in the background, and the most common example of this is sending an email or two. That can take kind of a long time. So instead, push that to the background and return to the user as quickly as possible. That's when you would reach for a queue. But here's the thing. We call this a job, but if I removed that entirely, and we can get rid of those traits and then clean this up, well, now this looks very much like a use case, doesn't it? But not only that, you might have also heard this term of a self-handling command, and this looks like that too.

But not only that, you might have also heard this term of a self-handling command, and this looks like that too. So now we're starting to see, yeah, basically, a use case or a non-queued job or a self-handling command. They're basically the same thing. Don't get too confused trying to figure out the difference between the three. You can treat them as the exact same thing for all intents and purposes. So why don't we try this? Let's go back to our custom use cases file, and I will take everything within here, and I'm going to move it over to our job, like so.

Let's go back to our custom use cases file, and I will take everything within here, and I'm going to move it over to our job, like so. Next, I'm going to go back to my controller here, and I'm not going to import use cases. I will import jobs. Finally, it's true, we don't have a perform method. We dispatch a job, and we can do that using a helpful function called dispatch. New purchase podcast. And now here is where you would pass through any arguments. In our case, we don't have any. Okay?

In our case, we don't have any. Okay? So let's go back to Chrome. This is what we had before when we had a use cases directory, but if I give it a refresh, we get the same thing, but now we're using Laravel's job interface. And in this case, if it needs to be queued, you could add the shouldQueue contract. But if not, just remove it entirely, and now you have what basically amounts to a use case or self-handling command. And that's all there is to it. Don't complicate it any more than that.

And that's all there is to it. Don't complicate it any more than that.

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