 It probably would have taken me a long time to figure out that the microphone has a switch on it. It's also very precariously balanced here and I'm like worried it's going to fall right on my laptop. So I'll try not to get too excited about Drupal 8 plugins. So I'm going to be, this presentation is going to be about the new plugin system in Drupal 8. If that's what you're here for, awesome. If you are expecting something else, you're in the wrong room and it's okay, you can wander out and I'll pretend not to notice. My name is Joe or EoJTheBrave on Drupal.org, Twitter. Pretty much anything internet related that was created after about 1995 or so, you can find me as EoJTheBrave. I currently work at Lullabot and at Lullabot I'm on the DrupalizeMe team. I spend a lot of time looking at all of the really awesome things that Drupal developers have built and trying to distill them into plain English so that other people can understand what these really smart people built. And that's kind of what I'm going to do here. The plugin system isn't something that I created. I've helped with it a little bit but there's a lot of other people that are way smarter about this stuff than I am that created the system and I'm simply trying to understand it and be able to explain it to others. So, kind of a word of warning. This presentation starts out pretty easy. We'll take a look at defining what a plugin is and what the problem is that plugins are trying to solve and then it's going to get really nerdy pretty quick. It ends with a bunch of code samples of how you might implement your own plugin types and so forth. If you want to follow along with the code or if you want to use it for reference in the future when you're trying to learn this stuff on your own, I'm sure everyone's going to go home after this session and then be like, oh man, I kind of want to practice that. There's some sample code that you can use to go home and practice with. All right, so when we talk about plugins, I think the first thing we really need to do is just kind of define what the term plugin means and it's really kind of tough within the Drupal ecosystem to do so. I was talking to one of my coworkers earlier today and they're like, what are you talking about to them? Oh, I'm talking about plugins and they're like, oh, isn't that like what you make for WordPress? It's like, well, kind of, but no. It's an interesting, it's a loaded term, especially when we talk about programming and people have that connotation of a plugin is essentially the same thing as a module, but it's important to know that they're not the same thing. And in Drupal 8, you don't create a plugin or a module. You actually create modules that provide plugins for the system. So plugins, the Drupal 8 plugin system, as it's sort of defined in the documentation, is a system that provides a set of guidelines and reusable code components to allow developers to expose pluggable components within their own code and support managing those pieces of code through the user interface. Basically, it's a system for providing individual units of functionality and a select list so you can choose which piece of functionality you want to use. We'll talk about sort of examples from Drupal 7 that have been replaced with plugins in Drupal 8 and hopefully it helps make some of that a bit clearer. Another way that I like to think about the plugin system is sort of by defining the problem that the system was created to solve and that helps me understand like what it is that I'm building. So, and for me to be able to kind of use the analogy of an ice cream shop is one way to do this. So let's pretend that I'm the owner of an ice cream shop and I need to provide a system where anyone that's an employee of my ice cream shop can sort of fairly efficiently, with a minimal amount of training, be able to step in and start serving my customer's ice cream. In order to allow for that, I need a system that provides things like when someone is asking for a scoop of vanilla ice cream, it needs to be easy for an employee, more Drupal in this case, to discover where that vanilla ice cream is, right? So maybe I want to consistently put things in the same order within the cooler so that people can find them, label them in the same way. I want to make sure that there's a consistent method for accessing these units of functionality, a.k.a. ice cream flavors so that like you don't have to have a different scoop for every container of ice cream, right? That would be horribly inefficient. And then you want to be able to do things like calculate what the cost of a scoop of ice cream is, it may be work with external vendors to bring in additional flavors of ice cream, but not have to like augment my system every time I get a new flavor of ice cream from somebody different. Like I want their ice cream to also come in the same container and use the same style of scoop. Things in Drupal that kind of map to this paradigm, the super simple example and the most common one is blocks. If you think about the way the block system works in Drupal, Drupal needs to be able to ask every enabled module for a list of the blocks that that module provides. So in Drupal 7, you have the concept of info hooks, which return an array, which is basically metadata that says you have a block that is named Joe, and this is where you get its title, and this is where you get its content. The plugin system kind of is in that same space, providing Drupal with a list of pieces of functionality. The other thing that you get to here then is not only does it need to be able to list what all the blocks are, but once it's found a block, it needs to be able to access the title of the block and the content of the block so that it can display it in some consistent manner. If there's a different way that Drupal had to access the content for every single block, you'd end up with a lot of spaghetti code really quick. Some other simple examples of this are... Some other examples of this are the image styles system. Again, it's a scenario where Drupal needs to be able to get a list of some type of functionality. In this case, it needs to get a list of all of the different things that Drupal could be able to do to manipulate an image. Once it's got that list and the user has chosen, I'd like to apply these three different effects to an image. It needs to do so. Drupal needs to be able to say, okay, here's the image. I'm just going to give it to you and expect that you're going to perform whatever transformation needs to happen and give it back to me in the format that I expect. In the case of an image, you get an image back. Excuse me. Probably the most common place that you'll end up seeing plugins used in Drupal 8 are scenarios where in Drupal 7 you probably would have implemented some info hook that said, hey, Drupal, I provide this functionality. Here's where you go to get that functionality. In a sense, plugins are a design pattern. A design pattern in code is something that we define as a general reusable solution to some sort of recurring problem within a given scope. What ended up happening was, as Drupal has evolved over time, we have over and over encountered this problem where you need to get a list of things and then you need to allow an administrator to choose one or more from that list of things. Depending on whatever configuration they've set, which things they've chosen, you need to display those blocks or use those field formatters or even use that field type. They're a design pattern, though. Plugins aren't a complete system. They're really a template for how you can provide additional functionality. It's not like there's just a plugin and it exists. What it is, is it's a whole set of PHP interfaces that you can implement, templates that you can follow in order to conform to this system so that when Drupal needs to get a list of the things that you're providing, it can do so. I talked about this a little. What are the problems that plugins are attempting to solve? The big one is replacing info hooks. When I first encountered this, I was like, why are we replacing info hooks? I don't get it. They work fine and you're basically solving the same problem again. We had already solved it. I think that plugins do it in a much cleaner manner. Some of the things that you get with plugins that you can't do with info hooks in Drupal 7, my favorite is that when you write the functionality for a plugin, all of the code that makes up that functionality is contained in the same place. The example would be in Drupal 7 if you wanted to implement a block. You'd have to write a hook block info function that says, here's a bunch of other functions that you should call. You can't implement hook block view and hook block save and delete. I don't even remember. There's a whole bunch of them. That's part of the problem right there. You can't even list what all of those pieces are that are necessary. With the plugin, that's all going to be implemented inside of a single discrete class, which I think is a developer that makes it a little bit easier for me to go, okay, this block that displays the powered by Drupal banner in the footer, all of the code for that and there's also nothing else in that one class. How many times have you written a custom module to provide a block for a site and then come back later and added another block and another block and another block and so now you've got hook block view and it passes in this parameter called delta and then it's like, alright, just do a big giant switch statement on this delta that says, well, if it's the system powered by block, do this, but if it's the login block, do this instead. You end up with a whole bunch of code for different blocks inside of a single function and it gets hard to maintain. There's a bunch of other really nice benefits to this. Because plugins are implemented as PHP classes, you have the ability to extend somebody else's plugin. Maybe a good example of that would be if I didn't like the way that the link module worked for Drupal 7, I didn't like the link field. I needed something slightly different. In order to make my better link field that's just slightly different, what I would do is copy and paste the link module and rename all of the functions to better link and then make my one change to the field formatter so that it worked the way that I wanted it to. With plugins though, I can actually just extend the existing link field type, override the one method that outputs that field formatter that outputs to link in some way and do my changes there but inherit all of the functionality from the original link field. It makes things a bit more clean in that sense. Before you can go about writing a plugin for Drupal, when you've decided, plugins are the system that I need to implement in order to provide a new block or a new image effect or whatever the case may be. There's a couple of things that you'll need to know about other systems within Drupal and just PHP in general in order to understand how and where to create your plugin. Those things are PSR4, annotations, dependency injection, and the Drupal service container. We'll cover each of these. I originally thought when I first started looking into writing plugins, I came into it with this idea that in order to write plugins I'm also going to need to understand how symphony works. It was a common misconception from people that I talked to who were learning about writing plugins as well. The truth is you don't actually have to know how symphony works in order to write plugins. It uses a lot of the same concepts and paradigms like PSR4, for example, annotations. These are all things that are used within symphony projects as well. But you don't actually have to know symphony to write a plugin. It won't hurt though. PSR4, the first part, is a PHP standard for mapping a PHP name space to the location of a file on disk. All you're doing is saying the file that contains the class with this name is located in this particular spot. The reason that you need to know this for implementing plugins is because Drupal will lazy load all of the plugins. Rather than implement each plugin inside of your .module file and have all of them loaded on every single page request, using PSR4, you can have each of those plugins live in its own file when you instantiate a copy of that plugin. So when you say show me the system powered by block, then and only then will Drupal actually load the code that makes up that block and make use of it. So there's a little bit of a performance gain from this. It also is just a consistent way of naming and placing things so that we don't have name space conflicts and that kind of thing. For the plugin system, the part that you need to know is really about the sub name space. So in the example up here, we've got vendor name space slash sub name space slash class name. The sub name space is important because depending on the type of plugin that you're implementing, that will define what sub name space to use. So for blocks for example, which is the example down here underneath in code is I want to use the plugin slash block sub name space and part of the reason for that is then Drupal knows anytime I'm going to load a block plugin I should look for classes that are in this sub name space. There's a lot of documentation on Drupal.org about how PSR4 works, but again basically what it maps to or what it comes down to is a naming convention. It's saying based on the name space I'm using, this is where I should put the code that makes up this particular PHP class. The other one that you'll need to learn about is the concept of annotations. Annotations are, they're kind of a PHPism but at least the way that we're using them is very PHP specific. But what it is, is it's a way for me to provide some metadata about the functionality that my plugin provides in a dock block comment so for that plugins class. It's a little bit confusing and initially it's kind of like well why wouldn't I just provide a method that returned an array that had that metadata or other places that that metadata could go. The reason is that we don't want to have to load and instantiate your block plugin just to know what the title of it is or just to know what the description of it is. The stuff that you'll find in these annotations is typically the pieces of information that Drupal needs in order to list your plugins in the user interface somewhere. So for blocks it would be like the title and the description of the block. So when you go to the admin UI and you've got the big list of all of the blocks those titles are coming from the block plugins annotation. For field types or entity types or various other things you'll also get the machine readable name of this plugin or pieces of information like that. So we need to learn how to use annotations. We'll talk a bit more about that when we actually write a plugin example but the important thing to remember is that we're using annotations to provide metadata. Mostly this is the stuff that you would have previously provided in a hook block info or an info hook implementation. You'll need to know a little bit about dependency injection. The reason for that is that we are creating our plugins as PHP classes and not always but most of the time we're going to want to do something within the code that makes up our plugin that will require using some of the other services that Drupal provides things like querying the database for example in a really simple block plugin you might not need any additional services you might just print out the string hello world but most likely you're going to do something more complex like use the HTTP service to query Twitter and get some results back and display those on the page. So when it comes to doing that you'll use the concept of dependency injection in order to take the database service that Drupal provides and inject it into your plugin to make use of Drupal's database querying layer or translation layer or whatever the case may be. Again I'm not going to go into a ton of detail about this but make sure that before you start writing plugins you're at least familiar with the concept of dependency injection. And finally you may need to know about service containers if you're going to implement your own new plugin type so if you were creating a system like the block system or like the field system you would want to declare your plugin manager as a service to Drupal and so understanding how the service container works is important. The service container is if we look at dependency injection where we're saying I'm creating a new PHP class and rather than instantiating a new copy of thing that queries the database inside of my class where it's now essentially hard coded, in the dependency injection version you're instantiating the database service outside of the context of your plugin and then giving the plugin the tools that it needs to query the database. That way in the case of say I'm writing tests and I'd rather not actually query the database. So I'm going to go back to my Twitter when my tests are running. I could say when the tests are running use this mock Twitter object that just always returns some known result. The problem is that it's really easy if you have one dependency but most likely you'll have many dependencies like you're going to need the translation manager and you're going to need to be able to access the database and maybe you want to access the current that need to be injected. So the service container is basically just a smart class that knows what all of the possible services in Drupal are and how to create a copy of that service and all of its dependencies. So all I have to do is say I need a copy of the database and the service container goes okay cool that means you also need X, Y and Z so I'll create those first, compile it all together and then give you the copy of the thing for accessing the database. Easy, right? If you're going to create plugins and your objective is to write a new plugin so you're going to create a new unit of functionality whether it's a block or a field formatter or an image effect you absolutely need to know PSR4 auto-loading and annotations. There's no way around it, you have to know how to do those things. You should have working familiarity with dependency injection. It's a pattern that you'll see happen where you can probably just copy and paste some other plugin that's already doing it and be like I know that that's dependency injection I'm sure of that. If you're going to create your own new plugin type you'll need to learn about the service container and how to define a new service within the context of Drupal. So let's look at creating a simple plugin. When it comes time to write a plugin and you're going to sit down and say okay I'm going to create a new block here's the things that you'll need to know about that plugin type in order to create a new instance of that plugin you need to know what type of plugin you're creating. So the plugin type like block or field widget or field formatter defines the recipe for the rest of how the plugin is going to be created. So you need to know that first. Once you know what type of plugin you're creating and that will tell you where should you define the metadata for that plugin. So the metadata again being information that Drupal would want to know about your plugin without actually having to turn the plugin on. So what's the name of the plugin what's its unique ID you might put it in a dock block. There's actually a handful of different ways that you can do it but it depends on what type of plugin you're implementing. You need to know where the code goes so that when Drupal wants to execute the code it turns out that's important. And another thing that you'll want to know is whether or not there's a base class that you can extend when implementing plugins of that type. In most cases there probably is. Or you could just forget the recipe altogether and decide that if I'm going to create a new block plugin I'll just find one that core did already and I'll copy and paste it and start changing it to meet my needs. That's totally my recipe for creating plugins. It's actually it works out really well because core implements plugins all over the place and it's not like Drupal's going to say hey let's just have this new plugin type and no implementations of that plugin type because what would be the point of that. So if a plugin type exists in Drupal core you can rest assured that there are also implementations of that plugin type and all you have to do is find one of those implementations and use that as a good starting point. So this is the hello world of writing a plugin for Drupal 8. It's a single class inside of a file that's located in a known namespace directory. So we're creating a block plugin here. We're placing the code in using the PSR4 standard into a file named chadblock.php inside of our module. We've got the namespace which includes the plugin slash block sub namespace. So I know that that's what it's supposed to be because I'm implementing a block plugin type. And then we we have the doc block which provides our annotation. I'll talk more about how you actually know what goes into that annotation because it does vary per plugin type. But in the case of a block you can see we're providing a unique ID for the block, the title block, and the category. So this is information that Drupal needs in order to list this block on the administration page. And finally we're extending the block base class and implementing the build method which returns our content. This is that element of plugins where the plugin system says I need to make sure that there's a consistent way for accessing the functionality of any block. So when I'm creating a plugin of the block type and I'm extending that base class I'm also implementing a PHP interface which is essentially me signing a contract that says my class will guarantee that it provides a method named title and build. I don't even remember offhand what they are for block but build is definitely one of them. That way Drupal will know if I have an object that is of the type block plugin I can be assured that if I call the method build it will return the content that should be displayed in that block. You can do whatever you want in that build function as long as it exists and it returns a renderable array that it will can be turned into the HTML for your block. I kind of covered this already but another tip that is really useful when it comes to making plugins is check to see if the plugin type has a base class that you can extend and start by extending that base class rather than implementing your plugin from scratch. The reason for that is that in most cases a plugin provides a discrete unit of functionality but most of the functionality is probably the same as every other block and it just varies slightly. So extend the base class which provides all of the generic functionality for blocks like determining whether or not the block should be visible, determining what the title of the block is for display in the administration screen and so forth. That logic is the same for basically every block you can override it if you need to but extend the base class and that way you don't have to provide that functionality for each plugin as well. Not every plugin type provides a base class but in my experience all of the ones that I've attempted to implement so far do have base classes that you can extend. So that's kind of the basics of creating a plugin. It's know the plugin type extend the base class and make sure that you're conforming to the contract that is provided by that plugin saying blocks have a build method fields have a couple of different methods that you have to make sure you implement in order for Drupal to be able to call those. So you can implement a plugin of a known type there's a bunch of plugin types already in Drupal. I think that the it's the times that you'll want to implement, create a new plugin type are probably relatively limited more often you'll just be providing a new plugin for one of the existing core plugin types but I think that looking at how plugin types work and how the pieces fit together helps provide a better framework within which to understand how the plugin system works and there are also going to be cases where you want to create a new plugin type. The a classic example of that would be say let's say you're the maintainer of the voting API module and you want to provide a system for anyone else to write a module that adds new ways of tallying votes that have been counted so that and that's exactly what the voting API module does right now it provides an API that any other module can implement and say you know what I provide a way to calculate instant runoff voting well I provide a way to calculate and display a pie chart or whatever the case is so the voting API would be a classic example of I'm a module and I want to make sure that other modules I'm a module that doesn't make any sense I'm actually a person not a module but the in order to allow for that unlimited flexibility you might decide I'm going to implement a new plugin type so that other modules can provide new pieces of functionality for calculating votes or figuring out how email should be sent maybe your modules job is to send email but are you going to use PHP mail or SMTP mail or whatever the case may be each of those could be a plugin let the user decide which functionality they want to use so behind the scenes this is all controlled by a tool called the plugin manager every plugin type is created by implementing a new plugin manager so there's a block plugin manager and there's a field plugin manager and there's a mail plugin manager and all the different plugin types are start from creating a new plugin manager the plugin manager defines what the template is that you'll use in order to implement a plugin so are you using annotations for discovery or are you using YAML are you like how do I get a copy of the plugin and so forth we'll walk through what each of the components are here but really what it comes down to is plugin managers is when you are defining the template for your plugin type so the first thing you need to define when you're defining new plugin type is if someone's going to implement a new unit of functionality for my plugin type where does that live how do I discover implementations of that plugin or instances of the plugin there's four different ways that this can be done annotated class discovery where those PHP annotations come into play is by far the most common and is also the one that I would recommend you use unless you have a really good reason not to annotated discovery is what most of core uses it works by allowing you to define the sub name space for the PSR4 standard where your plugins will live so here you've got plugin slash block that is the sub name space that we're using for our plugin type and then you define so it kind of wraps the two lines here but the Drupal slash ice cream slash flavor interface you're saying here's the PHP interface that you need to implement if your class is providing a new block or a new man this is my example is bad here this should probably be like flavor or something other than plugin slash block but the PHP interface then is a class that basically says these are all the methods that should be available for any plugins of this type and then you define the PSR4 path to or name space of a class that provides documentation of the annotation for plugins so this is how annotated plugins work remember when I said we were going to talk about how do I know like what the heck goes in this doc block annotation like I could you could put whatever you want there but only certain keys like or values in the comments are going to mean anything to Drupal that's defined by this for blocks it's this Drupal slash block slash annotation slash block so that's the path to a class and if you were to look at the code for that class it would just have a bunch of blank private properties on the class with documentation that's you know one of them is ID and one of them is title and the documentation there is the like what those are for each of the properties on that class is something that you could include in the annotation we'll take a look at a code example of that as well so annotated class discovery by far the most common also the one I would recommend you use unless you have a good reason not to hook discovery is essentially the equivalent to info hooks in Drupal 7 you define the name of a hook that you would like Drupal to trigger it will do a basically a module invoke all or the Drupal 8 equivalent to that call all functions that match you know joe underscore block underscore info or whatever the hook name is and then aggregate the returned information this is provided primarily as a backwards compatibility layer in order to allow for systems to be converted to the annotated class discovery over time so that you didn't have to like convert every single implementation of this type of functionality in one giant patch it's also used in a couple of other places but pretty rarely at this point there's also yaml discovery so this is used in order to allow you to provide a yaml file in your module that contains the metadata so instead of putting it in a class annotation you could put it into a yaml file these are used for plugin types that don't really require any php logic to run in order to do the thing that that plugin is supposed to do the most common use case in core is for menu items or contextual links and so instead of implementing hook menu you now have like to provide a new menu item each individual menu item is actually a plugin but if you think about it all that is is really a URL and a title right so you don't need to execute a whole bunch of php to figure out what the URL should be or what the title should be you can just load it out of the yaml file the other use case for yaml is for plugins that need to be executed really really early in the life cycle of a request so before things like doctrine which handles parsing the annotations has been loaded again probably pretty rare that you would use these but nice to know what they are and how they work it's also interesting the yaml one especially because you'll encounter this whenever you want to create new contextual links or menu items in Drupal and it's not immediately obvious that you're actually creating a new plugin but just by creating that yaml file you're creating a new plugin and finally there is static discovery which is essentially the equivalent of hard coding it you create a new class that provides a list of all of the plugins of that type that exist this is used for tests basically I tried and tried to come up with a reason like why you would actually want to have static discovery for your plugin and aside from tests I couldn't really come up with any if that isn't complicated enough when it comes to how these plugins are discovered so you've got annotations hooks yaml or static discovery there's also actually a whole other layer on top of that called decorator classes that allows for additional augmentation of that discovery mechanism the the use case would be the equivalent to what we in Drupal 7 refer to as an alter hook the scenario is Drupal needs to in a lot of cases build a list of all of the plugins that exist and then give every module an opportunity to make changes to that list and then finally display the list for the user and so you don't actually have to do anything to get the decoration on your discovery to work it'll just work out of the box for you but what it does is it ensures that when my module implements a new ice cream flavor plugin type and it goes off with all of these annotations to discover all of the existing ice cream flavors it builds up that big list and then it uses the decorator class which is basically a class wrapped around another class to say give everybody one last chance to manipulate this list before I say here's the final list of all of the plugin types for all of the plugins of this type the other one that you read probably from the back of the room but the other one that is really interesting about decorator classes is this derivative discovery decorator this comes into play for types of plugins where you probably don't actually need to have what would be a good example of this the if you think about the menu system in Drupal and so every time the user goes into the admin UI and creates a new menu every number of different menus each of those new menus also has a corresponding block that gets created in the block UI that you could use to place the menu in the header or the footer or in the sidebar or whatever the case may be rather than have to go and create a new PHP class with some code in it every time you create a new menu the derivative discovery allows for a single PHP class for every block that is a block that displays a menu and so when derivative discovery happens it says it actually finds the menu block plugin and then the menu block plugin says actually I'm not a plugin myself I'm just the thing that tells you how to make copies of me that contain the specific plugin so you would make a copy of the menu block plugin and it would say okay what you really wanted to display is the footer menu so let me go load the footer menu from the database and then essentially it's like a stand-in if you will it says I'm going to provide all the same methods that you can call but depending on the context in which that plugin is loaded it might return different content menu blocks are the simple example basically it's if you could think of any scenario in which you would want to provide new functionality of a certain type purely based off of different configuration and so a menu block is that the functionality is the same every time except for one parameter that you pass in that says the ID of the menu to display is main menu so it goes to the database it builds the main menu and displays that or the ID might be footer so it gets all the links for the footer and displays that so that's how plugin discovery works once the system has allowed you to create a list of all of the possible pieces of functionality and it has all of the different plugins in the list it also needs to provide you with a way to say ok what I really need right now is a scoop of vanilla ice cream so in order to hand the plugin manager the name of a plugin and have it load that block or that field type and return it you need to have a plugin factory the plugin factory is responsible for taking a unique name for a plugin and going off and figuring out ok you said you wanted the vanilla ice cream flavor I got to go over here and load this class using the PSR4 standard and instantiate a copy of it and then hand it back into your code your module that's making use of it and you get that instance so basically factories determine how to instantiate a copy of a plugin any instance of a plugin there's a handful of different plugin factories that are built in the default factory is basically just give me the ID of the block from the annotation metadata and I'll go off and find the block that matches that ID I'll instantiate a new copy of that class and I'll return it and now you can do things like called print block build so default factory discovery or just sorry default factory the container factory is the most commonly used one it's essentially the same thing as the default factory you give it the ID of a plugin and it will load the class that implements that plugins functionality in addition to loading it it will also use dependency injection to inject a copy of the service container into that class at the time that it's loaded so that in your block plugin you can now do things like query the database or query twitter or whatever functionality you need to do in order to build the content of it this is kind of how plugins work by default is using the container factory probably what you would want to do as well if you were implementing your own plugin type another one is the widget factory great name right a widget factory the use case for a widget factory is actually things like field widgets or field formatters where when you're instantiating a copy of the field formatter you also need some additional configuration information to provide to that class so it knows how to work if if the plugin type that you're implementing is an image effect and that image effect is scale and rotate whenever somebody gets a copy of the scale and rotate functionality you also need to tell that plugin what size should I scale it to and how much should I rotate it so there's some additional configuration and context that needs to be provided and then finally there's the reflection factory this is another one that I think is mostly here for completeness sake the only place that I've seen it used is in tests what it does is allow you to essentially pass any like n number of arguments into the constructor for a plugin but it uses introspection to say ok you randomly passed in 5 arguments to this constructor so I'm going to use those 5 arguments maybe I need 6 or maybe I need 4 depending on the specific use case it allows you to have a dynamically defined set of arguments that are passed in to the constructor of the plugin again I couldn't come up with many use cases the one place that I've seen it used in core is the autocomplete functionality so when you start typing in a user's name and it does that thing where it does a query off the Drupal and it builds a list I've typed jo and then it automatically returns jo and john and other names that start with jo I'm sure there are others than jo I can't think of them though because jo is the best name ever the autocomplete functionality though uses that reflection mapper so just like we had really complex ways to do plugin discovery and then we had decorator classes that made it even more interesting when it comes to plugin factories you can also get more interesting and more complicated by using what's called a plugin mapper I think an example of this would be if we go back to our ice cream store analogy you end up in the scenario sometimes where most people come into the ice cream store and there's a place that was provided by the discovery mechanism to say okay you've got vanilla and cherry and like lamb ice cream flavors I know for sure I would like a scoop of vanilla so you identify it by its ID and then the person working the counter just goes over based on their system of organizing it can scoop the vanilla out and give it to you no problem sometimes you get those snobby customers who are more ice cream connoisseurs and they come in and they're like you know what I've been to every ice cream shop in the area and I like trying all the different flavors but what I want to know is which one's your best which flavor of ice cream would you recommend for me so in this scenario I'm not able to identify for you I want vanilla or I want mint but I am able to identify I'd like a recommendation and so you as the person working at me and you're like okay white male five nine it looks kind of like a hipster he's probably going to want to try the lamb ice cream so I'm going to go ahead and say here's the ID for lamb ice cream get a scoop of that and return it the maybe slightly more practical example would be if you attended Wim's session yesterday where he talked about how the request and response cycle in Drupal works and part of what happens is you make a request to Drupal for some content and then it has to determine based on the incoming request how to return the content should it be HTML should it be plain text should it be JSON should it be a PDF the thing that renders an array a render array into the content that you are that you receive when you make a request to Drupal is actually a plugin and there's a couple different implementations of that response renderer plugin type one of them can turn a render array into JSON and one of them can turn a render array into HTML when you make that request it uses the incoming request content type header to say you know what they just asked for JSON I'm going to load the JSON plugin instance and use that to render the content this guy asked for HTML I'm going to use that one maybe other things would be like if you had plugins whose responsibility was to extract the contents of an archive file you might have one that's able to extract the contents of a zip file and one that's able to extract the contents of a tar file and so all I want to do is send the plugin mapper some file and it's smart enough to look at the file and say that's a .tgz extension so I should probably use the plugin that is capable of handling tar files to extract the contents of this file you combine all of those things together so you've got your mapper which handles basically I have an ID where do I go to get the thing you have the factory which is the thing that takes the ID and uses it to construct an instance of that plugin and then you have the discovery mechanism which is used for any other module developer to be able to list new plugins or new pieces of functionality of that type you combine it all together and you get what's called a plugin manager so if you want to create a new plugin type you implement the plugin manager interface and it will sort of set up all of those defaults for you my recommendation would be if you're going to create a new plugin type do so by extending the default plugin manager and what it does is it tries to be smart about knowing which discovery mechanism to use which factory to use and which mapper, plugin mapper to use when I said that annotation is the default and container factory is the default that's because if you extend default plugin manager it's assuming that you want to create an annotated class discovery mechanism that you want to use the annotated class plugin mapper and so forth what's awesome about extending the default plugin manager is that you can create a new plugin type with like ten lines of code so we're going to do that we're going to write the code to create a new plugin type so we're going to take everything that we just talked about and combine it all together in a code example we're going to create a new system that provides a plugin type for defining ice cream flavors what an ice cream flavor is what info is necessary in order for someone else to provide an ice cream flavor we're also really we're like nice developers and we want to make it easy for other people to interact with our system so we're going to provide a base class that they can extend and finally we're going to provide some sample ice cream flavors so the first thing that you would need to do in this case is we need to create a new plugin manager so we're going to call ours ice cream manager, we're going to create a new class that extends the default plugin manager within that class I don't actually have the sample code right here there's two lines of code that you need to implement and those are basically what's the sub namespace that this plugin type lives in and where's the location of the annotation and the interface classes that should be used to define the contract that someone is signing when they create a new ice cream flavor so we've got our ice cream manager and then we've got this other class immediately under flavor.php what this one is doing is in this case we're defining what information should be in the doc block annotation for a flavor plugin so we're extending this plugin class and simply providing all we're doing is providing empty variables inside of the class this exists primarily so that we can have this string of text right above the comment that says the annotation here value is the name of the flavor if I wanted to know what all the things were that I could put into the annotation for a block plugin I would find the block plugin manager's equivalent of this annotation class and read the documentation there and it would have a line that said block plugin ID block plugin title titles are used in the administrative user interface and so forth so you provide the annotation so that people really it's primarily documentation so people know what to put into the annotation and what metadata you need them to provide then you want to provide an interface so in php an interface is basically a class that provides a whole bunch of empty methods you're basically stating if you're going to create a new ice cream flavor you're going to create a php class for that functionality and if you implement this flavor interface you're guaranteeing that you're going to provide a method named get name so this is the contract that you have to sign in order to provide a new ice cream flavor what it does is it ensures that I as the plugin manager have a consistent way of interfacing with any new plugins of that type I know that they'll all have a get name method I know that all blocks will have a build method that I can call because they're implementing this interface you can you can provide a base class not required but I would recommend you do so partially because they just provide documentation of sort of like what are all of the base methods that someone might want to implement for this plugin type and also because again in a lot of cases most of the functionality for plugins of a given type is the same and it only varies with like slight differences in this example we're implementing a get name method in the base class so that get name method is the contract we signed from the interface and then we're just reading in data from the annotation so in the first bit of code here we said that our annotation is going to create or contain a value of name so what's the name of this flavor so I know for sure that that's going to be there I also know for sure because I'm implementing the interface that there's going to be a get name method that I can call rather than like have every new ice cream flavor also have to like have code that says my name is vanilla I mean I already included that in the metadata I'm just going to read in the metadata and print it out in the base class which means that when somebody wants to provide a new flavor of ice cream if they extend the base class they actually don't really have to do anything other than provide the annotation metadata because the plugin manager will say okay this dude wants a scoop of vanilla ice cream I'm going to use this factory to go off and find the vanilla class I'm going to I know where to find it because of the PSR4 standard I'm going to load that file and I'm going to parse the annotation and the annotation contains some metadata and then I can instantiate a copy of that the vanilla class which happens to extend the flavor base class which already provides the functionality that prints out the flavor's name which it read from the annotation so as a person that's providing new ice cream flavors this is really simple I can just you know I can start to rattle off a whole bunch of them really quick but if for some reason I wanted to do things a bit more complicated I can always override any of the methods that are provided from that base class if I wanted to do something like here the example was slogan but let's say I wanted to if for chocolate ice cream I want my chocolate ice cream flavor to be really smart and I wanted to go and anytime somebody requests a scoop of chocolate ice cream I also wanted to query the dairy farm to know what kind of chocolate cow the ice cream came from and then be able to append the cow's name to the ice cream flavor you know it's we like making these things personal right and so that way it's doing something a bit more dynamic it can if it needs to but it's not required to provide all of that additional functionality same thing with blocks right like most of the time all you want to do is print out the title of the block but sometimes let's say the objective of the block was to display a calendar and you want the title to be the current month so you can't just parse that out of the annotation because the annotation is static content so you could override the title method and use PHP's functionality to determine what the current month is and return that string instead of the annotation got it easy enough right so the system for creating a new plugin that is an implementation of the ice cream flavor plugin type that we just defined would be this follow the PSR4 standard use the namespace that we defined which is the plugin slash flavor so that's our sub namespace which says in addition to like this being an ice cream flavor this is where the code for that should always live so within my module any ice cream flavor will always be in your module name, source, plugin, flavor vanilla.php or chocolate.php or whatever the class name is follow the PSR4 standard use the sub namespace so that it can find it and then extend the base class that is provided by the plugin type assuming one exists the last little bit here would be again in the instance where you've defined a new plugin type yourself you probably aren't going to just define a plugin type and then be like yay plugins of that type exist you'll probably also want to allow Drupal to you know load up the ice cream flavors and do something with it or load the blocks and make use of them so you need to declare your new plugin manager as a service to Drupal so that Drupal's service container is aware of the fact that it exists and then within your module say the code that's supposed to display a page you can say alright Drupal's service container give me a copy of the ice cream manager and it'll give you a copy of the ice cream manager which you can then use to list all of the flavors of ice cream you can iterate through each one of them and display its title because you know each one of them will have a get name method and so forth so that's done using Drupal's services container basically you need to have a YAML file that declares your new service and then make use of it inside of your code so quick recap of all of this stuff at their root plugins are reusable pieces of functionality sometimes they're configurable most times in most cases they're reusable plugins are a discrete unit of functionality that functions dependent on the plugin type every single plugin is an implementation of a PHP class at their core really a plugin is just saying I'm implementing this interface but I'm doing it with all this extra stuff going on to make sure that Drupal can find all implementations of classes that are using that interface and provide a UI for people to create new fields on entity types and choose the field type which is actually a plugin or to choose the field formatter which is also a plugin being able to create a new plugin which you'll end up doing a lot of when you start writing modules for Drupal 8 requires knowledge of PSR4 and annotations for sure it requires a working understanding of dependency injection again you can probably in most cases just copy and paste the bits that are dependency injection but it is nice to know that that's what's going on and if you're going to create a new plugin type you'll need to know a little bit about the service container and how that works and finally plugin types are defined by and managed by a plugin manager so one way to know what all of the different plugin types are in Drupal 8 that you could implement would be to look for every class that extends the plugin manager interface and each one of those classes is defining a new plugin type and then you can read through that class and say okay this one's defining a plugin type that uses annotated class discovery this is where the file is that contains the class that documents the annotation so now I know what the PSR4 standard is and I know what goes in the annotation metadata at that point it becomes pretty easy to start creating plugins of that type there's a lot to learn here and it's pretty complicated stuff part of it is just a matter of getting into the code and digging around and trying things out and then part of it is having that understanding of how all of the pieces fit together I've written a lot of this down in multiple places as well because again it's like oh man that was a lot of stuff and it's like 6 o'clock on Wednesday evening I'm not going to remember any of this you can check out this urllb.cm slash d8 hyphen plugins and a lot of this is written down and documented there as well as on Drupal.org and various other places that's what I got it is I am happy to stick around and answer questions so yeah we'll go from there yeah absolutely we will totally have lots of content on how plugins are created yeah the question is like the plugin mapper is effectively a router a routing system to determine what plugin to load based on other application state or context it's for any scenario where you don't know for sure which plugin you want and you want this system to determine that for you you would use a mapper does that make sense cool you might have a bunch of plugins for days of the week and you want the plugin for today you could ask the mapper to calculate what today is and then load the Wednesday plugin and it uses application state to determine that sure so the question was can you combine discovery mechanisms so you could have annotated discovery and yaml discovery um yes the current system like you wouldn't be able to do it without writing your own discovery class but you could yeah what you would do is when you create your new plugin manager part of what you're doing is defining which discovery mechanism to use the ones that we talked about are the discovery mechanisms that core provides but you could also write your own too in this case yeah you could very easily write a class that is a wrapper around annotated discovery and yaml discovery yep try to quickly jump back to that slide but let's see this is one of those I was so confused by dependency injection at first and then eventually I realized like oh you mean that's just a really fancy name for this thing that I'm already doing at its heart dependency injection is about being able to provide a function or a class with the objects that it needs to perform certain operations rather than so in the code example here you've got it you're creating a new class with a constructor and inside of that constructor I'm creating a new copy of the database class so now my class is hard coded to always use the MySQL database class so in this first one in the top one there this one is that would be not injected this is a hard coded dependency the problem with this is what if I wanted to use SQLite or Postgres or something else I would have to edit this class and tell it to use a different object to connect to the database in the second example what I'm doing is in the constructor I'm passing in the database object as an argument and then it conforms to an interface that says I'm a database object this is how you do things so in the code below I first create a new database object and then I instantiate my class and I pass in that database object the benefit to this is if I ever wanted to use something different like Postgres instead I don't need to make any changes to my class or my plugin I just need to instantiate the Postgres handler instead and hand it to the class does it always have to be an interface object? no it could be anything in order for dependency injection to work you do need to have the concept of interfaces so the only reason that this works is because the Postgres object and the MySQL object and the SQLite object all implement a query method and or you know like all block plugins implement a build method because if they didn't you would get a thing that's a dollar sign block right and you're like well I don't know if it has a build method or not so in order for that to work they have to implement an interface but it's used for lots of different things the database is kind of the simple example another example might be something like you're querying a third part of your remote API and most of the time you want it to make that connection to Twitter and pull in the live data but when you're running tests in a local environment that doesn't have access to your Twitter account this code the dependency injection style allows you to just say you know what when I'm running tests let me put an if statement here that says if tests are running load the fake Twitter object otherwise load the one pass it into my block class that displays content from Twitter and all it needs to know is call the query Twitter method does that make sense does that help it's totally like it is literally passing the database object that you need into the function instead of creating it in the function that's it like right and this is like you mean I spent months freaking out about I'm going to have to learn dependency injection and then I was like oh shit I already do this like yeah dependency injection you also often hear it referred to as inversion of control so you're basically saying the thing that is responsible for controlling what is created happens outside of the context of where it's used