Refactoring for clarity0:50
if I needed to? Or if I handed this code or I showed this code to Joe or Sarah over here, would they understand my intentions? And then, of course, there's also a really nice element of creativity. Does this reflect my creativity? Do I want to code it this way? Or do I want to code it that way? And sometimes one is not necessarily better than the other. It comes down to your approach and how you want to communicate some of these concepts to your future self and, of course, others who might be on your team. Okay. So, with that in mind, let's return to one of our controllers. I will go into controllers, sessions, and store. Okay. So, this is the code that we wrote in the previous episode. And it handles the process of validating the form and then attempting all of this. It's not very clear. But if I break it down, we are attempting to log the user in and redirect them. And
out loud, even if I'm by myself in my office, as I am right now, I say it out loud. So, what does this code do? Well, it handles validation for a login form. Login form. Hmm. Why don't we create a class called LoginForm that can be responsible for handling validation? All right. Let's give that a shot. Now, the next question I have is where do I put this? Where do I put a LoginForm class? Does it go in controllers? Well, no, it's not a controller. Does it go in core? Well, I guess it could. But here's what I'm noticing. The core directory is almost like for the core of my application. The sort of functionality that ideally I could reuse across all of my projects. Or, in other words, these core files are not necessarily maybe excluding functions, which we should extract. But, yeah, otherwise, this core functionality isn't necessarily unique to this particular application. It's like infrastructure code,
maybe excluding functions, which we should extract. But, yeah, otherwise, this core functionality isn't necessarily unique to this particular application. It's like infrastructure code, validation, routing, interacting with a database, having a container, you know, things like that. So, if I were to put, you know, for example, a forms directory in here, well, those form classes are very much unique to this one application. And it just feels a little bit off. Right? So with that in mind, hmm, maybe once again we should restructure things. And, yeah, this is if you're annoyed by this, if you're thinking he keeps changing it, I'm doing it on purpose because this is the reality of programming. You try it this way, and then you think, yeah, that's not right. Why don't we change it? Why don't we move this over here? Maybe it would make more sense if this was not part of that, but instead part of this. This is the reality and the practice of being a programmer. So with that in mind,
Restructuring into HTTP4:04
Why don't we change it? Why don't we move this over here? Maybe it would make more sense if this was not part of that, but instead part of this. This is the reality and the practice of being a programmer. So with that in mind, why don't we store anything related to our application within this HTTP directory? This is the HTTP entry point into our application. So from that perspective, things like forms make perfect sense. But then further, even things like our controllers could go in there as well. So why don't I move that like so? But of course, you can't just do that. So if I try to load this in the browser, of course, it immediately fails. We get a warning. Oh, I tried to find this controller, but it was nowhere to be found. Okay, let's just take a quick moment and see if we can fix that. First up, I will go into my routes file. And yeah, right now we are providing a full path to the controllers directory. But you know what? Do I need like notice every single route controller is within this directory. So maybe I can have a convention.
Updating router conventions4:57
And yeah, right now we are providing a full path to the controllers directory. But you know what? Do I need like notice every single route controller is within this directory. So maybe I can have a convention that all controllers just go in that controllers directory, we don't need to be explicit. So with that in mind, I'm going to use multiple cursors to select every instance of that string and remove it. Now we just have something like this, when you visit the homepage, load this controller, and our application just knows where to find that controller. Okay, but of course, it's still not going to work. So if I come back, well, same problem, we're trying to find it in the root of your project, but it wasn't there. And of course, that is correct. Okay, let's go into my router. And then right here is where we require the corresponding controller. So this is a little bit app specific, maybe, but I think it's fine. So why don't we go into the base path into that new HTTP folder, and the controllers and then try to find the corresponding controller. So yeah, if I come back into routes, you
bit app specific, maybe, but I think it's fine. So why don't we go into the base path into that new HTTP folder, and the controllers and then try to find the corresponding controller. So yeah, if I come back into routes, you can see, if we have about that php, the router is actually if I switch back, going to look in HTTP controllers about that php. Okay, so cross our fingers, does it work, please? It doesn't work. Let's see what the problem is. What did I do wrong? In the root HTTP controllers, no such file or directory. All right, let's figure it out. So we have Oh, I'm sorry, you saw me do this controllers goes in HTTP. Just to disc. All right, come back, give it a refresh. And there we go. Good. That was close call, but we got it working. Okay. So that makes me feel a little better. Now I have a dedicated place. And I've separated things that are unique to my application. I've separated that from core infrastructure framework II code, which I like, I think, I think that's a good way to go. All right. So now let's create our first form. And you'll remember I said, we want a form class to handle a login form
Creating LoginForm class6:52
that from core infrastructure framework II code, which I like, I think that I think that's a good way to go. All right. So now let's create our first form. And you'll remember I said, we want a Form class to handle a login form and validation and everything that goes along with that. So why don't we say LoginForm? Keep it simple. Okay, but now I think my namespace is incorrect. This should actually be Http\Forms\ LoginForm. Okay. So next, I said, it's going to handle validation. So why don't we have a method like validate? And yeah, let's just see how we might interact with this. If I go back into Session::store, yeah, this is all the code that sort of needs to move there. So why don't we just, well, let's comment it out for now. And let's see, instead, we would instantiate LoginForm, and that gets imported at the top, just to make sure we are clear. So we'll have our form. And then we want to call form->validate() on it. But immediately, as I write this, I can see, well, I need to provide the attributes, right. So I could either provide an array of attributes, or I could pass them in individually. And we just have to decide what approach
validate on it. But immediately, as I write this, I can see, well, I need to provide the attributes, right. So I could either provide an array of attributes, or I could pass them in individually. And we just have to decide what approach do we want to take. I think I would probably do some kind of attributes thing. But for now, just to keep it as one to one as possible, why don't we pass them in individually like this email, password. Okay, so I'm just going to go back and forth. This is the refactoring process, introduce something new, try to interact with it, go back and forth. This accepts the email, and excuse me, and the password. And then I switch back. All right, what next? Well, that code would then need to run most of this. All right, I'll just paste it in, uncomment, reformat, import any missing classes. All right, how's this looking? We call validate, and then we run validation. But then right here, notice, this login form is going to return a view. And maybe you're okay with that. But this is where we get into discussions around, well, what is the responsibility of this class? Maybe this particular class should not be responsible for doing that particular thing, or
Defining validation responsibilities8:58
going to return a view. And maybe you're okay with that. But this is where we get into discussions around, well, what is the responsibility of this class? Maybe this particular class should not be responsible for doing that particular thing, or maybe it should. And again, this is where it comes back to creativity. What allows for the most flexibility, there's a number of decisions that go into or a number of considerations that go into even simple decisions like this. So in my mind, I'm not sure I want a validate method on a form class to load a view. I don't think that's quite right. So I'm going to get rid of it. And instead, I just want it to be simple. It's going to validate given attributes, and then return errors maybe. But really, if I come back, excuse me, let's go into our controller. I almost feel like form validate should just return a Boolean. Did it validate or did it not? But right now, it's just returning an array that could be populated or could be not. So instead, why don't we just return whether or not the array is empty. So if it's empty, it validated, right? Because there are no validation errors. It's empty. If it's not empty, then that would be falsy, of course, of course, or false, which
Exposing errors via getter10:03
not. So instead, why don't we just return whether or not the array is empty. So if it's empty, it validated, right? Because there are no validation errors. It's empty. If it's not empty, then that would be falsy, of course, of course, or false, which means the form did not validate. Okay, I like that. So now I could say, well, if the form did not validate, then this is where this code could go. So I will paste that in and uncomment. If the form did not validate, let's return that login form and pass through the errors. But now, where are the errors? Well, of course, they are locked inside of this validate method. Okay, so what if instead, we have a property called errors, something like this. And then I can get rid of this and simply write to that property like so. Okay, well, notice I've made this protected, and we've talked a little bit about visibility, right? This means, well, this property is protected from the outside world. They don't need to interact with it. But often, they do need to at least access it. So in this case, it'd be nice if I could grab the errors from the outside. A couple options are to make this public and just say, yeah, if you need it, fine. Some people would squawk at that because they'd say, well, then
need to at least access it. So in this case, it'd be nice if I could grab the errors from the outside. A couple options are to make this public and just say, yeah, if you need it, fine. Some people would squawk at that because they'd say, well, then from the outside, you could manipulate errors into a state or configuration that isn't quite right. There's lots of reasons to consider making it protected, and then adding what's known as a getter. And that getter is just a method that gets something. Return $this->errors. But now, it's almost like I have a hook by calling this method. I have a hook to potentially change things. Maybe other things need to be involved before I return the errors. And now I have a place to do that versus interacting with that property directly. But as always, it just sort of depends. Okay. So now that I have an errors method, I can just say, $formErrors. If the form did not validate, then return that loginForm and pass through the errors. Notice how this is adding more clarity versus what we had before, where this is very procedural. I'm building up an array, and then I'm writing to that array, and I'm doing all of these validation-specific checks. Overall, though, that condenses to
