 So I'm going to go ahead and get started. I'm going to be talking about the Drupal 8 plugin system. There's a bunch of new ways as module developers that you can extend and enhance Drupal 8 functionality. Drupal 7, this was almost all done using the concept of hooks. Anytime you wanted to change the way that Drupal did something or you wanted to add additional functionality or you wanted to mess with somebody else's functionality, the recommended way to do that was to use a hook. In Drupal 8, we've got a bunch of new ways to handle various types of interactions. One of those and the one that you're probably most likely to encounter first as a Drupal developer moving from Drupal 7 to Drupal 8 is the plugin system. So we're going to talk a bit about that. A bit about me first. My name is Joe or EOJTheBrave on Drupal.org and Twitter and pretty much anything internet that was invented after about 1990. I work at Lullabot. At Lullabot, I mostly work on the DrupalizeMe team doing educational stuff, trying to help take some of the more complex concepts and things about Drupal and break them down into easier to understand pieces of information. I really enjoy that too. So things like the plugin system, which I didn't actually write. This was written by a bunch of other people that are way smarter than I am. I came along behind them and kind of read what they did and asked them a lot of questions about how did you do this and why did you do this. Let me take that information and turn it into something that's useful for everyone else so that we can all figure out how to use it. This presentation, it starts out pretty simple with kind of a basic explanation of what plugins are, why plugins exist and sort of the problem that we're attempting to solve with plugins and then it gets really technical really fast. So it's going to start out with a bunch of cute illustrations and by the end we're just going to have slides full of code, I promise. But I'm going to talk about so what are plugins and why do they exist? And then I'm going to cover some of the prerequisites that you'll need to understand about how Drupal works and really about how PHP and object-oriented programming works in order to get the most out of the plugin system. And then we'll talk about in order to really understand how plugins work, how all of the pieces that make plugins in Drupal possible fit together. And I think that that'll help sort of create a mental model for understanding when to use plugins and how to use them. So Drupal.org handbook says this about plugins. The Drupal 8 plugin system provides a set of guidelines and reusable code component to allow developers to expose pluggable components within their code and as needed, support managing these components through the user interface. The first time I read that, the first like five times I read that I was like, what? I don't get it. So I've gone through and I've underlined the parts of this that I feel are kind of the most important aspect of what we're trying to do with plugins. Plugins, it aren't any like, there's no specific piece of code that is like, these are plugins, plugins is more of a guideline. It's a pattern that you can follow in order to solve a specific problem within a certain context in Drupal. Hopefully, when you write plugins, you're writing code that is reusable and hopefully more reusable than the code that we're writing in Drupal 7. Larry talked about this a bit this morning, but Drupal's position in the larger PHP ecosphere and how that's all kind of playing out. One of the ideas is that plugins allow us to write functionality as more discrete components that we can include into Drupal but may also be useful to other applications or other projects that we're working on. And the big thing here with plugins is that their plugins solve a problem in which we need to provide a user interface that allows people to choose from one or more of the many options to perform a certain action. We'll talk about what those types of actions are. Sometimes this is really complicated, like thinking it through all of this was hard for me at first. And so it was easier for me if I could break it down into something that was non-technical and not programming. And so one of the ways that I've been able to explain the problem that we're trying to solve with plugins is by thinking about what it would be like to be the owner of an ice cream shop and the types of tasks that you would have to deal with on a daily basis. So if you worked in an ice cream shop, so let's say my name's Drupal and I work in this colorful ice cream shop, when I show up in the morning and a customer comes in, I have to be able to do things like discover all of the different flavors of ice cream that are available in this ice cream shop. So there needs to be a way for me to, without having to, hopefully an easy way for me to just see, what are all of the options that are available that I could serve to someone? I need to make sure that there's an easy way for myself or any of my employees to consistently access that. So I don't want every single employee to have to learn a different way to scoop every type of ice cream, right? That would be so inefficient and it would cost so much. It'd be easier if every ice cream came in the same size tub and used the same type of scoop to get the ice cream out of the tub. I need the system or people that work in my ice cream shop to be able to do certain things with those flavors of ice cream, like calculate how much it should cost, figure out how to serve it to a customer and so forth. And sort of the most important thing here is once someone's come into the ice cream shop and they've talked to an employee who's discovered all the flavors of ice cream and they've selected the appropriate one to serve you, you need to be able to know what to do with that thing. Luckily, ice cream's pretty easy, right? You get it in a cone, there's a little ball on top and you just lick away and it's pretty easy. Plugins are, wow, some of them are a little more complicated, some of them are actually that easy. That's kind of the problem we're trying to solve with plugins in Drupal 8, though. Things for which Drupal needs to be able to generate or discover a list of all of the available options. Really common examples, blocks. Any module can come along and add a new block or multiple blocks to Drupal, but Drupal needs to know that your module is providing a block. Field types and widgets, actions, image effects, there's tons of examples that are that same thing. Drupal says, hey, modules, give me a list of all of your options for thing X. In Drupal 7, this was often accomplished with info hooks, right? So you'd have like hook block info and you'd return a list of all of the blocks that your module provided, excuse me. Or you might do image effects, same thing. And then once the system has discovered all of those discrete things that it can deal with, it needs to provide a user interface that allows administrators to choose one or more of the options for their specific use case. So you need to be able to choose like one block for the home page or the three blocks that make up the sidebar on the about page. You need to choose which image effect or multiple effects you combine together in order to manipulate the image and get the thumbnail that you want. Once you've chosen them, a lot of times those things also require some amount of configuration. So plugins, same thing. Instead of having an info hook that returns a list of all of the image effects, you've now got a list of image effect plugins. But each of those plugins has some amount of configuration. The idea being that each plugin or each image effect takes one piece of known input, so an image in this case, does whatever it needs to do and then returns some known output. As far as Drupal's concerned, it just needs to know I give you an image, you do something with it and I get a different version of that image back. And you might have configuration there. Like say, if I'm gonna change the color of the image, it doesn't make sense to write a plugin for every single color. You'd have like millions of colors. We would all wish that IE6 was still our default browser because then we'd only have to have 256 colors. But so plugins helps to solve those types of problems. What's interesting about this is that when I started thinking about it more, it kind of made me also realize that what we've got here is akin to what is often in programming referred to as a design pattern. So a design pattern is this idea of having a general and reusable solution to a recurring problem in some common or given context. It's not fully written code that solves the problem every time. It's an example of if you're in this situation, dependency injection is the right solution to the problem. If you need to sort an array using a binary sort is the right solution in this situation. Those are all design patterns. Plugins is the same thing. It's not actually a system that's fully written and all of the pieces are there and you just go, all right, plugins, it's working. It's really a pattern that describes how you can add additional functionality to Drupal. And so as a developer, what you need to do is learn the pattern so that you can see when it's time for me to create a block, I need to follow the pattern for creating a block plugin. If I wanna add the ability for people to write plugins for my code, here's the pattern that will allow them to do so. Think of it more like a template for solving a problem rather than being the full baked solution to the problem. So why plugins and not info hooks? There's a lot of reasons. These are some of my favorite. My absolute favorite thing about plugins is that all of the code that does the functionality is in the same place. So an example of this would be, if you ever wanted to create a block in Drupal 7, you'd have an info hook and hook block view and hook block configuration save. I don't even remember all of the hook names. There's a bunch of them that you would need to implement in order to make that possible. In Drupal 8, with a plugin, you've got all of the code for that specific block in one discrete class. And it makes it really easy to find all of the code that is doing the various different things. And I like that. Being able to have all of our code componentized and contained into a single class or a discrete object means that the code that we write is hopefully more reusable. Again, playing into what Larry was talking about this morning, designing systems in Drupal that allow us to write code so that our code is also usable in other contexts is pretty cool. And plugins attempts to solve that. It's not yet a perfect solution. And most likely you'll end up sort of, the plugin will be a bit of a wrapper around your more general PHP component, but I do feel that it's a step in the right direction. Plugins are extensible and you don't have to copy and paste them in order to make a different version of them. So a really great example of this is I recently had a project where I needed to make a slight change to the way that the image field in Drupal 7 worked. Basically I needed to add some links right under the field that would allow you to manipulate the image a bit. There wasn't an easy way for me to just hook in. There was no hook that would allow me to get in there and add the links to do just what I wanted to. So I go, okay. I guess I'm gonna have to make Joe's awesome advanced image field instead of just the regular image field. So I copied the image module and I renamed it to like image advanced. And then I went through and I renamed every function in there to image advanced as well because that was really the best way for me to extend Drupal 7's image field. Fields in Drupal 8 are plugins. So the image field type is a plugin. If I wanna do something different, that plugin is just a class. All I need to do is make a new class, Joe's awesome image, that extends Drupal 8's image field. Make the one change that I needed to and the method where I needed to change something and I inherit all of the rest of the functionality from the existing plugin. So it makes those things that are plugins much more reusable. There's some other benefits too. Plugins are lazy loaded into the system. So Drupal knows about all the plugins but it won't actually load and execute the code unless it needs to. Versus Drupal 7, where you would have to put all of your hook implementations inside of a .module file and that module file would have to be loaded on every page request just to make sure the function was there when Drupal does that, if function exists, my hook name and then execute the code. So that's kind of the awesome about plugins. Before you can really get into writing a plugin yourself or creating a new plugin system within Drupal, these are some of the things that you'll need to be able to do. Actually, not some of them. These are the things that you'll need to be able to do in order to write plugins. You're gonna need to understand the PSR4 standard. We'll talk about that briefly. You'll need to understand Drupal's annotations or rather doctrine's annotations and how Drupal uses them. You need to understand the concept of dependency injection and if you want to write a module that adds a new plugin type so someone else could write plugins to interact with your system, you'll also need to know how Drupal's service container works. Contrary to popular belief, you do not actually need to know how symphony works in order to write plugins. I bring this up because initially, I think people were very convinced that in order for me to be able to do this, I also have to know how symphony works. Not true. It certainly helps because symphony uses all of these same concepts for things that it does, but it's not a requirement. So real quick, PSR4 is a PHP standard that allows you to have systems that know where your code lives. Basically, it's a convention for the way that you name a class and then based on the name of that class, where in the file system you should place the code so that at runtime, when PHP needs to instantiate that class, it knows where to find the file and load it up. It works like this. You've got the concept of a vendor namespace, a subnamespace, and a class name. So in your code, you need to use the appropriate namespace for your class. And then based on that namespace, the code goes into a certain directory within your module. I won't go super in depth into how all of this works, but the idea is that what you're doing is you're putting the code that you write into a place that it can be automatically located. So without me having to include like, I guess the Drupal 7 way of doing this would be in your .info file. You'd have to add files, opening bracket, closing bracket, equals, path to the file, if you remember to. In Drupal 8, you don't need to do that, but you do need to make sure the code is placed in the right place. This is important with plugins because this subnamespace here becomes important. The type of plugin that you're writing, so if you're writing a new block plugin, for example, it will dictate what that subnamespace needs to be. So your class, if you're writing a block plugin, needs to be in the plugin slash block subnamespace in order for Drupal to find it and make use of it. More information here. I'll make sure all the slides are available in links as well. You need to know a little bit about how annotations work. The reason that we use annotations in the plugin system is primarily to provide metadata about our plugin for Drupal. The scenario is, when you go to the block administration page, Drupal needs a way to list all of the available blocks in the system. So this is part of that discoverability aspect of plugins. But in order for it to be efficient, rather than having to load every single plugin class and create a new instance of that object and run some code, Drupal actually just reads in these annotation blocks that you'll find at the top of a plugin and it gets some of the metadata that it needs from those. The idea of our plugin, usually things like the title and a human readable label, things that you'll see in the user interface that kind of allow an administrator or someone to say, oh yeah, that block, that's the system information block without having to actually run any of the plugins code. Drupal uses doctrines annotation parsing system with a couple of enhancements in order to allow for a translation of labels and stuff. So you can see here in this example, it's showing the admin label for a block. So that is the title that will show up on the administration page for someone who is choosing which blocks to display. And we wrap it with this at translation construct which allows the multi-language system to allow that label to be translatable. So taking the time to understand a little bit about how annotations work is important, later on we'll talk about how you know what information to put in an annotation depending on the type of plugin that you're creating. You'll also wanna know a little bit about dependency injection in order to deal with plugins. Again, I'm not gonna go too far into this. These are all sort of topics that like, I could probably talk for 45 minutes about how each of these works. But I wanna give you this information so that you can spend the time to brush up on it before you start getting into writing Drupal 8 plugins. Dependency injection, I've got the same bit of code here or two different ways of writing the same functionality. The one on the top is a not injected class. The idea here is that my code in this case is creating a new instance of the database object that it's going to make use of. So I know I'm gonna have to query the database so inside of my code I said cool, give me a new database instance. This, however, is now hard coded into my plugin. There's no way for someone else to come along and say actually block plugin, I want you to use this copy. I want you to connect to a postgres server instead of the MySQL server or whatever the case may be. The version on the bottom uses what's called dependency injection which really is like a really complicated way of saying passing in the objects that you're going to use as arguments instead of instantiating them inside of the class. So this one here, I've got two lines where I've said create a new MySQL database object and then create a new instance of my class and pass in the database object. The benefit of the latter version is that some other code could come along and say actually in this case I want you to use a different database object and as long as it conforms to the same interface the plugin will know how to deal with that. So that's a good thing to learn about. The thing is dependency injection is really easy when all you're doing is injecting one dependency but most things in Drupal are dependent on all the other things in Drupal. So you very quickly end up in this scenario where not only do you need to create a copy of the database but you also need one for form API and the plugin manager and all kinds of the request and the response services and so on and it could be really hard to map all of those dependencies. So Drupal has this service container. What the service container does is it's basically smart about what the various services you might need are. So I need the database service to make a query and it says cool the database service that's dependent on these other things. So if you ask me for a copy of the database service I will also make sure that those other things are present. This is another instance of something that Drupal has learned and inherited from other PHP projects. Our service container is largely based on the symphony service container. So you can learn a lot about how that works again by learning symphony but not necessarily required either because the truth is for the most part you don't really need to know how the intricacies of the service container work. You just need to know how to ask it for the service that you need to query the database or send a JSON response or whatever it is that you're trying to do. Okay, so before you write plugins take a couple of minutes to understand how PSR4 works really just to understand what the naming convention is there. Read up on annotations and learn a little bit about dependency injection and the service container mostly because you'll see these in action when you write plugins and for me it was one of those like what is going on here? Where did this variable come from? So I had to read a little bit further up the stack and go oh that's because my block plugin is actually an instance of an injected plugin so it got a copy of the services that I need when it was created. Knowing what's going on and how the system works means that you're gonna be able to write better plugins in the long run. Once you've got that part mastered this is how you write a plugin. The first thing you need to do figure out what type of plugin you're going to create. Are you creating a block plugin? Are you creating a new field widget? Is this an image effect? Knowing that will dictate the answer to the rest of these questions. So the first thing you do figure out what type of plugin you're gonna write. That will tell you where should I put the metadata for this plugin? So a block plugin as we just saw in the example uses annotations for metadata. There's a couple other ways that you can get that information and it depends on the type of plugin you're using. Where does the code go? So it's a block plugin or it's a field widget plugin that dictates the sub namespace in that PSR4 standard. So I have to know okay I'm gonna create a block plugin and I have to follow this PSR4 pattern in order to make sure that Drupal can locate my code when it needs it. And then another one is is there a base class? Generally when you're implementing a new plugin like a block for example, Drupal provides a base class that you can extend in order to create your plugin. The idea being that a lot of plugins probably have fairly boilerplate code. Blocks for example. Every block has that configuration form where you can say which pages is it visible on? Which region should it be in? In which theme? And all of that is like common for pretty much every block unless of course you need to make it slightly different for your block in which case you can. But why not just extend the base class which has all of that already? If you need to you can override one of the methods. So once you kind of have that information out of the way the other tip here is for the most part, what you can do with Drupal like this is one of the things that's awesome about open source and learning Drupal is really just copy and paste what somebody else did and make a couple of changes. And now you've got a block plugin. All of the systems in Drupal that implement a new plugin type, they don't just implement a plugin type and then are like yeah, this is just in case somebody wants to provide a plugin of this type sometime maybe. They implement it because Drupal needs to provide plugins of that type. So every time you know, okay, block plugins, field plugins, whatever the case may be, core will also contain instances of those plugins and a really great way to learn how that particular plugin type works is to look at an existing example. So, here's what a block plugin would look like. If I wanted to write a block plugin, I figured out okay, I want to write a block plugin. I need to make sure that I put it in the appropriate namespace based on the fact that it's using the PSR4 standard, so the plugin slash block namespace. I included my metadata for this in an annotation that's in the comment for this plugin class and then I extended the block base class and then I implemented in the case of a block plugin this build method which is responsible for returning the content of the block and that's it. This file will allow Drupal to have a block that printed the context hello world that had in the administration user interface a label that says Chad block. Apparently I wanted to name my block Chad and it's in the tacos category. I don't know what, it must have been late. All of this, so I've created a new block that prints out the text hello world and this is like 10 lines of executable code and that's it and all of the code is contained in one place too versus Drupal 7 you'd have to have an info hook, a hook block view, the configuration hook and so forth in order to accomplish this same thing. Not only that but what you'd really probably have is like hook block view with the delta or the idea of the block passed in and then a giant freaking switch statement that was like okay, which block do you actually want and you're like oh god, okay. What I really want is the system info block and you'd have to kind of parse through all that so you've got like this massive pile of code for generating all of the blocks that the system module wants to provide all in one place. Great. Again, pro tip, extend the base class when it exists. In like 99% of the time what you'll be doing is like you only want to deal with the things that are unique to your situation and allow Drupal to handle the rest of it. You don't need to deal with all the boilerplate code in a block for determining access restrictions and visibility and so forth. Let Drupal handle that by extending the base class. But of course you can, because it's all object oriented and you're just inheriting or extending that class, you can override any of the functionality in your own plugin should you need to. Whoa, that went the wrong way. There we go. Okay, so that's kind of the gist of like why plugins, the basics of how plugins work. If I wanted to write a block plugin, really what I would do is copy and paste somebody else's block plugin and rename it Joe's awesome block plugin. But if you really want to take advantage of the system, I think it helps to understand how all of the pieces work. So what we're gonna do now is walk through how Drupal or you if you wanted to in your own module could declare a new plugin type and dictate what the namespace is, where the metadata is found and how copies of those plugins get loaded by the system. So behind the scenes when you've got a plugin type, the thing that's controlling all of that is called a plugin manager. So there's a block plugin manager. There's a field formatter plugin manager. Some of them get really long names, I promise. What that manager does is it dictates how should plugins of this type be discovered? So where in the code or where in general should Drupal look or should the plugin system look to find block plugins? Once it's found one and somebody requests the copy of that block or of that field widget, how do I load and execute the code that is that plugin and then we'll talk a little bit about the mapper which also deals with how do you load and execute the appropriate code. All of this is done by implementing the plugin manager interface. So the interface here is basically me saying, I'm gonna implement this interface. I'm gonna sign a contract that says, I wanna create plugins that are of the type ice cream flavor and by doing so I promise to tell you how to discover them, how to instantiate a copy of it and in general how to deal with those ice cream flavors. So plugin discovery, there's a handful of ways that this can be handled in Drupal. By far the most common is annotated class discovery. That's what we saw with the block plugin where you had the annotation in the comment in above the class in your file. If you wanna use annotated class discovery and you do wanna use annotated class discovery, this is what you need to specify in your plugin manager. Plugin slash block, that's our sub namespace there. So that's the part where I'm saying the block system, when you're creating a new plugin and you wanna know what to put in for the PSR for sub namespace, we're declaring it that in our plugin manager. You also need to say, so here we've got Drupal slash ice cream slash flavor interface. So you're saying what namespace is it in? Plugins of my type need to implement this PHP interface. What that allows for is it means that the plugin manager can now get a copy of any plugin as long as it implements the interface and it knows what methods are available on that interface because you're mapping to an interface and by doing so you're saying I guarantee that my block plugin is going to have a build method because if it doesn't, PHP is gonna be really upset. So you're telling the system which interface those plugins need to conform to and then you're telling it here which class dictates the values for the annotation that's used for your plugin. What's a little bit interesting about these annotations is that the content of the annotation, the things that you put in it are different depending on the plugin type. Kind of like how in Drupal 7 when you had an info hook, the values that were returned in that giant associative array were different depending on the specific info hook. Blocks needed one thing and field types needed another. Same thing here, we need to provide different types or different metadata depending on the plugin type. So annotated class discovery is the most common by far in the one that I would recommend using if you're creating your own new plugin type unless of course you run into one of these other scenarios which are much rare, hook discovery. And actually this set of slides is a little bit old and I looked into this this morning and I couldn't find any examples of hook discovery being used in core anymore. But what this does and I think part of why it existed was sort of allowing for a transition from info hooks to annotated class discovery and not requiring us to move everything all at once. Hook discovery says instead of reading an annotation for the metadata implement a hook that returns an array that provides the metadata. So this would be like this hook discovery name of the hook that you wanna execute. This would be identical to implementing hook block info in Drupal 7. I mentioned this at this point because hook discovery is still an option in core but it's not actually used anywhere right now other than the test that makes sure that it works. So that YAML discovery is another way that we can provide metadata about our plugins. YAML discovery works by placing a mymodule.stringoftext.yml file inside of your module directory and Drupal will look there for the metadata about plugins. In this case, YAML discovery I said, okay, I'm gonna put the metadata into a file named blocks.yml. The reason for YAML discovery is to allow Drupal to allow Drupal to discover information about and create instances of plugins much earlier during the page request cycle. In a sense, for things that we want to be able to discover without actually having to use bootstrap Drupal and use PHP in order to discover them, we don't wanna have to instantiate the doctrine parser and so forth. A good example of this being used in core is for menu items. So now when you define a menu item, instead of implementing hook menu, you actually need to define a menu item plugin. And you do so by providing a YAML file or a .yml file in your module directory that says here are my instances of menu item plugins. This allows the system to read in that YAML file, find all of the plugins and cache that data and be a bit more efficient about loading it in the future. And finally, there is static discovery. Static discovery is basically like hard coding the discovery of your plugin. So this would be useful in the case that really it's useful for tests. But it's saying if my plugin manager, if my plugin type, I only want to ever have these two plugin instances and I don't wanna allow people to dynamically add them with annotations or YAML files or so forth, I can hard code the path to that file. So that's the four different ways in which plugins can be discovered. Primarily, we use annotated class discovery and I would recommend that you do that too if you're ever implementing your own plugin type. Of course, this is Drupal and we like to make things infinitely more flexible than just those four options. So we add the concept of decorator classes. So now you've basically got discovery mechanisms that wrap around your discovery mechanism to make sure that it's more flexible. This allows for things like the concept of an alter hook in Drupal 7. Drupal 7 calls hook block info and it gathers a big array of all of the blocks that can be used anywhere. And then immediately afterward, this says hook block info alter. Here's the list of all of the blocks. Does anybody wanna make changes to it? Decorator classes essentially allows for that in the plugin system. It says go off and get a list of all of the block plugins and then let anybody that wants to make changes to that list. It also adds some interesting things like the derivative discovery decorator here, which ends up being probably the most used in core. What this allows you to do is create a single plugin class that can be instantiated as multiple different instances of the same plugin. So think about how in core you can create new custom block types. Or actually probably a better example would be menus. So menus in core. Anytime you create a new menu in the UI, you also get a corresponding block for that menu that you can place somewhere in your theme. Rather than having to write a new block plugin for every single menu, there's actually one menu block plugin that uses this derivative discovery decorator. So you've got the class that is, this is the code that's capable of saying take a menu and render it. And then there's the decorator which wraps it and says, okay, but before you do that, here's the name of the menu I want you to use. It's really as simple as that. It's one set of code that you can pass in and say, I want the navigation menu or I want the footer menu or so forth. The code is smart enough to then go, okay, cool. I'll look up that menu and render that list of links rather than me having to write an individual plugin for every menu that I wanted to block for. So that's how discovery works. And that's how Drupal goes through the process of figuring out what plugins are available for the system and what it should list for users to be able to use. Once it's done that, so you've discovered all of the plugin, now you actually need to be able to, when a person says, okay, I want to display the system info block, how does Drupal get a copy of that plugin and make use of it? And it uses what are called plugin factory. There's a handful of different plugin factories that you can use in a plugin manager, but they all really boil down to this. Figuring out what's the name of the class that implements this particular block and what arguments do I need to pass into the constructor of that class when I create a new copy of it. There's a couple of these, so the default factory, hold, hang on here a second, right? We've got the default factory and the container factory, which both basically do the same thing. They just say, you can kind of read the code here. This variable is the name of the class, so the factory says, okay, I'm just gonna say name of the class, constructor and plugin or pass in a couple of arguments. The arguments here being any configuration for the plugin, the plugin ID and the plugin definition, these two variables are parsed directly out of that annotation or out of the YAML file or whatever. It's basically saying, hey, plugin instance, here's your metadata in case you wanna do anything with it. The container factory, which is actually the one that's used by default in most cases, so the naming is a little challenging, we'll say. The container factory does exactly the same thing. What's the name of the class? Here's the metadata that describes your plugin, but it also uses dependency injection to inject a copy of Drupal's services container so that your plugin now has access to all of the services. So for example, your block plugin, which is instantiated using a container factory, gets a copy of the service container and can use that to get an instance of the database object that it needs in order to query and find out which menu you're trying to display in this particular block or so forth. If you're creating your own plugin type, the default that Drupal will use if you implement the system is the container factory and in most cases, that's probably sufficient and you wouldn't need to do anything different. The default factory would be a little bit more efficient in terms of actually instantiating, but in most cases, you're gonna wanna allow people that are implementing your plugin type to also have access to all of the other services that Drupal provides. The other two are widget factory and reflection factory. The widget factory is used for instances where you've got plugins that take settings that are a bit more complicated than just what's in the annotation. The name here actually kind of works because this is used for things like field widgets, primarily, where field widgets are a plugin, but they have additional user configurable settings that aren't part of the annotation, right? So our block plugin has an admin label that we put into the annotation and it's okay to hard code that to say the system info block has a label of system info, but when you create a new field, you don't initially know what the label of that field is going to be, so you can't hard code it into the system. So you need to allow someone to fill out a form that says I'm creating a new field with this name and it has this label. When somebody creates, or when the system needs to get a new copy of the text field plugin, it needs to also tell that instance, hey, text field, your name is email and your human readable label is please insert your email address here. And so the widget factory allows for that. The reflection factory is also rarely used, but what it does is it allows for a plugin to basically do introspection on itself at the time that it's instantiated. So your plugin instance, the code within it can say this is how you should make a copy of me is basically what the reflection factory allows for. Probably when you would use that is if you had a plugin type that required a dynamic set of argument. So it's not a fixed number of arguments, it's not the same every time. The arguments that are passed in depend on application state or context. Kind of like we have decorators for discovering plugins. We also have the plugin mapper which adds an additional layer on top of how you instantiate a plugin. The idea here is that somebody asking for a copy of a plugin might not always know specifically which one they want right away. So we need to figure out for them and then return that. So somebody comes into your ice cream shop and they're not someone that like they're really into ice cream. They're a bit of a connoisseur and they're used to going in and asking instead of just saying oh I'd like some vanilla they come into the ice cream shop and they say what's your best flavor? What would you recommend I have? And the person working there needs to be able to figure out well this guy he's kinda tall, he's got red hair. I'm gonna guess based on these various different attributes that he'd probably like chocolate. So I'll get a copy of the chocolate plugin and give it to him. A mapper does that. Where we see this in Drupal is things like Drupal's REST server for example. The way that the REST server itself and how it responds and returns data is actually a plugin. And you can do it in a couple of different ways. You could return JSON or you could return XML. But you can't hard code that because it's based on the incoming request. So did my application specify a JSON header or an XML header? And depending on that Drupal needs to be able to say okay this request is asking for a plugin to build a response. It has the XML header so I need to learn. I need to learn. I need to load the XML response plugin and use that one. So it's a way of kind of based on other things that are going on in your environment figuring out which block or which plugin to get a copy of. That's the plugin manager. All of these things come together in order to create the plugin manager interface. If you want to create a plugin type of your own, what you need to do is sign the contract that says I'm going to declare all of those things. I'm going to declare which discovery method should I use. Once a plugin of this type is discovered how do I want to allow copies of it to be instantiated? So which factory should I use? And then do I want to allow for a mapper or not? The mapper here is optional. It kind of depends on the use case. Kind of like how we have base classes for blocks and other plugins so you don't have to do all of this boilerplate code all the time. If you want to create your own plugin type, you can do so by extending the default plugin manager which basically does everything for you. With some assumptions, the default plugin manager assumes certain discovery methods and certain factories and so forth. So we'll talk about that. What we're going to do real quick is write some code that creates a plugin manager that solves this problem. We're going to provide a new plugin type that allows us to define ice cream flavors. The plugin manager will define what does it mean to be an ice cream flavor? So what information do I have to provide if I am a flavor of ice cream? We're going to provide a base class because we're nice and we don't want people to have to do extra work if they don't have to. And we're going to provide some sample flavors because why would we implement a system that we're not ever going to use? So the first thing you would do, the code here is a little bit abbreviated, a very little bit. I'll have a link so you can see all of this code at the end. You extend the default plugin manager. When you do that, really all you have to do is declare what type of discovery do you want to use? And the truth is you want to use annotated class discovery. So all you really have to do is say, what's the PSR for namespace that I want plugins of my type to live in? What information is in the annotation and what's the interface that they need to implement? And this is that whole like you're basically setting up a system so that someone who wants to come along and implement a plugin of your type knows what they need to do and what information they need to provide. You then, so you've got your plugin manager. You've got, you need to provide a class that declares, what's the information that can go in this annotation? So that's done so, that's done by extending the plugin annotation class. So this class that's in the Drupal component annotation plugin namespace. What you do is you add new properties to that class, just empty properties, and then write a string of documentation that says, what should this property contain? These classes aren't actually ever used in the system at all other than to provide documentation for what should exist in an annotation. This is important because when you want to implement somebody else's plugin type and it's based on annotated class discovery, how do you know what information to put in the annotation? And the answer is you find this class that's in the module that is implementing that plugin type. So there is a block class that extends the annotation plugin class. And it has a number of different properties with documentation for each of those properties in the class. And those are the things that you could include in your annotation. Generally, it will say like, this ID property or this label property is required. But that's kind of how as a developer I can discover what should go in this annotation. This one was actually really tricky for me when I was trying to learn how all of this stuff worked. I kept reading these annotations and being like, okay I get it and I can copy and paste the existing one but what are all the things that could be here that I don't know about? And the way to find the things that weren't in the one that I copy and pasted was to find this annotation class and look at that. Then of course we need to provide an interface. So we extend the default or the plugin inspection interface with our new flavor interface. And what we're doing with an interface is we're saying that any instance of a plugin of our type needs to provide this functionality. So if you're gonna provide an ice cream flavor, you're required to provide a name or a get name method for that ice cream flavor. That ensures that I, as someone who just wants to get a scoop of ice cream, can say give me a scoop of ice cream and then based on you returning that, I know one of the things I can do with this thing that you've just given me is call the get name method because it's guaranteed it'll be there. Whether the variable is named dollar vanilla or dollar ice cream scoop or whatever, dollar block, I know I can call get name on that object and it will provide me the name of that flavor. Of course, we're super nice and we don't want people to have to do a lot of work. So we provide a base class that they can extend. In our base class, we implemented this get name function. And what I did here is I actually just read in from the annotation, the plugin definition. So back on the previous slide. Ah, that was a lot of previous slides. Back here, we said, okay, our plugins can have an annotation with the ID of name. And then in this thing, I said, okay, in my plugin, whatever the value of that annotation was, I'm just gonna return that as the name of the plugin. So when somebody wants to create a new ice cream flavor, really all they have to do in this case is actually just extend our base class give it their name, so vanilla in this case, make sure that it's in the appropriate sub namespace based on the PSR4 standard. And then provide an annotation. Our annotation has this name key in it. We extended flavor base, so we actually don't even have to do anything else at this point. It's already got that get name method that's reading in the annotation. But if we wanted to, we could of course do something a bit more complicated. You know, we might want to have a different flavor of ice cream, chocolate in this case. It's still got all of the other things are the same. It's got a name in the annotation. It extends the flavor base. But what we've done is overridden the slogan method because we decided that actually vanilla is not the best ice cream. Chocolate is the best flavor of ice cream. This is a pretty contrived example of what it demonstrates is a plugin system or whenever you're implementing plugin types of your own, you should make it really easy for someone to provide a new instance of that plugin type. Do all of the boilerplate and default work for them and make it so that they only need to write the code that is specific to their instance, right? Like if I want to write a hello world block, the only thing I should really have to do is write the string hello world so that it gets printed out on the screen. I need to worry about all of the other pieces of the system. If you're writing a plugin system or if your module is saying, okay, I'm gonna allow for people to have plugins, you wanna provide them with that same level of all I need to do is the work that is custom for my specific implementation. So summary of that, if you wanna create your own plugin type, you need to, or if you want and then implement a plugin of that type, you declare what sub names base those things are in. Basically, how are my plugins going to be discovered? You need to, excuse me, doing so. So you're saying, here's where the annotation is, here's the PSR for pattern that you need to follow and then extend the base class. Basically say, all right, I'm gonna create a block, there's a block base class, I'll just start from there and just make the changes that are unique for my specific instance. If you are doing a plugin manager of your own, in order to, right, so you've declared a plugin type, the other thing you're going to need to do is also like say, actually make use of those plugins. We could say, here's the block plugin type but Drupal also needs to say, okay, cool and you can place blocks on the pages and places and when you do so, their content will be displayed. So you need to expose your plugin manager to Drupal so that you, as the module developer who created the plugin manager, can also use the plugin manager to get a list of all the blocks or of all of the field types or whatever the case may be. In Drupal, we do that using the services container so I talked a little bit about that at the beginning. The implication here is that if you create a new plugin manager, you should do so by defining it as a service. That way when you, most likely, or anyone else wants to make use of your plugin manager, they ask the Drupal service container, hey, give me a copy of the ice cream plugin manager and I can use that to do things like get a list of all the ice cream flavors, I can use that to say, cool, I want a scoop of vanilla and the plugin manager will say, okay, cool, I know how to do that. You said that I'm gonna use the container factory for returning plugins of this type. It takes the vanilla ID, it uses that to locate the appropriate class based on the PSR4 standard and then it instantiates a copy of that class using the container factory and finally returns you a scoop of vanilla ice cream which you know what to do with because it implements that interface. So a recap of kind of like everything we covered here. Most importantly, plugins are a reusable bit of functionality that are configurable, reusable and really plugins do just one thing. So each instance of a plugin does exactly one thing. An image effect takes an image, it changes its color and returns a copy of that image. It doesn't take an image, change its color, send somebody an email and then return a copy of the image. It's just responsible for that one path. Plugins are PHP classes that implement a defined interface. So if you want to create a new block or a new field or implement a specific plugin type, really what you're doing is writing a new class that follows the PHP interface defined for that plugin type. If you want to create new plugin types or write plugins of your own, some of the background knowledge that you'll want to know about, we've covered this a bunch now as PSR for annotations and sometimes dependency injection and the service container. And finally, plugins in Drupal are, the type is defined by a plugin manager and if you ever want to add a new plugin type, you'll need to implement a plugin manager. So the exercise then here would be going through and figuring out when you're writing your own module, what are the things that you would want to allow people to write plugins for? When do you want to provide a user interface that will allow for an administrator to choose one from a list of options to execute some particular functionality? There's all kinds of examples of this in core, like blocks and field types and how do you send an email? Do you use SMTP or do you use the built-in PHP mail or all kinds of different options? In the contrib space or when you start writing your own, inevitably going to encounter a scenario and what you say to yourself, self, it would be really nice and make my code more reusable if I made it so that other people could provide a plugin that allowed their custom functionality. Offhand, something like the voting API module might be a good example of where you would implement a plugin type. Rather than me writing a module that's like, okay, in my code, I have to account for every possible way that someone could ever want to tally votes. Instead, I'll just create a plugin type and I'll write one tally plugin that says, well, just add them all together and the total is the outcome of the vote, but I'll make it possible so that anyone else can come along and write, well, for our specific use case, we need to use instant runoff voting or for our use case, we need to throw away all of the votes that were registered on Tuesday and Thursday because that's what we do on our website. So when you encounter those types of problems when you're writing a module, plugins is probably the right solution to implement. That's what I got. I've got, at this URL, lb.cm slash d8 hyphen plugin, I also have all of this information written out too, so if you wanna review, if you wanna go home and review afterwards, if you wanna look it up again at another time, this is all written out there, along with a bit more complete example code, the example code there, you can actually install in Drupal 8 and it will let you create new ice cream flavors because who doesn't like ice cream? And then, if you wouldn't mind taking a minute sometime today to provide feedback for this session, that would be awesome. The DA and the camps like this make use of this information to make sure that we're able to continue to offer really good sessions, and I can use this to make sure that next time I have to explain plugins to someone, I can do it even better. That's what I got. Thank you, and questions of course. We're kind of right up against the time, but I'm also happy to answer questions until they kick us out, and then we can stand over in the corner and keep talking, yeah. Is there any way to auto write your dependencies in your plugins? Is there any way to overwrite? Auto, auto inject. To inject dependencies automatically, yes. Okay, so the question is, is there any way to automatically inject dependencies into your plugin type, basically? You're like, I'm implementing a new plugin type, and I want all of the instances to get this dependency, or? Like, I'm gonna use, I have a service, new blog services, and I need to use an entity manager service. Is there any way that I can say, okay, I'm gonna use this entity manager service. Give me one instance, like automatically. Yes, yep, so the way to do that would be when you're creating your plugin manager to declare your new plugin type, and you have to declare the factory that it will use to create instances of your plugin, you could do two things in this case. You could use the default container factory, which will inject Drupal's service container, and you could have your dependency just be a service that's registered with the container, and then it'll be available, or there's nothing that stops you from creating your own new factory class. So in this case, you could say, you know what, the container factory isn't quite what I want, so I'll just extend the container factory and let it do all of its things, but I will also, when I call plugins of my type, pass in this one additional argument to their constructor. Does that make sense? Yeah, but I was kind of looking for something to inject the dependency without having to pass arguments, like a kind of aspect-oriented way to inject the Spring Angular. Yeah, I think the answer to the question is yes, and I think what you need to do in this particular case is either write your own or somehow modify one of the existing factories, because the factory is the thing that says, when I'm instantiating a copy of this plugin, here's how I should do it. Really, it's up to you. You can instantiate it however you want to, as long as it returns an instance of that class, and so there's a lot of different ways that that could be done, and it would be by overriding or just creating a new factory, I think. Thank you. You're welcome. Any other questions? Yes, you mentioned earlier that the plugin system was something that, some clarification maybe, it was similar to what Symphony was doing, and was the plugin system like the wrapper that was unique to Drupal, or is it a very similar system to what Symphony uses? Sure, yep. So the plugin system itself is very much a Drupalism at this point. That design pattern is unique to Drupal, but a lot of the things that the plugin system uses in order to work are also things that Symphony uses, like dependency injection. The service container that we use in Drupal is based off of Symphony's service container. So plugins themselves in that whole pattern are unique to Drupal, but learning a lot of the components of Symphony will also help you better understand the plugin system. Cool. Yeah, sure. You mentioned that in plugin discovery, there are the annotation discovery and hook discovery, but Drupal is not using the hook anymore. So will it be the correct way to proceed using only annotations? Well, Drupal is not using it. Yeah, so the question is essentially like, why does hook discovery exist if we're not using it? I think the best way to answer that question is it's mostly there as a compatibility layer during the time for which we're transitioning everything from hooks to annotations and plugins and so forth. If you're creating a new plugin type in Drupal 8, you don't want to use hook discovery, basically, unless it's probably slightly more efficient in terms of overall processing time, but YAML discovery would be even more efficient. And so, yeah, ultimately I would say annotated class discovery unless you need to have your plugins available really early, basically before the annotation parser has been instantiated in Drupal, then you would use YAML discovery. Static discovery is like if you're writing tests then you want to just make sure nobody can ever change this and hook discovery is basically a thing of the past at this point. All right, Joe. Just a small question about caching. Yeah. So we do have all these layers that our abstraction is not direct. We're not just declaring directly the elements right. So we depend on the auto loader, we depend on the declaration of services in YAML files and that stuff. So which parts of this are cached? Which do we have like just ready? Yeah, okay. So yeah, this is a complex system with a lot of moving parts and some of them would be very expensive to have to read every single time. For example, having to read the annotations on every single plugin class every time would be an expensive process. The discovery process of plugins is cached by default. When you create your new plugin type or you implement the default plugin manager, one of the things that it does is it provides a caching mechanism for whatever discovery you're using. So that information is cached. And that's fine because you really only need to get a list of plugins of what plugins are available at the time that somebody installs a new module, right? Because otherwise that list really rarely changes. Maybe if they add like, if they're a derivative plugin when they add a new menu or something, you'd also need to refresh that list. But for the most part, that list is just used for things like the admin UI. So it can be efficient for that. Instantiating a copy of a plugin is generally not cached because a lot of times the thing that the plugin needs to do is gonna be sensitive to whatever context and state the application is currently in. So the actual like instantiation of the block plugin and having the block plugin build its content, that process isn't cached. Though the block itself or that plugin, and in the case of blocks it does do this, its output could be cached, right? So you could say next time you call the system info block, you still have to create a copy of that class, but it doesn't have to do all the work to go off and query some external system and pull in the information. It can just use the cached output from the previous time. But that part becomes a little bit more dependent on the specific plugin type. And you as the person implementing a new plugin type would need to decide, are plugins of my type potentially doing expensive work to output their content? Do I wanna cache the content and so forth? All right, so it comes for free with the default plugin manager. Yes, caching of the discovery, you get virtually for free if you implement, if you extend the default plugin manager type, yep. Yeah, if you wanna learn more about how that works, I highly recommend, I highly recommend printing out a copy of the default plugin manager and reading it as a light bedtime reading sometime. It'll teach you a lot about where plugins come from, how plugins are created and so forth, and really help you better understand all of the moving parts of the system. Hello. What is the difference between plugins and modules? Yeah, right, this is really confusing because plugins which are provided by modules add extra functionality to Drupal, but they're parts of modules which add extra functionality to Drupal. It's like this recursive problem. Plugins have to be provided by a module. So in order for Drupal to even know that your plugin exists, the first step, of course, is creating a new module. The module that you're writing is going to dictate some of the things like when you're following the PSR4 standard, for example, what's the vendor namespace and so forth. So the answer to the question is, plugins exist as one of the things that modules can do? Just a quick one. How stable is all this Drupal plugin system? I mean, can we confidently create new plugins all around in modules or maybe do we have to expect some changes in the new? Yeah, so the question is kind of how stable is this system and do we anticipate it changing before a stable version of Drupal 8 comes out? I would say at this point, the plugin system is pretty stable. I wouldn't anticipate any major changes to how it works. At most, you're going to see things that make it faster, that make it like, so an example of something that changed somewhat recently, this has also existed for a couple of years now at this point, but of things that have changed recently is like, it used to, you used to not be required to provide an interface for your, sorry, yeah, an interface for your plugin type, but now you are required to. So there are enhancements that are happening to make the system easier for developers to learn and understand, but I doubt that any of the, how it works is going to change at this point, especially because like thousands of things in Drupal 8 have already been converted to use this plugin system. Virtually all of the things that were like, hook block info, give me the name of a function that I should call are now plugins in Drupal 8. I'm going to move so that whoever has to get up here next can do so, but I will, I'm happy to answer questions if people have additional questions or just reach out to me on Twitter and I can try to answer them there or whatever the case may be. Thank you.