Extract Publishing Service0:00
We can use decorators for opt-in functionality. And this is great when you have really messy code and you're not exactly sure how to clean it up. Let me give you an example. Let's make a controller and we'll call it maybe TutorialsController. All right, so if we visit that file, maybe we have a method store, and this is where you submit the form and you're ready to publish the tutorial. Now, initially, you just did something like new Tutorial and then you passed in the request data. But then, as it grew, it turned out that more and more things were needed to publish the tutorial. So at that point, you extracted a different class. Maybe it's something like PublishesTutorial, if you want to name it like that. Maybe you just moved the logic onto the model. If it's not too complex, then you would just have a Tutorial class and that would be your Eloquent model. It all just depends, right?
that. Maybe you just moved the logic onto the model. If it's not too complex, then you would just have a Tutorial class and that would be your Eloquent model. It all just depends, right? Let's stick with that idea of PublishesTutorial. This is something I especially like to use when, yeah, it just doesn't feel quite right in the controller and there's a few too many things going on at that point. Okay, so we would create something like an app, how about Tutorials, and then PublishesTutorial. Let's build that up. Namespace App\Tutorials, and then class PublishesTutorial. Okay, so here, you're going to have a publish method and you're probably accepting the request data or maybe that's coming through the constructor, whatever. It doesn't matter in this case. So now here, I'm going to simulate this, like we often do, by saying var_dump, saving the tutorial to the DB and publishing it. But yeah, in real life, you're doing a bunch
matter in this case. So now here, I'm going to simulate this, like we often do, by saying var_dump, saving the tutorial to the DB and publishing it. But yeah, in real life, you're doing a bunch of different stuff. You get the idea. All right, so back to TutorialsController. You're now ready to publish it, so you would new up the tutorial. We'll just say Tutorial, and now we'll publish it by saying Tutorial::publish(). Okay, so basic stuff so far, right? Remember, here, you would pass through the request data or a plain old php object, whatever you want. That then calls the method, performs the save, and publishes the tutorial. But now you're starting to find that this is useful in a number of places. So you've added the ability to email yourself a post, and then that should have the same end result. And in that case, you're not going through the web and through a controller at that point. So extracting this class is very useful. But also in the process, you're starting
Identifying Optional Behavior2:17
have the same end result. And in that case, you're not going through the web and through a controller at that point. So extracting this class is very useful. But also in the process, you're starting to see that in some cases, you need to perform a bit of action, but in other cases, not. So here's what I mean. Maybe initially, yeah, when you publish the tutorial, you also have a bit of logic here that automatically tweets a link to the post. And that was fine, but then you started to realize, well, in some contexts, I actually don't want that tweet to be performed. Maybe you're publishing something that you don't want to advertise, or it's backdated, or for whatever reason. This is a trap you often run into, where you extract some logic, and you want to use it, but in certain contexts, you don't want to use all of it. And that's where it gets kind of weird. And that's where a lot of people end up creating a lot of duplication. They'll create a new class that just
Creating a Decorator3:02
contexts, you don't want to use all of it. And that's where it gets kind of weird. And that's where a lot of people end up creating a lot of duplication. They'll create a new class that just does one less thing than the former. Okay, well, instead of that, you might consider decorating. So in this case, if we want the Twitter aspect to be opt-in, yeah, we decorate it like this. App\Tutorials. And how about we call this class, it's a single-use class, TweetsTutorial. Okay, so let's grab all of that, paste it in, change the name. But now I'm going to keep the same API, or the same contract. That is a key component to creating a decorator. Remember, when we say decorator, think of it just like the real life term. If you're decorating your house, well, maybe you want to add a framed picture right over here. Okay, well, it's the exact same process. So with your house, you're decorating, or you're adding items to get what
Delegation via Injection4:40
behavior in some way, and then you pass it on to the original implementation. Now we do that through injection. So I could say Tutorial, and then within our publish method, this is what we had from the original implementation. But now I'm just going to forward it on this Tutorial publish. Yeah, notice we stack on functionality by conforming to the exact same interface, and then when you're done modifying it however you need to, you delegate on to the original or the next implementation. So we might do this. We could decorate it by saying var_dump, tweet the Tutorial. Okay, so does that make sense? Let's go over it one more time just to be sure that we're all on the same page. So you have your main class, and we've decided you'd like to decorate it in some situations. So we do not change this at all. We create a new class that conforms to the same API. And in that case, it means add a publish method. So we do it.
Opting In at Call Site5:31
decorate it in some situations. So we do not change this at all. We create a new class that conforms to the same API. And in that case, it means add a publish method. So we do it. Step two is, perform your decoration, whatever you need to do, and then delegate on to the next implementation or the original implementation. And that's what we do right here. So in this case, this tutorial, that refers to an instance of publish tutorial. So we call this method, and then we perform the next piece of logic, and we keep both of those pieces of behavior separate from one another. Okay, so we opt in to this functionality like so. Well, why don't we begin by, let's just return tutorial publish. So in this context, we only want to save it to the database and publish it. So let's update our routes file, Route::get, let's just do the homepage. Yeah, we're going to fake a form submission.
we only want to save it to the database and publish it. So let's update our routes file, Route::get, let's just do the homepage. Yeah, we're going to fake a form submission. And then finally, we need to make sure in our controller that we import this. And I will use a little import to pull that in. Okay, so we can get rid of these guys, and this looks pretty good. So let's switch to Chrome. And here's our standard implementation. So we save the tutorial to the DB, and we publish it using pseudocode. But now, yeah, we've decided in certain contexts, we want to decorate or extend that functionality to also perform a tweet. Okay, all we have to do is build up our decorated version, and then pass through the original version as an argument. So this is what we end up with. So now if we import that class, and switch over to Chrome, there we go, we've stacked on functionality, we save it to the DB, we publish it, and then we
So this is what we end up with. So now if we import that class, and switch over to Chrome, there we go, we've stacked on functionality, we save it to the DB, we publish it, and then we tweet it only in this particular context. And that way elsewhere in your domain, if you need to call publishes tutorial, you don't also have to commit to tweeting the post if that's something you don't want to do. Okay, so final run through just to drill this in. When I was younger, I had trouble figuring out what a decorator was. It's weird, once you understand it, it makes perfect sense. But until then, it's still kind of blurry in your head. So I want to cover it one more time with you. You have a class that performs some kind of action, in this case, publish. Next, you want to, in certain situations, extend that functionality. So you create a new class, you conform to the exact same interface, you inject the original implementation through the constructor,
