 All right, so just a second. Those are my notes. Don't look at that. Okay. We're already a little slow to start, but let's get going. Thanks for being here. It's great to see a full room. Let's get started. So my name is Robin Berry. I work at Palantir, and I'm a senior engineer and team lead. And Larry, why don't you introduce yourself? I'm Larry Garfields, senior architect at Palantir, and Drupal 8's web services initiative lead. So Robin and I work together on projects, lots of them. It's true. We're best buddies now. Okay, so here's our lab format. We're going to do short lectures and then hands-on exercises, and we're recommending, especially with this full room, that people pair up so that way you can help your neighbor. Larry and I will try and walk around the room and answer questions, but with this many people, try to help yourselves as best you can. And each other. Yes. Well, that's what I meant. Help each other. That's right. It's all about community, right? So let's move forward with that. So there are a couple of things that we're assuming you have a basic understanding of, and if you don't, you'll still survive this lab, but you should look them up. And one is PHP 5 introduces namespaces and interfaces, which is something you'll just want to know about for object-oriented programming. And there's also PSR 0, which is about to turn into PSR 4, which controls the directory structures we'll see in the modules. And a little flag for you where that's going to change. The core team was trying to get that fixed in time for this week, but didn't quite make it, so that'll probably change next week. It's easy, though. Don't worry. That's right. And if you want to learn more, you go to github.com.php-fig. Or php-fig.org. Great. Okay. Our goals. That you will learn how to create routes and controllers for requests. That you'll be able to define common module plugins. That you can store default module settings and configuration. That you know how to create pages, blocks, and have an understanding of state. And hopefully we inspire you to learn more about Drupal 8. The subjects we'll be covering today include the HTTP kernel, routing and controllers, basics of theming for module developers, dependency injection, forms and configuration, plugins, including annotations. And now to your setup. So our goal is that you already have Drupal 8 installed on your machine. Did everyone bring their stuffed animal? This was in the lab description. Your stuffed animal. We got one. Here we go. So the stuffed animal will become relevant when I describe the Drupal gachi module, which is what we're going to be working with today. So get your stuffed animal ready or imagine that you have one. And what we would want to do is install the Drupal gachi module in site-solve modules. Actually it's in slash modules. In Drupal 8. Oh my God, my mistake. Many things have changed in Drupal 8, including the slide. Where it says site-solve modules just do slash modules. We'll explain the directory structure in a little bit. Great. Thanks, Larry. Old habits. And so with the Drupal gachi module, if you do have access to their net, make sure you check out the branch labeled lab-01-initial. So that's our starting point. And we're going to go from branch to branch to see the completed code as we go through each exercise. So a little bit about our Drupal gachi module. I don't know, does anybody remember Tomagachi? They're little handheld devices. All right, I got a couple hands up there. So it was like this little digital device that came out in the 90s. And basically you had to care for this little device and to help them learn about Earth. They're an alien species. So we've created a module that basically has the same needs. You're going to name. And basically what it does is it turns your website into a little Tomagachi of sorts. So your website will have a name and it has a certain amount of happiness it would like to have and it achieves that by having the admin user, right, UID equals 1, visiting the site repeatedly. So when other people visit, it's not as excited. But when you go to your website, it's a happy Drupal gachi. So now I'm going to switch over to Larry and we'll get into some of the details about D8. Okay. So one of the important changes with Drupal 8 is that it's now built more around the way the web itself is designed to work. So most PHP 4 applications, including Drupal itself, were built on this model. Can people see this slides? Okay. Can't really make it larger here, but... I have no idea how. I don't know if I can zoom it. Sort of. Okay. So you have got... When PHP process starts, that's a bit better. PHP process starts, you have a bunch of superglobals that are created by the system for you. And stuff happens that is whatever your program is and you generate output by a mixture of calling header to set HTTP headers or most cases just printing stuff at random places. And you hope you get that in the right order. And you hope that you print strings that line up properly. And it involves a lot of hope. And I am all for hope, but not as a basis of software architecture. This is how HTTP actually works. Hypertext transfer protocol. Conceptually, a request comes in. A request is a concept unto itself. It's a message. And then your server does whatever black magic it's going to do and returns a response. Not a string, it returns a response. A response is, again, a message. It's an encapsulated message of some kind that includes more than just a blob of string. A blob of text. This model is closer to HTTP kernel. This is one of the most important parts of the symphony framework. This is the part that we pulled in first. And this is what really kicked off the major changes in Drupal 8. That the entire architecture is modeled on this idea of a request comes in, response goes out, and there's just a process by which you convert a request to a response. Everything in Drupal now is a request comes in, response goes out, and stuff happens in the middle. But everything comes down to that model. And it's a really very simple interface. This is the entirety of the HTTP kernel interface. That is the basis of any symphony using projects, which is about two dozen projects now, including Drupal. Very simply, you have a handled method, request comes in, and response goes out. You will almost never see this yourself. Yeah. It's kind of dark. It's blurry. Is that any better? I think that's about as good as it's going to get. Okay. So this is a very intimate session. That's why we're turning down the lights. Anyway, so you as a model developer will almost never deal with this interface directly, unless you're doing some really advanced wacky stuff. But I'm showing this to emphasize that this is the model around which the system is built. It's no longer built on a Supergobles come in, build up a bunch of PHP stuff, print stuff, and hope it all works out and model. It's no longer built on exactly this. This request object encapsulates all of the incoming HTTP information, the body, the path, the accept headers, the language headers, the HTTP method, and all those other things that have always been there, but have been really hard and annoying for us to get at. And that request is where you'll pull all that information from. And then the entire purpose of the Drupal process, the HTTP kernel process, is generate a response, which is, again, some kind of body, maybe, plus headers. And those headers could include things like language, content type, you know, HTTP 200 error, or 404, or 14, or various other things. There's a lot more here that you can do very easily. Specific, and you probably can't see that. You can't actually zoom with this slideshow tool I discovered. Sorry, can't really zoom it in. That's what I tried to do. I think, hang on. Stand by. Let's see if I can get this bigger. Can I help at all? That's kind of weird. Yeah, it's zooming in on this center. Oh, hang on. Reveal JS, yes. What's that? Option click. Can you zoom what you're doing? Trying to zoom, so people in the back can see. Stop doing that. Alright, undo. Undo. I'll see what we can do with that. Let's just try the option click. Hang on. No, we don't want to mirror it. No, we've got slides. Notes here. Can you undo whatever it was you just did? Yeah, just go back to the right. Yeah, I think the notes window here is now weird. Okay, I'll just click. Option click, you said? Yes. Control click? No? Okay, there we go. On the wrong window. I'm not sure if this is revealed doing it or not. Alright. Moving right along. So specifically, we're using the HTTP kernel implementation provided by Symphony itself. So the actual pipeline here is identical when using Symphony full stack or Sylex or a number of other projects. Request comes in and then an event fires called a request event. Events, simplest explanation, object oriented hooks. It's basically what they are. And the request event you can think of is kind of like a hook request alter. There's various things you can do there. The main one though is enhancing the request and gathering information from the system based on that request. That includes the routing process to decide what's going to handle this request. And that determines something called a controller. A controller is the more generic name for what we've traditionally called the page callback. So what we used to call page callbacks are now called controllers close enough. And so there's an event there. You'll pretty much never use the controller event yourself, but it's there. And then that controller gets called. The controller can be any PHP callable. So with hook menu, the page callback has to be a function. With the new model in Drupal 8, it technically can be a function, a method of an object, a static method of a class, an anonymous function, or various other things. In practice, it will 99.4% of the time be a method on an object. And that's where you're going to be putting your controller code. That controller, just any PHP callable, can return a number of things. It can return a response. Yeah, all right. The controller can return any number of things, one of which can be an HTTP response object. If it is, great. We just send that along. And then your controller is responsible for the entirety of the response that requests. You can bypass the entire theme system, the entire lock wrapping whatever, just return a response object, and you have complete control over what gets sent back. It's very useful if you want to have custom one-off pages, wrapping some other system, perhaps of various other things. If it's not a response, which actually most cases won't be, then there's another event called a view event. It can take whatever that is, and turn it into a response object. Most cases, again, you won't have to deal with this directly. It's there to take whatever it is you return, usually a render array or a string, and turn that into a page. Then there's a response event that happens in either case. Again, essentially hook response alter is conceptually what it is. And that's where you can set values if you want to. That's where we're going to be doing caching, cache control in Trooplate, because we're using HTTP to control our caching now. And then that response gets sent, and then there's a terminate event, which is essentially hook exit. Important things to note here, unless your controller actually invokes hooks, you can get through this entire pipeline without ever touching a hook. Everything can be purely objects and methods, no hooks, no procedural code at all. And that's a good thing, because that makes it way more testable. So let's talk about these controllers. So controllers, formally PHP or page callbacks. This is the simplest possible controller. So you have a method, your controller, that method gets called by the routing system, and you return a response that is the entire response from HTML tag to HTML tag. And that's what gets sent back. You have now bypassed all of Drupal, and you're just going to return the entire page. You have that level of control if you want it. In most cases, you don't actually want that, unless you're doing Ajax. In most cases, you can also put multiple methods in the same class, and this is good for code organization. So they could be in the same class or separate classes, to decide what organization makes sense for your module. I think most core modules right now just have one class and a bunch of short methods that may break out a bit more, but that level of flexibility is something you can change as needed. And you can return not just an HTML response, you can also return JSON responses. So in this case we have a blob of JSON data. We'll just pass it in. Instead of doing an exit, no, no, no. That's a first class supported concept now. So you just return the JSON response object, which is a subclass of response, and it takes care of all the HTTP headers for you. So this will get sent back with the correct headers, correct encoding, all that kind of stuff. You can also just return a string. If you return a string, we'll take that and wrap it up into a page for you. So, again, this is the same as in Drupal 7. If you return a string from a page callback, the string is the body of the page, and then it gets wrapped up with blocks and header and all that kind of fun stuff. Pretty much the same thing here. And the more common case, render arrays are sadly still with us. So in this case we say, you know, return an array that's pound theme, which is the name of some, the key of some Drupal theme, themeable chunk defined by hook theme, which is still there, dust hasn't really changed, and whatever variables go into that. So that's your common cases. The fun part is when you get to more esoterics. So for example, let's say you're returning a CSV file of some kind. So you're pulling data out of a database table. You want to return that as a CSV. Great, wonderful. Traditionally you would do that by building up a gigantic string yourself and returning it, and possibly blowing out your memory. Or by iterating and sending stuff on the fly, and then calling exit early and bypassing half of Drupal, that Drupal is not designed to be bypassed, which sucked. Instead, what you can now do is use this thing called stream response. And so you can set its header specifically. So I'm sending back text CSV. And then instead of setting a string as the body, we just pass in a callable, in this case an anonymous function. And then later on, once we get past that response event to the response, then this will get called and one by one spool out each line. All of that's taken care of for you. You don't have to think about what's my memory usage going to be. How do I avoid blowing out my memory? Do I need to exit early? You don't. You just don't think about that because you have clear APIs for handling all of that kind of stuff. Good common case of that. In Drupal 7, there is a function you call that's manually spooled the file off disk in chunks of one kilobyte to try to avoid blowing out memory, which is actually the slowest possible way to do it in PHP. In Drupal 8 and in symphony, we built that we is in Drupal built and committed upstream to symphony, this binary file response. So you just give it the name of a file and you're done. And that file will then get streamed off disk to the browser with all the correct headers, all the correct length encoding, all of that handled for you, you don't even have to think about it. In fact, if you're on if you know you're running on nginx or pat you with the right installed options, there's an even faster way to do it using the xsen file header for which there's native support again, written by Drupalers for symphony. So just stick this into your settings PHP on your production site and when you're serving files out, they will be as fast as humanly possible. It's straight off the metal. You can also set your status code so you can take the response object itself set enough alternate status code and you would know what HTTP204 is no one 204, no content which simply means we're going to send back a response there is no body, there's headers but no body what's a good use case for that? Cron, this is what Cron does right now is do whatever it's going to do for Cron and send back a message saying okay done and then you can do anything that HTTP can do, you can do which includes, we do support HTTP418, I'm a teapot this is an actual defined part of the HTTP spec and people say engineers don't have a sense of humor you can also do parameters so in Drupal 7, if you wanted to have parameters out of the path, then you would put a percent sign into your hook menu and then it would match up based on the order of those parameters order doesn't matter anymore instead, you simply specify to and from, these are variables that are in your route definition and you can also get the request itself if we don't ask for the request we don't get the request, we don't need it if we actually need it, we can grab it and then you do whatever we're going to do if we're going to do an error array do some processing on it, whatever makes sense the route definition for that is now in a YAML file so hook menu at the moment still exists is going to stop existing very soon hook menu in Drupal 7 was doing about 8 different things that had no business being in the same system and caused all kinds of problems for Drupal 8, we pulled it apart so the parts that actually relate to routing are now handled through a routing.yaml file so it's very easy to edit you don't even have to be a PHP developer to do so and then the other pieces we're not going to talk about as much today broken out to other systems and other files but for the moment so we've got this route which we're defining by it's a machine name not keyed by path because a route could match on path or on mine type or on method, various other things so you can actually now have the same path that are handled by different controllers that's how we're doing rest in Drupal 8 we can specify placeholders with brackets so from and to here but notice here we say from to here we say to from that doesn't matter it matches by name not by position so you can put them in whatever order you want it's not going to break and that's handled magically on the fly and we specify underscore content is this method of this class which means this is going to be a normal page the contents of which are this is the controller for that hello world method of this class this replaces the page callback key essentially for has a requirement user has to have the permission to access content and one nice feature here access callback access callback is not a single value anymore you can stack multiple access control options on the same route so if you want to say you have to have this permission or this other permission you can do that you want to say the user must match this complex situation so a custom checker there or have this override permission access all views or something like that you don't need to do a completely custom wrapper for that a lot more we could say about that and you can also restrict those placeholders by by regular expression so if you want to say this has to be an integer you can restrict it to that in this case we're saying they both have to be strings so if you go to slash hello slash world slash one slash two this won't match because you don't want to deal with numbers you want to deal with strings and with that let's get your hands dirty so this is the you can see that github.com slash Palantirnet slash Drupalgotchi or the USB key that's working its way around the room I hope and then check out this branch and we want you to write these controllers we want a string that returns hello world as a Drupal page and a jason string that says hello world let's just start there there should be a skeleton you can just start filling in let's give it a try who has the module already copy down nice okay did the internet come back or are we just really good with sneaker net okay you did get it checked out good yeah check it out grab this branch turn the module on and start filling stuff in based on what we were just talking about where do you put it yes I thought we had this slide did it take it out okay we took that slide out the last second so the structure of Drupal 8 has changed the file structure you'll notice a directory called slash core don't touch anything in there everything that used to be at the top level is now down in there and that's the stuff that you pretty much never touch yeah yeah so at the top level oh we have nothing okay okay so we've got this core directory and that's where core modules go core libraries all this kind of stuff you are not going to edit files in there as a module developer there's now a top level modules directory that is for your modules and the question over here you can still do the contrib and custom directories under there that logic still works but this replaces sites all essentially there's also a theme directory where that's yeah themes and again this is for your custom themes for your site the sites directory is still there sites default settings works the same way it always has yeah so that part's still the same but essentially sites all has moved up a couple levels inside the module you'll find a couple of directories we're going to talk about some of these later your info file is now also in YAML who here's worked with YAML the file format before okay then this should all be very familiar so how do I make this bigger so the keys are pretty much the same as they were in Drupal 7 they're just done in YAML now name you do have to specify type of module this should all be in the module you downloaded description and core compatibility version still the dot module file pretty much nothing's going to go in there except hooks in practice routing file routing.yaml I think the module should have a sample of that already it does actually you have the master branch checked out there so do you want me to switch you over to the initial the master branch that is everything we're doing today completed so don't start there there will be a test later don't skip ahead you've got one sample route already defined here path is you probably were checked out to master yeah everyone check out the correct branch the 01 branch the USB key that's being passed around is a full repository so you can just do a local check out of the other branch if you get branch it'll list them you want the 01 branch it's a lab 01 initial so it's same as we saw before there's a path begins with a leading slash duplicate bracket person which means there's a person placeholder the defaults content that's class name and a method and in this case we have the access content information mentioned before about psr0 versus psr4 all those mean are organization for classes so we've got lib drupal drupal gotchie various directories this is where all of your classes live in your class and their names if we look at them match up with here we go match up with their name space so this class is in the drupal drupal gotchie controller name space and so it's in the the module directory lib drupal drupal gotchie controller the only difference that's going to happen in about a week is this extra drupal and drupal gotchie directories here are going to go away everything's just going to move up to levels that's the only only change there so as we were trying to get that done before this week it didn't quite make it so expect that next week Larry does that change the the namespace you would use too? it does not change the namespace it just changes the organization of files basically PSR0 is a namespace in an autoload standard that mandates this that your namespace and your class your class's namespace and your files on disk map one to one PSR4 is exactly the same thing except you get a prefix so when we configure the autoloader we skip over some directories that you don't want to have to repeat for every single module actually the support for PSR4 in Composer is being written by drupal developers we're going to be the first project using PSR4 so the class should already be there for you and then you're just going to fill in these these methods really all you should need to do is fill in here and here and then in the routing file and 139 now so question? I think that means there's a chair available what is the goal around it? the goal is to fill in these two controllers the first one just returns the string hello world and the second one returns a json message that says hello world ok and you're going to need to fill in the controller and your routing information in the routing yaml file please do work with people next to you it's kind of hard to walk around if you have questions raise your hand we'll try and come around to you I think we're going to take like 15-20 minutes for this just a note it looks like a couple of people are running drupal 8 alpha 3 that's not going to work there have been some subtle API changes you do want to be running a checkout that's like 2 days old at most so be running a very up to date version of drupal 8 head at the moment if you want to grab a copy of the slides they're on github github.com slash palantir net slash slides dash d8 dash lab the drupal gotcha module which is also was there a copy of core on the key? we didn't some people are saying it's alpha 3 which is unfortunately not going to work no it needs to be a version that's no more like 2 or 3 days old so if you can't see this URL right now we will post it on our our session page on the prog drupal con site so you will have access to the slides and the code dash dash branch 8.x if you're doing the git clone the branch is lab 0 1 dash initial the old branches were still in there I didn't have time to delete them that's how they were doing it thank god thank you lost without you the slides I'm using right now are on my laptop but it looks like the github repository for the slides is not publicly right now so we'll make sure that you guys have the slides I apologize for for any confusion about that but the slides will definitely be on the drupal con prog website I promise maybe I can get them out there right now I was thinking that maybe I should make sure I was on the wire I would get on you know what, for now I'm not going to be able to make it public easily because I tried to do that the other day and we're actually working off a fork from a private and then you can't you can't do what you want so I know people wanted some hints so I'm going to go back Larry so they can see some code from the earlier slides okay this is the routing.yaml file do people want to see that? are you more interested in the controller code? say controller if you want controller code I heard a controller oh there's one let's go there's the coffee do we have Jason? that's one I wouldn't mind showing folks there it is here it goes so here are the two methods hello and hello Jason so take a look at that and see if I can make it bigger can people see that a little bit or maybe come up front if you need to see some code and then I also want to check in just to see how folks are doing we have some other subjects we can cover so it's a little bit up to you if you want to learn some more about dependency injection Larry go ahead why don't you skip ahead and show the solution for this part and we can move on to the next section you need to type in the path for it because we didn't set up a menu item so Larry's coming up do you want to talk about that? now next step I think a lot of people managed to get through this one so next thing we have not talked about yet is templates we were just returning strings templates as you probably have heard by now in Drupal 8 are now all twig and by being twig that means a couple of things one means the syntax has changed two means you can put a lot more display logic into the template than ever before in the same fashion so they're more secure a lot more powerful and there's a lot fewer divs but that's not actually something we're talking about right here so this is what a twig template file could look like note here a couple of important things all of the markup is here as is the string so in Drupal 7 what we would probably do if we wanted to just take parameter out of the URL and say hello to that person we would use the t function in the page callback to format that string and then pass that string on to a theme function which would just put p tags around it and we're done you can push that logic off to the template now so instead we say let's see if we can get this bigger which button it is so what we pass through to twig in this case is two variables one named person one named name in twig syntax you place a variable with curly brace, curly brace double curly brace and that's the equivalent of print variable name we can also use this trend so curly brace percent sign is some kind of directive so you can do conditionals for each loops, while loops various other things in the twig template itself in a secure fashion including translation so in this case we can push the entire string off to the template because that's part of the display and we wrap it in trans and n trans and that string will get safely translated so it's available to translators that string will properly escape person and name just like a t-function will and you as a module developer can now give far far more power to your to your frontend developers which means you don't have to worry about it and they don't have to bug you to change something if they want to change that string they don't have to talk to you, they don't have to deal with the PHP module they can just do that in a template and that is awesome all the I've talked to have just loved this idea so I wanted to check plain, very good question that's actually the second half of the slide if I can scroll back out here so outside of trans you can actually control how a variable gets escaped in the template so in this case we're saying foo, whatever this variable is pipe, escape, html this means take this variable escape it for html and then print it you can also escape it for jason xml for a couple of other things and that's now controlled in the template the default handling around the escaping is still we're trying to let twig take care of all of it and get rid of all of our own escaping that's not entirely done yet but this is for the moment how you would do that escaping yourself if you wanted to say completely build your own a tag or something, yes so the question is are these Drupal's tags or symphony's tags these are mostly twig's tags so most tags that you find just from the twig documentation will work trans is a twig thing, not a Drupal thing not a symphony thing that's built in twig so this template here would work without modification on symphony on Sylex, on anything else that uses the twig template system, it's not Drupal specific you can do Drupal specific editions and I think we have some but most of it we're trying to keep as non-Drupal specific as possible so most of the templates are going to be reasonably portable to anything that uses twig in concept can I just add there are twig sessions over the next several days so definitely attend them if you're interested in learning more about twig and templates right, so do you want to take time on this one since we started late or just walk past it okay next one, same idea but in this case we say hello to some parameter that comes from the URL and let's actually just walk through this one directly I want to check out first yes, but I'm not sure which window I'm on I'll switch to that branch okay so first, number of people notice this we need to put a use statement to the top of the file so we have access to the JSON response object and then for our just basic hello page we can just return hello world for the JSON version we just return a JSON response object without array for the template version we do this we just return an array, this is a very small renderer array we specify our theme key and the value we're going to pass in that matches up with hook theme hook theme has not really changed at all from Drupal 7 oops, if you went the wrong direction so we just specify theme key the template file it's going to use and the variables that it's going to use and then the template lives in a templates directory and that's exactly the file we saw on the screen a moment ago so just pass those values through and print them that's actually for later functionality we haven't gotten to yet, here's the trans if your themeer wanted to change these p tags to divs or section or a side or whatever all of that's in here if you want to change what the actual string is going to be so it's not hello person my name is but you want to structure it differently like say yo instead of hello or whatever then you do that in the template the themeer doesn't have to bug you anymore and you don't have to do weird things to the translation system either questions on that yes the question is is it secure to just pass person on directly yes it is because anything in trans gets escaped just as if you were using a placeholder in T this actually compiles down to something that is actually the T function in practice so inside the T here is secure if you're not inside this trans block then just pipe escape HTML in the template so a lot of that escaping now moves a layer out to the template you should not be doing that escaping in your controller let's talk more about routing so we all just did some routing routing is simply the process of moving mapping from an incoming request to what controller is going to take care of it and I'm going to walk through this as an example of the architecture in troupel 8 this will not be on the test ok the idea here is not to understand every class I'm going to talk about just to understand the flow and the architectural concepts so as we said it's pretty much all based around listeners so there's the kernel request event that fires and one of the various things that happens there is matching matching is the process of taking you probably can't read this at all different keys does the zoom depending on whether I'm in the browser or in net beans thank you Mac so we're using a system called dynamic router which was a collaboration between troupel and symphony cmf so the request comes in and we call match on it which is given this request find metadata from it and we then go through a couple of steps route provider does an initial match basically the same path based lookup that we used in troupel 7 the logic is almost identical in terms of how that works so here we said you can have multiple routes on the same path now so just matching on path is not enough so instead this pulls back all routes that match just on that path which is probably not going to be more than three or four ever but conceptually could be some number some larger number so we get back something called a route collection which is a glorified array of route objects route an entry in hook menu in the past roughly corresponds to a route it's just represented as an object now then you can filter it with a series of filter passes and that says I'm going to filter out routes based on the request only the request is coming for text html this route only matches on jason so I'm just going to ignore it I'm going to throw that out and your modules can add more filters if they want to in practice you probably won't need to do that very often but something like say panels or page manager could use that to change routing based on for example the node type core is not doing that and then we do a final match that matches on everything path, mine type method all the regex requirements this is pulled straight out of symphony that will get back an array of attributes that those attributes include the name of the controller to use then there's something called a route enhancer a route enhancer basically think of it as an altar hook but done with objects and what that lets you do is take that information and build up new information what we're doing there the actual routing happens on a key called underscore controller in most cases you're just going to specify underscore content underscore content means figure out the controller based on the mine type why are we doing that do I still have a slide on this? we can say this actually is one of the route enhancers we have in core if there's no controller specified or there is a content specified figure out what the controller is based on the mine type which means every page callback you write every controller you write can be used as its own page or can be requested as an agex request or can be used as a popup all based on the mine type coming in the request so like the overlay or the dialogue we have now in Drupal 8 we have built in modal mechanism any page can show up in that modal simply by telling the javascript to send the right mine type that's where a lot of this power comes from so we can reuse a lot of the same code a lot better follow that pattern and your code will just magically work in agex someone says you who I agree another step in here access control we talked about this a little bit who's ever heard of the distinction between authentication and authorization people familiar with that concept about half of you okay so basic idea authentication who are you it's just identifying is this Larry is this Robin is this Bob is this you know some terrorist you just figure out who the person is authorization is okay now that we know who this is are we gonna let them do what they're trying to do we can confirm this is Larry but we're not gonna let Larry do that we can confirm this is Robin we're gonna let Robin do that because Robin is more power than Larry does on the site just on that site and this is again handled through these listeners you will pretty much never deal with authentication yourself aside from the fact that do not touch global user that global is now gone actually it technically still exists just to support the installer but otherwise you should never ever ever touch it yourself it was a security hole in the first place instead we now have a service called current user if you have an object or a class that cares about the current user you requested explicitly there is no global anymore the access control part as I said we now allow multiple checks per route we couldn't come up with a better name than a checker so we're full of checkers now sorry to all the chess fans in the room and an access checker can say given this route I'm actually going to care about it or not and if it cares then when a request comes in and it matches the route we can say alright this checker is going to allow, deny or kill allow, deny or kill what's killing so with access callbacks they could simply return true or false allow or not when we have multiple it gets a bit more interesting so instead you can stack them and then you can stack them and say for this route all of them need to pass or any one of them can pass if you say any one of them can pass then at least one needs to allow and we don't care if we need to deny but at least one needs to allow if we require all they all have to return allow and none can return deny or doesn't matter what your setting is if you return kill access to deny why would we bother doing that because let's say you're organic groups and you want to add on to every route that's dealing with an entity and potentially deny access based on group membership you don't care if it's any or all you're just going to allow unless the user doesn't have access for that group and then you just terminate entirely you can override if that way in most cases your access checks are just going to allow or deny so here's an example let's see if I can zoom in a bit further so this is from the comment module so we have comments edit.edit page this is the editing a comment page and the access mode is any so in order to edit have access to edit this comment either have the edit any comment permission or you can have the comment update access from the entity access system and there's a bunch of other options here you can write custom rules as well most of the time it will be using permission just like in the past but this way we don't need to write a new custom access check for every possible case we can stack them this is a built in part of Drupal this is a built in part of Drupal will allow you to have either one of those and then you're good to go the actual permission checker an example here so it accesses the current user service so it does have access to the current user this is not exactly what's in core right now I've tweaked a little to fit on a slide and then we have the applies to method should have a route parameter to it I apologize for that and it checks is there an underscore permission key in that route definition under requirements if so it's going to want to get called for this route if not don't even bother calling it this allows us to have 47 access checkers in Drupal and only one or two run on each route it's very good for performance then assuming it does apply then on actual routing when we come in alright let's get that permission string and then does this current user have the permission whatever that permission is so here we said edit any comment permission so does the current user have the edit any comment permission if so return allow if not return deny and we're never going to block it entirely so does this completely block someone from accessing this route that's not this object's job to check it doesn't care it just says I'm going to allow or I'm not going to allow I'm going to allow or deny questions on this part everyone completely confused yes it is done on route build so there's still a route build process just like there's a menu rebuild process in the past and that's when applies to gets called so all 47 access checkers will have applies to called on every every one of the routes which a couple hundred maybe a thousand but that only happens on build that information is then stored on the route so when we load the route after it's been matched it has a list of these the three access checkers to use and then just those three we call the access method on those are called the two very different times and that gets us very good performance despite the fact we now have a lot more flexibility in the access system than we've ever had before I know multiple access call backs was a request that's going back years we now have it so the question for the recording is basically can you do can you combine ands and ors say if a model comes along and adds another checker no we tried to figure out how to do nested boolean logic for that and couldn't come up with a way to encode that that wasn't evil so in that case you probably would need to remove the access checkers and write a custom one that wraps it we have found actually in core at least which is now a rather big system almost everything fits into just and an or or any and all nested cases are actually quite rare and so those for that edge case we're okay with just having a custom access checker in that case to handle it other questions before we move on someone coming up to the mic just as a summary now that we see the details as a summary can you go back to the overview slide of these and go through that once more please sure this one here so nested matcher, so a route object comes in here pass nested matcher, route provider returns a request object comes through here goes to route provider route provider gets a list of routes that match just on path so it goes from the 500 routes in the system to 3 very quickly then you can filter that really the only filter we have at this point is mine type get back a smaller route collection do a full match, get back a list of attributes that attribute list is everything that's in the defaults section and anything that's a placeholder so that's what attributes mean it's those two lists combined and that's how you also do default values for a placeholder as well you provide it there and then enhance add on additional attributes essentially figure out the wrapper to use based on the mine type potentially other stuff there we're actually doing upcasting there so if you have a node then do bracket node and type that in your controller and then you'll get an actual node object just like you would in Drupal 7 that also happens throughout enhancers that comes back and then a step after that is all the access control stuff now that we know the route we can look at the route and say what's the permission on it what's the entity access on it and so forth so next this is a concept that is way scarier than it should be for most people really dependency injection sounds like a chip to the doctor it's not a dependency that's it it's some other piece of code that your code is going to use is a dependency a service is specifically a global stateless object global stateless what does that mean it means stateless in the sense that once it's been set up and configured you can call methods on it and its state won't change you can call it multiple times and the exact same thing will happen it does not persist information as you call through the system and then return it later you call it, you get something back that's it, it's a pure function essentially and it's global in the sense that there's only one in the system at any given time you do not implement that as a singleton singletons are evil you instead use a dependency injection container to simulate that and we'll get to that in a moment so as an example say we have this class status assume this okay and we have this show method on it, great and it's going to pull data out of the database don't worry about exactly what we're pulling out and return it and great and if we want to unit test this how do we do that well we have to make sure the dbquery function is defined and we have to make sure that the database is set up and that the whatever table it's using is there and that's a lot of work for a unit test you're testing your database connection don't do that so first step to fix that is simply pass in your database connection in the constructor save it and then you can call the connection that way and then you set it up you create your database connection pass that in and then you can call that show method great now when we want to do a unit test I can pass in a fake database connection a mock database connection and I don't need a real database I can test this this class in isolation but how about the database class here that's still as hard coded to something so first thing we do is instead of database class we pass in a database interface 98% of the time you want to type in on an interface not a class type in on interfaces not classes that makes it a lot easier to swap out the dependencies without breaking things interfaces are your friend but that doesn't help enough the database itself needs to also have its credentials pass in and this is now getting really ugly because just to call this show we need to have four lines of code and set up a bunch of objects so how do we simplify this so that I don't have to do this myself every time that's a dependency injection container we have one in Drupal now it is your friend it sounds scary it is your friend it is simply the place where you wire stuff up so that you don't have to wire it up manually that's all it is it is the scariest possible name for a glorified array of objects that's it it's nothing fancier than that so once the container is wired up you just call get status on it and that gets back that status object set up with the database and the credentials and all of the other dependencies it's just taken care of elsewhere and you don't think about it that's the idea you will pretty much never in code call this directly except for a few specific places in like a controller the main configuration for it is you have another YAML file there will be I think five YAML files in a fully baked Drupal 8 module the syntax for it is identical to the syntax in symphony it's a symphony dependency injection container so we're just using it wholesale which has a ton of features in it your individual classes however do not know that they are using a dependency injection container in almost all cases if your code knows that there's a dependency injection container you did it wrong there are a few places where there's an exception with that mostly factories for setting up objects in most part your code should not know that there's a container it just gets stuff passed to it via its constructor the benefit here is primarily testability and swapability because this lets doing this properly lets us take any arbitrary piece of code and write a test for it using PHP unit instead of simple test which means it runs in about 40 microseconds rather than 40 minutes who's tried to actually run web tests in simple tests how many cups of coffee were able to go get before it even finished one test yeah when you do a true unit test you can run through the entire core PHP unit set right now just some 600 tests in about 5 seconds was it something like that you want your code to be fast to test you want it to be dependency injected if you don't want your code to be easy to test I don't want to use your module so here's an example out of the core YAML file let's see if I can make this bigger a little bit so we've got this top level services why did you do that services key and then we specify service by name and here's its class that's pretty much it each of these arguments begins with an at sign which means this is the name of another service so in this case the the router.dynamics service uses the symphony cmf component routing dynamic router class its constructor has 3 parameters to which we pass the router request contact service, the router matrix service and the URL generator don't worry for now about what those are if those words mean nothing don't worry about that for the time being the important thing here is this wiring you can change all of those five nested objects we saw before the dynamic router and the flow chart and all that kind of stuff that can all be rewired and you can replace classes out of it at any time just by changing the injection container what this means if you want to run your routing system based on MongoDB instead of on MySQL you replace two classes in the container and you're done you want to run it off Redis, RIAC, something like that two classes you're done you want to rip out the entire routing system because you think you can do it better than Drupal can you can do that and it doesn't count as hacking core yeah, someone said wow that's the benefit of this level of abstraction is you're able to pull pieces apart unit test them work on them independently swap them out reconfigure the whole system without having to edit code just edit the configuration or override it with a compiler pass or whatever but you can hack core without hacking core essentially and that's just really cool the kittens are fine that's the great thing here's save kittens lives questions then I'm going to hand it back over to Robin who is I'm sorry this gets compiled down into this PHP code essentially it's not the exact code but this is what you would have to do yourself if you were doing it yourself you don't want to do it yourself so the injection container does it for you now I'm going to hand it over to Robin to talk about configuration thanks Larry it's been a Larry show the whole time alright I think it's all you from here on in probably will be so configuration management one of the initiatives in D8 and it's pretty exciting stuff so we're going to cover what's happened with configuration management how that works in D8 and then actually implement some settings for our Drupal gachi module so we'll see it in action when I have the window there so configuration is everything users and editors do not write so think about it in terms of our usual suspects for configuration like views and content types view modes, image styles permissions, things like that and our module settings so when an administrator comes in and configures our Drupal gachi module that's configuration as well and when this system was implemented basically all of that configuration moved into the YAML files that we've been mentioning again and again through this session and it eliminated more than 50 tables from the Drupal database from core yeah it's pretty exciting and when what happens is when you're actually saving configuration it is written directly to files and not to the database yes there's a question there is some caching in the database but when you're actually clicking save it's going directly into a file in your default files directory and if you're using an alternate cache like memcache or redis or something like that it goes to there instead for caching purposes the canonical version is the YAML on disk nope it's just on disk it's not where you don't have the weird double life that features has I think I'm going to have try and ask people to come up to the mic to ask questions because I don't want to miss any of these so folks can start doing that that would be great and I know I've got one guy here is it possible to store multiple configuration for test system for example so I'm not overwriting the settings from the product of system oh I see so you wanted to have different configuration in your test environment yes you could do that I don't think we're going to get into that level of detail here but the way the configuration is stored in these YAML files it's written into a directory called the active directory there's another directory called staging so that can be your test environment so it can store different configuration for your staging environment some other important things so we talked about YAML for those folks who haven't written YAML files aren't used to that you can check it out on Wikipedia they have a good description of how YAML works and an important aspect to these files is that configuration is now translatable so anybody who works with multilingual sites this is a big plus it's always been a problem okay so let's talk about forms and configuration you have to go to the mic please if you don't I don't want you to export some settings you want a local environment for your configuration settings right so that's a matter of deciding how you're going to save those files whether they're going into this active directory or staging and that's set in the settings.php file so you can specify basically the directory path about where your configuration is saved so maybe so are you talking about like data your module is saving that you don't want to be deployed that may be a use case for the state system which is a new feature of Drupal 8 we're going to I think kind of glaze over some examples of it in the module if you look at the master branch but the state system is a key value store that is not deployed so that's where we're recording things like the last time Cron was run or the Drupal got you module records the happiness of the site in state because you don't want to deploy that different sites going to have a different level of happiness but you do need to persist it so that might be something to look into what you're describing okay let's get back to forms for a little bit so when you're going to create your own form you'll implement the form interface and it comes with some methods the build form validate and submit form methods which should sound somewhat familiar and the code is quite similar inside of those methods to how we create module forms in D7 but today we're actually going to focus on the administrative settings for our Drupal got you module which works a little bit differently so let's check that out we think this is a typical use case for module developers that they need to have configuration settings for their module so what we're going to do is we're going to create this administrative settings form in fact let me show it to you I'm going to quickly just check out some code here I'm already on the lab control so let's go we can just see what this looks like quickly I wonder when I last cleared the cache just to be safe oh bad so one note on Drupal 8 it does compile PHP code to disk in a couple of places I said the dependency injection container is one of them the other is too big if that gets out of state or out of sync the normal cache clear methods don't always work on that the easy way to do that is if you can't get to this page sites default files PHP just delete that directory as of right now you need to sudo to use it there's a patch in the queue right now to not need to be sudo to do that but that's how you clear that cache okay thanks Larry that was a nice filler I'm good at filling in for things so under configuration we're going to have in the system section configure Drupal got you and basically this is where administrator would choose the name of their Drupal got you this is where your stuffed animal becomes very important whatever your stuffed animals name is that would be the name you would enter here and you can decide how needy it is how much attention it needs so the more the sliders to the right here the neediest increases so I'm just going to continue with these values I have here but this is the form that we're going to work on right now and note this range slider here this is an HTML5 element that should work in any Chrome version and in just the most recent Firefox and I think IE's does it now I think so if it doesn't it naturally falls back to a text field which is how HTML5 is designed but it's just a native fappy element now okay so here's what you're going to need to get started you need a route you should already know how to do that but now our route will be different it's going to point to a form instead of content we're going to create a menu item for it and this is so that we can actually see that configure Drupal got you on the configuration page so we still need hook menu we're going to actually place menu items in the navigation we're going to create configuration schema which basically defines the values of the Drupal got you name and the neediness value so it's kind of describing what's the data type for Drupal got you name and what kind of label do we give it that sort of thing we're going to provide some default values for this configuration when I went to that page there were already some settings in there so you can make sure default values are in the form and we're going to make sure that our form class extends something called config form base so this is specific to creating configuration type settings for your module so if you haven't checked out lab-02-controller-complete that's the branch you want to start from it has some PHP steps in there for us to get started so you're going to start with your route first and I'm just going to point out some of the unique features of the code from what we were doing before actually Larry has this pointer but what's important is under defaults we have underscore form in your previous routes that you were working on was underscore content so that's one of our differences here and it points to our new class that's called settings form so that's under when we get into the directory we'll see that's under lib slash drupal and then form will be a new directory that should already be there in that branch with the file in it so in our drupal.module file we're creating our typical menu item with hook menu so that's all pretty much the same thing the one difference is the route name is going to point to your new route in the routing.yaml file Larry? Also note in about two to three weeks I expect this hook will get renamed to hook default menu items because it won't be doing menus and routing anymore it will just be default menu links and menu link items. So that is a separation from how things worked in D7 Yes, there's a question it's lab02 lab-o2-controller so basically that has the full controller code and then our PHP steps are working on the form another question yes because we forgot to update this slide it changed from pattern to path about a week and a half ago sorry I tried to catch all of those so it should be path not pattern nice catch ok so we went through our menu item configuration schema so this is new you should see in your dribble gachi module there is a directory called config and within it is another one called schema so that file will be empty and basically we're going to add in this configuration structure for our module so the way it works is we specify in dribble gachi.settings the type is mapping and then you see the mapping section below this applies directly to the two values we're going to store for our dribble gachi module right so there's the name it's of type string we can give it a label and needy is determining how much attention our dribble gachi module needs and then what you can do is so here we were at slash config slash schema I can provide default values at slash config and it's very simple you put in the name of the field or the machine name really of the value you want to store so like needy colon and then the value so this is pretty straightforward you just need to kind of pass in the values that you'd like to provide these are the default values for the settings and then we get into lib dribble dribble gachi form settingsform.php so you're going to you need a construct that pulls in our config we're going to use a method called the create method which basically brings back it's static and brings back our dribble gachi settings do I have this right in the container is that correct make sure I have that right the create static method you'll see in a couple of places this is pretty much the only place you'll ever interact with the container the dependency injection container directly the idea is you don't want to have to register every form as a service or every controller as a service that's nuts if you have if you implement the right interface which the base class here does then this then this create method gets used as a factory for your class and it gets passed the container and so you can then return a new instance of static which is php534 this class it's the same as self but works correctly and you pass to it parameters in this case we're going to pass in just the config object that we want, dribble gachi settings so this is just a pattern you're going to use over and over again you grab the configuration factory get the config object that is relevant for your module pass it to the constructor and then you can use that config object throughout your module or throughout that class great thanks Larry and then another method that I'm showing down here that you'll need is the get form so this is your machine name for your form and just returns a simple string two there are a couple more methods we have our build form which is just like the forms you use to build in d7 so get used to your form array and all of those lovely items so I'm not going to go over this in too much detail because you can find this easily in d7 just note that for this dribble gachi module that name is a string and that the needy field is a range field of type range could go back one step one other thing that changed very recently since we were updating the slides another slide update the t function you should not use anymore that's now a service most of the common base classes like forms and controllers that have a this arrow t method you can call instead which does exactly the same thing but you want to use that instead of calling the t function directly called t function directly you can't test this without doing the full minute and a half boot up of a web test so this t is your friend in procedural code I think the t function still works or you can access the service the t function is not just a wrapper around the service I think the last vestiges of procedural code in Drupal still have some weirdness you have to do to get at services most things are going to be object oriented aside from hooks themselves sorry I was just checking we still have the t function in our code as well so you guys feel free to fix that Patch is welcome okay so we're building our form and I just want to point out also is parent build form and then you pass in the typical form and form state arguments okay so and then finally we have a submit form method and basically all we need to do is make sure we add in our new fields and their values to make sure they get saved it's so straightforward I love it so makes me really happy and then we're at the end of our class for our form so get into settings form dot PHP remember that's in Drupal Drupal Drupal got you form settings form dot PHP and start working on filling out those methods and Larry and I will walk around it's just calling the parent first to so here's again the list of things you're doing you're creating your configuration schema and the default values and then you're going into settings form dot PHP to manage that form someone wanted to see this code slide again so we leave this up for a moment you're right this should be this config set does she miss it yet another bug on the slide we have another bug report the config set here should be this config set sorry about that it's just the bug in the slide okay so we're winding down to the end here so there's one question that a couple people had we want to go over again this create method so we talked before about dependency injection and wiring up services with the YAML file who here wants to have to wire up a YAML file for every single controller in every single form one person you sir are weird so instead we have a pattern called factory method it's a very common pattern in OO when a controller or a form is wired up to a route when the system is going through instantiating that object it will first check and say alright does it implement the container injection interface which the config form base implements for us if so we know it has this create method call that create method and we'll let it take care of making that object which means you need services you can inject them yourself in that little factory if it's not there then it just calls new whatever that class is new settings form and the constructor gets no parameters this lets us do injection lets us specify which services this object is going to need without having to wire everything up to the container and end up with a container that has 5000 items in it because that would be ludicrous the static keyword here a couple people are asking for it this is a self keyword before in OO static is exactly like self but it's not broken the self keyword the way inheritance works with it is totally broken in PHP so static is exactly like self but it's inheritance works correctly is the base weight to describe it if we instead here did return new settings form it would work perfectly static is just a generic for we're just going to skip ahead here and do a little bit of wrap up key takeaways if you want to make sure you get out of this session first think in loosely coupled objects we've all been used to the idea of make small modules that work together that same concept take another level down and instead of having big functions that do five things have loosely coupled objects that you assemble and let them do their thing let them do one task that way you can reconfigure them service container forms whatever and change your code without hacking your code that's the goal separate your business logic from your glue code you'll notice that controllers we wrote were really really small we're used to having page callbacks that are like 50, 100, 300 lines long don't do that if you have that kind of logic break it out to a service have your controller access that service and then use it that makes it easier to reuse that logic elsewhere makes it easier to unit test that logic and if that logic isn't coupled to something like forms it means your logic is decoupled from Drupal itself which means should someone break this API again you're insulated from that that's a good thing so things like controllers should just be thin glue code and that logic should be separate from that display logic happens at the display layer twig is awesome twig does way more than PHP template ever did let twig do what it's good at let your themers do what they're good at they will thank you at least my themers thank me I have a more complex example of that template at one point that I showed to people like Morton and other hardcore themers who hate module developers and all the stuff we put them through and they love the level of control that it's giving them so let the theme layer do have that kind of power like your themers have that kind of power you'll be a lot happier, they'll be a lot happier the future is a rather different place this is very different than Drupal 7 that's okay because you can do an awful lot more your ability to reconfigure your system to rewrite your system your ability to change code without changing code essentially is far higher than any previous version of Drupal your ability to unit test and actually bother testing your module at all is way higher than previous versions of Drupal embrace that, leverage it build lucy coupled code and you will have an easier time maintaining your modules going forward this is supposed to be a Hitchhiker's Guide reference that I think we took out that was the don't panic slide that went missing we are going to be offering extended versions of this class through Palantir coming up in Chicago one's in December, one in February we're looking at a two-day training for that so this was very compressed as I'm sure everyone feels take that, stretch it out to a day and then we have another day covering additional topics, more advanced topics so look for more information on that on the Palantir blog Palantir.net we are considering doing that outside of Chicago as well basically when we find there's a market for it we're willing to go after it for the moment we're just doing Chicago but keep your eyes open if you want you or your company wants a larger extended version and thank you enjoy the rest of the conference the next slide, thank you please do rate the session we love the feedback we'll be around for a little while if you still have questions that's right, it's coffee break time so if people still want to work on code a little bit longer, Larry and I can hang around for a little bit longer and now that you all know Drupal 8 I expect you all at the sprints on Friday oh yeah, sprint on Friday