 Rydyn ni'n ddweud y mycfrenon? Rydyn ni, rydyn ni'n ddweud Rydyn ni'n ddweud Rydyn ni'n ddweud, rydyn ni'n ddweud Rydyn ni'n ddweud Rydyn ni'n ddweud Rydyn ni'n ddweud am ymddor James Sickham Rydyn ni'n ddweud hb oedd oedd 2002 yw Ysgrifenned Cymr ymdyn oedd a rydych chi'n rhaid i gynni gynni'n cyffredinol ymdyn i'r mfodol ac rydych chi'n ddweud ac rydyn ni'n ddweud I'm not a shill for Zen, by the way. I run the PHP Hampshire user group and also the PHP South Coast Conference, tickets now available. And I contribute to various open source projects, Zen framework, doctrine and lead developer on a couple as well. And my day job, I'm a consultant at ROVE who purveyers of fine elephants, but we haven't got them done yet, so that's just the prototype. Anyway, enough about me. So what's Zend Expressive, right? We're here to find out about Zend Expressive and doctrine. So I'm going to start at the bottom and this is kind of what's going on underneath an application in Expressive. It's kind of a lot of things here, but I'm going to break it down and look through it bit by bit. First up, PSR7. Hopefully many of us have now heard of FIG and the efforts to standardise things. PSR7 is one of those and it is basically modelling HTTP messages, right? And it's just a set of interfaces. There's nothing complex about this. And HTTP messages are the foundation of the web, right? We've seen them before. You've got the verb requested page, HTTP version and so on, the host and maybe a payload depending on what you're trying to do. And the response is pretty similar, right? We've seen these, this is not complex stuff. And PSR7 models those in a way that you can use in your applications as objects, right? So the next, the first layer of Zend Expressive that's actual implementation is this package called Deactorus. Deactorus is a silly-sounding name. It's Greek and it means messenger, so that kind of makes sense, I think. It's just an implementation of PSR7, so it takes those interfaces, implements them. It allows you to modify them in an immutable way. And what that means is that you're never mutating the same instance, you're getting a new instance back every time you say with added header and things like that. And there's benefits to that, but I'm not going to go into that because it's not so relevant for this talk. Deactorus also handles serialisation and deserialisation of requests, so you can take just a string like it's had on the slides a minute ago and it will turn it into an object or do the same the other way. It also handles the core stream handling stuff, so the body of your payload, whether it's request or response, is a stream. So that kind of defies the immutability thing, but again, that's a different argument. We also have a URI implementation, so I believe there's actually a PSR in progress to do that separately, but for now Deactorus has one, which is kind of useful. And you also have the very basic ability to dispatch a request to a callable, similar to what you might have seen with Node HTTP server, if you've done Node.js before, and really it's not so useful, it doesn't do very much. And also the execution model of PHP is fundamentally different, right? It's shared nothing on a server API, Node.js is very much different. You're building an actual server that listens. Anyway, strategility is the next layer. It's another silly-sounding name. Clearly Zendlove, the name, appagility a lot, so use that kind of theme, but I don't know why they didn't stick with it with Deactorus messagility. Anyway, this is a library for creating and dispatching middleware pipelines. It's built to rely on the PSR7 implementation naturally. And in theory, I guess any kind of PSR7 implementation would work, but we're going to use Deactorus for this. So what's middleware then, right? For those of you who are like, what are you talking about, James? What's this middleware thing? It's basically an invocable class, right? This is modelled on, there is another PSR that defines how middlewares should look, their function signatures and what they return and so on. So previously you may have seen, for example in Slim Framework, or any kind of middleware patterns, if you like, it would take a request and a response and so on, and a next middleware to be executed. In this one we have just the request and the delegate interface. That is basically the next thing to be executed. So the way this works, right? We have some code that may happen before something else happens, and then we have delegate process, which is calling the next middleware in the chain, and then you can have some code after potentially, and then return a response, right? It's fairly straightforward and it's kind of nice and atomic, and that's kind of the point of middlewares, is that you can do small atomic operations and chain them all together into this big line of stuff that happens. So, as I said, this structure is based on this package, HTTP interrupt. I can't even talk today, which is no good, because I'm meant to be speaking to you. HTTP middleware. And it's a work in progress, so actually it's slightly different, the implementation that we have so far is slightly different from the PSR, but I'm sure in time that will be sorted out. An expressive 1.1 sort of encourages using this new request and delegate function signature. And, yeah, if you've used middleware before, obviously you get the response in the function signature, but there is a fundamental problem with that. If you modify the response before something else creates a response, then you're going to get unexpected behavior, because the next middleware down the chain might return a completely new response. So the mutation that you've made to the response coming in is lost. It's gone now. So that's why we have this delegate interface and no request in the function signature anymore. So what if you do want to do it? If you want to modify something? Well, like I have here, you modify it on the way out, because then it will be passed back up the chain correctly. And if any of you read Terry Pratchett, you'll know what a clax is. So this is how we could, in a very basic way, pipe up a load of middleware. In using strategality we can just say, well pipe, that's basically just add to the pipe a load of middleware that do various things. And the middleware pipe when you run it, I've missed out a run call on this slide, but it doesn't matter. When you run this, it will descend through each one. And the strategality middleware pipe will take care of the delegate interface and it will run the next one in the chain and so on. And you would descend through in order that you add them. So let's have a look at what these might look like. Logging errors is kind of nice. So we could wrap everything below in a try catch and catch everything, for example. And so when we call delegate process, obviously we were returning the response directly, but if an exception happens further down the chain, we catch it and we return a JSON response, for example. Session initialising middleware. It's kind of fairly self-explanatory. We call session start. And that's what I mean. You can do lots of atomic operations that are meaningful and you can name the middleware appropriately. It's initialising the session, right? And it's very clear what this thing does. Authentication, perhaps. Do some authentication checking, or whatever you're doing. If it's invalid, you can return a JSON response. And the nice thing there is the pipe of middleware is cut off then because you're not calling delegate process. You're not going any further down the chain. You just return back up with your response and that's great. Authentication is a perfect example of short-circuiting that logic. And then, of course, you might have an action, an index action or something like that where you might want to render a template or perform some kind of action. And it's in the same kind of structure as we've seen, but in this case, we're not calling delegate because it's the end of the chain. And we're returning a response directly there. Think of it as like a controller in an MVC framework if you're used to that. So expressive itself, one ring to bring them all in the darkness, bind them. Expressive is kind of actually just a glue that sticks all this stuff together with a few extra nice stuff. So it uses a PSR7 implementation. It uses the middleware pipes from strategy. And it also adds in the routing layer. So you can route your requests to appropriate middlewares. You can create services in your dependency injection container and dispatch the middlewares. You can optionally handle templating and error handling as well. So routing is kind of nice. The way this works is you just pick whichever one you like. You can use aura-router, Nikita Popov's fast-router or Zen Framework's MVC-router, Zen-router. My personal preference is fast-router because it's fast, as the name may suggest. And it's a very nice little router, actually. Designed to be fast. Depends on the injection container. Anything that implements container interop will work. Out of the box you could use a Zen service manager, aura-di or Pimple. But anything should work. My personal favourite is Zen service manager because I like making factories all over the place. And optionally templating. It's optional because, well, not all applications need templating, right? If you're writing just an API, well, you don't need any templating, right? You're just returning JSON all the time or XML or whatever. But if you do want templating, if you want to make a website, you do that sometimes, right? Several are supported. ZenView, plates, twig are supported out of the box. My personal favourite is ZenView because I like having to escape things explicitly all the time. Wow, there we go. Piping and routing. So Expressive has two places to plug in middleware. There is the pipe which we've kind of already discussed, but it's basically always on middleware. And that's basically the part that strategy handles nicely. And it's the main application life cycle. It's useful for logging stuff as we've seen, error handling, if you like, global authentication authorisation and things like that. And, of course, triggering, routing and dispatching. And Expressive, in fact, the routing and dispatching steps in an Expressive application are also middlewares that you have to explicitly add to the chain. If you're using the skeleton application which we'll look at in a moment, that's already done for you, so you don't have to do that. And routing as well. Obviously, you want to be able to assign middlewares to specific routes that perform specific actions. And that's useful as well for partial authentication authorisation. So, for example, most of your website is public, for example, but then you have some specific admin panel or something like that. And, of course, running the middleware on specific routes, or even HCTP verbs. So, I'm going to step back a moment into Zen Framework 2 & 3. Because you might be thinking, well, what about, where does that leave a Zen Framework? And it's purely an alternative, right? It's a different way of structuring your application. A different paradigm. Zen Framework 2 & 3, if you're not aware, it focuses on sort of a quartet of components. So there's the MVC component itself. There's a module manager, which we'll have a look at in a little bit. An event manager, which the whole MVC life cycle is kind of based around events. Strictly speaking, they're not events, but that, again, that's another topic. Zen Service Manager as well. So, Expressive isn't designed to be a replacement for Zen Framework. It's just an alternative. Zen MVC is still powered by these events and so on. Events. And it's still a viable option for applications and it's kind of half preference and half like how you want to structure applications and so on. So if you are familiar with Zen Framework and you wanted to get into Expressive, you kind of need a bit of a mind shift as well. So where in a typical MVC application you would do a load of stuff, you can break that up into these small middlewares that do specific things. You don't have to, of course. You can just have one action middleware that does everything, but you're kind of not leveraging the power that you have in Expressive there. Expressive doesn't have modules as such, so if you aren't familiar with Zen Framework, you would have a module and you'd have this file called module.php and the module manager would load that up and you have things like configuration and some kind of bootstrap initialization type thing for each module and it merges all that down into a big configuration file because Zen Framework likes arrays a lot. And Expressive does as well, so make sure you like arrays. But you have to do this explicitly in Expressive. So you'd think, well maybe I can use Zen Framework components in an Expressive application, because there's a lot out there that do various stuff. There's doctrine module and all kinds of stuff which we'll look at in a moment. But it's not quite as straightforward. So the module manager is missing and it's probably quite difficult to integrate into an Expressive application. So we wouldn't even go there. So there's a caveat. Anything that module.php does, you need to do manually outside of just a configuration. So this is what you might see in a Zen Framework module. If it's as simple as this just returning your config array, that's good because you can use this to your benefit. There's these things called config providers. This fairly new concept in Zen Framework. And it's basically a replacement for that module.config.php thing. I'm going to use Zenform as an example. And all we do is just move that config returning into a callable object. The advantage, of course, hopefully you can see, is that you don't need to specify the path to a config file. You can use autoloading because we like autoloading. So you can just say, give me this object that provides configuration and return it. And Zen Framework has started to adopt this for their modules. Some of them. And it's very simple stuff, right? This is just an example of configuration that we would have seen and it's just in a function that we return it, broken down nicely. You know, it's not a lot different. But it's more portable because we can use the autoloader to locate this configuration instead. So now if we look at Zenform, this is what we see. We actually see that the module.php uses that config provider and gets the same benefits. So this module could now work in an expressive application and a Zen Framework application. Good. This is how you would use it in a Zen Expressive application. You just return the array. It's very straightforward. And yeah, I mean, as I said, if the module.php does more than that, just the config, then you might need to add some bootstrap code and duplicate it up, which is kind of a bit annoying. Anyway, your application, let's write one. I'm going to show you an application I've built. If you have a laptop open and you like following along, click on the code on GitHub. What I'm going to do is a very simple application. It's going to be a book library. There's going to be an action to check in things into the library and check out things from the library. So if you would like to follow along and have a look at the source code, please do. I will give you a moment. Okay. Does anyone still need the link? No? Okay, good. All right. I mentioned earlier this expressive skeleton, which is by far the fastest and easiest way to get set up. So I did this, right, for this talk, and you use a CLI tool to configure everything. It uses the composer installer stuff, so they didn't obviously write all themselves, which we don't do anymore. But you can choose the router DI view templating and error handling as well. So you use composer create project and we'll call it book library. It's very straightforward. It will first ask you if you want to do a minimal installation or not. You probably want to do a full installation because minimal will mean that you don't get very much configured and you have to do everything manually. We don't like doing things manually. You'll be asked which router I opted for fast route because I like fast routing. You'll be asked what container implementation to use. I opted as a service manager because factory is for the win. And a templating engine. In this case, I'm making an API, so it's just JSON. So I picked none. And finally, it will ask you if you want to install whoops or not. I didn't for various reasons. Fine. But after we've done this, we have already got expressive application. Hopefully, you can go off and do the composer install. It even comes with a bundled command composer serve, which times out after a while, which is annoying. But anyway, again, a different topic. But if you navigate to localhost8080 in your browser, you will see some JSON. That's it. It's as simple as that. Right? We're going to start off with this. We're going to write our actual application. So we're going to create a book entity. We're going to create an interface for finding the book entity, which we'll go ahead and implement later. And two endpoints. So two actions, one to check in a book, one to check out a book. The book entity is very simple. We're going to keep it very simple. There's just one property. Actually, in the actual implementation, you'll see there's two properties. Two IDs all the time. And it's got a single property in stock or Boolean, true or false. So you can only have one book. One copy of a book. We're keeping the example simple. Check out method. Again, there's not a lot here. Right? If it's not in stock, obviously you can't check it out. So we're going to throw an exception. And then if it is in stock, then we can change it to be not in stock. Keep it simple. Check in method. Does the same. It's just the opposite way around, right? So I also wrote an interface, find a book by UUID. And we're not going to implement it yet. We're just going to assume that however we implement this later, the clues kind of in the title it will be with doctrine, but we give it a UUID and it should return us a book entity. And that's all we want, right? So apologies if it's a bit small at the back. But this is the action. It implements middleware interface as we kind of talked about earlier. So we've got the request, the delegate and it should return a response. In this case I've specified a JSON response because we're just dealing with JSON here. Most of this is just try catching and returning helpful error messages. It's kind of a contrived example, but fine. It's fine for demonstrating. The main meat of this function is the invoking the find book by UUID. Checking it out if we can, obviously. And obviously if something goes wrong at that point we can return a useful response. The check-in action is essentially the same. I'm not going to show that. So we're going to add some ORM, right? We're at the point where we can now implement something with doctrine and get integrated, right? I'm not going to talk about the ODM. If you're not sure what those are there's relational database uses the ORM hence object relationship mapper, an ODM object document mapper. But I'm not going to talk about the ODM so you'll see me refer to entity manager which I'll talk about in just a moment rather than document manager or anything separate. So who's not used an ORM before? Who's not used doctrine ORM? A few. So we'll have a look. Basically this is how doctrine works. Very, very high level. Because it's very complicated underneath. The main parts of this is the database abstraction or DEBAL, and that if you're not aware, allows you to talk to lots of different databases. And then on top of that we have the ORM which has the entity manager and that's the main thing we focus on. Your application houses these entities. So we've already created one. We created the book entity. These are in doctrine's world just plain old PHP objects. They don't extend anything. There's nothing complicated to them. Doctrine through some magical wizardry will track changes to your entities. And then when you've finished your request you will flush those changes to the database by using a call to flush. Literally. And your application should have ways of finding these things, right? So you can call them finders, services, whatever you want to call them, find. These would use the entity manager to locate entities and populate them. Entity manager deals with hydrating stuff in the database and so on. An example of this, we've already written one. Find book by UUID interface. And that's going to use the entity manager eventually. So if you've ever written any zenfraimwork applications before, you will and use doctrine as well. You may be familiar with doctrine. So that is zenfraimwork bindings for doctrine. Funny enough. Well a question I've been asked before is why wouldn't you just use doctrine. It has advantages in zenfraimwork world, right? You've got that wired in configuration from the module PHP as we kind of looked at earlier. You can have, all your services are pre-configured from that configuration. You've got CLI tools already set up and if you use it zend developer toolbar integration and so on, it also has some nice zenform integration as well. And surprisingly reasonable documentation but that's because it's not part of zenfraimwork, right? I actually like zenfraimwork. It doesn't sound like I do but so can we use this in expressive, right? Yeah you can but you obviously run into this problem very quickly that there is no config provider. So we have to write something like this which is kind of annoying a bunch of code that pulls in the configuration manually. You don't have that advantage of the config being all too loadable and you need to manually configure the CLI and things like that. So you could do this. I've submitted a patch to both Doctrine module and Doctrine-RM module because you need both and you need to pull in the configuration from both. I've submitted patches to get config providers in there but they're sitting there waiting to be merged. So hopefully eventually this will become easier and simpler. So why would you use this module? Like I said, zenform integration is nice if you like zenform hydratas and things like that and that makes certain activities easier. But wait, there's more. There is a package called Container Interop Doctrine. It's written by someone called Ben Sholzen. I probably pronounced his name wrong, he's German. He's got an umlaut on the O. Anyway, sidetracked. He's written this component and it's not actually specific to Expressive. You can use it anywhere. You use Container Interop hence the name Container Interop Doctrine. What this does is it allows you to automatically configure doctrine with factories and things like that. It's just a bunch of factories that automatically configure it. Cool. So composer require blah blah blah. If you don't already have doctrine as a dependency it will add it and in your configuration I would suggest making a separate configuration file called doctrine.global.php whatever. That's where your configuration files go in Expressive. And it's very simple. You just wire up this one factory and you get doctrine ready to use. And wherever you have your container you can pull the entity manager and other things like connections and whatever. And this works fine if you just have the default that's called ORM default namespace for connections. It does work with multiple configurations if you want. Check the documentation. It's written on how to do that. And there's examples which is kind of nice. So you obviously you also need to configure it to point to a database so also in that configuration file you would add your database credentials and so on. Don't put passwords into git. That's bad. I'm using Postgres but any database should work in theory. That's what the database abstraction layer is for. And there's full examples in container and interrupt doctrine. Yes, obviously don't put that with your actual passwords in there. You can use local.php which is automatically git ignored so that you don't accidentally commit your database credentials or secret keys, whatever. So if you look at the example application, the book library application on github I've done it the right way there. So the slides are slightly out of sync there perhaps. CLI config as well because doctrine is much easier to use if you have these CLI tools that come with it. So there is things like schema generation or the other way around so you can generate your entities from your existing database. You can plug in doctrine migrations as well which I'm not covering in this talk. And these CLI tools are very useful. They can validate your schema as well so you make sure you've written your entities properly and things like that. So you probably want to do that. It's basically just copy and paste this code. That's all I can say really. You don't need much more than that. And then you can run Vendorbin doctrine and you will get those CLI tools which is very useful. We'll have a look at using that in a moment as well. So as I said, entities are just plain old PHP objects. But how does doctrine actually work with that? You can use these things called annotations. They're just comments with specific syntax. And you might think, well, loading that every time is going to be really slow. It's okay, doctrine caches those. You can also do these annotations but they're not called annotations then but you can have your entity configurations as XML if you like or YAML if you like pain but YAML is going away from doctrine so maybe don't use YAML. Again, a different talk perhaps. So this is what an annotation might look like. We have the table name book in this case and we have an ID column and I'm using UUIDs rather than auto incrementing primary keys. That's a good practice. Again, there's a whole other talk about that. And the benefits is that you get fewer collisions. You can do distributed systems nicer and things like that. So there is also actually a library from Ben Ramsay who wrote the UUID library that I also use in the book library application that has a specific doctrine type so it kind of integrates slightly nicer but I actually haven't used it yet. I apparently like doing things manually. Silly me. But yeah, you have these annotations at ORM backslash on. There's lots of different options you can put in caching configurations and your foreign key associations indices and all that kind of stuff. So anything you can do in a normal database you can chuck into these annotations. Documentation is reasonably good for this so do check it out if you're not sure what's going on. So yeah, we have I already explained the IDs, that's fine. So let's go ahead and implement this. We're going to call it doctrine find book by UUID and that's the implementation of the interface we wrote earlier on. It's very straightforward really. The class constructor, if you've got the code open you'll be able to see that in this file. It takes an object repository, doctrine that's something that we configured earlier with the factory and we just call the find method. We can cast our UUID to a string because I believe it casts it to a string anyway but I like being explicit. If we don't find it doctrine will return null by default so I turn this into a noisy exception because our interface mandated that if you can't find a book we throw an exception. So the checkout action we can update those and we're calling this funny little function called transactional. This is kind of pointless for this specific use case but it's a good example of doing transactions with doctrine so that's why I put it in there. So it's kind of an academic example but it's nice because you can have atomic operations. So multiple queries may happen that depend on other things and if something breaks doctrine will roll that back so it begins a transaction in the database it runs the callable that you provided in this case this just calls the one function and then you call flush at the end or it calls flush at the end rather and as I said if there's any exception it will roll back in the database. In real terms all we're doing here is taking advantage of the automatic flushing for this case but it's a very practical example. The atomicicity may be necessary for your application. If you want to create a user and take payment or the payment fails you might want to roll things back and deal with that in a specific way. What does it get? Try and get in the habit of making properly demarsated transaction I don't know how you pronounce that word sounds right to me anyway. Generate the schema manually configured the CLI tool so we can run this command ORM schema tool create and that will examine the entities and the annotations that you've given it and automatically create your database for you which is pretty cool. Don't run it in production though because it may nuke your database these are just development tools and then we can insert some data pretty self-explanatory we need a book that we can check in and out and then now when we visit our URL you should see the JSON response you should see you've checked out the great escape and similarly if you check in you should see what you've checked in them and then if you try and do check in twice or check out twice then you'll see an exception on the second time and so on and hopefully everything is working, excellent. So let's pretend we didn't put a transaction in there flushing is a key part of the ORM process because if you don't call flush on the entity manager nothing in your database changes so the way doctrine as I mentioned earlier doctrine tracks changes to your entities and it stores them up in this thing called a unit of work and it's kind of like a to-do list of what do I want to do in the database that doctrine builds up as you change things and then when you call flush it will analyse all the changes that have been made and execute them into the database so just as an academic example let's write a middleware that does this flush at the end of a request for example it's not actually useful in our case because we already called transactional but anyway so things are pretty straightforward here I want to point out that we're using the old style of middleware so with the request I've done that on purpose so I can show you what it looks like but we need a next thing to call so we have to make sure that it's there and this is kind of a good practice if we need to call it we need to make sure it's there in most cases it will be if you configured it properly but if you forgot to configure the middleware pipe correctly or screwed something up then this will be useful for you so it's kind of saving your self pain later down the line make sure that it's piped correctly and of course that's kind of endemic because you can provide null as that parameter which makes sense sometimes but so we check this middleware doesn't return its own response so we just return the response that we get from out or the next middleware whatever you want to call it and after that so we call the next middleware and then we check if the entity manager is open so if something breaks or an exception is thrown database exception and so on the entity manager becomes closed and that basically means you need to clean up the request don't do any more database operations um yeah it's kind of a weird thing anyway so we call flush essentially and that will save the changes to the database and then we can return the response that we got from the callable and of course this is kind of the fundamental part of the middleware structure we are calling the next thing and it goes down the middleware chain and then this happens after everything else has happened hence why we've put the code after the call to out so we've got a good functioning application now which is kind of nice so far we've set up expressive with a skeleton application that was super quick we've created endpoints to check in and out the book and we've added doctrine integration cool we can do more stuff though authentication let's have a look at it in a bit more detail so normally with an API you probably want to do something like OAuth or some kind of token probably just OAuth but we're going to keep this API super secure with a magic query string um yeah don't do this in the real world but uh yeah so the actual authentication is very simple if we've got authenticated equals one in the query string let them in um we can catch that failure and return back up the chain very quickly we can short circuit that middleware pipeline because we've not executed next so we're coming straight out of the pipeline there because authentication failed and if we do pass the authentication we can execute the next middleware again this is the old style I mean it's still current the current style of middlewares request and response and so on but don't change the response beforehand because you'll get that unexpected behaviour that I've discussed so um a nice option here is to use a library again from Ben Sholeson or Daspread this is uh internet name thing a nice option here is to use a library called Helios and that uses uh JWT which if you were in the talk just uh before mine uh you will have learnt all about JWTs uh but for those of you who weren't um it's jason web tokens and it's kind of this stateless um storage and you can um store it without server side sessions so it stores it in this token this JWT which is signed and things like that and you can pass it down in a cookie and things like that so you don't have to use sessions but again that's a separate talk as well um and Helios implements uh authentication via these middlewares right um you register an identity lookup interface which as you might have guessed it will look up an identity or user whatever you want to call it for example you can pull it from adoption repository and return it then you register your identity middleware into your pipeline so you add that into your configuration and that will inject uh the authentication user into the request which is kind of nice and we'll uh we'll look at that in a bit more detail in a moment and then obviously you need to implement your sign in sign out actions if you're doing uh you know if you need a login log out type thing uh and you can use the cookie manager to inject and expire authentication and so on obviously the JWT stuff may be not so useful for uh api stuff because apis don't usually use cookies hopefully um there's also another library called PSR7 session uh which uses these JWTs to store your session data in cookies um it's HTTPS only by default you can actually override it which we'll have a look at in a moment um and again it provides another middleware which you add into your middleware pipe and it adds this session container into your request so after every middleware later on you can then access this session container and it does all the stuff for you which is kind of nice so I'm going to uh if you've got the code you may have already noticed this but I'm going to use this um to add a counter into our responses which is kind of pointless for an api but hey and it relies on cookies um anyway so factory the middleware there's lots of code here um it basically our copy and pasted it right it's pretty straightforward um there's a symmetric key written in there um but don't hard code that put it into your local dot php like I kind of explained earlier um because you want to be able to hide that away and not put that in git because that's bad also note that I've uh here with secure is false I've done that on purpose because I'm running this on php's built-in server um which is not hctps and without that it won't work it will say well you're not on hctps so good luck so as I said we add the the middleware into our pipe so this is our applications pipe configuration um and you'll see that there's a routing middleware dispatch middleware those are provided by expressive as I mentioned earlier uh we've got a URL helper and some authentication but here we've added our session middleware so everything after that middleware has executed will then have access to this session container which has been chucked into the request attributes and this is how we use it so in uh a further a middleware further down we can say request get attribute and it's got this constant that uh refers to the key that is in the attributes we can get that session container we can call set get remove and so on and that's very useful right so to summarize um why do I do bullet points like this kind of annoying anyway uh psr7 is really what kicked off all this stuff and it's really useful um to be able to model that uh you know your requests and responses and so on the actor is just a psr7 implementation it's pretty straightforward um the only complex thing really is the serialization and deserialization of these requests strategility is a middleware pipeline thing you can use this independently you know you don't have to use the whole expressive thing um if you just want uh the middleware component it's actually kind of useful expressive glues it altogether it has your routing your di and whatnot doctrine module can be used with that bit of fiddling hopefully that will become easier once we have the conflict providers in there um so I would probably say in most use cases use container interop doctrine because it's easier we like easy things and middleware are all the things right there's lots of packages popping up um if you search packages for middleware you'll probably get loads and loads of results already um because lots of people are doing things and then uh doing things with middlewares and as I kind of mentioned getting those nice atomic operations is nice because you can actually then go and share these middlewares and avoid having to write the same code over and over again so like using psr7 session or uh Helios and things like that you're taking your pain away from yourself by using code that someone else has written um and of course we thank those people for their time and contributions and so on um okay are there any questions either I explain that terrifically well or come and speak to me after if you have any further questions but thank you very much folks