 Baiklah, hari ini saya akan berkongsi tentang PSL-15, Http Service Request Handlers Just a bit about myself, my name is Zion. I'm a Zen Certified Engineer. Currently, I'm working as a freelance web developer and a part-time IT consultant. If you want to find out more details, you can go to my website at Zion.sg So, just a show of hands of who here knows what PSL is. 1, 2, 3, 4, 5. Okay, very good. So, my next slide is not wasted. What's that program? No, that was done using HTML, CSS and JavaScript. Hey, we are web developers right? So, just a list of some PSLs by PHP, FIG, the framework interface. Okay, PSL0. So, these are all standards. It's just in the phases. It's not compulsory. It's just PHP standards recommendation. So, you are recommended to use it, but it's not compulsory. So, PSL0 auto-loading standard. So, in the past when we wrote our own scripts, our own libraries using plain PHP. So, how do we use other people's PHP libraries in our own code? We just use an include statement. But sometimes, we had hard-code the Dart3s and now, it's a bit troublesome. So, later on, they came out of this PSL0. So, basically, it says that you must have namespaces in your PHP classes and it must reside in a certain Dart3 structure. So, Composer makes use of PSL0. So, right now, for a lot of PHP projects, we just put Composer.json and we put Composer.install and everything, they will pull all the projects from GitHub, from packages and you can easily use components from other PHP projects in your projects. This also enables, for example, if you are using a Xen Framework application, you can pull a component from Symphony Framework and use it in your Xen Framework project. Next one would be PSL1, basic code standard. So, it says that your PHP files must be encoded in UTFA Revolver the byte order mark and certain other things that how you should name your variables. It should be using camel case. They may as well say the first letter is a small letter. How do you name your classes? Your classes should start with a capital letter, Pascal case or Studly Caps. To add on, they have a PSL2. This is where all the braces spaces come in, your indentation. Use spaces for indentation, four spaces. Does your brace for the class, opening of the class, does it go on the same line or the next line? Your if-else statement, does the opening brace go on the first same line as the if statement or the next line? So, things like that. So, it is to reduce cognitive friction. So, when someone, let's say I look at your somewhere else PHP code, I won't feel like, it's all over the place. All your indentation is all inconsistent. So, everyone is going towards PSL2. PSL4 is update to PSL0. So, basically PSL0 is deprecated now. It's just, it's a bit more flexible with regards to the auto-loading file structure. And there are many, many more. Currently, there are 10 accepted PSLs. One in review, two drafts, five abandoned, and one deprecated. So, the idea why these people came together to form the PHP FIG. It is for project representatives to talk about common things. And to find ways to work together as PHP developers. Do I need like and clear to say, oh, you are from ZAM framework, you are from Symphony framework, you are from RuPaul. No, we are all PHP developers. Let's try to make our job easier. So, let's say if I move to another company, that uses a different framework, I will find the learning curve last tip. Now, there are about 13 voting members in PSR. From various projects like Composer, RuPaul, Magento, Paired, and ZAM framework. So, why do these projects adopt PSR? Because they want the developers that use their frameworks or projects. And they want the developers that contribute to their projects to adopt best practices and to learn best practices. So, PHP FIG. You can find out more on the PHP FIG website over here. Now, before we even start talking about PSR 15, we had to learn know what is middleware. Before we even talk about middleware, we have to know what is PSR 7, HTTP Message Interfaces. So, let's start with PSR 7, HTTP Message Interfaces. Now, in the past, about 25 years ago, this would be how I would write a simple script to process a form submission and then output the variables from the query string. Very simple script. Today, or probably 5, 6 years ago when I started using ZAM framework, this would be how I would write it. I have a controller class extending abstract action controller proprietary to ZAM framework. And supposing, let's say I have a test route and I have an index page. So, I must call it index action. So, how do I get a request? Abstract action controller arrow get request. And then from request, actually I already suppose and I'll be turning a view model. There are many ways of doing this. The code cannot be reused. Different frameworks, different way of doing things. Every framework comes out with their own abstraction of HTTP request and response. There are new things to learn. You cannot switch easily. So, let's say I learning ZAM framework. I go to another company they are using LeraFile. I do relearn a lot of things. The syntax and how the classes work together. Now, can you see a similarity? So basically, you are receiving a request let's say from the form, processing it and returning a response. So, what do frameworks abstract? Form post Over abstract the request URI for routing purposes. Handle for uploads input and output streams writing the files and returning of response. So, every framework ZAM, symphony, KPHP, co-initre, LeraFile They come out with proprietary classes and ways to handle this which cannot be reused easily outside their framework. So, let's look at a simple form of HTTP request message. It has this form a post which is the verb, a path, a diversion the host header and the body. A response has a similar structure. It has HTTP 1.1 the version 200 as status code okay as a reason phrase content type header and again a body. So, this is a very big overview of PSR7 every box you see here is an interface. Now, PSR recommendation so they only recommend an interface they don't detect your implementation you can implement however you want you can even use C as the underlying implementation they don't care as long as you provide this interfaces so someone says that I'm PSR7 compatible that means if classes they will exist okay let's look at the first one I will only go through a few not a full thing message interface so message interface at this matters getHaters getHater getBody withHater withBody a note about withHater and withBody this one will return new instances objects are passed by reference in PHP hence the concern or immutability now if I were to modify the body here just like that it may affect the original object which is used somewhere else so to please say they have this withHater and withBody matters that were explicitly written request interface extends message or request is basically a message so request as a get method getURI getStream Streams are used for bodies and the new request is how you can change the methods together to return a new instance in this case there will be four new instances so if I go to Xam framework and they implement PSR7 request and I go to symphony framework and they implement PSR7 request I can use the exact same methods and they will still work so this one will reduce reduce the learning curve for us PHP developers response interface also it is a type of message so it extends a message interface a request as a status code a recent phrase body and same thing you have the with methods now server request interface extends request interface basically it will time all these server super global how to get the query programs the pass body and the uploader files and supposing let's say using a framework after routing you want to get a route parameter so they have a request attribute so there are many more interfaces in PSR7 but I won't be covering them because middleware the next topic only uses this interfaces middleware what is middleware middleware is basically a lambda black box it takes in a request a PSR7 request and returns a PSR7 response I don't care how it is implemented it is just a black box this is a schematic of a desktop I don't have a laser pointer here there are many ways of using middleware one way is what we call the onion stuff the onion that you eat for your food where you peel off layer by layer now this is a DevStar it is a powerful weapon in Star Wars that can wipe off planets just shooting something out of its cannon so the DevStar cannon consists of many layers so for simplicity sake look at the red color part there are four distinct parts a red rectangle a red square underneath it a red over and a red core so imagine imagine the cannon sucks in light ok, I know I'm pushing it something like just like the request and then it processes it truah 4 years and then it shoots out a powerful laser that is the response so now let's come with an easier to understand analogy ok, this is the typical diagram used for illustrating a middleware so you see the application your routed endpoint is at a core supposing if I were to write basically some URL that I can call with some parameters and return me some information now supposing I write a REST API with 1000 endpoints 1000 URL and supposing I have one class for each endpoint so let's say I have 1000 PHP files supposing I want to add authentication ok, that means before I even go to let's say slash demo I want to check for authentication but check whether the person has the right to use this endpoint do I go to each of the 1000 classes and then add one and say if this is authenticated continue else truah exception or is it if I say like I use annotations I add an annotation say add is secure authenticated there is 1000 classes with middleware there is no need so the routed endpoint imagine is an application call the one in the red color in the middle and I will just add one authentication middleware on top of it the authentication middleware will basically receive the request check if not authenticated I throw back a response it doesn't even reach the call if it's authenticated I'll pass the request the same request the same PSR7 request and pass it into the call which is the rest API endpoint and the API endpoint will basically process it throw out the response the response will pass back truah authentication middleware you can send it along so basically it's like you're going truah the same 4 layers you go truah the same 4 layers what if I want to do logging same thing I will just add another logging middleware the third the most layer so when the request comes in the logging middleware will receive the original request log it and put it in the database after that I just pass the request down to the authentication middleware after that authentication middleware will pass it down to the rest API endpoint which is the call application call application will return the response back up to the authentication middleware authentication middleware will pass the response back to the logging middleware and the logging middleware can just log the response truah in the database again so this is how the understyle of the middleware works now in code I assume that we are all developers here it's very simple middleware is basically a function that takes in a PSR7 server request interface takes in a response interface and a callable NATS which is supposed to be the NATS middleware now remember this signature because it will change in PSR15 so we can have factory production line like human chain so the human chain will just keep passing along this server request the response and the NATS middleware to call so it's like factory production line before before the advent of middleware what we have is framework specific methods parent classes and naming conventions so this is how you will look like probably request and view model which is tied to the framework after now that we are using middleware okay notice that this class extends the Zen specific class abstract action controller next one is a plain old PHP class it does not extend anything the only thing it has is the invoke method the invoke method is the middleware signature takes in the PSR7 server request PSR7 response and NATS and if you look at the content get pass body get body these are all PSR7 methods it will work if I take this class and put it in Zen framework slim and level which already have a PSR7 reference so someone may ask me sayang but you look at the renderer the renderer is it's not PSR7 so doesn't this break compatibility no it doesn't because the renderer is passing via the constructor through dependency injection so your application we should probably have sign dependency manager you can just configure and throw whatever renderer or object that you want you can easily replace it with a dummy renderer as well for testing now symphony has symphony bundles Zen framework has Zen framework modules level has level packages so people are solving the same problem over and over again but wrapping them up as framework specific solutions so that was the problem so the also of PSR7 giving way to middleware allows us to do much more and break away from framework silos so you are no longer oh i'm from Zen framework i'm from symphony framework no we are all PHP developers okay finally actually not finally so quite a lot of slides PSR15, HTTP server request handlers why border the signature is already there PSR7 and middleware signature that is used by a lot of frameworks and projects so why border defining a new PSR15 the standard standard captain so PSR7 does not define request handlers or middleware so middleware has existed in PHP many PSR7 a lot of frameworks have adopted middleware so PSR15 provides a former standard it enables any middleware to run in any framework it eliminates duplicate effort duplicate interfaces and minor discrepancies in the method signature so previously middleware okay let's look at the next next is basically another middleware that are processing the request and response next was just a callable no type hinting no type can be enforced now with PSR15 we have a request handler interface as a handle method it is in the PSR7 request it returns a PSR7 response okay we are not using underscore because it is less transparent than the name method so let's move on to middleware the same old middleware signature look at the magic input method it is in the a response interface and a next callable now with PSR15 PSR15 defines a middleware interface it is a process method it is in the PSR7 request of PSR15 request handler it returns a PSR7 response interface all these are interfaces they do not detect the implementation now why why didn't they reuse the magic input method because it will conflict with existing middleware implementations and they look at some of the frameworks symphony, HTTP kernel users handle method the same framework dispatchable interface users dispatch method so in computer science the two most difficult things is naming things and invalidating cache so they finally say we are just processing stuff so let's just call it process now this nature has been changed previously it takes in the request response and the next now it takes in the request handler this is called a single pass currently the two most common approaches to middleware is double pass and single pass so double pass, those people who use express.js with no.js, they will be more familiar with that it takes in request a response and the next middleware and produces a response single pass is they take in the request, the next middleware and produce a response there are currently 23 projects double pass signature slim, zen versus 3 projects using the single pass signature guzzar, step php and level single pass has been used many years those people will use step php and double pass is newer is mainly adopted by people who started adopting PSR7 but there is a problem now this is a double pass the old middleware signature taking the request response and the next middleware what's the problem first problem the first middleware will be passed an empty response object is empty but there's no guarantee because it will be modified by subsequent middleware so the state will be totally different incorrect haters from previous middleware now supposing let's say I have a cache middleware request and the response will add one cache then after that it goes to the next middleware and the next middleware decides there's some problem, there's a 500 error so I'll just take the response that pass to me I will just say it has a 500 error and then I throw back the response so when the client receives a response error response with cache haters so it's like totally wrong case the haters are totally wrong because you don't know what the previous middleware injected corrupted body content supposing the first middleware writes to the body the quick brown force jumps over the lazy old dog pass the request and the response to the next middleware the next middleware will just take the response and write the lazy old fox and throw back the response so what will be the final content? the lazy old fox jumps over the lazy old dog because the newer content was shorter they didn't override everything they only override partially now some people say that we pass in an empty response in the first place so that subsequent middleware don't need to know how to create a new response so we can skip the implementation but that's not a valid excuse because it can be solved better with factories you are using middleware in an application the application usually will have factories and dependency managers use that and PSR17 not PSR7, not PSR15 PSR17 HTTP factories give a standard approach to factories so we are waiting for that and fifthly next in the old middleware signature it was a callable there is no way to enforce type no way to enforce street typing you cannot be assured that next is definitely a middleware so finally they decided screw the 23 projects i don't care, let's choose the single pass approach take in the request and then the next middleware and return the response if you want to implement go ahead sorry for more i know just pull out from the PHP FIG membership so ya it's totally volunteering so let's look at an example how this PSR15 basically only detects 2 interfaces so let's see how it may be used now firstly the braces are not according to we will have a noted that because i don't have space now this is a request handler a request handler only needs to implement one method the handle method taking in the PSR7 request and returning a response so basically this one we are taking the fallback handler you can add middleware you are maintaining a queue of middleware and then when executing the first middleware you pass itself in just remember this this is a queue request handler of middleware how you add to the queue you use the M method M method is not defined by PSR15 it is your own application this is a play PHP class it does not extend any concrete class so you can put any other methods you like as long as you put the handle method now in your actual application bootstrap basically your application in desktop PHP this is how you implemented i create a fallback handler basically you just return not file response my application basically is made up of the queue request handler i passing the fallback handler and i add middleware i add authorization middleware i add routing middleware and the very last line i will just call the handle method of the queue request handler now the how do i passing the server request this is what i mean by factory in your application you will have factories that can take all the super global and then form a PSR7 request this implementation the request handler does not need to know how other middleware are being created how it is being added to the middleware it only provides an method it doesn't need to know how the PSR7 request a response is being implemented, doesn't matter the middleware is executed in the order that it is added to the queue and the generating of the fallback response is up to the developer not found or default page we also have done compiler in the studies before we heard of a compiler that can compile itself an interpreter that can interpret itself so basically right now it's like this is a request handler they can handle itself they can handle the middleware itself so it's kind of regressive for logic over here this example is taken from the link over there it's taken from the PSR15 meta documents i'm passing the authorization middleware and routing middleware so authorization middleware implement the PSR15 middleware interface it has a method called process which takes in PSR7 request and the PSR15 request handler so basically the code just if there's no need for authorization pass request handler if the request is not authorized, return the error response if need authorization and pass to the handler the handler will just return the response PSR7 response and then when it returns or just sign this thing is authorized today as we signed by me or i get no sign and returning back so the middleware is not concerned how the request handler is implemented it just uses it to produce a response when preconditions are met the other middleware is the routing middleware so the router is injected via the constructor and in the process method of the middleware interface it will just pass the request to the router and check then i will get the request handler from the router to handle it so the router returns a result which has a get handler method to return the PSR15 request handler if nothing is routed no route is matched i will just pass in to the request handler so the second argument in this now if you are interested in more about middleware and actually doing coding you can actually look at ZEN Expressive Tree ZEN Expressive Tree you can just run this command in your terminal composer, create project, blah blah blah PSR15 middleware PSR7 consumes PSR7 HTTP messages when you first run the composer command they will actually let you choose what router library you want to use you don't need to use ZEN router this is by ZEN framework you can use other like Aura, router or Pimper dependency injection middleware only defines one method you can inject all your dependencies all the other middleware or any helpers that you want via the constructor templating is by ZEN framework you can use 2-week mode start play whatever so with this go back and try just search for ZEN Expressive Tree and then you can try it out and with that metaphor review happy star one day