 All right, let's go ahead and get started. Welcome to Drupal 8's The Crash Course. My name's Larry Garfield, you may know me online as Krell. I've got a few fans here, apparently. I'm a senior architect with Palantir.net, we're a web agency based in Chicago. We do mostly, but not exclusively, Drupal, and mostly, but not exclusively, institutional nonprofits. Universities, museums, hospitals, public radio stations, publishing, that's kind of our standard fare. For Drupal 8, I was the web services initiative lead, which is the fancy way of saying you can blame me for about a third of what you see on the screen here. Drupal representative to the framework interoperability group, which is kind of the United Nations of PHP, with all the positive and negative connotations that come with that. Advisors of the Drupal Association, and your friendly neighborhood singing crab. Those who are in the pre-note know what I'm talking about. Those who weren't, you don't know what you missed. We're gonna be looking at a lot of code in this session, so if you want to play along at home, everything is available at this link, github.com slash palantir.net slash hugs. You can download that now or later, the slides will be available later as well. All right, so let's talk about Drupal 8. Kind of a big deal, right? You've all heard something about it by this point, I hope? Who hasn't heard of Drupal 8? I know better about you. So, talking about Drupal 8 and listening to people, you talk about their expectations, generally I hear one of two responses. From Drupal people, I hear it's so different, will I ever be able to learn it? Who's in that group? Not that many people. So then I guess the rest of you are in the second group. Drupal 8 is finally not weird. This means I'll be able to use it. Who's in that category? Slightly more people, okay. Who didn't raise their hand? So you're just here to troll me then. Okay, well I'm happy to tell those first two groups anyway that the answer to both of these questions is yes. Because really, the more things change, the more they stay the same. It's still Drupal. The concepts that you're used to in Drupal of nodes, entities, forms, fields, views, blocks are all essentially the same. The architecture under the hood, however, has been heavily modernized and heavily refactored to be a lot more approachable, a lot more consistent, a lot more familiar to developers coming in from outside of Drupal. And that really is the theme for the redevelopment of Drupal 8. This is only an hour long talk, so I'm not going to go into every detail. I also don't want you to focus on the specific APIs that we're gonna talk about. Don't focus on syntax. Focus on the broad strokes, focus on the patterns. You'll be able to look up syntax later. Don't worry about that. I want you to focus on the way the system puts together and the way Drupal wants you to think about it, because that's really what's gonna help you be successful with Drupal 8. So let's start with just enough theory. This is the way a PHP 4 application was built, which means Drupal 7 and earlier, as well as pretty much anything built before 2010. PHP starts up and you've got a whole bunch of superglobals that get populated by magic. And you do something, and your something is its job is to call the header function and print. And that's how you produce your output. And you hope you do it in that order, because if you don't get the order right, then bad things happen in weird ways and things may magically stop working. Problem, this is not actually how the web works. HTTP, which is kind of the point of all of our jobs, is built on this model. You have a request message that is received. Your server does some kind of black magic, and a response comes out. These are messages, not variables. They are a conceptual wrapper around an HTTP message, which is headers and a body. Fortunately, when we started Drupal 8, we said, all right, we need to modernize this. We need to move to this proper model. Is there anything out there that's already there so we can save ourselves an awful lot of time? Turns out, yes, it's called Symphony. Symphony's HTTP kernel library, which is the heart of any Symphony application, is built on essentially the same model. You have a request object, object message, same deal, and a response object, and this thing called an HTTP kernel in the middle, which is a very simple process that takes in a request and returns a response, which is exactly what HTTP is supposed to do. In fact, that entire design can be found in this one trivial interface. This is code straight out of Symphony and now out of Drupal 8. It's an interface HTTP kernel interface, which has a single method on it called handle, which takes a request and returns a response, and that's it. Everything else happens inside of there. Almost all of Drupal runs inside of that and any other simply based application, so Laravel, Symphony itself, Sylex, anything. In particular, Symphony includes a default implementation that Drupal 8 is using pretty much verbatim and works like this. Request comes in and it's kind of hard for me to see the slides from this angle, so please bear with the pointer. Request comes in and something called a request event fires. Think, hook request alter. It's basically the same idea, just events are more generic object oriented equivalent of hooks. And that can take action based on that incoming request, the most important of which is routing. Routing is the process of deciding what piece of code, called a controller, is going to handle this incoming request. What's going to be responsible for it? After that, there's another event called a controller event. Think, hook controller alter, which you will almost never touch yourself. In actual practice, I don't think more than a dozen contrib modules are ever going to need to touch that, but it's there. And then end result there is calling a controller, which is just some piece of code that will deal with that request. And that controller can return a response or something that is not a response. If it's something that is not a response, there's a view listener that fires, which can have any number of listeners on it. Any of which can say, all right, here's this, whatever it is the controller gave me, do I know how to turn that into a response? That's where page theming happens. That's where rendering blocks to wrap around your content happens. Or any number of other things you want. It's very flexible. You can put arbitrary additional logic there if you want. And then as soon as one listener says, oh, okay, I can turn this into a response, it does so and the rest don't fire. Then there's a response event, think hook response alter, which among other things is where caching happens and a lot of post rendering cleanup. Then the response gets sent out and there's a terminated event, think hook exit. That is the entire pipeline. That is the core of symphony, of Drupal, of symphony CMF, of easy publish, of about a dozen other systems that all work on pretty much that exact core pipeline. The only difference is what we hang off of those different events. So this is a symphony talk, by the way, you didn't know that, right? So let's talk about those controllers a bit. This might be a new word for some of the Drupal people in the audience. Think page callbacks. Page callbacks in Drupal 7 are what everyone else in the world calls a controller. And technically in symphony and in Drupal 8, they can be any PHP callable. Callable means a function, an anonymous function, a method of an object, a static method of a class, pretty much anything you can put parentheses after and have PHP not break is a callable. That's the idea. In actual practice, in Drupal, 99.9% of the time, your controller will be a method of an object. So controllers can be dead simple. In this case, we've got a class, MyControllers, which is a single method, which returns a response. So if this controller is what fires, it will return a response that is that HTML string. And you're done. No other theming happens. The theme system won't kick in, you won't get blocks, you won't get any sort of filtering that you can control the entire output of what comes back that way if you want to. Also important to note, the method is the controller, not the class, the method. Because you can put multiple methods, multiple controllers in the same class if it makes sense to do so. So here, we're going to return, instead of returning a response, we're gonna return JSON response, which is just a subclass of response that takes an array as its constructor parameter rather than a string and renders that into JSON, sets the correct, accept headers, or content type headers on the response, does all that other cleanup you need to do to be playing nice with HTTP and sends that. And you can have any number of subclasses of response that have whatever additional logic makes sense for you. That's, there are some standards that you'll be using, but you can do custom ones if you want to. One of my favorite is stream response. So let's say you're writing out here, producing a CSV file for a request. Request comes in if you're loading a CSV file out of something in the database. You really don't want to build a whole CSV file as one gigantic string and then pass it around, because then you have your source data and this entire rendered blob of CSV, which, depending on your use case, could be a gigabyte in size, sitting in memory on your web server. And this is going to pull out your memory and your server will crash and your assistant will hate you. And you don't want your assistant to hate you, believe me. So instead, we're gonna create this stream response, set the header on it, the content type header, for text CSV, note nice simple logical API for that rather than guessing what the PHP global is and sending it in the right order. And then we're gonna set this anonymous function as a callback so that when the response gets sent, only then does that code run. And that code then can produce that CSV one line at a time without ever storing the entire string in memory. That entire CSV string is never in memory at once, only one line at a time, which means you can output a 100 gigabyte CSV file without the long past 64 megabytes on your web server, because that's just Drupal itself. Cool. It was a huge pain to do this in the past. It's now just a fully supported feature of really anything that uses symphony. Even better, usually in that sort of case, what you're returning is not something dynamic, but just a file off disk. So you're doing private files and you want to stream a file off disk that has been generated or that's your access controlling. You just use this binary file response object and poof. That's that entire file just gets streamed right off disk in the fastest possible way. There's about eight different ways to stream files off disk in PHP. You don't need to worry about which one gets used. The fastest one will get used. If you're on something like Nginx, it has an even faster option that just bypasses PHP entirely, that can get used. The reason I love this one is Drupal developers actually wrote this feature of symphony. After we started using symphony, we started contributing back upstream, and this is one of the things we did, because we needed this. There's nothing Drupal specific about it, so let's share it with the wider PHP community. So far, we have not talked about Drupal at all. This is all symphony. This is all something that's common across three dozen projects in the PHP space. In actual practice in Drupal, most of the time, you will be returning a render array rather than a response. Render arrays do still exist, I apologize. But they are better. They actually kind of work now. You recommend the way of doing that. You still have pound theme, which is some theme callable you have, same theme callback, and whatever your properties are for that. And we'll see a bit more of this in a moment. You can also take parameters from the URL. So if we have a request that goes to hello world, and then we've got placeholders for from and to, then we can just have as parameters to the method, to the controller, from and to. And whatever gets passed in to those parameters in the URL, gets passed into our controller. From and to or backwards. Is that seem right to anyone? Doesn't matter. It's matched up by name, not position. You can reorder those however you want. It's not going to break it. That's just figured out on the fly with reflection. You can also get the entire request object if we want. Rarely do we need to do so. But if you want it, just specify it, and that will get passed to you as well. Really the only time you would need to access that is if you're doing something with get parameters, which is not actually that common of a task. Other than that, you can just use the parameters themselves. And then you can wire that up in the routing system, which we'll cover again in a moment. By saying here's our path, and then here's the underscore controller, which is just that class that we specified before, and the method. And then the requirements for it. So in this case, you need the permission access content. And we can also apply regular expressions to those parameters. So we can say only match this route if this value is a string. Only if it's a digit. Only if it is one of these three strings that I'm going to specify. And that's just baked in automatically. We inherited that from Symphony. All right, you're thinking, Larry, shut up. Enough theory. I wanted to actually see something Drupal-y. Enough Symphony. So when you're dealing in Drupal-8, pretty much everything you do is gonna break down into two steps. Build a tool, wire it up. You do not actually solve your problem. You build a tool that you can use to solve your problem and then wire it into the system. You don't write one-off code, you build a tool and add it into Drupal. That is the way you want to work with Drupal. Put another way, you extend a base class, order implemented interface, and you tell Drupal about it. That is almost everything you do in Drupal-8 is implement an interface, usually by extending a base class, and tell Drupal about it. So let's see some examples of that. How do we define a module in the first place? Well, we need a file to tell Drupal about it. It's going to be in the Hugs module, and notice, we're putting this in the Global Modules directory. If you put a module into the Global Top-Level Modules directory, on Drupal-7, what happens? Someone slaps you because you're not supposed to do that. In Drupal-8, you're supposed to do that because all of the built-in modules have moved to a subdirectory in slash core, slash modules, to get them out of the way. So the Top-Level Modules and Themes directory are where you're supposed to put stuff now. Just to confuse you. But we have this YAML file, which replaces the old info file. So we got rid of that custom syntax that existed nowhere except in Drupal, and replaced it with a standard YAML. The properties are all pretty much identical. So our module is named Hugs. Here's our description. We'd say that it's a type of module, and it's compatible with core version-8. And we're done. Go into the Modules page. Our module is there, ready to enable. What's missing here? A .module file, which is now optional. It only took us 15 years. So if you have no code for your .module file, you can leave it out. Cool. Now that we've got our module, how do we make a page? Let's just put a page somewhere on our site. Well, what's our pattern? Extend a base class, tell Drupal about it. Here's our controller. We're going to extend from this controller base class, which is optional, but you'll do that 99% of the time, which has a bunch of useful utility methods in it, such as this T. Same idea as the T function, but this is a class, so you don't want to be calling functions directly because that makes it untestable. So instead, that base class has a T method on it, works exactly like the T function you're used to. So in this case, you've got two parameters we're taking in, from and to, and we're just going to put those into that T string, they'll get escaped automatically by T, and then we return a render array that is just that string as markup. Normally, you don't want to do a hash markup, but we'll see the better version in a moment. And now we tell Drupal about it. We have a hugs.routing.yaml file, which replaces hook menu. We have our route, which has a name. All routes now have names. Modulame.somethingmeaningful. Our path, which is slash hug, slash from to. Our controller, which is that class and method we just defined. And underscore title is the title of the page, if it's aesthetic, and you need to have access content. And Drupal will see this, wire it up, request comes in, matches to this route. It will instantiate that hugs controller class, and then call the hug method of that object. And there's our output. Hug LarryDrupalcon. Larry sends hugs to Drupalcon, because who doesn't want to hug Drupalcon, right? If you haven't hugged Drupalcon yet, you'll have time to do so at the conference. Easy peasy. So let's make it themeable, because you want to make your content themeable so that Morton is not angry at you, right? So let's go ahead and create our .modul file. We do still have hooks, they're just less used than they were in the past. But hook theme works more or less the same way. So we're gonna define a hug page theme key, which is going to take two properties from and to, and the template for it is gonna be hug page. And then we create a twig template file, because Drupal8 now uses twig, because we decided that custom rolling our own Turing complete template engine is not actually a good idea. And put our display logic there. Please note this trans directive. That's trans directive says whatever is inside these two tags is a translatable string. It works exactly like the T function, or the T method. And then double curly braces are on the values we want to place there. This puts all of the presentation logic, including the text to display in the template in a translatable fashion. I cannot overstate how important this is, what a big difference this makes. Display logic belongs at the display layer in the template. You'll see almost no display logic in controllers here. That's a good thing. For much more information on that, go see Morton's session this morning. Took you a moment. The video's up already, I'm sure. Then we modify our controller, which is going to take from and to, and all it's gonna do is return a render array that specifies we're gonna use that hug page, themeable, we just defined, and the parameters to it are from and to, and then the template takes care of everything else. You wanna change the markup, you wanna change the structure, you wanna decide you don't even want a translatable string in there. That's all the template's job, not your job as a module developer, as it should be. And now we get a slightly formatted, if you can see that, with strong and EM tags output. You don't want strong and EM tags? Fine, change it in templates, that's where it belongs. How do I make a config form? It's kind of important. Drupal's thing is all configuration. It's kind of our reason for existing. So this has changed quite a bit. What was the configuration system available in Drupal 7? Anyone know? Trick question, there wasn't one. We had the variable system, but really that, that did not cut it as a configuration system, really? Which meant everyone rolled their own. Drupal 7's configuration system was, here's a database, have fun. Yet no, no, no, no, that does not cut it anymore. So we have a new completely rewritten configuration system. That eliminates the need for most of features. So let's start off, in our module we're going to have a config directory, site of which is install, and then a hugs.setting.yaml file. Configuration in Drupal 8 is configuration objects that map one to one to yaml files. They're stored in the database in production and read out of there in a key value store fashion. But can then be trivially dumped out to disk as yaml files are imported. So the features, export, import, is automatically there for every module, for everything. Without any shenanigans about callback hooks and three layers of nonsense, yeah. So that's just baked in. And this config object can have any number of properties on it. I'm just gonna have one at this point, default count. And we also need to have a schema file for it, which defines what the properties are in that config file, and most importantly, which ones are translatable strings. If you have a config setting, which is a user supplied string, you should mark it as such in a schema, which means the translation system can pick it up and make it translatable. Configuration is translatable for every property baked in from the get go for the first time in Drupal history. And then we've got our config form. Oh my God, wall of code. It's not that bad really. Remember we said extend the base class? We're going to extend config form base. So there's a form base class for most forms and a config form base that you can extend off of. This is the equivalent of the system settings form function from Drupal seven. We're going to give our form an explicit ID, in this case it's hug config. And we're going to specify what config objects we're actually going to be editing in this config file, or in this config form. And that's the hugs.setting object that we created before. Why do we need to say that? Well, when you load a config object, there's actually other actions that can run. So dynamically customize the configuration, which if you're editing it, you don't want to do. So this skips that part. Then we have a build form method, which takes a form array and form state. Form state is now an object. Yay. Forms are still a big anonymous array. The form API itself is essentially the same. So we're going to grab our config object, this config, and then just create our form elements here, as little or as many as you have, same as in Drupal seven. One thing to note here, we are using number, if I got this right. We do now support all the HTML5 fancy form elements. So number, what are the others? Number, telephone, various others are all supported now. And again, note this arrow T, instead of using the T function. You'll never use the T function outside of procedural code, which you should almost never write. And then we can just return the parent implementation of build form, that will add all the buttons for us and so on. Then there's a submit form method, also a validate form if you want to validate. Same idea as the callback functions before, they're just now wrapped up into a class, in which you call the parent, and then we take our config object, set the values on it that the user saved, the user provided and call save. And that's then pushed into the config system. Now we tell Drupal about it. We're gonna wire that form up directly to a route. We're gonna create a route called hug config, hug.config, we're gonna give it a path in admin config system hugs, just same structure as before. Gonna give it a title, but this time instead of giving it a controller, we're gonna specify underscore form, and just give it the class name. Which means this form that I've defined, stick it at this URL, and Drupal will wrap the controller logic around it as needed, and that form then shows up at that URL. And you need to configure hugs permission in order to access it. Oh yeah, permissions. Those haven't really changed except that they're now a YAML file. You'll notice a pattern emerging here. Permission configure hugs, give it a title and a description just like before. And then we need to add an item to the menu, which is another YAML file. Why do we have so many different YAML files for this? Well, in Drupal 7, Hook menu did about nine different things. Implicitly, with pre-baked logic that only sometimes made sense, and was a huge pain to try and work around if it didn't. And having one system that does nine different things is an absolutely terrible idea because it makes maintaining it impossible. So in Drupal 8, we've pulled all of those responsibilities out to separate systems and separate configuration so that you have the ability to put things, to configure that more to your liking. So we took away a lot of automation so that you have the flexibility. And it's just the YAML files really. So we add a link to the menu system. It gets a machine name now too. Give it a title, description, the name of the route that it's going to link to, which is this route. And the parent menu item. So the parentage is not automatic, which means you can put an item as a parent of anywhere in the menu structure. We do that. And now we have our Hugs configuration showing up in the admin form, there in the admin menu. And it looks like that. There's our number fields. You can fill in a value, hit save. It is an HTML5 number field. So if you're on a web browser that supports HTML5 properly, the browser will lock it down to just digits and not even let you type in letters. And that will also automatically get validated on the server side. And if you're on a browser that doesn't, like Firefox, which for some reason still doesn't support the number field, I don't know why. Okay, it just falls back to a text field. All of that HTML5 form goodness is just baked in. So now that we've got this configured value, let's modify our controller again. We're gonna give it another parameter, count, and then say if the count is a false value, we'll grab that default. We're gonna go grab this config. It's another one of those methods on the base class. And then get that config object and get the default count property off of it. And just provide that as a default. And then pass that count value on to the template. We modify our route. Let's give it an extra parameter. And we're also going to give it a default value for count of zero. So if it's not provided, count gets a value of zero. If it is provided, it's whatever the user supplies. Which means we always know we will get a value there of some kind by the time it gets to the controller. And we know it's gonna be an integer because we only allow digits. We're going to apply a regular expression to say digits only. So if you put in slash hugs, slash larry, slash duplicon, slash foo, that won't even match. There will be no controller. You'll get a 404 as you should because there's nothing there for it. Update our theme hook to give it an extra parameter and update the template to say all right, this translatable string varies depending on whether count is singular or plural. So we can say if it's singular, hugs one time. If it's plural, hugs times with an S. Again, that logic belongs to the template. And now if we don't specify a count, we get our default of three. So it says hugs three times. And if we do specify one, one time. Again, all of that display logic in the template work belongs. This is where Morton is happy with you. Everyone's still with me. All right. Blocks. Who's worked with blocks in Drupal 7? Who thought that was an easy to use API? One hand. Yeah. So let's back up a bit. Let's define a few new terms. We have this thing called a plugin. A plugin in Drupal speak is a swappable user defined piece of functionality. A plugin type is a category of interchangeable plugins. And discovery is the process of finding all of those plugins of that type. Put another way, think plugin type is an interface. A plugin is any class that implements that interface. And discovery is find all instance of. It doesn't actually use that as the logic, but that's the idea. It's just cataloging all of the plugins of given type. Really, it's just standard OO practices. Wired up in a way that you can access it from the UI. Drupal 7, what was our extension mechanism in 7? Hooks, info hooks. This is all you get. Info hooks for everything. Except that not everything you work use them the same way. Some things use magic callbacks. Some use fully named functions. Some things did wire objects into it. Core did about eight different things. It made no sense at all. If you're in the contrib space, you could use C-tools plugins, which were great, aside from the fact that they were written for PHP 4, which means they're trying to re-implement object-oriented techniques without using classes, because that's a great idea. So, extensibility in Drupal 7 is actually very haphazard. Extensibility is kind of important for Drupal, but in 7, it was a very haphazard, inconsistent mess. There's nothing actually in common. In Drupal 8, if you want to have something where users can pick between a series of configured options, your answer is plugins. Always. What those plugins can be your own type. They'll follow the same pattern as all of the others, but it's a very consistent pattern for users. You define an interface for your plugin type, you create a manager class, and you're pretty much done. If you want standard behavior, there's even a class you can just subclass off of. This is the idea of learn once, apply everywhere. I love this line. It's from Lee Rollins, one of the lead core developers. What is a plugin in Drupal 8? All of these are plugins. All of these now use the same architecture. All of these use a consistent way of allowing modules to provide new implementations. So once you learn the pattern for text formats and field widgets, you can write entity reference select rates or migration, or backends to the search API, or image toolkits, or mail backends, all of them using the same pattern. It's just a different interface for each one, but hey, PHP interfaces are fairly self-documenting, which you can't save or erase, can you? So if you've worked with views at any point, that's probably the closest Drupal 7 equivalent where you have a class, you extend something, and the system picks it up, and you're good to go, and then you can wire that into the UI. And blocks are now a plugin. So this is a fairly basic block. We're gonna create a block that shows the status of hugs on the site. So we have a class called hug status. It extends a base class, and it has this weird blob of stuff over it. This is an annotation. This is a way of putting metadata about a class into the same file as the class using a comment. This is honestly the most controversial thing in Drupal 8 because a lot of people look at this and go, oh my God, you're putting code into a comment, that's terrible, to which the answer is, well, if the PHP internal developers would give us proper annotations in the language, like several other languages have, we wouldn't have to. But until then, there's about two dozen PHP projects that are using this exact library, it's the Doctrine Annotations Library, to do this kind of metadata. And we're not one of them. What this means is that the entirety of what you need for a block or any other plugin is in this one file. It's a single class with a couple of annotations at the top. Just say, at block, say this thing is gonna be block, give it a machine name ID, a label, that it's translatable, category that's translatable, and then the block has a method build, which works basically like a controller. It's the controller for that block, in essence. And we're gonna return a string, this is a hug-enabled site. Now we go into the block admin, and you'll notice there's no hug status in the list here. Instead, you go over here and create a new block off of that class. So you click the ad-hug status over here, and you get a config form where you can put in a region, configure it to visibility, all the kind of stuff you can in the past, and it then shows up on the page. And you can do this multiple times because the configured instance of that block is what you're placing, not the class, which means you can place a block multiple times on the same page, and it actually works in core. Hee! There's the big win in Drupal 8. You can place a block multiple times. And here we go. Our block shows up, and it says that this is a hug-enabled site. Now you probably want to configure blocks at some point. So just add some more methods that the base class provides defaults for. You can override them. We're gonna create a default configuration method, which is just an array of keys, just like you would have in the ML file, of what the default configuration parameters are for this block. Got a block form, works exactly the same as the build form method for the form. We would return that. A submit method is also a validate if you need. And we just save whatever the user submitted to our configuration array, and it gets saved automatically. And then we modify our build method to say, all right, switch on that configuration and send a different message. And we could totally pass that configuration value onto a template, or two if you wanted to, which you should do. And then we get that config option showing up in the form. If you wanted to, there's another method you can override, and blast away this entire config form, and take over all of the block configuration. You'll almost never want to do that, but if you want to, it's there. It's a lot of options available now that we're doing things with classes that you can override. Services, I'm not talking about web services. I mean services in the programming sense, an object that does something. They are stateless, and you usually have only one of these. This does not mean it's a singleton, it's not self-enforcing. Examples here, I think database connection, or cache connection, or the routing system is a service, essentially a series of services wired together. Most of the logic of your site and of your module belongs in services, not in forms, not in controllers, not in blocks, in services. Services, you can unit test very easily. If you cannot unit test your code, you are doing it wrong. So let's have a look at this sample service. We're gonna call it hug tracker. Notice, in this case, we're not extending anything. This has no coupling to any core Drupal class, but it does have a dependency on this state interface, which is the state service in Drupal. What's the state system? So I remember we said that the variables table was terrible for configuration, that's because it's not really configuration. State is information about the site that is going to vary per instance. Configuration is something that you want to be able to deploy from development to staging to production. State is for things like the last time Cron ran, who the flood control, who the last user to post a comment was. Those things, you really do not want to push from dev to production or production to dev. So that belongs in a state system, which is just a simple key value store. This is much closer to the variable system actually than configuration was. And so we have, in our hug tracker service, we have a method ad hug, which records, all right, who is the last person hugged? And we're just going to set that property on this state service, and get last recipient, which retrieves that value. Why are we abstracting this away from the state system? Because this is business logic, it does not belong in controllers. You can very easily extend this to be more than a trivial get and set, in which case that logic belongs in a service you can reuse rather than tie it up in a controller. Your controllers should be thin. So now that we've got our service class defined, we tell Drupal about it. A services.yaml file, hugs.services.yaml, in which we specify machine name for it, hugs.hug tracker. We tell it the class and the arguments. In this case, the argument to the constructor is the state service. This is the exact same syntax as symphony uses. Who here has worked with symphony before? All right. We're using the symphony dependency injection container too. So this is the exact same syntax that you're familiar with from any symphony project. So we've got our service created. We told Drupal about it. Now we need to use it. So in our controller, we'll add another method. There's a static method called create, which there's an interface that triggers that it's going to be there, which controller base implements for us. And then that create method acts as a factory for our controller object. It gets past the container. We're going to pull out that service we just created and pass that to the constructor. Static is PHP for the class I'm in. It's just, you could say return new hug controller if you wanted to. Static is more generic. The constructor, we just save that to a property. Good to go. And then in our controller method itself, in the hug method, we say, all right, the two, whoever is being hugged, we'll just record that. Call the state, set that property. We're good. And then the rest of that is the same we saw before. Let's update our block as well. In this case, we need to add an interface to it to indicate that, hey, we're going to use that create method thingy. And we're going to have another create method. In this case, for blocks, there's a couple of extra properties you need to pass in as well. Don't worry about what those are. Just pass them through. They're part of the block setup in the first place. But it's the exact same idea. And then in our build method, we customize the message. So if hugs are not enabled, then we just say, no hugs. If they are enabled, then we'll say who the last hugged person was, which we get out of the service. Again, trivial logic, some of this could even be pushed off to the template. And there we go, our message is now saying who the last person to be hugged was. All right, enough framework stuff. Content, that's kind of important, right? CMS, content, kind of go together? Yep, okay. Entities, they actually work now. Conceptually, an entity is any storable piece of content that's going to have an ID that you're going to reference by some ID number, or ID field. In Drupal, we divide them into config entities and content entities. Content entities are fieldable. That means they can have configured fields on them. This is what we're used to with Drupal 7 with fields and nodes and all that kind of stuff. Configuration entities are a useful shortcut. They're actually what plugins use under the hood. I'm not going to get too far into those, but you can look them up if you need to. And yeah, the API actually is finished. It actually works now, which is more than I can say for Drupal 7. Lots of things are now entities. Nodes, users, taxonomy terms, files, comments. There's about a dozen different things in Drupal now that are content entities, which means they are then fieldable. You can do all kinds of fun things with them that you're used to doing with nodes. Nodes are no longer special. You can make your own entities and they get all of this stuff. You can make your own fieldable entities quite easily. So let's go ahead and create a node. Just gonna give it a title, give it a body, give it some tags. It's just an article node default out of Drupal. And make another custom page. We're gonna put this at node slash node slash hug. Give it a controller, give it permission. Same as we've seen before, nothing new here. That controller then is going to have its first print. It's a one parameter B node. And we're also type printing it to the node interface. Entities are actually classed objects. They're no longer arrays of funny syntax. So the terrible, terrible list of arrows and brackets you had to use to get to anything in Drupal 7? Gone. And let's find a fascinating which things people applaud at when I give this talk. And because we're using the name node, the variable, and type printing at its node interface, it will automatically get cast up. So instead of getting a node ID, we'll get the actual node object at this point. Same kind of thing you could do in Drupal 7 with the menu, but it's now a lot cleaner. And now, you wanna check if a node is published? You call the isPublished method. Oh, goodie. You wanna access a value out of it? Let's get the value column out of the body field. That's it. If it's multi-value, then you can put a bracket in there and specify which index you want. Wait a minute, how in the world does that work? We're actually using PHP's magic underscore underscore get and underscore underscore set methods. So both of these get the body field first instance value column. That way, if you have a field that is multi-value, you can treat it as multi-value. If you have a field that you only want to use as if it were single value, you can use it as if it were single value. Under the hood, everything is still multi-value all the time, but it's a lot easier to access and this is not gonna break when you change the field to suddenly be multi-value. That first line will still always work to give you the first property. But what you really want is the processed property which takes that field and runs it through all of Drupal's filters. So please never use value, use processed, otherwise you have a security hole. Thank you. You want the, you can get the tag field which is an array iterate over that and for each one, we're going to call the entity pseudo property which loads the actual taxonomy term object and we're gonna get the label of it. The label method of an entity is consistent across all entity types. You want the title of a node, node label. You want the username of a user, user label. You want the tag name of a tag, tag label. Same for all entities now. You want the node owner. There's a nice method for that. This gets the username of the owner of the node and then there's the nodes title, node bundle that's the node type. Bundle is the generic term that's used across all entities and just build up our string and return our render array. Now I'm doing it this way to show you how to use the entity API but really all that logic belongs in a template. Don't actually do this, put this in a template. But in a twig template, you can call these methods as if they were properties and properties as if they were methods. It's a consistent thing in the twig template so all of that happens for you there too. It's super powerful and it also means you don't need to touch preprocess all that much either. Yay. And so here's our output. Ta-da. Let's review Drupal in two steps. Build a tool, wire it up. Extend the base class, tell Drupal about it. The way you tell Drupal about it may vary. It's typically going to be either a YAML file or an annotation. How do you know which one it's gonna be? Well if it's, plugins are not always annotations, some of those things that use YAML are actually plugins under the hood. What's the distinction? If you're using this metadata to tell Drupal what something is, that's an annotation. If you're telling Drupal where it goes, that's gonna be in YAML. That's not a hard and fast rule but that is how the system is shaken out. What it is is an annotation where it goes is YAML. And the thing itself is a class. Congratulations. That sentence is Drupal 8. Some last guidelines. You want small classes and smaller methods. If you have a method that does 17 things and has 40 variables in it, it's too big. Break it up. Single responsibility principle. Learn it, love it. Your controllers should be stupid. That includes the build method of a block which you should treat the same way. If they have code in them, complex enough that it is worth bothering to test, you have too much code there. Factor it out to a service. Your controllers should be stupid glue code. If most of your controllers are return render array with a bunch of properties directly, that's a good thing. If you're doing anything more than that, you probably want a service. Services are where your logic belongs. That makes it unit testable. That makes it, in many cases, Drupal agnostic. That means your code could be used outside of Drupal. It means if we break stuff again in Drupal 9 in six years, or seven or eight, yeah, then it becomes much easier to port. You could port it to a symphony application and change very little if you do your services properly. Even if you can't make it Drupal independent, this makes it easier to test and easier to maintain. You'll notice I did not have a single SQL query on any slide. I spent an obscene amount of time in Drupal 7 building a new fancy database API that was very easy and friendly to use and I'm here to tell you now in Drupal 8, please don't use it because Drupal can now run with no SQL database at all. Drupal cannot run entirely on MongoDB or Cassandra or whatever other backend you want because we have a much more robust set of pluggable APIs. Any of these services that you're telling Drupal about, you can swap those out. Any class we have that has actual SQL in it, you can swap out for one that has a MongoDB backend. You can swap it out to have a different version of the code for MySQL versus Postgres. There's actually built-in support for that too. If you have to have code that does SQL queries yourself for performance reasons, make sure it is done in a swappable fashion. It's your own custom module for a site, whatever, but if it's something you're releasing on Drupal.org, make it backend agnostic. And once again, if it is hard to unit test, you are doing it wrong. If you find yourself writing code in like ag, there's too many dependencies here, it's tight into this thing, that's because you're putting the code in the wrong place, factored out to a service. Your service is too big to test conveniently, break it up into multiple services. This is probably the best guideline for high-quality code in the modern PHP world. If it's easy to unit test, you're on the right track. If it's hard to unit test, you are doing it wrong, fix it. And that, in a very large nutshell, is Drupal 8. Thank you. We've got a couple minutes for questions. There's a microphone over here if you'd like, so let me know if there's anything you don't get. I'd like to ask just a really simple question, because I did attend the presentation this morning about Symphony, and I'm super-duper excited about Symphony and Drupal 8. I think that's gonna be total awesome this for us. In his presentation... This is Ryan Weaver's presentation? Yes, yes. Thank you for helping me out with that. I was drawing a blank on it. Ryan's a great guy. In his presentation, the way he had put his slides up there, and he said right up front, he's not a Drupal developer, but the way he had demonstrated his slides when he was showing the various responses for things is that when he concatenated things, for instance, he didn't have the space on either side. And he had also showed where you did like with the annotations here, when you're gonna do your... I don't remember if we used Chung as a service or whatever, but instead of having a separate router YAML, and then like your module file, for instance, he put it together with the annotations. So my question is this, did Drupal coding standards in Drupal 8 for doing these types of things? So one, I'm assuming we're not changing our standards in terms of like space on either side of the concatenated, et cetera, et cetera. And then the other thing that may be a new standard is, are we gonna follow, because he said the way that symphony does things, generally when you write it is that you put all those things in the one file and use the annotations. So this is a standards question for Drupal 8. So Drupal still has its own coding standards. We are not switching to PSR2, which is what symphony uses. As for where the configuration goes, symphony supports about four different ways to configure anything. They support YAML, XML, annotations, PHP config files, all kinds of things, and not every symphony shop uses the same one. So you can do routing from a YAML file in symphony. You can also do it from an XML file. You can also do it from extra annotations on the controllers themselves. In Drupal, the way I showed is the only supported way. Well, correction, there is an event that fires where you can do dynamic routes, but then you're doing custom PHP code for those. But no, we do not support routing via annotation on the class. Thank you for your talk, and also for your song this morning, which I thought was really cool, and you crushed it. So my question is about the service container. I've actually heard you give a similar talk before where you said something similar that if you directly knew up an object, if you say like var equals new, my class, that the code in which you've done that will no longer be unit testable. And I'm not, I'm still not sure I get why. Could you just kind of expand on that? So anywhere you have a hard-coded class name, you have a hard-coded dependency on that class, that specific implementation class. In the vast majority of cases, you actually don't want that because it means you cannot use your code or test your code without that class. You cannot mock it. If, so if something is a service, you always inject that. If you have something like, the exception to that is if you have a value object of some kind, like you have an object that represents an address, which is three or four different properties or whatever. That's a value object. That's just data, that's not logic. That may make sense to instantiate yourself or get out of a factory, if you're loading it from a database or something. But that's different than a service. It's an important, it's a little bit of a tangent, but there are types of objects that are B objects. They are responsible for representing data. And there are doer objects that are responsible for having business logic. Those are services. Those you never instantiate yourself, you always inject. The B objects, sometimes you can instantiate yourself, sometimes you would load them from a factory service. Drupal does better than it used to in keeping that distinction. It is not complete in that distinction, but very often, when you run into, this is just a thoroughly bizarre chain of objects. Oh, that's because you got that B versus do wrong. So does that help a bit? So when you reference mocking out objects, is the expectation then that when you're unit testing your code that you would, I guess you would change the service that you're using would return some different object. You'd be replacing the service. Right, so if you're testing a service and that service depends on another service object, then you're not even using the container. You're creating a mock version of that other service and pass it into the constructor of the class you're testing. And if you're in PHP unit, which we now have in Drupal 8, that has its own mocking framework, it actually has two now. It's moving over to Prophecy, which is a newer mocking framework a lot of people like, so you can use that in Drupal 8. You're not actually gonna touch the container. That's another example. If you're writing a unit test and you have to have a container, you're doing it wrong. Okay. Lots of cores still uses a container in their tests that means they're doing it wrong. But for your code, you can be better than core. Thank you very much. Kind of still along the dependency injection conversation. I just thought it was interesting that the, I think it was the controller had that static create method which was using the container to create itself versus having that, in other cases where I've used dependency injection, we kind of avoided pushing the container to other parts of the code other than the kind of single point of initialization. So I was just wondering if you could elaborate on that a little bit. So there's, in symphony, there's two schools of thought about how to deal with services that are used in a controller. One says use a common controller base class that has the container and just accept that the container's gonna be there and use it because you have no business putting code in there that is worth testing anyway. The other is controllers should be clean as well. And so you have controllers registered as services. We looked at that and said, well, we're gonna have a couple thousand controllers that'd be a couple thousand services, let's not do that. So the middle ground we came up with was this create method. So the controller object itself does not have, well, I shouldn't say that. The controller itself does not have an exposed container in it. Your services are passed into it via the constructor, through via the constructor from your little factory method, your create factory method. So that's kind of our middle ground that we came up with for that. Makes sense. If you want to be hardcore about it and have controller services, those are supported, they're just not really used much in core. So when you started talking about theming, you introduced the trans tag. And I'm a little bit confused because you also used the T method before that in the controller. So is there some sort of magic link between the two? The way it works, it actually compiles down to PHP code and that's what gets run at run time. The trans tag compiles down to a T function call. So did we run it through the T function twice then? No, when you indicate a trans block in a TIG template, when that gets compiled, what the actual PHP code that runs is the T function, whatever string you had. So the net result is the same, which means both are exposed to translation system in the same way. It's not double called, if that's what you mean. So why would I choose to translate in the theming layer versus in a controller? If, so in practice, most of the time I would actually put it into the theme layer at this point. The things you'd still do with the T function would be things like the label of a form element, for example. Or some other piece like that. And actually that's the only one I'm coming up with off the top of my head. There may be a few other places where you might need to, but anything that's user facing output that a themeer might conceivably want to touch, put that in a template. I would say put that in a high level custom template. You can do very deeply nested render arrays just like you could before. I would encourage you to not do that. Just pass values in to a custom template, the highest level you possibly can, like from a controller, and then all of the actual logic of if this value is less than three, show this string. If it's greater than three, show this string. If it's greater than 10, show this string. All of that belongs in the template layer. None of that belongs in the controller. It belongs somewhere that the themeer can get at it. All right, thanks. Yeah, so I'm being told I have to, I'm getting the hook here, so let's talk after. Thank you. Hey. Okay, so the fact that we are really flexible in flipping databases, right? And the fact that the symphony is a foundation. So are we using Doctrine or RAM actually to work on databases? I need to pack up here, so come up to the stage.