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

Goal: Order Model Classes0:00

For our final bit of automation, let's make something a little more complex. This will allow us to apply everything we've learned in this series. A bit of automation I've always wanted is something that automatically orders common classes within my Laravel application. For example, my models. Models have some common features within the classes, and it'd be nice to see them ordered. So things like having properties at the top is pretty straightforward, but once you start getting into the different type of functions, you can have things like custom static functions, the different relationship methods, scopes, attributes, all sorts of different methods. It'd be really cool if these were in a consistent order across all of my models.

Create OrderModel Task0:37

the different relationship methods, scopes, attributes, all sorts of different methods. It'd be really cool if these were in a consistent order across all of my models. Tighten actually has a package called tlint, which includes a check to see if your models are in a particular order. Unfortunately, I don't believe that particular lint has an automatic fix. So let's build it ourselves. The first thing we'll do is make another task, and this is actually going to use a finder just like debug calls. So I'll copy this and call it OrderModel. Let's change this class name to OrderModel, and now let's trim it down to do what we need.

So I'll copy this and call it OrderModel. Let's change this class name to OrderModel, and now let's trim it down to do what we need. So we'll still want to find all files. We'll want to call a finder, in this case, ClassDefinition. We're not going to worry about any kind of failures because it's going to format these classes automatically, much like our code format task. So we can get rid of this line. We will want to pull out the contents. We're not going to need to pre-filter by any kind of debug calls or method calls, so we can remove this as well.

We're not going to need to pre-filter by any kind of debug calls or method calls, so we can remove this as well. All right, the rest of this looks okay. We don't need to worry again about any failures, displaying of the errors. We will probably want to loop over instances, but we'll rebuild that ourselves when the time comes, and I'll comment out this file putContents. And again, this is always going to return zero, meaning that the task ran successfully. All right, we don't need these display errors, and we will keep findFiles. Now the difference here will be in the current working directory, assuming this is running in a Laravel application, that all the files we care about would be underneath App, Models.

Now the difference here will be in the current working directory, assuming this is running in a LayerFile application, that all the files we care about would be underneath App, Models. Now again, you can adjust this for your project if your models are located somewhere else. And since we're always looking underneath that directory, we don't need to exclude Vendor, but of course we will keep our .php file extension. Before we forget, let's open up our task manifest, and let's register this new model Order task. So we'll say order model, and the task is order model. If we jump back out to the command line, we can make sure that works by doing shift discover. And there it is, the order model task was automatically discovered. All right, let's go back up here and start on our finder.

Build ClassDefinition Finder2:50

And there it is, the Order model task was automatically discovered. All right, let's go back up here and start on our finder. Again, this is going to be a lot like the debug calls finder, so let's take a look at this to make sure we're doing everything the same. So I'll copy these two methods that we need, and we'll paste them into our class definition and give them a review. All right, now our search is going to be pretty straightforward. We really just need to filter anything that's a class. So we can remove all this code and effectively say return node is an instance of class. And this will be a class statement.

So we can remove all this code and effectively say return node is an instance of class. And this will be a class statement. If we take a look at this inside of Nickic parser, we can see that this has all sorts of meta information about the class, its visibility, if it's abstract, final, read-only, an anonymous class. All of that information about the constants, properties, and methods within the class. And that's what we need process to do. Instead of getting the function information, we need all of that meta information about the class. That way we can sort the code within it.

Extract Property Metadata3:55

the class. That way we can sort the code within it. So we'll need the constants, we'll need the properties, and we'll need the methods. All right, let's start with the properties because I think that's going to be the most involved. So we'll say this, getProperties, and we'll pass in the instance. Let's generate this method with phpStorm, and instead of mixed, we can say that we know this will be a class, and we'll change this to class. Now this will be a bit of an accumulator method, so we'll say properties is an empty array, and we'll go ahead and return properties.

Now this will be a bit of an accumulator method, so we'll say properties is an empty array, and we'll go ahead and return properties. So now what we can do is loop over the class properties as property, and we'll add that property meta information to our properties array. So properties, ideally the property name, and then our definition. Now much like our class instance itself, we will want to have line and offset, which is going to make it easier to manipulate the contents of the file. We're also going to want to know the name of the property, so that'll be pulled out of name. We'll want to know its visibility, that'll help us sort private versus public methods.

of name. We'll want to know its visibility, that'll help us sort private versus public methods. So for now we'll just mark that as null, and we'll also want to know if it's static. That way we can move any kind of static class method higher up in the ordering. Now we have access to this directly, so we can say isStatic, and there's one more bit of information we're going to want to track. We need to know if this has any kind of doc block comment associated with it. This is a bit of a nuance about NickicParser. Comments are only loosely attached to the node, so we need to extract that separately. So for now I'll just make it an empty array, but we will need its line and offset information.

Comments are only loosely attached to the node, so we need to extract that separately. So for now I'll just make it an empty array, but we will need its line and offset information. So let's fix some of these squigglies that we have here from phpStorm. So first it's not instance, it's going to be property. Next let's pull off this thing's name. So name is going to be property, and if we take a look at what properties gives us, it gives us an instance of property. And if we dig down inside of here, we get information about its attributes, its type, its flags or modifiers, and we see this property property array of its properties. That's a little redundant, but if we dig down inside of here, we can see that it has a name.

its flags or modifiers, and we see this property property array of its properties. That's a little redundant, but if we dig down inside of here, we can see that it has a name and a default value of the property, and that's what we're going to want to pull off. So if we go back to our class definition finder, we can say props, get the first one for its name, and get that as a string. Great, that should give us our name, and now we can properly key that in our properties array and name should be working. Alright, let's work on visibility. We saw that we have these methods of isPrivate or isPublic or isProtected. What would be nice is to turn that into a simple string like public.

We saw that we have these methods of isPrivate or isPublic or isProtected. What would be nice is to turn that into a simple string like public. So let's make a little helper method on our finder that says getVisibility, and we'll pass it in the property. Let's add that method, and we're not always going to pass this thing a property, so let's just pass it a node, but we know that we will return a string. And we can say if the node is private, assuming that it has that method based on what we passed in, we'll return private, else if node is protected, we would return protected, and finally our default would be just to return public. Great, that handles the visibility.

finally our default would be just to return public. Great, that handles the visibility. Alright, let's do the tricky one for comments. Let's also make a little helper method called getComments, and again we'll pass in this property. Similarly, it won't always be a property, it's going to be mixed, so we'll just say node. Let's pull off comments as node->getComments(). This is a common method inside of NikkikParser, just like the startLine or endLine. So if the comments are empty, then let's go ahead and return null, otherwise we're going

This is a common method inside of NikkikParser, just like the start line or end line. So if the comments are empty, then let's go ahead and return null, otherwise we're going to want to return an array, again that gives us the information about the line and offsets, so we can easily pull that from our contents. So let's just copy this same structure to keep everything uniform, and we'll change this to comments. Now comments is actually an array, so we're going to need to get the first comment in the block, or zero in this case, but for the end we'll want to know the last comment in the block. Now unfortunately php doesn't have something like negative one, this is kind of old school.

Add Constants and Methods9:13

the block. Now unfortunately php doesn't have something like negative one, this is kind of old school from my Perl days, but what we can do is put in a reference here to say last, and we can get that information by saying array_key_last(comments), and that'll give us that last index. This should be everything we need for the properties. Going back to our process method, we're going to need to do the same thing for constants, and the same thing for methods. So let's make these two helper methods pretty quickly. So we'll say constants and methods, we'll use phpStorm to go ahead and generate those.

So let's make these two helper methods pretty quickly. So we'll say constants and methods, we'll use phpStorm to go ahead and generate those for us, and let's update these signatures to follow that same class type int for class, and we'll return an array. Now for both of these, we can really just copy everything we've done for properties. So let's change properties to constants, let's change getProperties to getConstants, and let's change property to constant. Now constants can't necessarily be static, so let's go ahead and remove that, and it's no longer props, this is called consts, but it's the same type of structure as properties. Alright that should be pretty good, moving down to methods.

no longer props, this is called consts, but it's the same type of structure as properties. Alright that should be pretty good, moving down to methods. Let's paste in our properties, and again we'll rename these to methods. Let's get methods, and we'll rename property to method. Now I don't remember what the name of the method is, I think it's a top level property, let's take a look. Yes, it is, name. So we don't need to access it through an array, we should be able to access it directly by its name. Great.

Run and Validate Output11:22

its name. Great. Let's go back to our task, and for now we'll just print_r on instances, and let's see what things look like. Let's do php shift run order model. Oh, of course, within our CLI project there is no such thing as app models. Okay, let's temporarily hack this to simply just return the path to that license.php file. Let's clear out this noise and try to run our order model again. Great, it doesn't seem like it's exploding, so let's take a look at some of the information we got here.

Great, it doesn't seem like it's exploding, so let's take a look at some of the information we got here. We have this generateKey, on line 127, ends on line 130, it doesn't have any comments, it's private and static. Let's go see if that's true. Jumping in our license file, it said 130 is the end line, it's private, static, generateKey. Awesome. It seems to be working there. Let's check one of the properties.

It seems to be working there. Let's check one of the properties. If we scroll up to the properties section, we have guarded on line 20, but it also has a comment on line 17 and 19. Let's see if our comments is working. So scrolling up to line 20, great, there's our property definition, and on lines 17 through 19 is our doc block that's associated with that property. Awesome. So I think this gives us everything we need to know about the class, and now we can use that to sort and reorder this class.

So I think this gives us everything we need to know about the class, and now we can use that to sort and reorder this class.

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