So we need to do all the steps from this list that I have created here inside our router PHP file.
Let's begin by normalizing the URI.
And as I write this function, I'm going to explain what does it exactly means and what needs to be
done.
So let's create a function that we're gonna call normalize URI.
It accepts the URI as a parameter and it returns a string.
So the URI let's make some changes to it.
First I'd like to make it lowercase as our files our route handlers.
They're also going to be lowercase.
So to be able to find a file we need to care about the character case.
Because on Unix systems the character case in file names matter.
Next up I'd like to use trim to remove all the white spaces from the URI and also remove some additional
characters, which would be slashes.
We want to get rid of those completely.
Next up, we've got this URI and we're going to return a value.
But there is one special case that we need to think of.
If the URI is empty, this means we are on the main page.
That's why we need to look for a route handler that will be called index.
Otherwise we just return the URI.
Now it's time to see this in action.
So let's move to the dispatch function.
And we are implementing the first step.
So the URI is the result of calling the normalize URI function we've just defined on the URI that is
passed to this function.
Now at this point it would be useful to see what that actually is.
For that I'm going to just do var dump with uri and die.
So we stop this function and we see what is the effect.
Now this dispatch function it needs to be called inside the index, the front controller.
So let's call dispatch.
And what do we pass in here.
Well we can get something from our server super global that we already know.
And this is simply the request URI.
That would be our URI.
And the method we also get from the node server.
But server super global.
And that is on the other hand called request method.
That's everything that we need to do in here.
The next thing to do is to start the server.
So let's make sure that we jump into the public folder and we start the server from there.
So I run php dash s localhost 8000 and the file name is index php.
Now we should have the server running.
And let's now head to localhost 8000 to see what's the output.
So now I have magically moved into the browser, and when I just type localhost 8000, the result is
index.
Let me try with slash contact.
So you see that this works fine for the guestbook.
It should also work fine.
So we are getting the route handler name without the method attached.
We're going to be working on this a little bit later, but we can see that our edge case is also working
fine.
By the way, you might have probably noticed that I have the documentation for the stream function open,
and I'm not ashamed of that.
I don't remember the names and order of every function parameters.
That's why I make sure that I have the documentation open on every single project, language, or framework
that I work with, and I suggest you do the same.
Okay, so let's enlarge the working space, the code editor again and then jump to router.
PHP file.
So we've got this first step handled.
I can comment out this line.
By the way, this combination of VAR dumping and dying is a common practice in PHP.
I use it for debugging all the time.
We might as well extract it to a function.
That's for later.
Now we need to handle the second point.
The only allowed HTTP methods that we allow is get or post.
So another good practice that I'd like to introduce is to not hide the magic values inside functions.
So we've got two examples right now this get and post method.
Those are the ones that we handle.
We should not hide this detail inside the dispatch function, because this might be an interesting knowledge
that might be used across the whole project.
That's why we should go with a constant.
So we should define that the allowed methods is get and post.
Now this can be accessed in different places.
Another thing that we should be extracting into constants is maybe the index URI.
This is an empty string.
This might look trivial, but believe me, this is really a good practice.
Now I'm not comparing that to an empty string, and I can configure the behavior of the project without
changing the implementation of the functions.
I can also do index route to say that if we are looking at this main page without any specific URI,
the route name is index.
I can use this constant right here.
This would be index route.
So now every single time you go back to this file or any other developer on your team.
They don't have to scan the implementation of every single function and try to understand what is happening.
And it might feel a lot safer to just change one of those values, to change the behavior of the app,
instead of changing it directly inside the function.
So this is a very good practice.
Now let's jump to this second step.
Let's make sure that we only handle specific HTTP methods.
So we're going to add an if statement and use an in array function to check if the method that was passed
here is one of the allowed methods.
Now if it's not, we should return a 404 response that can be summarized as a not found response.
Now also, we need to normalize the method.
So the method variable, well let's convert it to uppercase.
On the other hand, because this is how we have defined those methods inside this constant like this.
So let's go back into this if statement and let's call a non-existing Notfound function.
So we need to add this function because this is something that might really be reusable across the whole
application.
So by calling this function it immediately returns the response from PHP.
It stops the execution and it returns an HTTP response code that is specific to this case.
404 means that the page wasn't found.
Next we can echo 404 not found and the exit statement will stop the execution of the script.
So you might be wondering how do I test that?
If we have the allowed methods as get and post and get is the default method of the browser.
When you just go to a website and post is the method that you typically use with forms.
Well, it's easy to test that we can temporarily remove the get from allowed methods.
And now you can see that this was working fine.
And if I now go to the main page we've got 404 not found.
So this was just a temporary measure to try this out to test the functionality.
It worked fine.
Let's bring back the get method from the allowed methods.
And when I refresh the page we don't see anything, which actually is a good sign.
It means that this dispatch function went to the very end and it didn't stop at this point.
So the next step is to figure out what is the actual file name for that, let's define a function that
will be called Getfile path.
Now this function might be super simple.
It depends on our requirements.
Now, if I pass the URI to it and the method, I expect to have a string returned, that would be the
full path to the PHP file that can match the route.
So let's jump to the index file because I think we need another constant.
We've got the includes directory.
Now let's also have the routes directory in a constant that we can use everywhere.
And we're gonna have a new folder called routes.
Let's create this folder now.
So this is routes.
This would contain all the routes that we define.
Let's go back to router.
Now I think that here we can just return a value.
This would be the routes directory If I remember the constant name properly, then a directory separator,
then I think that we can directly translate the URI into the pathname, but we might normalize it first.
So let's do normalize URI to just make sure it's matching the case of the path names.
So this is this.
Next up we should append the method after an underscore.
So first we are we are adding the underscore.
Next up I'm concatenating the method which by the way I might have to lowercase.
So I do str two lower because all of our path names and file names should be in lower case.
And finally I concatenate the extension the PHP.
Now let's just see if this works.
If this is fine, I'm gonna var dump the.
What's the function name?
Get file path okay.
Get file path.
Passing the URI and method that we already have here and calling die to stop the execution.
Let me refresh the page.
Now this looks fine.
I really expect to have this directory and I expect to have this file inside once I create it.
Of course.
And this also works on windows.
If I refresh this script and zoom out a little bit, even though we've got a mixture of slashes and
forward slashes, they both work on windows, so you should be fine on windows as well.
Now the next step should be to create a file and see if it really works, if we can really load a specific
PHP file.
Okay, now let me open the files.
And here let's create the contact get PHP.
One file is more than enough.
It can do echo.
Hello something super simple.
Now let's jump back to the router.
And at this point we should just check if this file exists.
So let me remove the var dump and just leave this fragment and assign it to the file path variable.
And next up we're going to do a check using file exists function from PHP.
We're going to check if this file exists because if it does I'm just going to use include And I'm going
to include this file so it can run and I can return to.
Just make sure we stop at this point because if this file won't be found.
I run the not found which would display a 404 not found page.
Okay, it's time for a final test.
So let me go to this URL and as expected, I see the text.
Hello.
Let's also verify that on windows.
And if I go to main page well this was expected.
The index file is not created.
But if I jump to contact page I see the same text.
Hello.
All right so we've created a working router.
So our next steps should be to start implementing some specific logic.
Some specific pages of this application.