Adding Authorization Check1:27
So this is where authorization comes into play. Let's see how. Let's go into note.php, and yeah, remember, this is the controller that handles displaying this particular page. And yeah, we can see right here, we are grabbing the note that has an ID that matches the one that's currently in the query string, as we see right there. So yeah, not a lick of authorization in place. All right, so we have a few ways that we might deal with this. Your first thought might be to simply update your SQL query, like this. SELECT * FROM notes WHERE user_id = current_user.id AND id = ?
Your first thought might be to simply update your SQL query, like this. SELECT * from notes where the user_id matches the currentUser, and the id matches the one that's in the query string. Okay, so now if I were to clean this up real quick, we could pass them through. User is, and I'm going to just hard code it for now, because remember, we haven't yet reviewed authentication, but I promise we'll cover that in this series. At the moment though, we're just going to assume that the user with an id of one is the currently authenticated user, until we learn more. Okay, so let's give this a shot. If we come back and give it a refresh, I think it's going to change.
Handling Missing Notes2:49
A boolean, true or false. So it looks like we have a value that's a boolean, could be true, could be false, but we're trying to interact with that value as if it were an array. And why would that be? Well, let's inspect it. We'll come back to phpStorm, and I will pass note to our dd function, and we'll inspect it. Give it a refresh, and sure enough, it's false. So now that makes perfect sense. We load the view, and we are interacting with false as if it were an array, and that's why
So now that makes perfect sense. We load the view, and we are interacting with false as if it were an array, and that's why we get that error or that warning. Okay, so why is note equal to false? Well, it makes perfect sense. We didn't get anything from the database. Let's try a different record. We'll come back. Here's the id of 7, and that note was created by the currentUser, so we return the appropriate record.
Here's the id of 7, and that note was created by the current user, so we return the appropriate record. Okay, so this seems to be working, but how do we deal with situations like this, where false is returned? Well, we could do something like this. We could say, well, if there is not a note, then there was some kind of issue, right? So we can call our abort function and be done. So let's give it a shot. We come back to Firefox, give it a refresh, and yeah, it works, so I guess that's good, but it doesn't work in the way I would like, and here's what I mean.
Distinguishing 404 vs 4034:32
not found. But another reason might be due to this little section that we added here. All right, so imagine, yes, a corresponding note exists in the database, but you did not create it. Okay, so that's a very different thing. In the first example, we display a 404 because a note was not found. That makes sense. But in the second example, that's an authorization issue. Yes, the note exists, so it was found, but you are not authorized to view it. All right, so we can see that there's two different reasons why we might want to abort,
Yes, the note exists, so it was found, but you are not authorized to view it. All right, so we can see that there's two different reasons why we might want to abort, and when we have these two different reasons, it might be useful to provide a hint or a status code that indicates what the problem is. Okay, so let's do this. Let's get rid of this check here. Bring it back to a simple findNote with a corresponding id. Then we can say, well, if there's not a note, abort. We want to display a 404. But then let's add another one.
We want to display a 404. But then let's add another one. We might say, well, if the note's user_id does not equal 1, well, then you're trying to access a note that was created by someone else. So we would abort in that case. But again, the 404 status code isn't quite right. Remember, a status code of 404 means page not found. But as we just discussed, in this particular example, that's not appropriate. Instead, I need some way to signal that, well, it was found, but you are not authorized to see it.
Instead, I need some way to signal that, well, it was found, but you are not authorized to see it. And as it turns out, that corresponding status code is 403, a 403 Forbidden. Okay, so now we've separated the two different reasons why we might not be able to access this particular note. So let's go back to Firefox, give it a refresh, and we get Uncaught PDOException invalid parameter. Oh, yeah, I'm sorry. We removed the $user parameter, but I forgot to remove the binding as well. All right, so come back, give it a refresh, and there we go.
We removed the user parameter, but I forgot to remove the binding as well. All right, so come back, give it a refresh, and there we go. So notice in this example, we are trying to access some fictional Note that does not exist in the database. So we get a 404 page not found. But this time, let's change it back to two, which is a Note that was created by someone else. Okay, and you can see right here, it's trying to load our 403 view. So it seems like everything is working. We just need to create a corresponding view for that particular status code.
Creating the 403 View6:51
So it seems like everything is working. We just need to create a corresponding view for that particular status code. So I'm going to copy 404. I renamed it to 403, and I'll update the heading to Unauthorized. Okay, so come back, give that a refresh, and there we go. And in fact, if you want to be crystal clear here, you could say you are not authorized to view this page, just to make it crystal clear to the user. So switch back to notes, I see my notes. I can view a note. But yeah, if I try to tweak it to a note that I do not have access to, I'm going to see
Reducing Magic Numbers7:55
So yeah, in this case, one. What does that mean? What is the significance of one? Well, we know the answer to that question right now. We haven't yet reviewed sessions and authentication. So I'm hard coding that one to signify or to represent the current user, right? But yeah, imagine six months from now, you might forget what that one refers to. And this happens all the time, by the way. You're looking at code and you think, well, what does that mean? What is the meaning of that number?
You're looking at code and you think, well, what does that mean? What is the meaning of that number? What does it refer to? Why is it important? And yeah, even if its meaning might seem obvious to you at the time, it could be that a year later or multiple years later, if this is a long running application, it may not be so obvious. So one option would be to extract that to a variable. Let's just assign a name. I could say currentUserId equals 1.
Let's just assign a name. I could say currentUserId equals 1. And now I can substitute it here. Yeah, it's just a small tweak. And actually, notice how we're breaking that guideline from an episode or two ago, where we noticed that we only declared a variable once, so we inlined it, right? But there's also situations where even though it's only being declared once, it still serves a purpose. It serves the purpose of identifying what the value is. It provides more clarity as to what the value is.
It serves the purpose of identifying what the value is. It provides more clarity as to what the value is. And that's what we're going to do here. All right, next, 403. This is another good example. You'll definitely get to a point in your career where you see the number 404 or 403. It's attached or related to a response of some kind, and you instantly know what it is. Oh, 404 not found, or 403 forbidden, it makes perfect sense. But it still doesn't change the fact that it is kind of a magic number.
How can I make this more clear? How can I remove the need for a comment? This is what so much of programming is. So how could we do this? Well, I could do the same thing as what we did up here. I could say forbidden equals 403. And yeah, I mean, that would work. But in this particular example, I actually don't like this approach. And the reason is because, well, I might want to abort with a 403 all over the place. So yeah, would I just have to assign it to a variable every single time?
Introducing Response Constants10:45
And that's not true. If you want to create another file, you know how you do it? You just create another file, and then you keep going. I know it sounds simple, but trust me, that is often a roadblock for newcomers. So in this case, why don't we create a class to represent this response? I'm going to call it response.php. We'll make it a class. And you learned about constants a number of episodes ago. So why don't we create constants for each of the common status codes that we might want to return?
So why don't we create constants for each of the common status codes that we might want to return? So we'll start with the 404. What does that mean? Not found. So we'll call it notFound equals 404. Let's do another one for forbidden. forbidden equals 403. OK, so now check this out. If I come back into our note, if I want, yeah, I can bring this back to what we had before.
If you decide, no, everybody knows what a 403 means, then keep it, right? It's all give and take. You decide what's appropriate and what needs to be clarified a bit more. OK, but anyways, if we instead require our new little Response class, I can now reference it within our note like this, abort with a response of forbidden. OK, so notice it's a small little change, but it does improve readability. And all of programming is making small little changes that improves readability and functionality. So think about it. Before, we were saying abort with this magic number 403 that you are supposed to know what it means.
Before, we were saying abort with this magic number 403 that you are supposed to know what it means. But after, we're saying abort with a response of forbidden. We're just tweaking the clarity that much. And I think that's a pretty good refactor. OK, so a little cleanup like that. And yeah, here is our NoteController as it currently sits. Still lots of room for improvement, but I think we're making pretty good progress. OK, so to wrap up, we try to track down the note that has an ID that matches the one in the query string.
OK, so to wrap up, we try to track down the Note that has an ID that matches the one in the query string. But if we couldn't find any matching note from the database, of course, we abort. 404, page not found. I don't know what you want here. Otherwise, if there is a corresponding note, then we continue on and we do a second check. Well, was this note created by the currentUser? And if it was not, well, then once again, we should abort with a response of forbidden. Otherwise, if a note exists in the database and it was created by the currentUser, only at that point do we continue on where we load the view and we display the details of that.
Otherwise, if a note exists in the database and it was created by the current user, only at that point do we continue on where we load the view and we display the details of that corresponding note. All right, let's do our final test in Firefox and we will be done for the day. So let's review. How about this one here? This note was created by me, so I see it. No problem. Next, though, the note with an ID of two was not created by me, so I get an unauthorized. And then finally, if I do some kind of ID that doesn't exist in the database, then I
Next, though, the note with an ID of 2 was not created by me, so I get an unauthorized. And then finally, if I do some kind of ID that doesn't exist in the database, then I get a 404 not found. OK, everything seems to be working and we've solved that pesky authorization issue. I'll see you in the next episode. There's much more to cover.
