 Guys, I'm gonna move around a little bit. Hey, who said hi? Hi, awesome. This is why I love Drupal Conferences. The first one I ever went to, I was talking about B-Hat. How many people have heard about B-Hat or used B-Hat? Yeah, like, oh, it's amazing, like the ridiculous number of hands. And I did not make B-Hat, I was just talking about it and I showed something in the middle and the whole room broke out in applause. I was like, this day like never happened before. I was like, this is awesome. So I think some people are still grabbing last second tacos, but I'll let them wander in. I come from the symphony world. This is my third Drupal Con, which is amazing for me. And today I'm gonna be talking about the Drupal 8 Request Life Cycle because amazingly, awesomely, I'm actually qualified to talk about that because there's so much in common between requests and responses in symphony and requests and responses in Drupal 8, which personally I love because I can open up Drupal 8 and go, oh yeah, oh yeah, see what they're doing there. That's clever, I like that. Makes sense to me. So I come from the symphony world. I am a writer for tutorials on a website called kmpuniversity.com. How many people have seen stuff on Drupalize Me? Yeah, good number of hands. Yeah, you might see a couple of our things up there too. So they're friends of ours. We have a couple of our object oriented and stuff over there. You'll hear my wife, Leanna's voice. Where is Leanna? Leanna, she's late. We'll just wait then. Just kidding. Usually we, I sell her out in some way. Well, she'll come in the middle if I see her, I'll sell her out then. So, let's get into things and hold on one second. Well, actually it's okay. I totally didn't hook up my clicker, but I'm not gonna want it very far anyways. So, let's start off. So I feel like making a page in Drupalate. How many people have done at least a little bit with Drupalate at this point? That's very, very good. So it was like half, I think maybe more than half the hands, which is actually, that's a really good audience. If you haven't, I'm not gonna leave you behind either. We'll cover the whole basis. So we're gonna create a page. So we need three steps, module, route and controller. And we're gonna go do all three as indicated by the empty checkboxes. So step one, making a module, pretty simple. Even if you haven't done a second of Drupalate, you'd be like, yeah, that looks familiar, cool. So the top is cutting off barely. That's the modules directory on top. And then I'm creating a module called dino underscore roar. Cause pretty much everything we do in my world, we just somehow work a dinosaur into. So dino roar and then we enable it, which you can do apparently with Drush or on your web interface, or probably hack into the database if you're feeling particularly brave. And then we're done. So let's get into the interesting stuff, a route. So a page is always these two parts. People that have done some stuff with Drupalate are like, yes, route and controller. So we're gonna create a route and a controller. It's always just those two ingredients to create a page. So step one is gonna be the route. So when you have a module in Drupalate, you can always have the module name dot routing dot yml. And then this is gonna be red. The route is only two parts. You'll see more kind of fanciest things added to a route in Drupalate. But you wanna focus on the path, which is the URL to your page. So hook menu, right? Looks familiar. And then the second part is going to be the function that builds that page. And probably most or all of you have heard the word controller before. And I like to say controller is a fancy word for a function that builds your page. So you have the path. And then we have this underscore controller key, just the way that you indicate what functions going to build your page. So that's it for the route. So step one is we created this route. It's got the path. It's got the name to that function. Oh, by the way, I should say, and I realize that that greenish yellow is maybe hard to read in the back. The underscore controller is a class name, full class name, colon, colon, and then a method name. And it can be, well, not exactly anything you want, but it's class name, colon, colon, a method name. So it's kind of a name of a function. So route, check, controller. So we open up our controller and then we just build our page. There's two things I want to highlight that are important here. One is that the path is we're inside of our module, so dino underscore roar, and then you create an SRC directory, then a container directory, then our roar controller dot php, just because that's, I called my class roar controller in the previous thing. And then two important things to highlight here are one, whenever you create a class and a module in Drupal 8, you will always have a namespace that starts with Drupal and then the name of your module. It's just a rule. There's a reason for it related to auto loading, but you always start with Drupal and then the module name. And then after that, it's just whatever directories you want. So I decided, because it's a standard, to create a controller directory, and so therefore I have Drupal slash dino roar, my module name, slash controller. And if I created like three more directories deep, I would just add more namespaces. So your namespace has to match your directory structure. So that's thing number one that's important. Thing number two that's important is that our Java's developers is always just to create and return a response. So like imagine we're all Java developers, a request comes into our server, we create a response. That's just the basics of the web, and it's no different than symphony or Drupal 8 or anything else. So this function here, this roar function that builds our page, its job is to create a symphony response object and return it. So I'm gonna break this rule later, but your controller always creates and returns a response object. And the response object is pretty simple. It's just the text you want, and then you can set headers on it. But basically it's just the content that you want for your page. So route check, controller check. And there's our beautiful page. You guys like my styling skills? There's no other HTML behind that. I return the response roar. That's literally just the words roar on the page. It didn't get wrapped in any way by a layout or anything like that. There's no theming going on or anything magic behind the scenes. It's really straightforward. So then really Drupal 8 is kind of this structure. We talk about Drupal 8 as a framework. It's really a routing controller framework. We start with the request, then it goes to the routing. The routing calls the controller, which we write, we build the function in the controller, and then we return the response from the controller, and that's it. So it's a routing controller framework. I use the same slide, by the way, some of you guys have seen me speak before. I use the same slide to describe the symphony framework and also the Sylex Micro framework because they all have this fundamental thing exactly in common. All right, so there's actually one other small little detail. And if you've done Drupal 8 a little bit, you've probably seen this. I changed the path here to be slash the slash dino slash says slash curly brace count curly brace. So that's the way you do wild cards. This would match the dino says slash anything, 10, 15, foo, whatever you want. So you can do that in a route, okay? Not dissimilar from the way you could do that something like that in Drupal 7, except it has a name, curly brace count. The important part, which is gonna be even more important later, is that this maps as an argument to your controller function. So the fact that I have a curly brace count means that in my controller function, I have a dollar sign count. And that's really, really handy, but for what we wanna do today, really important, because we're gonna circle back to what's causing that a couple of times. Cool, so we have our basic page and the whole goal of this is to be like, okay, but how does that work behind the scenes? What's actually going on to make that flow? So we're gonna put a couple debugging tools in and Drupal 8 has some really amazing ones already. So the idea is, this is another thing I really like about Drupal 8, every single page, whether it's some random admin interface, has a route and a controller that fuels it. That's no different than a route and a controller that we build. So if you can find the route and controller for some random page, you can just open up that route and controller and see how some random core Drupal 8 page's working if you want to. So could we get a list of all these routes? Because we know there are a lot of admin interfaces and if they all have routes, can we get a big list of them? Well, there's actually a couple different ways to do that. One, how many people have seen Drupal Console project at this point? Okay, cool. There was like a quarter or a third, so I'm happy that a lot of you guys are gonna see this. This is a command line tool, so you install it once. It's kind of like, well, it's like Drush, but it has kind of a slightly different aim, more kind of debugging and code generation. But if you know Drush, command line tool, this gives you a command line tool called Drupal. And one of the things that you can do with it, among many, is a command called router colon debug, and it just prints all of the routes in the system. So you can't see it's cut off slightly on top, but I'm actually counting all of them. There's 339 routes in a kind of standard Drupal 8 beta 10 installation. And if you run it just by itself, it's just gonna print all of those. And you can just like run down there and basically see, hey, when I'm at this URL, here's the route that it is. And by the way, the thing on the left is the machine name for the route. So every route has kind of an internal machine name that you use to refer to it. So if we wanted to, let's say that we kind of inherited a project and we realized we had this dyno page and we didn't know what was fueling that. We're like, what code is causing this page to happen? We could go in here and just run router debug, pipe that through grep for slash dyno. And it tells me, hey, there's a route whose machine name is dyno underscore says. And then if I run it again with router debug in that route name, that machine name, it's gonna give me all the information about that route, including the most important part, of course, that your controller is this Drupal dyno roar controller, roar controller, colon, colon, roar. So you're like, yes, that's the function that's building my page. I'm gonna go open that up and do whatever work I need to do. So let's actually go up one level from this. So this is awesome. Can we get something like this on the web? How many people have seen the web profiler for Drupal 8? Even less hands, okay. Even better. That's why I've become to these conferences. By the way, I take no credit for any of this except being the guy that happens to be in front of you today telling you about them. I do none of the work on these projects other than, I guess, evangelizing them because I think they're amazing. So the web profiler is a contrib module and you can, is Luca in the room? No, I know he's here because I stalked him on Drupal.org last night and saw that it says he's at this conference. Anyways, he is the main guy behind this so you can thank him. All of his handle up later as well. So it's just a normal module so you download it like you normally do. It has two dependencies on two random JavaScript files that you need to put inside that directory but it's just a normal module. So that's the only reason I have this slide up is it's nothing special at all and then using your favorite method of enabling modules, you enable that module. That Drupal thing I was just talking about actually has a way to enable modules. So there's just kind of showing that off here but nothing special at all. And as soon as you do that, every single page that you load in the site gets this magical little bar along the bottom. Well, every single HTML page. This will not be on your JSON pages. You're welcome. And this has some incredible stuff. Probably most importantly, if you hover over the little 200, hopefully it's a 200 status code, if you hover over the 200, it tells you the controller and the route for this page that you're on right now. So you can surf through a page and be like what's the controller that fuels this page right there. I also have, I'm not gonna talk about everything because it has a million things. I also has database queries. So you can see how many database queries are on your page and as you'll see in a second, you'll be able to see what those database queries actually are. When you install this, for a good time, click all of the pretty check boxes. It actually has a whole bunch of things it collects. Not all of these are checked by default. So if you really wanna figure out how things are working, open up the settings and make sure you check all the boxes. All right, cool. So from this screen, which is the same I showed a second ago, you can click almost any of those icons on the bottom and it will take you to another screen called the Profiler. And the Profiler's like the web debug toolbar, done crazily. It's like a hundred times more information. Along the left you have all these tabs that just show you different information. This happens to be the one for the database. Shows you all the queries and you can even sort it by who was making those queries so you can figure out where they're coming from. But what I'm really interested in is a couple of things. One, this is another way to see your routes. So it has a routing tab and it's like here's all the routes in your system. So similar to what we saw in the command line a second ago. This is one of the most important things in my opinion that you can have in symphony or Drupal because we have this in symphony as well. This is the timeline. This is everything that's happening between request and response including how long they're taking. The purpose of this is for profiling. So you can figure out why things are slow but it has a secondary thing which is you can see what's actually happening like what are the magical layers that are causing things to happen between your request and your response. These are, I know these are really small. These are class names. So you can be like, oh, up in the beginning there's something called an Ajax subscriber. Like, I wonder what that's doing? Boom, open it up and find out. One of the rules with sort of this modern object-oriented PHP development is that a class name is always in a file of the same name. So you can, if you see Ajax subscriber up there and wanna look up to that, look that up. Just if you have some, a lot of editors have hot key shortcuts just to look for Ajax subscriber.php. That's gonna be your file that holds that class. So I do that all the time. So we're gonna come back to this but it's really, really, I mean, this is amazingly important. So kind of like we were saying, let's, I wanna dive in. Honestly, this is how I approached Drupal 8 as an outside error. I was like, I wanna see how these things actually work behind the scenes. So let's say we go to slash admin slash structure. You know, like the main structure link on the admin bar. How does that page actually work? Well, it turns out, as promised, you go there, web debug toolbar on the bottom and it tells you the exact controller that runs that. So you can open up that controller. The class is called system controller. So again, systemcontroller.php would be the file if you were the type that likes to open up things and see what's going on inside. You can open that guy up and actually see what's going on behind the scenes. All right. So we have kind of this route controller flow and like, I'm gonna talk about services in the container for like 30 seconds because other people are talking about them but they're so fundamentally important have to at least mention them. So you'll hear the word service a lot and if you haven't already been told this by me or somebody else, a service is a fancy name for a useful object. Like, if I give you an object that makes database queries like a connection object, that's a service and that's basically it. So when you see that word, it's like, that's a useful object. In Drupal 8, it's just, Drupal 8's basically made up of useful objects. So every job that you do in Drupal is actually some object that does that. For example, in Drupal 7, when you wanted to translate something, there was a function, T. In Drupal 8, there's an object called string language translator, I think. It's actually just an object. So if you wanna translate something, it's all about getting that object and then calling a method on it. So it's the same basic idea but there's all these useful objects. There's also shortcut methods so you'll still see that T method all over the place but it's just going out to that useful object in reality. So Drupal's made of these useful objects that are floating around. And then the container is just a place to put them in. There's more to it than that but you'll see the service container, dependency injection container thing. It's basically a big bucket, almost like an associative array that holds all of your useful objects. Every object in there has a nickname. You'll see that in a second, like a little machine name. So if you wanna get an object out of the container, you just ask for it by its machine name, like give me the string translator or the language translator, I can't remember what it's called and it gives you that object back. So in Drupal 8, what is Drupal 8? Drupal 8 is really just a bunch of these useful objects so that service container comes populated with a whole bunch of them and you can see them again on another tab inside of that profiler. So this is the services or the container tab on that profiler and there's 485 as of today services that are in the container. And these are basically, this is amazing because these are basically tools. And if you go in here, you can see what tools you have available to you. And you can see the nickname on the left there like there's one called access underscore check.csrf. So if you need it for some reason to actually check CSRF protection manually, that's the object that you're going to wanna get out of the container. And then really important again, if for debugging, well not debugging, is that my goal of this is to take you guys kind of a step deeper than you might normally need to go to figure out how things are going. So there's a file. So all of these services that are in that container are defined somewhere. And for the most part, like all the core services are defined in one big file, which makes them really easy to look at. And it's, can't see up there, but it's the, yeah, just core. It's core slash core.services.yml. It's this big long file that just shows you all of those services and all the classes that are behind those services. So for example here, there's a service called state, which is kind of like a nice little key value store thing. So if I give you, its nickname is literally states. If I give you the service container, you can ask for the service whose ID is state and it will return you this object. And then you can use that object. So if you wanted to set something, nice little key value store from a controller, it's just a matter of asking for the state service and then calling whatever methods are on that object. All right, so we've gone like one slight level up. We saw this request controller response type of thing, but now I just want you to realize there's this container floating around full of useful objects. And really whenever you do anything, whenever you get any work done, it's actually being done by a service inside of that container. So even as we'll see later, like the whole theming layer is just like, there's services in the container that are actually taking care of that theming layer. All right, so events. So we're gonna go up one slight level above here. So just like with hooks, Drupalight also has something called events. And if you're not familiar with them, just think of them, they have the exact same purpose. It's a different pattern on accomplishing the same thing where when something happens in core, you want to have some way to hook into that process. So it's done a little bit different, but it's the same exact thing. And for the most part, and I could be a little wrong about this. For the most part, I believe most of the hooks in Drupal 7 are still hooks. They're just now a few additional events. So the hook system hasn't been replaced by the event system. We're just putting, starting to put more stuff into events. All right, so a little bit unlike hooks, at least from what I've seen are about getting something done, like hook menu is about like, hey, we're building the menu. The kind of core events in Drupal are more about timing. It's about like, hey, as we're going through this request response process, if you want to hook really early into the process, the event that you want to kind of listen to, that you want to attach to, is called kernel.request. It's just early, so it's about timing. The last one is called kernel.response. So if you want to do something like way at the end of the request response flow, that's what you're going to actually hook into. I'm not going to go specifically into how you do that, but just know, just like hooks, it's about basically creating a function, and then there's a mechanism to tell core, I want you to call this function when the kernel.response event happens. So call me at the end of the request response flow. Cool, and one of the questions I've gotten already at this conference repeatedly is can I see what listeners there are to those events? Because that's the problem with hooks and events. It allows you to have this nice decoupled code in a sense, but you have no idea what's going on. You're like, whoa, wait, but what listeners are there to this? Like, and what are they actually doing? So the web profiler has that as well. There's an events tab, and this is massively important because if something magical is happening, there's about an 80% chance that it's happening because of a listener. So you can go here and actually see what the listeners are. So almost that entire screen there are kernel.request. That's the first one. So those are listeners that are happening at the very beginning of the request, so before our controller is called. So when I first went into Drupal 8 to see how it worked, I basically went here and just started opening up these classes. I was like, well, what does this do? Well, what does this do? So we have the container floating around, and we have these events happening, okay? So I'm gonna go back to this page here. So I'm back on my page that says the slash dino slash says slash 10, or whatever wild card number I wanted to put there, because remember the URL in this had the little curly brace count thing at the end of it. Oh, yeah. And one problem with this page is because this is not a full HTML page, I don't have my cute little web debug toolbar anymore. Want, want. No more debugging tools. And this is the same if you had a JSON response. You're not going to have a web debug toolbar. And that is the end of my presentation. I'm kidding. No, there's a way around this. If you go to the profiler for any other request, there's a link on the top that says view last 10, which takes you to basically a search. Because as you request, by the way, this is of course only happening in like in dev mode, or where, I guess, where you have your web profiler enabled. So as you're making requests that web profile is collecting information, it's storing it in the database. So it's not just a one and done thing, it actually keeps track of all those. So you can go here and actually, I can actually find the profiler for that request even though it didn't have the web debug toolbar. Again, this is really important if you're building an API and you're hitting the endpoint, and you're like, oh, something broke or something, and I want to see more information about what happened. So I click into there, and there's a tab called request. And in the request, it has something right at the top called request attributes, which is one of the more important ideas in Drupal 8 if you are trying to understand things at a deeper level. If you're not, you may not ever really realize this is happening, but again, we're sitting here, so I'm gonna get us down one level deeper. So one thing to notice here in the request attributes, so I'm gonna put my route back up there, is that in my route path, I had a curly brace count curly brace wild card. That goes into my request attributes. I have a count down there whose value is 10 because 10 was what was in the URL. So far, I want you to know that these request attribute thingies exist, but you should not be making a connection about why that's important. Just know that they exist, and they're populated from the routing. Another key that's in there is the underscore controller. So more broadly, anything that you put under the defaults key in your route ends up in your request attributes. Again, why do you care that it's in the request attributes? We don't have that piece yet, but the routing puts stuff into the request attributes. There's also a couple of other things, and this is gonna be important. Drupal actually is going to put other things into the request attributes. So we have something down there called the route object, and another thing called access result, which is kind of like something that keeps track of whether or not you should be denied access to this page or not. So actually, all right, so why is this important? Well, it turns out that, remember we had curly brace count in our route, and that past $2 count is an argument to our controller. Turns out what really happens is that the curly braces in your route become request attributes, as well as anything under that defaults key become request attributes. Anything in your request attributes can become an argument. So it's actually two steps behind the scenes. So the fact that I have a count request attribute there means I can have a dollar sign count. Or, I mean, not even thinking about how these, or caring about how these are populated, the fact that I have a underscore route and an underscore access underscore result, request attribute means I can have those as arguments to my controller. So this, the request attributes, is actually the thing that feeds arguments into our controller. And just to kind of like drive that point home, the, well there's actually two, but there's basically one extra thing that can become an argument to your controller. So basically if you put something as an argument to your controller that is not in the request attributes, you're gonna get a huge exception. It's like, dude, I'm trying to help you out, but you gotta meet me halfway. I don't know where you got the idea that you could have a foobar variable to your argument to your controller. So normally that's just gonna blow up. The one exception is the request object, because sometimes in your controller it's convenient to be able to get the request, maybe because you need to read query parameters. So the one exception of the rule is you can have a request argument, as long as it's type hinted, so the capital R request, with symphonies request class. That's a way of kind of signaling to the core that like this argument's request object. And once you've done that, as one of the highlight, another way to get that count curly brace thing is actually to say request attributes get count. So that's how you get those request attributes. Again, not that you would do this, but I want to take this a level deeper here and be like it's these request attribute thingies that are actually important. Now real quick, the request object is really, really simple object. You guys are gonna use it in reality in your code to get information off the request, like headers, query parameters, cookies, things like that. The request object has a number of public properties and they're forgetting things like that. So if you want to get a header, like I don't even know, an accept header off of the request, then you can say request arrow headers arrow get and then you pass it the argument accept. So there's a bunch of public properties that deal with real HTTP request kind of stuff. The one oddball is attributes. You can see it says attributes no equivalent. Attributes is like one random spot where we just kind of like shove things into the request that are specific to our application. And again, the importance in reality in Drupal 8 of that request attributes is those become the arguments to your controller. All right, so the one thing added here now is we sort of know that the arguments to our controller are actually populated via this request arrow attributes. And kind of where I'm going with this, as far as understanding how the core works, is that so far the only thing that we know that really puts things into request attributes is the routing layer. When routing runs, any curly brace things or any things under the defaults key of our route go into request attributes. But there's nothing stopping any listener, so any hook, to the kernel.request event or the kernel.controller event, because those both happen before the controller. There's nothing stopping any of those functions from adding more stuff to the request attributes. So it's not, the routing's not the only way that we can get stuff in there. And an example of that is the upcasting of nodes. How many people know what I'm talking about with upcasting of nodes? Maybe because I'm calling it the wrong thing. But I think that's what the terminology is. So what I have here is I have another page and it's URL is the slash dino slash curly brace node. And it points to another controller method called in my roar controller called node. So far this is basically, it's really simple just like the last route I made. And inside of my controller, because I have curly brace node, I'm past dollar sign node, simple. And that's just the node ID. So whatever's in my URL, there's no magic at all happening right here. And then I'm just printing out the node is five or whatever I put in my URL. Cool, totally straightforward. If I go into my request attributes thing, I see that. I see node is one. And so that's what value is being passed as an argument. All right, so, but we can actually make this a little bit more interesting. If you take that route and you add an options key on the bottom and by the way, there's gonna be an easier way to do this in a second. But this is actually what's happening behind the scenes. You had an options parameters key and then below that I have node because of my curly brace is called node. So that's why that's called node down there. And below that I say type colon entity colon node. What I'm basically saying here is that I have an argument, I have a curly brace in my route called node and it's of type entity colon node. You're signaling to core that this is not just an ID, this is a entity type of node. So I want you to actually go like query for that and give it to me as an argument. So that's the only part that changed down in there is the kind of the options thing. You're kind of attaching more metadata to your route to signal to core what's going on with some of your curly brace parts of your route. And as soon as you do that, that node is now an object. It's not the node object inside of there. So I can call get title on it. Okay, this is called upcasting. You'll see why in a second. There's a layer inside of Drupal's core called param converters. And this is a layer where you can basically take any of your curly brace things in your route and really anything that's in your request attributes and change them before your controller is called. And so there's an existing one in there that does exactly what I just said. We're gonna say, hey, this argument here is actually an entity of this type. So go query for that for me and pass that object in. And what's cool about this is you can see this inside of core.services.yml. That's where all the services in. You can go in there and search for param converter. And I'm not gonna talk about what the tags thing is there. It's a little bit more advanced. But if you search for the tags of param converter, these are all of the classes that are responsible for doing that param conversion. These are all the things that may be changing your arguments to something else, like taking the node ID and turning it into a node arguments. Also in the web profiler, if you go to the services tab, they actually have one of their search boxes as you can search by tag. So you can actually see all of the things in the system, including maybe contrib modules that you've installed that might have a param converter like that. And this is gonna be a theme that you'll hear over and over again with Drupal 8. When you wanna get something done, like I wanna have a custom block plugin or I wanna have a custom param converter, the way you're gonna do that is you're going to create a class and it's gonna implement an interface. So in the case of a param converter, if you wanna create your own, you just create a class in your module and you have implement param converter interface. And the interface there is pretty simple, like the important method there is called convert. And it basically passes you like the argument node and says you can change this if you want to. And that would be your opportunity, for example, to maybe query for that. I mean, that's already done in core, but you can do whatever you want in there and then change those arguments and upcast them or whatever you want. And then you'd register this as a service and give it that same param converter tag. Ah, yeah, yeah. And if you do this, the first argument to convert is the value, like 10, because maybe that's the value of the argument. The second thing there is definition, so it's gonna get past anything that you've kinda put in your route there. So you could randomly, this is a little bit more advanced, I realize, and you're not necessarily gonna do this. It's more of like, I want you guys to understand what's going on in core. You guys could, instead of type, colon, entity, colon, node, you could put whatever other random information you want there on a route and then have your custom param converter read that information off the route and do something different to change one of your arguments. All right, cool. So same things we have before, but now we have this idea of param converter. So we have, like, going back to that simple request controller thing, we have this, you know, our routing ran, it called our controller and it passed in any curly braces as arguments. And it's still true, but we now have the opportunity to maybe change what those arguments are, like change one to the node object that represents node number one. All right, so I promised there was an easier way to do this, and there is. So this is that same route before, but it took off that ugly options thing. And this is the way you're actually gonna see it done most of the time inside of Drupal 8. This is why it's called upcasting because you can take an argument like that, like node, and type int it, so with, well, entity interface, or you could type in with node, whatever your actual class is for your entity type. And that's gonna give that same signal as we had in our route before. So the same param converter system, instead of reading those options from the route and saying you want a node, it's gonna actually look at the type int there and say, oh, it looks like you want a node or whatever other type of thing, it's gonna query for that for you. So this is the same end result. All right, the render array. Which I think the render array has kind of a bad connotation in Drupal. I see the render array, but we're like, oh, yeah. I think it's kind of fun. Kind of returning an array with a bunch of stuff. I mean, the hashtags are a little weird, but I think it's kind of a cool thing. Anyways, how the heck does that work? So we're gonna take that same controller because now we're being passed the node object. Next, you can see I changed my type int from entity interface to node because I know it's gonna be a node you can use either. Now I'm gonna return my nice little render array with hashtag title and here's me, Symphony guy doing some Drupal stuff. I don't totally understand everything, but I know I can do this, which is cool. And when I go, instead of getting just like the words on the top of the screen, I'm all of a sudden decorated inside of my theme and my content shows up in the middle of the page. Yes, so you guys all understand this. In fact, way better than I do. But how does that work? Because it shouldn't work because your controller should always return a response. So who the heck created the response here? We have to create a response. Returning an array is not sufficient enough inside of Drupal or Symphony framework to actually send that back to the user. So somebody did that. The answer is, because when it's magic, it's probably an event listener, and web profiler even tells us what event listeners we have, which is awesome. It's an event listener, and it happens to be an event listener on kernel.view, which is the first event that happens after your controller is executed. So if you go into your timeline, this is just a little bit of the timeline, so let's say I'm debugging this, I refresh, I click into my timeline, there's part of the timeline, and see the first big dark bar there is, if you look to the left, the small text there is kernel.view. That's actually telling you how long all of the listeners for the kernel.view event are taking. And below that, you can see all of the listeners for the kernel.view event. In particular, the one giant green bar right below it is for a class called main content view subscriber. So there's the kernel.view event there, and then main content view subscriber. So already you'd be like, hmm, okay, what's this main content view subscriber thing doing there? So the main content view subscriber is actually the thing that takes care of the render array. And it does that by turning your array into a response, which I'll show in a second, based on the format, because of course we have HTML, but we also have JSON, and there's some Ajax and Modely type of things too inside of there. It's a couple different formats. And it does this with something called, so before I talked about the param converter system, this is called the render dot main content renderer system. It's not quite as short as the other one. And it's kind of the same thing. So that listener I just said, you could actually open up that class, and what you would see it doing is actually looking at what format the client wants. Does the client want an HTML format, or do they want a JSON format? And then offloading the work to another class. And this is, again, this is back in core.services.yml. You can see this class here has a tag for render dot main content renderer with a format of HTML. Again, if you're not familiar with tags, don't worry about the details here. What I wanna highlight is you can actually go into this core.services.yml file, search for render dot main content renderer, and you'll see a class that takes care of the render array for all of your formats. So there's one here for HTML, there's another one for Ajax, and there's like two or three other ones for other formats. So now I know this class here is the HTML renderer. This is actually the guy when we're rendering a whole page which takes care of the render array. And if you open it up, this is just obviously a massive summary. It's exactly what we expect. It basically somehow generates some HTML, and ultimately it creates that response. So the point of this is like, our job is always to create a response. We can do it in the controller. I could basically use Drupal 8 without using any of the CMS features. I would just always return a response from my controller. Be like, done. No thank you theming layer. I just don't need you in this case. But if you do return an array, then it offloads to this layer, but ultimately it always returns that same, like it always returns a symphony response object back to, well, by the end of it. Oh, and I wanna highlight again, to go into the interface thing. I think you guys are gonna dig interfaces the way they're used. If you wanted to have your own main content renderer for some other format, I think with the serializer and REST modules, there are other ways to do this. But you see this implements main content render interface, so you can create your own class, implement this interface, and then just give it that same tag in the service container, and then maybe you make your formats, I don't even know, like, well, simple example, you make your format JSON, and then basically if the client is requesting JSON, your class is gonna be called when you return a render array instead of this guy being called. So you can plug into this system, and that's a big theme of Drupal 8. It's almost not even on purpose, just the way that Drupal 8 is built, like everything can be plugged into. You can even unplug stuff, so that's, you're probably doing stuff you shouldn't, but technically you can even replace this class entirely with your own. You're like, no thank you, I'm gonna do it myself. All right, so the one thing we've added here now are as content renderers. So if you don't return a response from your controller, which you are totally welcome to always return a response from your controller, there's one last thing here called the content renderer system, which is actually gonna turn your render array into the response. So this, well, let me say it this way. Drupal 8, like Drupal 7, there are a lot of layers. And even though, okay, I realize I'm talking beyond what I can say here, but me going into Drupal 8, there are a massive amount of tools that I can use to actually dive in and be like, yes, but how does that work? Probably more than Drupal 7, I'm guessing, just because the tools that I've shown you are like are so powerful. So let me give you like one last quick example here of Ryan being like, yeah, but how does that work? Cause I don't, that doesn't make sense to me. So a route, every page is a route in a controller. This route does not have a controller. Dun, dun, dun. So it shouldn't work, but it does work. Instead it has underscore form and you should kind of recognize this even if you haven't done Drupal stuff yet. This is gonna render that form instead of actually, you know, it's gonna render a form. So, but how does that work? Cause you need to have an underscore controller, always. Cause there needs to be some function that builds your page. Well, like all magic inside of symphony or Drupal, turns out it's a listener. And you can actually see this if you go into your timeline or your events tab of your profiler. You can actually see there's a listener called content controller subscriber, which is one of the simplest listeners you'll see. It's called early on inside of the request response flow. It says, hey, if request attributes, because remember everything in the defaults array of a route becomes a request attribute. If request attributes has underscore form, then just set underscore controller to be this controller right there. And that's it. So it's like, there's a little bit of magic there. Not really. In fact, there's a core issue on this. They were discussing, it's a little weird to have underscore controller in most places, but then underscore form without an underscore controller other places. You know, and they're like, maybe we should just make it consistent and always have underscore controller. Well, it turns out if you do that in this case, you just have to have more in your route. Cause then you have to have this underscore controller key and you have to have an underscore form key. So this is kind of almost like a little usability developer experience thing. We're like, we'll just make them have underscore form. But in reality, we all know that there's still an underscore controller going on behind the scenes. And if you follow this through, it's not quite this simple, but if you follow this through and actually opened up that controller function, you would see it using the underscore form argument. Cause that really is the purpose. The underscore form argument still is important. It's going to use that inside of this controller to figure out what form you want to render. So man, you guys, like, for me, Drupalate is fun because I have all these massively amazing tools. In fact, a lot of these tools are based off of things that are in the symphony world, but in some ways they're actually already better than the things that we have in the symphony world. So thing number one, try out this Drupal console. So this is drupalconsole.org. I'll have a link on the end in a second. Second thing, profiler, please try out the profiler. Cannot believe how much amazing work has been put into this thing. On there, like the things I want you guys to look at are the events tab. Cause that's going to show you all of the magic things that go on behind the scenes. And there are more than the events that I showed you. So down in this list, it's going to show you all of the events. Even if an event wasn't called, cause some events don't always happen, the ones I showed you happen on every request response. But sometimes events only happen sometimes. At the bottom of this list, it tells you which events weren't called and which listeners are attached to those. And one really important family of events are the router events. So Drupal loads your routes only every time it needs to actually rebuild the cache. So on a request response cycle, all of the routing stuff, the routing loading stuff, doesn't happen. So you'll see those down at the bottom as the not called listeners. But if you are kind of hooking into figuring out how the routing process or how routes are loaded, those are massively important. And in fact, there are hooks. I think it's called something like Route Alter, kind of like probably hook menu alter, that you can hook into to actually modify the routes when they're coming into the system. But again, that only happens when you actually need to do it once when you're building the cache. So the events tab, the timeline tab, massively, massively important to understand things. The services tab, this is actually the one I'm jealous about because you can search it and there's the tags, search box over there if you wanna search by tags. And then, and this is probably the one that will go mostly unnoticed by most Drupal developers so you guys can kind of pass it along. The request tab and the request attributes. Because even if you don't fully understand the param converters and the upcasting and that kind of stuff, you make a page and then go here, these are the things that you can have as arguments to your controller. Even if you're not sure how your node ID became a node object, you can go here and be like, yes, I can use these things. And then the last thing is the core.services.yml. As you get more, especially when you get more into the service dependency injection container kind of stuff, I didn't talk about it too much here. This is massively, massively important. And then to go beyond this, every time you open a module, you'll see a module name.services.yml and you can see what extra stuff it's actually adding inside of there. So this is what we ended up with here. But I'm gonna scoot a few things out of there. I want us to remember that ultimately, this is really what's important. We have a routing controller framework. And there are hook points in between there. But that's all it is. We're gonna have a route. It's gonna call controller. That controller is gonna return a response. Or in the case of the render array, we return an array and there's one little extra layer that returns that response. But it's just this. We just have a container of services flowing around. So when you guys think about Drupal 8 and how things are working, like keep this in mind, look at the timeline with this in mind because you'll see those events happening there. You can start opening up the listeners and figuring out what the heck's going on behind the scenes. All right, so thank you guys very much. And also if you get a chance to tweet at those guys, thank those guys. And there are those links down at the bottom for that. So thank you guys very much. All right, who has questions? Yeah, good question. Yeah, he said the count curly brace thing. Can you kind of force that to be an integer? Yeah, it's a, there's a key in most routes you'll see called requirements. And Drupal uses the requirements key usually for permissions. So you see like an underscore permissions key into there. But the real purpose of the requirements in the routes is actually for that. So under requirements, you'd have, maybe you still have permissions. And under that you have ID. And then what you pass it is a, the inside of a regular expression. So in that case, slash D plus, a digit of any length. Very good question. And kind of corollary to that, because this is when it becomes important. Route, routes match from top to bottom. So if you have two routes that have the same pattern, first one will win. So usually you don't necessarily care about forcing something to be a digit. For example, if you didn't force something to be a digit and somebody passes a string, kind of worst case scenario, that means you're just gonna be querying the database for an ID that matches a string and it's not gonna be found and they'll 404. So it might not really matter that much to do the, make sure that node is an ID or that counts an ID, or sorry, it is an integer. But if you have two routes that would match otherwise. Like for example, we have like slash, slash blog slash curly brace ID. And then you have slash blog slash, and actually slash blog slash slug, which is gonna be like a string, like slash blog slash hello world. But then you also have slash blog slash curly brace page. So it's like, hey, if you go to slash blog slash hello world, that's, you're viewing one. If you go to slash blog slash two, that's page two of the blog list. In that case, you'd actually need to do, well there's two ways to do it, but doing a requirement so it makes sure that they, one only matches IDs and the other matches everything else. So I'm sorry, long answer to your question. Yep, question? Yeah, in Drupal 7 and before routes were sort of uncomfortably mashed in with menus. So now that it seems to be decoupled, where are the menus defined? I actually do not know the answer to that. So the question was the routes in Drupal 7 were uncomfortably tight to the menus, hook menu, that kind of stuff. And they're not now, so like, where is the menu kind of stuff? Yep. Cool, separate YAML file called menu links YAML. So I'm guessing like module name dot menu links dot YAML. Awesome. And then I'm guessing, cause I've actually seen that now that you mentioned it, you're, I believe you're referencing the route names. Yeah, so when you make a menu, you're like it's that route name, that machine name that I gave the route, that's how you reference it. Yep, another question? Yeah, so using the routing to define where the controller is to build something new, that kind of makes sense. But if I wanna jack into an existing, like a form alter or a node presaver or something, is that still using the old hook system, like in a dot module file, or do we still use a controller and tie into the new event system? Yeah, most, and people can correct me if I'm wrong, but most, my impression is most hooks are still hooks. And so that hasn't changed much, like the, maybe the file name that you put that hook into like changed slightly, but basically like those old hooks are still new hooks. They're not, at least mostly aren't converted over to the new system. Do you have an addendum to that? Yeah, exactly. You're talking about the new events? Yeah, yeah, so the one difference, the question is kind of like, do you have to, the new events, do you have to kind of like hook them into the correct listener? So the big difference between hooks and events is that hooks were done by the function name. So the core, the core when Drupal boots doesn't know what hooks are listening to anything. It just, once a hook actually happens, it just iterates over all the modules calling function exists, function exists, function exists. So the difference between that and events you make the function, and the function can be called anything, but there's an extra step to tell the core of Drupal this function listens to this event. So call my function foobar when kernel.request event, that's the name of the event, happens. So you plug everything into the center, into the core. The advantage of that, I mean one advantage of that is that it means your core, like the core of Drupal, it knows at all times basically when it starts to boot, it knows all listeners to all events, which gives you the ability to have the nice like events web profiler tab. Cause it's just like, hey, everyone had to pre-register all their listeners with me, so I can very easily just tell you exactly who's listening to what event. Go ahead. Do events have like a global scope or is there some kind of bubbling like you have in JavaScript and a way to prevent them from going up or catching them like that? Ask that again. Are you talking about something in the theming layer or are you talking about just like you said, first you said kind of global scope? Well, so I guess there's like theming events and then there's controller events. So I saw yesterday in a talk that yeah, the theming ones do have some kind of bubbling going on, like the ones from the field will go up to the node level. Yeah, I believe that's unique to the theming layer. I've seen some of the bubbling stuff actually in the, when I was looking at that HTML render, that class that showed at the end that does the HTML page for it, you can see the bubbling kind of stuff happening in there. So on the controller level, they're kind of like just free for all, like you have hooks? Yeah, yeah, yeah. It's on the controller level events. There's no like bubbling or this events related to that event or has a parent event. It's just probably, this might be wrong, but probably more like traditional non-theme hooks for Drupal 7, just like this module hooks into it and that module hooks into it. They don't really know or care that either of them are doing it. It's just kind of a flat field of events. There is a priority for events. Usually you don't care about that. Usually you're just like, hey, I want to listen to kernel.request because I need to do something really early on. Occasionally you're like, I need to happen before this other event or after this other event because maybe that event does something. So that happens sometimes. You'll see that in Drupal's core, if I remember correctly, one of the first listeners that's called on kernel.request is the authentication listener and they set that in core with a really high priority in case you register something with kernel.request, you'll have access to the authenticated user because they made sure that they had a really high priority. If you want to, I think you can even make an even higher priority, but you'd have to go out of your way to do that. So by default, you'll kind of end up where you want to. Yep. Oh boy. Yeah, it's asking a really good question. Asking about YAML files. If you're coming from Drupal 7 to Drupal 8, the YAML file stuff is just, I like you said, just like lots of colons and spaces. So I may not be the best person to ask because I've been using YAML, I feel like since before I was potty trained at this point because I've just been using it for so long. But YAML does come from, if you don't know, from an official YAML spec, just like a JSON spec. So there's an official YAML spec. You do get really nice errors with the YAML parser. So we will tell you when things go wrong. So I don't know of like a specific resource to go to. The thing I will tell you though is obviously, so like, I'll give you three tips to remember with it. One is, it is space oriented, which you probably saw. And with that, keep in mind that when you parse a YAML file, it always turns into a big array. So just keep them back in your mind. Like this is an array structure in reality. So when I go out to spaces, that's going to be inside of the array that I've indented myself from. So it is space oriented and you can actually use two or four spaces as long as you're consistent basically. So it's these spaces and it's like, ooh, you're now inside of that array. The second thing is don't use tabs. Most editors will correct that for you because they'll see that you have a YAML file and you'll hit tab and it'll put spaces for you. If you do use tabs, you'll get a very clear exception though because Symphony's YAML parser freaks out and tells you you have tabs in a certain thing. But that's thing number two. Thing number three is at the end of every line, you always have a colon. It's a key value pair with like, you know, key colon and then the value. So that's basically how those things work. The gotcha on there, which is kind of an odd gotcha, is it always has to be key colon and then at least one space and then the value. It's probably like the number one gotcha that would give you a weird error. You can even have, like I said, you have key colon, space, space, space, space, space, value, but it has to have key colon, a space and then a value. Oh, like why would you have one key versus another key? Very good question. So where do the keys come from? So as far as the YAML format, YAML doesn't care what keys you have. You know, you could just put anything you want. So it depends on who's parsing those keys. So in this case of the routing file, the thing that loads the routes is defining like what keys that you have. So whoever wrote that is saying, hmm, we should have a path key. Now the good news is most of the time, and if this isn't the case somewhere, this is always a good thing to kind of like make an issue to core that we can do a better job, most of the time those are validated. Most of the time the class that's loading that YAML file will see that you have a path key, a default key, a requirements key and then it'll see you have something else that it doesn't recognize and it should throw an exception to be like you said, you know, options expected these keys. In some cases in Symphony Core, because those classes are oftentimes shared between Drupal and Symphony, so it means we've had like years of getting them kind of tuned for those good acceptance meshes. Sometimes it'll even go as far as saying, you said options, did you mean options? Because how many people have used the Levenstein functions? I'm saying that correctly, Levenstein functions. There's a crazy, there's a hand in the back, yeah, there's a crazy function in PHP. It's from some algorithm where you can actually give a function two strings and it calculates the distance between those and so you can actually, inside of those classes, if you detect that you have something that's invalid, like if you're a core maintainer, you can actually then iterate over all of the valid keys and find out if any of them are very close to the one that the user typed and then say, did you mean options? Because you just typed options with two O's and Levenstein says those are awfully close. Yep, yeah, so is there a limit to the number of kind of arguments or curly brace wildcards you can put in the route and therefore arguments inside of your controller? There's no limit on those. You can put as many as you want. Couple important pieces of information and let me know if this satisfies kind of how this works with Drupal 7, is that order doesn't matter. So if you have like slash curly brace count, slash curly brace ID, you can have dollar sign count, dollar sign ID or dollar sign ID, dollar sign count. So it's all matching by name. So you can have whatever order you want. The curly brace things are required by default. So if you have a curly brace count, like slash hello slash curly brace count, as soon as you put that curly brace count on there, you can't go to slash hello anymore. If you just have one that's that slash hello, if that's the path, you can go to slash hello. As soon as you add that wildcard, it's required and you have to have a value for it. Unless you add something under your defaults key. So remember in defaults, you usually have underscore controller. You can also then say count colon five. As soon as you give that curly brace default value, then it's no longer required. You can go to slash hello, or you can go to slash hello slash curly brace count. Now, if you have multiple ones, like slash curly brace count slash curly brace ID, if you make count optional, it still has to be there because it's kind of in the middle there. So you'd still have that case have to say slash hello slash five slash something. So you can kind of play with those with the, what's that? Oh yeah, very good. Unless you made also the ID optional, then you could have neither of them. And if you even need more flexibility, there's nothing stopping you from creating a second controller with a totally different pattern that passes to the same exact controller. Because I need to move arguments around in some kind of weird way that I could never quite get the exact optional, non-optional thing. So second route, different manipulation of those orders, same controller. Yep, and then I gotta stop the last question here. Yeah, yeah, yeah. If that over your head, yeah, you could create two routes, one which is hello, which is slash hello, and another route which is slash hello slash curly brace ID. And never worry about wildcards. And you have two routes, one's slash hello, and the other one's slash hello with a required wildcard. Yep, very good. All right, I'm running late on my time now. So if you guys have more questions, like file means come up and we'll nerd out. Let me get out of the way. Thank you. Good, good, good. Yeah.