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

Adding Default Name0:00

Next, I'd like to add some defaults to make the process of adding a new achievement as simple as possible. So for example, if we go to, how about, LaracastMastery. At the moment, you are required to give us a name, a description, and an icon. But you'll notice in this case, LaracastMastery is just the name of the class, right, with a space in it. So maybe we could add a sensible default. If you don't provide this, we will make a nice, readable form of the class name. Or if you do provide it, we'll use whatever you put there, right, a good, sensible default. Okay, so we're going to apply that to our abstract parent class.

Writing Unit Test0:31

Or if you do provide it, we'll use whatever you put there, right, a good, sensible default. Okay, so we're going to apply that to our abstract parent class. Let's get started. I'm going to begin by making a new test. This will be a unit test for the AchievementType. All right, so AchievementTypeTest. And we'll add useRefreshDatabase. Or actually, for my particular project, I have this custom IntegrationTestCase class that does all of that stuff for me. So I will get rid of all of that, like so.

that does all of that stuff for me. So I will get rid of all of that, like so. Anyways, let's get started. So to begin, it sets a default name. But now how do we test an abstract class like this? Well, usually I'll just create a fake class that extends from this. So we could do that even right up here, right at the bottom. We'll say FakeAchievementType, and that will extend the AchievementType class. Okay, so now I can instantiate that for the purposes of testing some of the methods here. Okay, so if I were to instantiate this, well, the name of the class should be, or the default

Okay, so now I can instantiate that for the purposes of testing some of the methods here. Okay, so if I were to instantiate this, well, the name of the class should be, or the default name should be, this turned into a word. So I could say this->assertEquals fakeAchievementType, like so. Okay, so if we give that a run, integration test case not found. Whoops. All right, one more time. All right, now, of course, the name property is not found. And that's what we're working on. We want that to be optional.

Implementing Name Getter2:24

And yeah, we got to get to work on that. So it sounds like we want to allow the User to specify a name, like traditionally, or the current functionality is you would have to do this. And if we ran that, we would get green. But we don't want to have to do that. So it sounds like we need a hook to check to see did the User add this name property. And if not, well, let's just look at the name of the class. Okay, so maybe instead, we'll make that a method name. All right, let's come back to AchievementType. Now, when we do have this database query, and that does present an n plus one issue,

All right, let's come back to achievement type. Now, when we do have this database query, and that does present an n + 1 issue, but I'm going to save that for a little later to talk about and then some options we might have there. If we don't have too many achievements, it's kind of a non-issue. But if you do have 100 different achievements, it's very much something we need to consider. All right, for later, though. Until then, the name, well, it looks like we need to reference that as a method. All right, come back, give it another run. This new method name does not exist.

All right, come back, give it another run. This new method name does not exist. So of course, we will create that. Run it again. Okay, column name cannot be null. Of course, we're returning nothing. And we're trying to pass that to the database. So to start, we could just, you know, treat it as a basic getter. And give it a run. And now we've changed the error.

And give it a run. And now we've changed the error. But we're back to that same issue where we're trying to find a name property, but it may or may not exist. So we could say we could do a couple things here, but we could do property_exists. And you'll see if we click through, we need the class name as well as the property name. So this and name. So if that property exists, then return it. Otherwise, and we'll do this in a couple steps. So first, we'll just get the class name.

Otherwise, and we'll do this in a couple steps. So first, we'll just get the class name. Like so. Give it a run. And now we can see, all right, well, we expected a nicely formatted version. But instead, we just got the full namespaced path. Not what we want. Now Laravel does offer a, what is it called, class_basename. Yeah, we could try that. Give it a run.

Yeah, we could try that. Give it a run. Okay, so now that just gives us the short name that strips off the rest of the namespace. It sounds like next, we need to separate every new capital letter with a space. Laravel does have a String class, but I'm not sure. Somebody correct me in the comments if I'm wrong, but I'm not sure if there's anything that will convert camelCase to sentence case. Something like that. Not that I can think of. So, hmm, there's probably some regular expression we could copy and paste.

Formatting Name with Regex4:51

Not that I can think of. So, hmm, there's probably some regular expression we could copy and paste. Let's see if we can do it really quick just with a simple regular expression. What I'm thinking, this is what I often do. I use this regular expression site. So, yeah, let's say we have my class name, and we're going to use server side regex and replace. And we're going to look for, I guess, any capital letter. So, A to Z, only capital. And we could replace that with whatever was matched there, preceded by a space.

So, how about preg_replace our pattern, what we are replacing it with, and the subject. So, we're looking for a capital A to Z, and we're going to replace that with a single space, or just that, and whatever you matched. So, let's give that a run. All right, now we have fakeAchievementType. Again, this is a very simplistic conversion there, but I think it's okay for a default. And then I just want to trim. So, we'll say trim here. All right, give it a run, and we get green. Yeah, and that does it.

Anyhow, the end result is now name is optional, or you can add it if you want something special. And, of course, it's going to fail here because that is overriding it, but you get the idea. Now, do we need a default for either of these? I don't think so. I mean, I always want a unique description and an icon. So, I will leave those as properties, but again, later if we need to, we'll make those methods just like this. And that's why some people would consider it a good practice to always use a getter just in case you need to intercept that logic like we've done here. It just depends.

Enforcing Qualifier Contract7:11

just in case you need to intercept that logic like we've done here. It just depends. Anyhow, what else? Here you can see the related models being stored as a public property, but at the moment I don't see any need to expose that, so why don't we make that protected instead? The next thing is, well, you'll notice in our test here, this is a valid class even though we've decided that any AchievementType needs to have this qualifier method that determines whether or not the provided user is valid. So, we need to determine whether or not the provided user qualifies for this achievement. But in our test, we didn't include that and everything still worked, right?

So, we need to determine whether or not the provided User qualifies for this achievement. But in our test, we didn't include that and everything still worked, right? So, we're not honoring the terms of the contract, but everything still worked. We can fix that by going to the parent class and saying, look, I need you to provide a qualifier method. So, we'll do that here. qualifier, it accepts the User. Now, if we try to run our test, it should blow up, and it does. It's saying, hey, you created this class, but there's one abstract method that has not yet been implemented.

It's saying, hey, you created this class, but there's one abstract method that has not yet been implemented. So, you need to do that in order for things to function the way you want. Okay, fair enough. So, we would come back here, and in fact, phpStorm is squawking. So, we'll add that method stub. And here, it's irrelevant, so I can just return true. Give it another run, and we're back to green. These are all things to think about. So, now, at this point, behind the scenes, I would clean things up, I would format, I

These are all things to think about. So, now, at this point, behind the scenes, I would clean things up, I would format, I would add my doc blocks, and I would move on to the next requirement for achievements.

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