در حال بارگذاری ...

Refactoring Goals Overview0:00

All right, welcome back. So why don't we wrap up this refactoring chapter with one more technique. I will show you how to both extract a class, and then take members, methods, or properties, and pull them up to the parents. All right, let's get going. So for this example, I've created an achievements directory with two different people achievement badges or awards. Very similar to what you might see at a site like Laracasts. So we have one called FirstThousand. Here we can see an achievement badge has a name, in this case First Thousand, a description, so you get this one after you reach your first thousand points, a level, so how difficult is it to acquire this badge, an icon,

Extracting Constants for Levels2:00

it's just a lot of repetition and duplication, and there's an opportunity for these things to become out of sync, even if it's just a capitalization issue, or maybe you forget, and you forgot that it was beginner, intermediate, and advanced, and you assumed it was basic, medium, and high. You get the idea. There's an opportunity for things to become out of sync. So instead, we usually solve this problem by extracting either a constant or an enum. Both are fine. Let's just keep it simple and extract a constant. So we'll do that now. I will select the word, Ctrl+T to bring up the refactoring menu, and we want number 2. Introduce constant. Or again, I can just start typing. Alright, and here's the suggestion. I think that's fine for now. So return, and we commit it. Okay, so now that adds a constant

Extracting Parent Class2:40

Or again, I can just start typing. Alright, and here's the suggestion. I think that's fine for now. So return, and we commit it. Okay, so now that adds a constant to the top of the file. And yeah, I mean, I guess we could do the same thing for the first thousand. So I will manually just paste that in, and then swap it out down here. But as you're probably thinking, that sort of defeats the purpose, doesn't it? Now I'm just hard-coding the string within every single AchievementBadge class, and we haven't really fixed the issue. So why don't we extract this to a parent class that all of these achievement classes can then inherit from. Alright, let's do that now. Now, of course, I could manually create the new file, or I can let phpstorm do it for me. So once again, Ctrl-T to bring up the refactoring menu,

Alright, let's do that now. Now, of course, I could manually create the new file, or I can let phpStorm do it for me. So once again, Ctrl-T to bring up the refactoring menu, and this time I want to extract a class. Let's call the class AchievementType. And yeah, for now, I will only include the constant. But yeah, in real life, I would do a lot of these steps at once, but for educational purposes, one at a time. Alright, and there we go. We have our new AchievementType class. And now if I switch back here, you will see, well, it didn't know that we wanted to inherit. We didn't know that it's a parent class. So if I scroll down, you can see it's just deferring there, and we get a squiggly line because that constant has protected visibility. Alright, so let's fix this. I will extend from AchievementType, and then right down here,

and we get a squiggly line because that constant has protected visibility. Alright, so let's fix this. I will extend from AchievementType, and then right down here, Okay, so I can grab that, and if I switch to Welcome to the Community, I can do the exact same thing here. Paste it in, and then inherit from AchievementType. Cool. But now, while I'm here, I'm noticing that both of these return beginner. And maybe it'll turn out that, well, beginner is a sensible default for AchievementTypes. So you want to have the option to change that, but then again, you assume beginner for any new achievements that we create. That might be a good choice. So in these situations, here's what I can do. I will select the method, press Ctrl T to once again refactor,

Enforcing Abstract Methods5:22

we're just making small incremental steps to make things a little bit more cleaner and intuitive. Alright, let's keep going. What else? Well, what about the qualifier here? It sounds like every single achievement has or requires a qualifier. So why don't we make that explicit? And again, you can declare an interface, or because we already have a parent class, why don't we just create an abstract class like this? public abstract function qualifier that will expect a User, and it then returns a Boolean that indicates if you qualify for that badge. And yeah, of course, right now, PHPStorm's letting me know, well, hey, you have an abstract method here. So in those situations, you also have to declare that the class itself is abstract. So again, I can manually do that, or I can bring up the quick fix menu with Option + Return.

So in those situations, you also have to declare that the class itself is abstract. So again, I can manually do that, or I can bring up the quick fix menu with option return. And yeah, here, I can do that automatically. Cool. So are there any other places we should do that? Well, maybe for now the description. So let's come back. I will duplicate this and update it. description, and that will return a string. Okay, so now think about it. If I create a new Achievement class, I extend from that parent, but I forget to include a description, it's going to notify me right away. So for example, if I got rid of that one as well, yeah, you either have to declare this abstract or implement the methods. So if I hit option return, you'll see there is an option to add the missing method stubs. And in this case, that would be qualifier and description. And that's what you want.

Pulling Up Default Implementations6:53

So if I hit Option Return, you'll see there is an option to add the missing method stubs. And in this case, that would be qualifier and description. And that's what you want. All right, cool. So I'm going to hit Command C a couple times to bring back what we had before. And we're making good progress. Okay, so the next things I see are stuff like this. Notice the icon follows a common pattern. It's basically the file name, but lowercase, and then camelCase, and then we add .svg at the end. So first1000.php turns into first-thousand.svg. And the same thing is true for welcome to the community. All right, so in situations like this, it's probably true that every single achievement icon will follow this exact same pattern. But we still want to offer the ability to override it if necessary. I just want to assume, again, a sensible default. So let's do that.

will follow this exact same pattern. But we still want to offer the ability to override it if necessary. I just want to assume, again, a sensible default. So let's do that. First, though, before I can push this or pull this up to a parent class, I need to make it dynamic so that the implementation is the same across all Achievement classes. So I think what we could do is something like this. Let me know in the comments if you can think of a quicker way. But off the top of my head, Laravel has a function called classBasename() that's going to give me effectively the name of the file only. So if I do this, this would correspond to welcome to the community. I could then pass that to str_kebab(), and that would then give me welcome to the community.

So if I do this, this would correspond to welcome to the community. I could then pass that to string kebab, and that would then give me welcome to the community. And then it looks like the only thing that's remaining is to concatenate .svg, and that will give us this. Okay, cool. So think about it. If I get rid of that, I could then effectively swap out first-thousands implementation with a dynamic version as well, and everything—I haven't tested this, but I think that's right—everything will still work. Okay, so now that I've made them the same, I can then pull the implementation up to the parent. So select the method, Ctrl-T, bring it up into the parent, perform the refactor, and now it's gone, and it's instead in the parent, as you see right here.

So select the method, Ctrl-T, bring it up into the parent, perform the refactor, and now it's gone, and it's instead in the parent, as you see right here. Okay, and actually, I'd probably prefer this to come up a couple levels. So I will hit Shift-Command-Up to bring this up directly below the level method. All right, cool. So in first-thousands, we already did that. Welcome to the community. This one can leave as well. All right, finally, I think we can do the exact same thing for the name method. Now, again, off the top of my head, I'm not sure if Laravel offers a way to convert something that is studly case into sentence case, although it rings a bell. It's just not coming to me right now.

to convert something that is studly case into sentence case, although it rings a bell. It's just not coming to me right now. So why don't we manually do it with preg_replace? I think I could do this. I could look for any capital letter within this file name and replace it with a space. So something like space, and then the matching letter, and then feed it the name of the file. And yeah, again, I'm not going to test this, but I think this is right. Think about it. If we have WelcomeToTheCommunity, we're going to match every capital letter, like this one in here, and those capital letters

identical across all implementations, so I can now pull it up a level to the parent. Like so. Come to Welcome to the Community, and this one can go as well. Alright, so now, yeah, have a look at how much cleaner this is. Now, each Achievement class I create only requires a description and a qualifier, and everything else, all of the other nitty-gritty details are instead located within the parent class, as you see here. And I'm going to bring this up as well. Maybe like this. Name, level, icon, and then two abstract methods. And actually, let's put description like that.

Creating New Achievement Type11:15

Name, level, icon, and then two abstract methods. And actually, let's put description like that. Okay, so here's first thousand, and here's Welcome to the Community. So yeah, now you can imagine, if I create a new Achievement class, let's do something like, at Laracast, you get a badge if you have a lifetime account. So let's call this Lifer. If I want, I can extend Achievement type directly from within here. And now you can see, as part of that, it also includes the method stubs that I will need to fill out. And that's pretty cool. So return earned if you are a lifetime subscriber.

that I will need to fill out. And that's pretty cool. So return earned if you are a lifetime subscriber. And then finally, the qualifier would be something like, I don't have this method in our example project, but something like this. Some kind of check that determines if the User is on the lifetime plan. And yeah, notice how much easier this is to prepare versus what we had at the beginning of the video, where every single achievement type was basically following the exact same pattern for what a name is, for what the level is, for what the icon is. Now, I only have to override those default

the exact same pattern for what a name is, for what the level is, for what the icon is. Now, I only have to override those default implementations, or those parent implementations, when and if I need to. So for example, assuming first thousand is much more difficult to acquire, which it's not. But if it was, in that case, I can override that method. And again, I can just manually do it, or with phpStorm, I can press Command-N and I'm going to override a parent method, and I'll just start typing. In this case, the method is level, and I see it right there. All right? And now, yeah, I can return a constant,

typing. In this case, the method is level, and I see it right there. All right? And now, yeah, I can return a constant, or the string, whatever you want, whatever makes sense. And I've now overwritten that default implementation. So let's finish up by making advanced a constant as well, and then we will be done. Control-T, introduce constant called advanced. I will move it to another class, though. All right? The target class will be our parent, like so. And again, I can use self. Okay. So now, we have two constants, one for beginner, and one for advanced, and then our base.

self. Okay. So now, we have two constants, one for beginner, and one for advanced, and then our base implementations. I think this is good. All right. So I think you now have a general understanding of phpStorm's refactoring capabilities. So with that in mind, let's move on to a new section in the next lesson.

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