 I always get really nervous before these presentations, so I'm like, ah, it's gonna start in like a minute. And it's like, oh, whatever, I can just start now. Nobody will mind if I start the part where I introduce myself early. Closer to the mic, is that better? Can you guys hear all the way in the back? Awesome, all right, I'll try not to move too far from this position, but I make no promises. So I'm gonna be talking about the Drupal 8 plugin system. So if that's what you're looking for, you're in the right room. If that's not what you're looking for, feel free to go find something else. My name is Joe, or EOJTheBrave on Drupal.org, IRC, pretty much anything internet related since about 1995, where I thought, oh, I need a really kick-ass name for playing Warcraft, and well, it's stuck ever since. I currently work for Lullabot. I'm part of the DrupalizeMe team. I do a lot of educational video, helping maintain the DrupalizeMe website. I've been doing Drupal stuff for quite a long time at this point. I built my first Drupal site with Drupal 4.5, and have pretty much stuck with it ever since. I have had a few forays into other things, but keep coming back to Drupal. I really enjoy teaching people about Drupal, being able to stand up and talk about things like the plugin system and get to spend the time to understand how a particular system in Drupal works and then share that knowledge with other people. This is kind of like my warning. This presentation starts out pretty simple, well, kind of simple. Actually, the hardest part of this presentation is explaining what a plugin is, and then explaining how the whole system works is actually not that complicated, but it does get really code heavy towards the end. So we'll kind of start out with some basics, talking about what a plugin is, what the problem is that we're trying to solve with plugins and how they work, and then we'll look at a lot of the code that's involved with that. All of the code is available in this repository on GitHub, so you can take a look at it now if you want, or afterwards, hopefully it'll serve as a good reference for figuring these things out for yourself in the future. So explaining what a plugin is is kind of complicated. It's a pretty abstract concept, and for me it makes sense to try to step back and divorce it from what are we trying to do with the code, but what is the problem that we're trying to solve with plugins? And I think that one way to understand that problem is to think about the whole plugin system with the analogy of an ice cream shop. At a really, really high level, if you think about how an ice cream shop works, as a customer, I'm able to walk into an ice cream shop and purchase a scoop of ice cream. Regardless of what happens, all I have to do is ask the person at that front desk, I'd like a scoop of vanilla. They go off, they do a bunch of work, they maybe find the vanilla in the cooler, maybe they've got to go to the basement, they've got to get a scoop, they scoop it out, they put it in the cone, they do all this work, that doesn't really matter to me what they're doing. As long as at the end, they hand me, in exchange for the money that I've given them, a scoop of vanilla ice cream and an ice cream cone. Once I've got that ice cream cone, as a ice cream consumer, I know what to do with it. Like it doesn't matter where it came from, I know how to eat that scoop of ice cream. So there's a lot of components there, like when you go and ask for that scoop of ice cream, there's a lot of things that need to happen. And part of what the plug-in system does is it tries to provide an abstract pattern for all of those things. Things like discoverability. When I ask for a scoop of vanilla ice cream, how does the system, the ice cream shop in this case, find the vanilla ice cream in the cooler? They've got some way to discover it, so they know where all of their ice cream is. There's a consistent method for them to access that. It would be really silly if a employee of an ice cream shop had a different way to scoop every kind of ice cream. Could you imagine if every tub of ice cream had a different lid? And whenever somebody asked for chocolate, we had to figure out, okay, this is how the lid for the chocolate works. And they're like, oh, strawberry rhubarb. And you're like, oh, that one's this one. I gotta figure that out. Something like different actions that need to be performed. With ice cream, you need to do things like calculate the price of the scoop so that you can charge the customer for it. The ability to serve it and sort of a known interface for me as a consumer to eat that ice cream. It'd be really weird also if every time you ordered a scoop of ice cream, there was a different way that you had to eat it. It's like, well, if it's vanilla, you've got to hold it in your left hand. But if it's chocolate, you've got to hold it in your right hand, tilted to the side a little bit. Just wouldn't make sense. This applies to a lot of things in Drupal, too. Maybe think about it. Think about blocks. What the block system needs to be able to do is it needs to know what blocks are enabled and which module provides those blocks and where to find it. And once it knows where to find the block, it needs to know how to get the title of the block. And once it got the title of the block, it needs to do things like listed in the block administration interface so that as an administrator, I can move them around to where I want to. Or image effects. So you create an image style by combining a bunch of effects together. The image system needs to know what are all the effects that are available in this particular instance of Drupal? And that can change depending on the modules that you've got installed. Once it discovers an image effect and you add it and you say, here's my style, it can rotate things and it can turn them black and white, the system needs to know how to ask that particular effect to do whatever it is that it does. But you don't want to have to write custom code every time and say, okay, when you want to call the effect that rotates the image, do this, when you want to call the effect that changes the color, do this, you want to provide a simple way to say, hey, image style, do your thing. The Drupal.org handbook says this about plugins. The Drupal 8 plugin system provides a set of guidelines and reusable code components to allow developers to expose pluggable components within their code and, as needed, support managing these components through the user interface. So that's another maybe helpful definition. If you're more of a coder or kind of like to think in terms of design strategies or programming analogies, plugins are a discrete class that executes an operation within the context of a given scope as a means to extend Drupal's functionality. So both of these kind of get again at that. Plugins are all about providing a consistent way for creating a list or for Drupal to discover all of the things of a given type and then know what to do with them regardless of where it founded or who provided it. So, I need a glass of water, hold on. Plugins in Drupal are limited in scope. What this means is that every single instance of a plugin does exactly one thing. Each block provides a title and its content. Each image effect provides the name of the image effect and the action that that effect does. Every field widget provides its name, its settings, and kind of whatever is necessary in order for it, that field widget to do its thing. But it only does that one thing. A lot of plugins are designed to be configurable and reusable. An example of that would be an image effect that changes the color of an image when it's applied. Rather than write a new plugin for red, green, blue, yellow, you write one that's changed the color and then allow it to have configuration that says when this plugin is called in this context and the application is in this state, use the color green. When it's in this state, use the color red. Once I get to thinking about what plugins are and how it all works, I kind of realized that what we've got here is what in the computer science world we refer to as a design pattern. Sort of like a service container or dependency injection or a binary sort. They're all patterns for accomplishing some relatively common problem in a generic way. But design patterns also aren't just a, here's the chunk of code that you need. Go ahead and use it. They're a strategy or a template for solving the problem. You're still generally required to do some of the work yourself, but if you're going to do it, here's a good place to start and follow the pattern. So plugins are that. They're a solution to the problem of I need a generic list of things and I need an easy way to deal with that list. It doesn't handle everything for us, but it gets us started. And what it does is by providing that pattern we also have consistency across all of the different systems in Drupal that make use of plugins. So examples of things in Drupal that are plugins includes, but is not limited to blocks, field types, field widgets, field formatters. If you've got the actions module enabled, all of the different actions that you can perform are represented as plugins, image effects, the buttons on the CK Editor widget, each of those are not widget, I guess you would say WYSIWYG are individual plugins. You start to see a pattern here. Remember in Drupal 7, and how could you forget? We're still using Drupal 7. Remember yesterday when you were working on writing some code for your module and you had to implement this pattern? First thing you do, implement the info hook, which returns an array that describes sort of what your thing is, the title of your block, the ID of your image effect, whatever the case is, and then implement some set of callback functions that are sort of magically, if they exist, they'll be called, if they don't exist, well, no one will ever know. This is a really common pattern in Drupal 7, and this is dealing with that whole thing, discoverability, right? The info hook is how the block system discovers what blocks are available. The hook block view is a known function that when Drupal wants to display a specific block, it says, okay, I need to call the view hook for that block. Plugins accomplish the same thing, just using a slightly different pattern. We're using object-oriented programming here, so we've got a bunch of classes. The discoverability happens and that Drupal now knows, okay, I need to find the class that is the representation of this block. Once I've found it, I can call the get title method on that class, or I can call the get content method, which is kind of akin to calling the view hook in Drupal 7. So that's kind of the problem that plugins are designed to solve and a little bit about what a plugin is. Hopefully all of those different analogies help us kind of go, okay, I think I've got to handle on what plugins are. How about why plugins? Why a system like this and why is this important? There's a lot of different reasons. The biggest one being there is an identified problem of we need Drupal to have a way to have a generic list of things and then handle that list. And it was done already in Drupal 7 with info hooks, but we felt that there were ways that that could be improved and make the whole system a little bit easier to understand and to work a little bit better. Plugins are awesome because all of the code for executing that or being that block is in one place. You've got one PHP file that represents one block and it's great rather than like, wow, there's a hook here and there's another one at the bottom of the module and there's actually a callback that's happening inside of this other module that's named something totally different. All of the code that makes up the system information block that displays the little Drupalcon in the footer is in one place. This helps make it easy to reuse. You're not dealing with a scenario where you've got multiple different modules that you need to install in order to get one plugin to work. It makes your code more portable across systems. I feel like I'm standing on my tippy-dose. Here we go. Plugins are lazy loaded. So using the PSR4 auto loader, you can put all of your code that makes up a block into your .php file, store it away inside your module. Drupal won't even bother loading the code in that file until somebody actually asks for and needs that plugin which is great because in Drupal 7, you've got a module that has 15 different blocks. They're all in the .module file. That's a lot of code that needs to be loaded into the opcode cache and all of that that isn't necessarily used on every single page. It's not a huge performance benefit but it does start to help, especially when you have sites that have hundreds or more modules installed that .php overhead can start to be a thing. And you don't have this crazy, this is one of my favorite parts about plugins. The elimination of things like hook block view or the scenario where you've got an info hook that defines five different blocks and then you've got a view hook that's called with a delta parameter. And inside of that hook, you've got to do like a big switch statement or an if statement says, okay, if it's this block, do this thing. But if it's this other block, do that other thing. It makes the code a little bit hard to read, especially as you get more and more of them. Having everything contained in one place is really nice. Before we can go ahead and start writing our own plugins. So if we wanted to implement a block or a new field widget or something like that, there's a few things that we're going to need to understand about how the system works. Number one, I write this, you don't need to know symphony in order to write plugins. When I first started trying to figure out this system, I was under the impression that like, okay, I'm gonna need to understand how symphony works if I wanna understand how plugins and all of that work cause I need to know about dependency injection and the services container. And ultimately I realized like, those are patterns, those are things that symphony does and knowing symphony will certainly help you understand how plugins work and make it easier, but you don't need to know it in order to write a plugin. You do, however, need to know and understand how PSR4 works and I'll have samples of all of these. So PSR4, annotations, dependency injection, and if you're going to write your own, create your own new plugin type, you'll also wanna understand how the service container works. PSR4 is a auto loading standard. Essentially it's a naming convention. It says name your class this, put the file in this place, and Drupal will automatically discover it. This is how it does that lazy loading thing of saying, when I wanna view the system information block, I load this class and I instantiate an instance of it, Drupal knows, okay, I gotta go here, I gotta find that PHP file, I've gotta bring that into memory, now the class is there and you can make a copy of it. The plugin system uses this extensively in order to be able to do that discoverability of plugins. A lot of the discoverability has to do with placing your class into the appropriate namespace, which then because of the PSR4 standard means if it's in this namespace, I need to put it in this set of subdirectories and the file needs to be named with this specific name. Drupal can now find all of the blocks, block plugins because they're in the block plugin namespace. So here's a kind of an example of that. PSR4 basically breaks down into, you've got your vendor namespace, which in the case of Drupal, it's just always going to be Drupal. You've got your subnamespace, which when we talk about plugins is kind of the more important bit here. So the subnamespace for the block plugins is plugin slash block. You can see the directory structure there. Namespace under code here, it says Drupal slash Peter slash plugin slash block. So the Drupal slash Peter in this case is the vendor namespace slash plugin slash block is the subnamespace and then you've got the name of your class. So there's a ton of information about the PSR4 standard on Drupal.org. So you can take a look at it there. Annotations are another important thing to understand. Annotations are essentially a way of dealing with the metadata that we used to put inside of Info Hooks and now we put it in the doc block that's associated with the class. This works because kind of a funky thing that the opcode parsers do in PHP. If you write a comment that is in this style on the, I guess that's the right with the traditional doc block style, those comments are still available inside of the opcode and so PHP can perform introspection and it can read the content of that comment. So then we write specially formatted comments that contain things like the ID or the title of this block. So rather than having an Info Hook which says here's the ID of this block, here's the title of that block, it's contained within the comment that goes along with the class that defines the block. Love it or hate it, annotations is the way that we handle this scenario. You're gonna need to know a little bit about dependency injection when writing plugins, especially if you're going to be doing something like having your plugin use the database for something. So your block maybe needs to query the database to get a list of all of the recent forum posts so that it can display it. In Drupal 8, if you wanna do things like access the database or make use of any of the different services, we use dependency injection. So you inject a database controller into your plugin, you make use of it there. This is an example of how dependency injection works. I'm not gonna get too in-depth in this. There's like, I think this week there was an entire hour long talk about dependency injection and how it works. The gist of it is you give a class or some code a copy of the thing that it needs to do its job. So in this case you're saying rather than instantiating your own instance of the database class, take the one that I've already got and make use of that. That's really dependency injection in a nutshell. And if you're going to write your own plugin manager, which we are going to do before the end of this presentation, you'll need to know a little bit about the Drupal service container. This is part of the whole system of dealing with dependency injection. You can imagine where you've got, okay, I need to instantiate a copy of the database so that I can give it to your block plugin so that you can make use of it. But there's also a lot of other services and some of those services have interdependencies like the database system also needs this other system, the block system also needs these other three systems in order to work. The service container allows us to do things like say, give me a copy of the database, Drupal, go ahead and take care of instantiating and making copies of any other dependency of the dependency that I've just asked for. We're going to use this when we write a new plugin manager and we'll say give me a copy of the plugin manager that I just created and it'll take care of things like, oh, you also need a database controller, oh, you also need an HTML render and all that kind of stuff. So before you write your own plugins, you're going to need to know how the PSR for auto loading standard works. You'll need to know a little bit about annotations, really just how to write them, not so much how the system works, but more like how to know what to put into the annotation, dependency injection and our service container. That's what you need to know about Drupal and about PHP. You're also going to need to know this about your plugin. What type of plugin are you going to create an instance of? Are you trying to create a new block? Are you trying to create a new field widget? Are you creating a new image action? Once you know what type of plugin you're creating, that will by definition tell you where the code for that plugin goes. So following the PSR for standard, if I'm going to implement a block, I need to put it in the plugin block namespace, which means that in my module, I need to put it in the appropriate directory to match that namespace. Most plugins use annotations for their metadata, things like the ID of the block or the title and that kind of stuff. Not all of them do though. There's a couple of other formats that you can provide the metadata and then we'll take a look at those as well. You need to know which format this particular type of plugin uses. So the pattern then is things like, you need to know the type so that you can know how it's discovered. You need to know the type so that you can know how its metadata is used. You need to know the type so that you can know which interface to implement. Interface is being a PHP interface, so there's the block plugin interface. So if you're going to create a new block, you need to implement the block plugin interface which has things like enforcing that you have a get title method and a get content method. This is the plugin systems way of knowing that if you're a block, you will absolutely have these three different methods that I can call when I need to. I don't care what you do in those or how you get the title or where the content comes from. As long as when I call get title, I get some title back. The best thing about this whole system is it's all in Drupal and it's all open source. So really what you need to know how to do is copy and paste what somebody else did and then make a few changes to it. In most cases, and in fact in core, in every case where there's some system that is implementing a new plugin type, there are also instances of that plugin type, right? Why would we create a plugin type that we're gonna be like, ah, but it's just here for fun. We're not actually gonna write any plugins. So you wanna create a block? Take a look at how the system module created a block. Take a look at how the node module created a block. Copy and paste that code and start making changes. All right, you ready? We're gonna write our first plugin. This is our first block plugin. Seriously, that's it. This is all of the code that's necessary in order for me to create a Hello World block in Drupal. And if you take a look at this and read it, probably 50% or more of that code is actually comments. Almost all of the rest of it is just boilerplate things, like declaring the namespace and the name of my class and so forth. And then there's this one line here. Well, it's like four lines that returns a render API array that says the content of this block is Hello World. So what we've done in order to create a new block plugin is create a class named ChadBlock that extends the block base class. We've put it into the namespace that includes the subnamespace of plugin slash block. When we've done that, because of the PSR4 standard, the file that contains this code is inside of our module in a directory named SRC and then inside of that plugin slash block slash ChadBlock.php, or the name of our class.php. The block system can now, just by doing that, it can find the code that is our block. We've got an annotation at the top of the class here. This annotation provides metadata about our block. The annotation is nice because Drupal can locate the code that makes up our block. It can parse the annotation and it can do things like get the ID and the administrative label and the category. You recognize these things are all used on the block administration interface where somebody can go and see the name of your block and drag it around and put it into the right sidebar or the left sidebar and so forth. Because it's in this metadata that's provided by the annotation, Drupal doesn't need to instantiate a copy of your block class in order to know its title. It can just read it right out of the annotation. So there's a little less overhead there and not having to create a copy of that class in memory, call some method on it to get the thing that it needs. It can just read it right out of the annotation. That annotation, then, of course, all of the data from it is fed when a copy of the block is instantiated. The information that's in the annotation is passed into the block itself so you can make use of those labels there. You see that we're extending the block base class. This is another really common pattern. Most of the plugin types, I think maybe all of them now actually, I don't quote me on that, but I'm pretty sure all of them in-core have a base class that you can extend when you're creating a new instance of that type of plugin. If you think about it, there's a lot more to a block than just, hey, here's the content that goes in the body of the block. There's things like the form that you can use to figure the block and decide which region it's in and the theme. There's things like being able to save the content of that form when somebody clicks the submit button, knowing who has access to view the block in under what settings. There's that in the form you can say, display this block on this page, but not on that page, or display it for logged in users, but not anonymous users. All blocks can do that stuff, but that's kind of the same for every block. The form's the same. The ability to alter the visibility is roughly the same, and so all of that code gets contained inside of this block base class. This means that I don't have to rewrite boilerplate code all of the time just to implement a block. I extend the base class. It provides me with the form for doing configuration and all of that if I want to. If I had a need to, say, provide a configuration option inside of my block so that it could say hello, and then I could write my name or whatever to say hello, Joe, instead of hello, world, I could override that form and make changes to it, but I don't have to unless I need to. So here's a pro tip. Anytime you're creating an instance of a plugin, do it by extending the base class for that plugin type. If you're going the copy and paste method, well, this will probably already be happening for you because you'll just be copying what core does, which is extend the base class, but a great way to get started figuring out what any new type of plugin can do is by extending that base class and taking a look at the things that the base class does. The base class will also always be an instance of the interface. So we've got the block plugin interface that says if you're a block plugin, you've got to have these five different methods and these two properties. The block base class is an implementation of that interface and it already provides those base methods. So things like get the ID or get title are already done for us. We don't even need to have that boilerplate code inside of our plugin. That's kind of the gist of if there is an already an existing plugin type and you'd like to provide a new instance of that. So if you want to create a new block or you want to create a new field widget, or really if you want to create any of those things that we, not any, but most of those things that we used to do with info hooks, this is how you do it. Know what type you're going to create so that you can then know where the code needs to go, what needs to be in the annotation to go with it, and which base class to extend. It hasn't all played out yet because we're still kind of figuring out how all the pieces of Drupal 8 fit together and how all of the modules that are in contrib get ported to Drupal 8. But my sense is that as we move more and more to doing development in Drupal 8, understanding how to create and write your own plugins is going to become really important. I think this is, as a module developer, we're going to end up spending a very large portion of our time writing plugins to provide additional functionality for systems within Drupal. Of course, we're also going to occasionally need to write our own plugin type. Let's say you're the voting API module and you want to provide a way for people to vote on something and then tally those votes. So you write the voting API module. Okay, you're not actually the voting API module. You're the maintainer of it. So you write the voting API module and it allows for someone to come and say, yep, plus one to that and then tally the score and display it. And then later on somebody else comes along and they're like, well, I have this special requirement where when somebody plus ones it, if it's a Wednesday, it actually needs to be a plus 1.75. But if it's a Friday, it needs to be a plus 1.2. Could you make some changes? Here's a patch for the module. And then we're like, okay, you applied that patch. And then somebody else comes along and they're like, well, actually, when somebody plus ones things on my site, I need it to be a plus two because I've got some other crazy requirements. And so you start, you keep patching those things into your module. You end up with this kind of spaghetti code where you've got like, well, if this, then that, otherwise this, otherwise that. Instead of trying to be everything for everyone that ever wanted to do some kind of voting, you could provide a plugin type that did something like say, this is how we tally votes. So now the voting API module implements a new plugin type, probably provides one instance of that plugin type. That's just a simple plus one, but lets any other module provide whatever kind of tallying it needs, instant runoff, multiple choice, whatever the case may be. And it ultimately provides for more flexibility. So if you want to do that, and you're probably going to end up doing so at some time, this is the process that you'll go through in order to create what is called a plugin manager. And I also think that by taking the time to look at how plugin managers work and looking at the code, will give us a much better understanding of how the plugin system as a whole works. So this is the part where we're like, all right, I'm going to build my own ice cream shop. Behind the scenes when you're building a plugin manager, these are the kind of components that make up that system. You need the plugin manager itself. You need the thing that can say, give me a list of all of the plugins of this type. Really the plugin manager defines what the plugin type is. So there's the block plugin manager. You've got a block plugin type. There's the image effect plugin manager and so forth. The plugin manager takes care of handling discovery instantiation via a factory, a mapper which is another way of handling this whole figuring out which plugin to get an instance of. We'll talk more about that. And then they are all implementations of the plugin manager interface. This is kind of the list of, okay, this is what we're going to do. We're going to build a plugin manager. We're going to define the discovery mechanism. We're going to define which factory to use when creating instances of a plugin. All of that is going to be an implementation of this interface. The way it works is you, there are already a handful of different discovery mechanisms built into Drupal, and likely what you're going to do is rather than write your own discovery mechanism, you'll use one of the existing ones. So you might use something like annotated class discovery, which is what we just saw with the block plugin. And the annotated class discovery is definitely the most common discovery mechanism. It's the one that says, follow the PSR4 standard. If the class is in this namespace, it must be an instance of the plugin that I'm defining. And then go ahead and read in that annotation. So inside of your plugin manager, all you really need to do is tell the system, hey, I'm going to use annotated class discovery. This is kind of what that would look like in the arguments here for the annotated class discovery class. You pass in a couple of things. You can see there's plugin slash block. So I'm defining the sub namespace in which my plugin lives. So for the ice cream store, this might be something like plugin slash flavors, because I've got flavors of ice cream. You pass in the alternately an array of additional namespaces. And then you can, excuse me, the last one here is the class that provides the annotation for the, in our case, block plugin. But if we're going to create a new one for like flavor plugin, this class, drupal slash block slash annotation slash block, is really just a class with a bunch of properties on it and the properties are all empty. But what it does is it serves as documentation for what could go into a block plugin annotation. So if you're ever curious about like, oh man, what the heck goes in this doc block at the top of the block plugin? I've seen a couple of instances, but maybe there's more things. Figure out which class is the representation of the annotation. Open up that file and all of the properties in there will have comments for them that explain what they are. And if you then go back to your annotation, those properties of that annotation class map to what you could put in your annotation. This was a really tricky part for me initially. It was like I could copy and paste the plugin. But then I would know there was additional, or at least I would assume there were additional things that I could put into the annotations, but I could never really figure out what it was. And your IDE isn't going to figure it out either because the IDE doesn't read the comments in the doc block. So knowing where to find that information was really important. There's a couple of other discovery mechanisms that you could use, hook discovery. This is that info hook thing, right? You say call my info hook, we'll say block underscore info. It's going to return an array of information that is both the metadata and the information necessary in order to locate the code that makes up this plugin. This one exists. Unless you have a really good use case for hooks, I would still recommend going with annotated class discovery. I think this mostly exists in order to provide some level of backwards compatibility as all of the systems within Drupal are slowly migrated to plugin types. There's a YAML discovery mechanism. The use case for this is when you need to be able to... things that need to be discovered, their metadata discovered and used really early on in Drupal's bootstraps, really early in the life cycle of a page load, things like menus. You see this all the time with menus. You've got your mymodule.menu.yml. What that is is an implementation of YAML discovery for a menu plugin. It does that because really early on, Drupal can read in and parse that YAML file and get the information before it's got access to the database, before it's completely loaded all of the classes and so forth. The instance in which you would use this in your own plugin type is if you need your plugins to be accessible really early in the life cycle of Drupal, basically before Drupal's been fully bootstrapped. Then there's static discovery. I have no idea why you would actually use this one, but you could if you wanted to. Static discovery is basically hard coding. Here's the location of the plugin. Go ahead and load it. It's used a couple of times in core. In core, it's just used for loading tests. So mocks for different tests within Drupal use the static discovery. As far as I know, there aren't any other uses of it currently. If you have to pick one, pick annotated class discovery. It's the most commonly used in core, and by doing that, by following what core uses is the most common pattern, you're making your system easier to use because people go, oh, I already know how blocks work. If this works the same way that blocks do, it's easier for me to implement. If that wasn't confusing enough, or if you wanted to make it even more interesting for people to figure out how to where and when and why and how to implement a plugin of your type, there are what are called discovery decorators. A decorator class is a design pattern in which you've got a class that implements an interface and wraps another class that implements the same interface. The decorator class may do some additional processing that the normal class wouldn't do. Think about Drupal 7 alter hooks. You call hook info, you say, you know, module invoke hook info, give me a list of all of the blocks. And immediately after you call Drupal alter, here's the list of all the blocks. What this is doing is saying, give every module a chance to list a block and then give every module a chance to change the list of blocks. The discovery decorators can do things like that. So if you're using the hook discovery plugin discovery type, you can also use the hook discovery alter. I don't even know the name offhand. You probably can't read it because I can't. Oh, info hook decorator. There we go. And that will do things like allow for essentially calling an alter hook after it's done the discovery. The most commonly used one and the one that you'll probably end up running into the most is the derivative discovery decorator. Got that? Derivative discovery decorator. What the derivative discovery decorator does is it allows for a single plugin instance to provide multiple copies of itself as separate instances back to the plugin manager. Think about menus in Drupal. As an administrator, I can go and... Drupal comes with a handful of menus, navigation, main menu, secondary menu, and so forth. As an administrator, I can go and fill out a form and hit submit and I've just created a new menu and I can do that any number of times. Every single menu in Drupal has a corresponding block in the block system that I can go and place into your region or however you want. It wouldn't make any sense if every time I created a new menu, I also had to go create a new PHP class that was an implementation of the block plugin system that knew about just my specific menu. Instead, the menu plugin manager, the block plugin manager, uses derivative discovery and what that does is allows the menu module to provide a menu block plugin, but the menu block plugin, when it's loaded, can then go and query the database and say actually there's five different menus defined in the database, so just pretend like there's actually five copies of me, the menu block, but each of them has a different ID. That's the use case for things like derivative discovery. Once you've determined in your plugin manager what type of discovery you're going to use, you need to also determine which factory you're going to use to create instances of the plugin. Really what this does is say, this is the part where somebody comes into your ice cream shop and they ask you for a scoop of vanilla ice cream and you go okay, cool, I know where the vanilla ice cream is because I've implemented derivative discovery of my ice cream as one does. You go into the cooler, you locate the vanilla ice cream, and now you instantiate an ice cream cone with a scoop of vanilla ice cream in it. You've just kind of created an instance of that vanilla plugin and you can hand it to the consumer. Factories deal with taking a plugin ID and doing whatever is necessary in order to load the code that makes up that plugin and instantiate a copy of the class. It might be a little bit different because some classes might need to have the services container injected into the class so that you can do things like query the database. Some of them might not need that. Some of them might need things like additional settings passed into the class. A field widget, for example, needs the service container so that it can query the database and get the content of the field, but it also needs to have the settings that you configured when you created an instance of a field on an entity. You filled out that form that said, well, okay, this is an image field and you can upload PNG and JPEG files and megabytes are less and here's the alternate text and you can have two. That information needs to be passed into the plugin, the widget plugin when you instantiate it and so the factory takes care of all of that for you just by me saying, I need a copy of the image field widget. There's a bunch of different factories that we can make use of and so this is again like there were a bunch of discovery mechanisms that we could use in our own plugin manager, there's a bunch of factories that we could use in our plugin manager. They are, don't worry, this is really confusing. There's the default factory which is basically just say, all right, here's the name of the class, go ahead and instantiate a copy of it. Every time I do so, I'm going to pass in this dollar sign config, the plugins ID and the plugin definition. The plugin ID and the plugin definition are both read in from the annotation. So remember how I said you can make use of the data that's in your annotation inside of the plugin. When a copy of a block plugin is instantiated, one of the things that's passed into the constructor is this plugin definition and that's just an array that contains all of the values that were in the annotation along with a little extra information. So that's your default factory and then there's the container factory which is actually the one that's used by default. It's really confusing. I'm not making this up. The container factory is the default factory with the service container injected. So otherwise it's exactly the same. You give it the name of the class that you're going to instantiate a copy of, it passes in the configuration, the plugin ID, the plugin definition, and a copy of the Drupal services container. This is the default because in most cases you're going to write a plugin that needs to make use of other systems within Drupal. Generally you're not going to just write a block that returns the string hello world. You're going to do things like query the database for additional information or ping some external API to pull in a list of tweets from Twitter or whatever the case may be. When you do so you make use of the service container there. That's the dependency injection part. The nice thing is for the most part, the plugin system will handle injecting those dependencies into your plugin class for you or the plugin manager will really. If you use the container factory, which is the default factory, not the default factory. There's also a core provides one called the widget factory. This is that example of needing to instantiate an instance of a plugin that is different than or takes additional arguments. So here you can see the field configuration information is being passed in with the widget factory. I point this one out, you probably wouldn't ever write your own plugin manager that uses the widget factory, but this is a really good example that you could steal from. So in the case where you do actually need to write your own factory, take a look at how the widget factory works, copy and paste it, change its name and make a few changes. Ultimately what that factory needs to do is know how to instantiate a copy of the class that makes up a plugin. And then there's the reflection factory for those days when you just feel like sitting on the couch and reflecting on life and what might be going on inside your Drupal code. This one is a little bit confusing for me. There aren't really any uses of this in core other than inside of some tests at the moment, or at least last I checked. But what the reflection factory does is it allows you to instantiate a copy of a class and pass some unknown number of arguments into the constructor for that class. So honestly I haven't yet come up with the use case for this. What it does, the code actually takes a look at the definition of your plugin class, looks at its constructor, says, okay this one's got six arguments and then it passes six arguments to the constructor. Now you can take a look at it. There's also the plugin mapper. So the factory, if you know the ID of the thing that you want to copy of, you can just ask the factory. You can say, alright, I know I want chocolate, give me a scoop of chocolate. But if somebody comes into your ice cream shop and they're more of an ice cream connoisseur, they like to travel around the world and check out all the different ice cream shops and every time they walk into an ice cream shop, rather than just order vanilla, they like to ask the person working there, well what's the best one? What's your best flavor? And have them decide, oh, okay. Based on the fact that you're male and you're from Colorado and you're approximately 5'10", and you're wearing glasses, I'm going to assume that you're probably the kind of guy that would like a scoop of pistachio ice cream. So I'm going to get a scoop of pistachio, or I'm going to identify that you want pistachio, and I'm going to give that ID to the factory that can then get a scoop of pistachio ice cream. A plug-in mapper makes use of additional context and state information inside of Drupal in order to determine which instance of a plug-in it should return. So you ask the plug-in manager and you say, I need a plug-in. I don't quite know which one I need, but I know I need one, and I need you to figure that out for me. Think about a rest server. So when you make a request to a rest server, you can pass in a header that says return JSON, or return XML, or return YAML, or whatever the case may be. In Drupal, you might do that by saying if you were the thing that needed to handle that request, you could do so by saying, hey, rest server plug-in manager, here's an incoming request that I need to respond to. Can you give me an instance of the plug-in that will respond to this? The rest plug-in manager might have a JSON plug-in instance and it might have a YAML plug-in instance. And in my incoming request, I said, I need application JSON. And so the plug-in manager reads that request and then says, okay, cool, this one needs JSON. I'll go ahead and load the JSON plug-in and return that. As the module, I've now gotten a copy of the plug-in that I need. And because it implements the plug-in interface, it doesn't even matter to me what type of plug-in that is or what instance it is, I know I can just call the, you know, parse response return content method that'll exist. It doesn't matter to me if it's JSON or YAML or whatever the case is. I know that I can make use of that. So that's the use case for a plug-in mapper. So if you're going to create a new plug-in manager, you need to implement all of those things inside of your plug-in manager. Really what you need to do is implement the plug-in manager interface, which implements the mapper, factory and discovery interface. By doing so, you're essentially signing a contract that says, as a plug-in manager, I agree to do all of these different things. And each of those has different methods that you'll need to provide inside of your own plug-in manager. Even better than implementing the plug-in manager interface, you can just extend the default plug-in manager. It turns out most of this is pretty much the same no matter what plug-in system you are. Like I said, the annotated class discovery is the most common and that the container factory is the default factory, not the default factory being the default factory. It's because most plug-in systems in Drupal extend the default plug-in manager. And the default plug-in manager takes care of saying, okay, I'm a plug-in manager and I have annotated class discovery and I use the container factory and here's the mapper and so forth. When I'm creating my own new plug-in manager, I'm only required to tweak a couple of things or really do the parts that are required for my particular system. So we're going to write a plug-in manager. And this is the pieces that we're going to create. We're going to provide a new plug-in type for defining ice cream flavors. We're going to... The plug-in itself will need to define what goes inside of that plug-in. What does an ice cream flavor do? We're going to provide a base class because we're nice developers and we want to make it easier for the next person that comes along and wants to provide ice cream for our shop to just easily provide us with some new ice cream flavors. And then we're going to provide two instances of our plug-in. Sound like a plan? All right. This is the entirety of our plug-in manager. We've got a class named Ice Cream Manager which extends the default plug-in manager. There's a bunch of boilerplate code that says, like, here's the namespace. Here's the different classes that I'm going to be using. You need to declare those things. Really, you need to copy and paste those things from somebody else who already declared them. And you need to change this line. This line here, which calls the constructor on the default plug-in manager, assumes that our plug-in manager is going to use annotated class discovery. You can see what we're doing is saying, here's the sub namespace where plug-ins should live that are of our type. Here's the... So flavor interface here, we're saying, here's the interface that is the contract that any flavor has to sign and says what this plug-in does. And here's the class that defines the annotation that we're going to use with our flavor plug-in. So here, you can see, we've got our manager. We've said what the namespace is. Not much to do there other than know the namespace. We do need to provide a class that has the interface, and we need to provide a class that has the annotation so that someone that comes along will know how to use those things. Most of this is boilerplate, though. If you did want to make changes, like say you wanted to use hook discovery instead of annotated class discovery inside of your constructor for your plug-in manager, you can set the discovery property to whichever of those classes you want. So you can just instantiate a new copy and assign it inside of your constructor here from there on because it implements the discovery interface. The plug-in manager will make use of it in all the places that it needs to. You then need to provide an interface. This is saying, what does a flavor do? If I'm going to implement a flavor plug-in, what do I need to provide? My interface is just saying, if you're going to provide a new flavor, I need to know that there is a getName, getPrice, and slogan method that I can call as the plug-in manager whenever I need to do so. Don't care how you get that information, as long as you have a method that provides that information for me. Generally, you would want to document this a little bit better than I have here, mostly because it didn't all fit on the page, but you'd probably want to do something like say, what's the expected return value from a getName method? What's the expected return value from getPrice? Is it a string or is it a float? The interface itself, though, doesn't really do any logic. It just provides a definition for the person that's going to be implementing a flavor plug-in to know what they need to do. It's not actually even required by the plug-in system. It'll totally work without this, but I highly recommend that you do provide an interface, because otherwise there's no way to know how your plug-in works or what they need to do as an instance of your plug-in. You need to provide documentation of the annotations. If you're using annotated class discovery, which you are, because that's what everyone else is doing. This is really just a class that's in the annotation namespace that extends the plug-in class also in the annotation namespace. The plug-in class, it's all about reducing boilerplate code and not having to repeat ourselves. The plug-in class provides a couple of elements that can exist in any annotation throughout all of Drupal. We're adding the things that are specific to our plug-in type. You basically just define an empty variable inside of the class there. That documentation is what I would then read in order to know what to put into the annotation for a flavor plug-in when I want to write a flavor plug-in. We're nice developers. We want to make it easy for other people to create new flavors for our ice cream store, so we're going to provide them with a base class. The base class here is we've just defined a new class. Really, we can put it into whatever namespace we want to. We just want to make sure that it's somewhere that people can find it and make use of it. Our base class, we're going to extend the plug-in base. Plug-in base, again, boilerplate. It does things like provide your plug-in with a getID method and a couple of other really basics that are common to all plug-ins. The nice thing about this, if you're extending the plug-in base, is that any plug-in manager, not just the one that you've created, can assume that any copy of any plug-in in Drupal will have a getID method that I can call. There's a couple of others as well. A couple of methods here. GetName, GetPrice, and Slogan. We've implemented the interface. We've also provided a default what happens. All I've done here is take the information that was provided in the annotation. Remember, we had name and price were something we could put in our annotation. Name, price. I'm just reading those in and returning them. That's the like, okay, cool. I want to provide a new flavor. All I have to do is extend the base class and provide an annotation. It's an implementation of the flavor interface by virtue of the fact that it's extending the flavor base class, but the flavor base class already has a getSlogan and getPrice and so forth method, so I don't need to do those. I just need to say, well, here's my class and here's the annotation. Literally, this is a very, very simple as vanilla is. Implementation of the plug-in system that we just created. If somebody asks for a scoop of vanilla, the plug-in manager can go and find it because it's using annotated class discovery. It knows where it lives because we put it in the appropriate namespace, vendor, so Drupal slash ice cream is the vendor, and then plug-in slash flavor is our sub namespace. We're in the right sub namespace. This is the PSR4 part. It's an extension of the flavor base class, so I've said, go ahead, let's use the ice cream flavor base class. I'll extend it, I'll provide an annotation. Somebody asks for a copy of vanilla ice cream. The plug-in manager locates the code, instantiates a copy of it, reads in the annotation, passes a copy of the annotation into the instantiated plug-in. Our plug-in, which is then an extension of flavor base, just says, cool, you want to know the price? I read it out of the annotation. Here it is. Sometimes things get a little complicated though, right? Like, what if I wanted to change the slogan? Chocolate's a little bit different than vanilla, or what if I wanted to have a different method? My ice cream store is really sophisticated, and rather than just have a price that ice cream is, what I actually do is go off and query the international ice cream price database and get a return, like, what's the going rate for chocolate right now? Calculate that price, and then when you ask for a scoop of chocolate ice cream, I can give you the exact up-to-the-minute price. I can just override the getPrice method inside of my instance of that plug-in. So you could do really simple, like, I just want a new flavor, or you could do really complicated, like, change the slogan. Oh, man. Okay. So here's what we did. And what anyone else that wanted to provide a new flavor would need to do. In order to get a new ice cream in our store, this is what someone would need to do. They need to create a file that contains some PHP code following the PSR4 standard. They need to put their new ice cream flavor into the appropriate namespace. So they need to put it in the plug-in slash flavor namespace. We defined that way back in the beginning when we said we're using annotated class discovery. You then need to extend the base class and provide your plug-in. Okay. Let's move this way forward. To make use of the plug-in manager that we just created inside of our own module, we could just, like, hard-code it in instantiated class of the plug-in manager that we just, wherever we wanted it, a better way to do this, though, is to actually use the services container and provide your plug-in manager as a new service inside of the service container because you create my module name, so icecream.services.yml file, you declare that you here's the class that represents my service. Here's the, it's the parent service. So the parent service in this case is the default plug-in manager service. Now inside of my code, when I want to use the plug-in manager and I want to do things like say, give me a list of all the ice cream flavors, I want to use the example service container for a copy of the ice cream manager, and then I'll ask the ice cream manager, hey, can you get definitions? The ice cream manager is an implementation of the plug-in manager interface. By virtue of that, it's got these methods that can do things like you call get definitions. It says, okay, cool. I'm a plug-in manager. I'm using annotated class discovery. I'll go and use that information to find all of the defined plugins in the current implementation of Drupal and give you a list of them. I can then do something like say, hey, plug-in manager, give me an instance of a plug-in. Specifically, I want the vanilla ice cream one. It calls your factory. It instantiates a copy of the vanilla ice cream plug-in and returns that and I can make use of it. So, quick recap. Plug-ins in Drupal are reusable bits of functionality that are configurable generally. So, you know, you probably wouldn't necessarily have a new plug-in for every different flavor. You might provide one flavor plug-in that could be configured for different things and so forth. Every plug-in does exactly one thing. So, an image effect plug-in, for example, you would have one plug-in that rotates an image, one plug-in that can, you know, change the color and so forth. You wouldn't have one that does all of those things. Another PHP class is that implements an interface. Really, that's all they are. It's like this whole system that exists just so that you can, you know, say dollar sign plug-in equals give me a copy of the plug-in and then know what methods are available. Creating a new plug-in manager requires knowledge of things like PSR4, annotations, the dependency injection system a little bit. If you're mostly that's handled for you, right, the container factory automatically injected the service container into our plug-ins and then a little bit about how the service container works. Plug-in types, so if you want to create a new plug-in type, the thing that you're looking to do is actually create a plug-in manager. By implementing a plug-in manager, you've now defined a new plug-in type. That's it. That's pretty much everything I know about plug-ins. A lot of this is written down, so if you, you feel like brushing up on this at home in your spare time, I've written most of this down, there's the URL there. I'll post these slides on the page for this session on the DrupalCon site. And I would also appreciate people taking a moment to fill out this survey and tell me how I could make this presentation even better in the future. Thank you. I don't know how much time we have left, but I'm happy to answer questions until we get kicked out and I'm happy to stand in the hallway and answer questions. If anybody has questions, I guess that means everyone's going to go home and write their own plug-in manager, right? All right, cool. Yeah, if you do have a question, I'll hang out up here for a little bit too. Free for you to come up and ask.