WEBVTT

00:00.560 --> 00:01.280
Right guys?

00:01.280 --> 00:07.670
So next up I'd like to introduce a super interesting concept that is called Middlewares.

00:08.120 --> 00:16.940
That's something that you are going to find in every single HTTP framework, not only in PHP frameworks

00:16.940 --> 00:21.890
like Laravel, but also in Node.js, Python, Ruby, everywhere.

00:21.980 --> 00:23.630
So what is middleware?

00:23.660 --> 00:28.730
So let's take a look at those two example diagrams.

00:28.730 --> 00:30.410
First is how it works.

00:30.410 --> 00:32.210
So you need a router.

00:32.210 --> 00:34.100
We have a router class right here.

00:34.100 --> 00:41.690
And the concept of Middlewares is that you would like to run some code in the middle.

00:41.690 --> 00:45.680
So before you run the route code and that's everything.

00:45.710 --> 00:49.670
And you'd like to have a couple of those middlewares.

00:49.670 --> 00:56.030
And every single one of them does some specific job, has some specific responsibility.

01:00.410 --> 01:08.690
And the way it is constructed is that the Middlewares they call the next middleware in line.

01:09.110 --> 01:14.960
So it's about how the middleware should be implemented in the router.

01:15.710 --> 01:23.030
So it is implemented the way that you're going to add the middlewares to run before a route.

01:23.060 --> 01:27.740
And it is a responsibility of the middleware to call the next one.

01:27.770 --> 01:32.210
Now not always the middleware calls the next one.

01:32.210 --> 01:34.340
It can break the chain.

01:34.340 --> 01:36.530
That's another feature of middleware.

01:36.680 --> 01:42.320
And let me just come up with an example of what you can use Middlewares for.

01:42.350 --> 01:50.570
So in our case we can have two obvious use cases that would be checking if the user is authenticated

01:50.570 --> 01:55.340
and the other one is sharing the user object with all the views.

01:56.540 --> 01:59.480
So let me jump into our front controller.

01:59.510 --> 02:07.940
That's one of the obvious use Cases that can be a middleware that runs always, that just shares the

02:07.940 --> 02:14.960
currently authenticated user whether he is logged in or not with the views, so that we just don't run

02:14.960 --> 02:16.910
this code in the front controller.

02:16.940 --> 02:25.250
But another middleware can be an auth middleware, and this can be applied conditionally on specific

02:25.250 --> 02:26.240
routes.

02:26.270 --> 02:32.900
That's another concept that we can have global middleware that needs to run at all times.

02:32.900 --> 02:41.570
And sometimes we might have specific route specific middleware like auth that will basically require

02:41.570 --> 02:43.340
the user to be authenticated.

02:43.340 --> 02:52.460
If he is not, the middleware will break the chain by, for example, redirecting to a for one page.

02:53.060 --> 02:55.610
Now currently we just do it manually.

02:55.610 --> 03:04.290
Like in this command controller we're getting the user, and if the user is not signed in, we redirect

03:04.290 --> 03:09.540
to unauthorized page and this can be done by middleware.

03:09.540 --> 03:12.150
It will just simplify our logic.

03:12.180 --> 03:15.180
Another case is CSRF tokens.

03:15.390 --> 03:20.700
I think this should be automated for our app to be secure.

03:20.790 --> 03:31.110
So every single time we encounter a request that's different than Get head or options, we should just

03:31.110 --> 03:32.700
check the CSRF token.

03:32.730 --> 03:42.450
So if you would forget to generate the token in the form like in here, then you will just know what's

03:42.450 --> 03:50.340
the problem, because the middleware will just take care of making sure the token is generated and verified.

03:51.990 --> 03:59.850
Okay, so after this introduction, let's just jump right ahead into implementing the middleware so

03:59.850 --> 04:06.390
you can see what's the best way to approach this, and then in the next videos we're going to be adding

04:06.390 --> 04:07.350
some middleware.

04:07.350 --> 04:14.640
For example, for the CSRF tokens, authentication, sharing user and all the future useful appliances

04:14.640 --> 04:15.540
of middleware.

04:16.590 --> 04:20.580
Let's jump to implementing the middleware logic.

04:22.770 --> 04:28.770
Okay, so let's try to implement the middleware starting with an interface as the first time we are

04:28.770 --> 04:34.890
using an interface, and we are using it because we would like to enforce the same structure on every

04:34.890 --> 04:42.660
single middleware, as it is important that every single middleware accepts the next one to call.

04:43.230 --> 04:45.360
Let me create this interface.

04:45.360 --> 04:49.320
Maybe things will become much more clear as we go.

04:50.310 --> 04:53.220
I'm just going to call this file middleware PHP.

04:53.250 --> 04:59.520
Let me zoom in a little bit and it's going to have a namespace that's just call.

04:59.820 --> 05:05.370
And I'm creating an interface called middleware.

05:05.370 --> 05:14.520
It's simple because it only has one public method called handle, and it accepts an argument of type

05:14.520 --> 05:16.320
callable that is.

05:16.320 --> 05:17.160
Next.

05:17.190 --> 05:22.890
Essentially what this means is this should be the next thing to call.

05:23.040 --> 05:27.030
And if you look at this diagram, this is actually super simple.

05:27.030 --> 05:31.410
The first middleware should call the next one that is registered.

05:31.680 --> 05:38.160
And the second middleware, if we have only two, should actually call the root code.

05:38.190 --> 05:48.750
So what will change in our router is instead of just calling the root like we do right here explicitly,

05:48.780 --> 05:51.000
we're going to be calling the middleware first.

05:51.000 --> 05:55.410
And that's the job of the middleware to eventually call the root.

05:57.300 --> 06:02.970
If this sounds complicated, I'm sure it won't look complicated once we have some examples.

06:02.970 --> 06:05.790
So then you just need to bear with me.

06:07.020 --> 06:07.440
Okay, guys.

06:07.440 --> 06:12.150
So now let me jump to the router and let's make some changes here.

06:12.240 --> 06:18.510
We've got an array with routes, and now we need to also keep the middleware someplace.

06:18.510 --> 06:32.220
And as I said I like the global middleware and also the route middleware which is applied per route.

06:34.020 --> 06:37.230
Both are associative arrays or maybe not.

06:37.260 --> 06:40.800
The global middleware would just be an array of middlewares.

06:41.250 --> 06:48.510
And the changes we'd like to make is to this add method that adds a route.

06:48.510 --> 06:56.280
We're going to have another parameter which is an array, and it would just be called Middlewares.

06:56.520 --> 07:04.740
This is Middlewares that's initialize with an empty array and to every route.

07:06.610 --> 07:07.960
We're going to add this.

07:07.960 --> 07:13.900
So we just know what middleware should be applied to a route.

07:15.130 --> 07:22.930
Now we should add some methods that will just allow us to add those middlewares first to add the global

07:22.930 --> 07:23.680
ones.

07:25.690 --> 07:31.690
So the argument here would be a string y a string because this would be the class name.

07:31.900 --> 07:38.860
So currently in the first implementation of Middlewares, we would be responsible inside this router

07:38.860 --> 07:42.640
class to create an instance of such middleware.

07:44.110 --> 07:46.030
This is void doesn't return anything.

07:46.030 --> 07:48.220
And well it's quite simple.

07:48.220 --> 07:55.000
We've got this global middleware field to which we add a middleware.

07:55.420 --> 08:03.460
Next up let me add another one called Add Route middleware.

08:03.820 --> 08:06.820
So this would have two parts.

08:07.150 --> 08:11.980
There would be a name, a short name of the middleware.

08:11.980 --> 08:15.580
So we don't have to use the class name every single time.

08:15.580 --> 08:18.220
And also the actual class.

08:19.240 --> 08:28.420
And in this case, inside the root middleware we're going to be adding an entry using specific key.

08:28.450 --> 08:29.620
That's a name.

08:29.620 --> 08:34.810
And to this we're going to add the class name of the middleware.

08:35.170 --> 08:35.500
Okay.

08:35.530 --> 08:40.930
So this was all very theoretical I'm aware of that.

08:41.050 --> 08:45.850
Now it's time that we jump to the dispatch method.

08:45.850 --> 08:54.370
And we can see how we should be getting all the middleware that should be run and how do we execute

08:54.370 --> 08:56.200
it all together.

08:59.680 --> 09:00.010
Okay.

09:00.010 --> 09:08.200
So before we run a specific action, we need to collect all the middlewares that we should be running.

09:08.230 --> 09:12.850
So we have to mix the global and the route specific one.

09:13.060 --> 09:16.270
So at this point we already have a found route.

09:16.300 --> 09:21.160
This means it might have some specific middleware that it needs to run.

09:21.580 --> 09:28.180
Let me just use this unpacking operator and just grab the global middleware.

09:28.210 --> 09:32.020
First it should run as the first middleware.

09:33.490 --> 09:46.180
And then let me use array map to map all the shortcut names of all the route specific middleware into

09:46.180 --> 09:47.800
the actual class names.

09:47.980 --> 09:54.790
That's why I'm going to start with the second argument, which is the route specific middleware.

09:54.790 --> 10:00.700
If I'm right, we've used the yeah, we've used the Middlewares key.

10:00.700 --> 10:02.230
So I wasn't right.

10:02.260 --> 10:03.280
That's middleware.

10:03.430 --> 10:10.810
And let me move that into a separate line like this.

10:10.840 --> 10:11.170
Okay.

10:11.200 --> 10:20.380
And here I'd like the arrow function that would convert the name of a middleware into the actual class

10:20.380 --> 10:21.130
name.

10:22.510 --> 10:24.850
This would be this route.

10:24.880 --> 10:25.690
Middleware.

10:25.720 --> 10:31.270
That's the field that just contains the names or maps.

10:31.300 --> 10:37.750
The shortcut middleware names to the actual class name like that.

10:37.750 --> 10:45.640
So maybe to illustrate what I mean with this mapping, I'd like to be able to do it like this.

10:45.640 --> 10:48.310
I'd like to use the auth middleware.

10:48.430 --> 10:49.810
That's the shortcut name.

10:49.810 --> 10:54.700
And it would mean let's see what can we have.

10:54.730 --> 10:57.910
Um maybe up middle.

10:58.060 --> 11:02.830
Where's auth middleware.

11:04.450 --> 11:11.540
So I would like to create a mapping that would allow me to use this short names that maps to full name

11:11.570 --> 11:18.770
space, and when I add routes, I can just use this shortcut name for convenience, especially if I

11:18.770 --> 11:22.940
need to apply multiple middlewares per route.

11:25.610 --> 11:31.130
Okay, so next up we need to add a function that will just run all the middleware.

11:31.340 --> 11:36.980
And if we think about it, we just need a function that will just run all the steps.

11:37.010 --> 11:42.830
As we take a look at this example, we just need to run first middleware, second middleware, and then

11:42.830 --> 11:44.150
the actual route.

11:44.150 --> 11:47.930
So we need a method that will do this.

11:47.930 --> 11:55.310
Let me call this protected function called run middleware.

11:56.900 --> 12:02.030
It will get an array of all the middlewares.

12:02.030 --> 12:09.290
And finally it gets the callable which is the target the final action to run.

12:11.390 --> 12:15.020
And it can return a mixed value.

12:15.020 --> 12:20.840
So instead of just calling the action now we're going to run this method that will just run all those

12:20.840 --> 12:25.040
steps first middleware, second middleware and then the route.

12:25.130 --> 12:34.040
So how this would work we need to know what are we going to run next that is initialized with a target.

12:34.430 --> 12:41.210
Next up we are going to iterate over all the middlewares in reverse order.

12:42.470 --> 12:46.940
So we do array reverse with Middlewares.

12:49.640 --> 12:51.530
As middleware.

12:52.100 --> 12:52.310
Okay.

12:52.340 --> 12:55.460
So why do we reverse those middlewares.

12:57.920 --> 13:05.750
So I'm reversing this array because it is a common pattern in middleware implementations that the last

13:05.750 --> 13:14.420
middleware actually runs first, or to be precise, the middleware that was added last runs first,

13:14.420 --> 13:19.340
and it kind of wraps all the other middlewares.

13:19.700 --> 13:26.660
Okay, so we need to figure out what is the next middleware to run.

13:26.660 --> 13:30.410
We essentially create a linked list.

13:31.940 --> 13:34.730
So for every middleware we need to create a class.

13:34.730 --> 13:41.600
Remember that's possible in PHP you can create a class based on the variable that contains the class

13:41.600 --> 13:42.290
name.

13:42.440 --> 13:45.140
And on this class we call handle.

13:45.140 --> 13:50.390
We know it has this method because every middleware needs to implement an interface.

13:50.810 --> 13:57.410
And remember that every middleware has this next argument, which is the callable.

13:57.410 --> 14:01.790
So it just knows what is the next middleware to call.

14:01.790 --> 14:05.870
And this just happens inside the middleware.

14:06.380 --> 14:14.870
So basically if we create this chain of middlewares that leads up to a route, this middleware does

14:14.870 --> 14:21.740
whatever it needs to do, and it is the responsible responsibility of this middleware to call the next

14:21.740 --> 14:22.340
one.

14:22.340 --> 14:25.160
So this one will do whatever it needs to do.

14:25.160 --> 14:31.100
And then it calls the thing that's next, which might be a route or another middleware.

14:31.100 --> 14:39.200
And it's implemented this way because if you want to break the chain like someone's not authenticated

14:39.200 --> 14:43.490
and you want to stop the processing, you just don't call the next middleware.

14:43.490 --> 14:46.130
And this is how you break the chain.

14:46.880 --> 14:54.020
And finally this just returns a call to next, which would be callable in this case.

14:59.000 --> 15:04.850
And now after implementing this method we can finally wrap.

15:07.310 --> 15:11.190
This fragment that actually runs the actual action.

15:11.190 --> 15:18.240
And here we're gonna return this run middleware.

15:19.200 --> 15:27.060
Here we pass our array of middlewares that we have just created like that.

15:27.630 --> 15:32.040
The second argument is anonymous function.

15:34.620 --> 15:36.990
Where we need to use a route.

15:38.730 --> 15:45.240
So outside variables are not accessible inside anonymous anonymous functions unless you use this use

15:45.240 --> 15:46.110
keyword.

15:46.230 --> 15:51.150
And here we just paste the code that is executing the action.

15:52.560 --> 15:57.660
So with this middleware implementation I think maybe it's not clear.

15:57.660 --> 16:03.030
But you can see that the worst case scenario we are going to call the action.

16:03.030 --> 16:07.890
So next is initially the action of the controller.

16:07.890 --> 16:10.650
And if there is no middleware defined.

16:10.680 --> 16:13.710
We're just going to run the controller action.

16:13.710 --> 16:21.990
But if there is any middleware defined, we reverse the order of the order.

16:22.140 --> 16:25.200
How the middleware was added to the list.

16:25.200 --> 16:28.080
And then we first initialize the middleware.

16:28.260 --> 16:30.630
We run it passing to it.

16:30.630 --> 16:32.520
The next thing to call.

16:33.570 --> 16:40.680
And inside the middleware you will be responsible for actually calling the next thing on the chain,

16:40.680 --> 16:46.020
which eventually is always our own controller action.

16:46.350 --> 16:54.360
So I think, and I agree that this is kind of complicated, maybe even very complicated.

16:54.360 --> 17:01.020
Anyway, I'd like you to bear with me because when we run this in the next video, we create some simple

17:01.020 --> 17:01.800
middlewares.

17:01.800 --> 17:09.570
You will see how powerful mechanism that is, and I think you might just understand everything a little

17:09.600 --> 17:10.260
better.
