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

Support Controller Overview0:27

you look at your statement and you think, oh my gosh, I'm drowning in debt, how did I get here? Well, it was the small stuff. So back on track, let's focus on code here. Here I have a basic SupportController, where I validate the request. So this would be like a support form, where you provide your name, email address, you ask your question, and answer a verification question. We then prepare an email to support@laracast.com. We build up a Mailable. We then fire off the mail synchronously.

We build up a Mailable. We then fire off the mail synchronously. We then check to see, well, is this an AJAX request or is it not? If it is, we return some JSON with a status. Otherwise, we prepare a flash message and we redirect back to the home page. Okay, so again, fairly simple, but still real-world enough, and it's full of small little tweaks we can make. Okay, so when I approach a class like this, I first pay attention to the things that immediately pop out at me, and often this will be very long lines. Now in this case, not too bad.

Imports and Request Validation1:24

pop out at me, and often this will be very long lines. Now in this case, not too bad. I think we're okay here. Next, I will move on to the imports. I can see I have one import here, and actually there's another hidden one right here. Now as a convention, I like to import just about everything. There might be some situations where I don't, but as a general rule, I will always import it. All right, a little bit better. Next, I can see that when this code was written, we're calling a validate method, and this

All right, a little bit better. Next, I can see that when this code was written, we're calling a validate method, and this is available through the ValidatesRequests trait that's available on all controllers. However, in recent versions of Laravel, we can instead call a validate method directly off of the request. So that means I could instead do something like this. Now I've made some changes, so I'm going to rerun my tests. Now you'll see I have a single class worth of tests. Very quickly, let's go over it. You'll see we just have a handful of methods here.

Inlining Temporary Variables2:17

Very quickly, let's go over it. You'll see we just have a handful of methods here. One, to ensure that an email is in fact sent, and then a handful more just to confirm that this form requires a name, an email, a question, and a verification. Okay, so if I run all of that, you'll see we do get green. Let's switch back. Okay, next, I will often take a look at temporary variables. So again, we're just focusing on small little things here. We're doing our first cycle through a class. So here I can see we create an email, and that's the support address, and then we reference

We're doing our first cycle through a class. So here I can see we create an email, and that's the support address, and then we reference it here. Well, do we really need to create a temporary variable if I'm only using it once? In other words, can I instead just inline this directly, run the tests? We're still good. All right, so again, it doesn't matter, and nothing happens if you have a variable there and you reference it, but again, it's a small little improvement. We've just reduced the body of this method by about two lines. It's insignificant, right?

Moving Constants to Config3:12

We've just reduced the body of this method by about two lines. It's insignificant, right? However, if we have 50 of those small insignificant changes, they again very quickly grow into big changes. That, in fact, will define your entire architecture, and even more than that, it will define the shape that all future pull requests take because those PRs are going to adopt the style and the approach that you have used in the code. Okay, but now next, we've hard-coded the support email address, and maybe that's fine. But if there are multiple places in your app that will use this email address, well, what if down the line somebody changes it to contact@lericast.com?

But if there are multiple places in your app that will use this email address, well, what if down the line somebody changes it to contact@lericast.com? You have to remember to hunt through the code base to find all places where that email was referenced. So, instead, you might consider storing this sort of information within a configuration file. For example, if I go to config/lericast.php, you'll see I have some basic things I can reference, including a supportEmail. That means I can instead replace this with config('lericast.supportEmail'), and we'll still get green.

That means I can instead replace this with config('lericast.supportemail'), and we'll still get green. Okay, what else? Next, you'll see I'm using request input here. This is where a good understanding of the framework can really help you. So yes, we can use request input, and that'll be fine. However, I can also just reference it like this. I don't have to call input explicitly. Run the tests. We're still good.

Run the tests. We're still good. And in fact, because that's now shorter, we can maybe get away with putting all of this on its own line. All right, we'll talk about this more in a minute. Next, I have this exact same thing again, where I'm creating a mailable temporary variable only to reference it here. So let's see. Let's just inline it. But now, yeah, this is why people often will create a single-use temporary variable, and

Formatting and Queuing Mail5:02

Let's just inline it. But now, yeah, this is why people often will create a single-use temporary variable, and it's because the line's getting a little bit long and harder to consume. Okay, well, maybe instead of creating the variable, I'll just format this a bit differently. Here's our send method, so I'll make it very clear that when I call send, this is what I'm passing. Next, I'm calling mail send. Now it's possible the mailable is explicit that it should be queued, but it's usually not. So let's change that over to queue to make sure that we don't force the user to wait.

not. So let's change that over to queue to make sure that we don't force the User to wait for the email to be sent before providing a response. Next, I come to an if-else. If-else is often a good place to ask if you're missing something, or at least to ask if there's anywhere you can clean things up a little bit. And in this case, it's very clear to me, because in both cases, we return. Okay, so let's go through this piece by piece as we spot things. First, I can see inconsistent formatting. Now, these are things you should be able to automate.

First, I can see inconsistent formatting. Now, these are things you should be able to automate. So if I run phpStorm's autoformat, you'll see it picks up on that. But if you're using something like Sublime, just make sure you're being consistent. If you're going to put your braces on their own line, that's fine. It's not PSR-2, but that's okay. The important thing is you pick a convention, and then you follow it. And everyone on your team follows it. So again, I'm going to stick with PSR-2, so I don't have to think about it as much. And in general, that's a rule I like to follow.

Okay, let's run our test. Are we still good? Yes. All right, so I'm returning here, and then I have an else where I flash and return again. Now, I think there are situations where even, well, let's put it this way. I can get rid of this else because I'm already returning here, which means this is effectively our else statement. So I will often do this. But having said that, there are situations where I do think the if-else combo makes it very clear.

But having said that, there are situations where I do think the if-else combo makes it very clear. If some condition is true, I want to do this thing. Otherwise, I want to do that thing. It does help with readability sometimes. So this is more of a context thing that you have to judge for each case. All right, that being said, I like this approach. No need for an else here. Here, we are redirecting to the home page. Again, nothing wrong there whatsoever.

Here, we are redirecting to the home page. Again, nothing wrong there whatsoever. However, there's also a home helper function. So again, this is an example of making sure you really understand what the framework provides you. You may not have even known that there's a home helper function, but there is. All you have to do is, in your routes file, just make sure you provide a name to whatever route should be considered the home route. All right, I run my tests. I'm still okay.

All right, I run my tests. I'm still okay. What else can we do here? Well, already, I think it's looking a little more succinct. And we didn't do anything drastic. We only focused on the small little things. A little bit of indentation there, or an inline variable here, or embracing what the framework offers here and here. These things do, in fact, make a difference. Now, in my case, I kind of like doc blocks.

These things do, in fact, make a difference. Now, in my case, I kind of like doc blocks. It actually goes against some of my sensibilities. But I like the fact that the doc blocks for your methods, they do help with general documentation, especially if you're not applying types religiously, they help with that. But I think even more than that, they help just to give a bit of breathing room between your methods. So we'll say here, submit a new support request. And yeah, it's true, sometimes the doc blocks feel absurdly redundant,

So we'll say here, submit a new support request. And yeah, it's true, sometimes the doc blocks feel absurdly redundant, where you're repeating exactly what the method says. But that's not always the case, but I won't beat you up either way here. I fully get the arguments on both sides there. So that's a preference thing. Okay, what else? Some things to consider. When you call request->validate, did you know that it's going to return the validated attributes?

When you call request()->validate(), did you know that it's going to return the validated attributes? So for example, if we were to dd() that, and if I run it, you'll see I do get an array of all the validated attributes. Okay, so that means if you want, here's what we could do. Let's do this. Let's change this to attributes. And then here, you could reference them. attributes, email, and attributes, question. Run the test again, and we still get green.

FormRequest Extraction Criteria11:14

It's fine if you want, but I don't think it's necessarily better. So I'd rather not create the temporary variable and instead stick with this. Okay, so I think we're about done. Now for those of you watching, some of you might think, well, this should be extracted to a FormRequest class. I disagree. Now remember, the end goal isn't exclusively to make this controller method as small as possible. Now often it's the case, the more you can remove unnecessary variables or

method as small as possible. Now often it's the case, the more you can remove unnecessary variables or lines or indentation, I think that does improve readability. But if you're just taking code like this and moving it to another file, are you really improving the code? Or have you instead just split up the method between multiple files? So again, this is a case by case issue. Now my metric for whether to extract validation like this to a FormRequest class is often, it often comes down to how complex is it? If I had all these different attributes from the form, yeah,

a FormRequest class is often, it often comes down to how complex is it? If I had all these different attributes from the form, yeah, there is a point where it's like, this is gross. I'm gonna get this into a FormRequest. But otherwise, what I have here, it's simple enough. And six months from now, when I come back to the controller, if I need to make a tweak, it's really easy to take in. So I would personally not refactor to a FormRequest, unless I really felt that it improved the code. But yeah, once again, using that en passant comparison,

unless I really felt that it improved the code. But yeah, once again, using that en passant comparison, don't do it just because you can, do it because it improves the code. All right, and I think we're gonna call it a day there. So what we ended up with is still very simple. We just focused on small tweaks. Like if you wanted to be explicit about the request, you could do this, and then call request validate. And then here, this would be request email and request, what was it, question? And then finally, reference this.

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