 Okay. How's that? Yeah? Okay. All right. So we're a couple of minutes past, we still got some people filing in here. So we're just going to go ahead and get started and other people can catch up or whatever. This is the Drupal 8 plugin deep dive session and so very quickly we wanted to introduce ourselves. I'm Chris Vanderwater, I'm with Commerce Guys, I'm a lead dev over there. I'm also the initiative owner for the Drupal 8 blocks and layouts initiative. I'll let everybody introduce themselves. Well, I'll also do James Gilliland real quick. He's not on the panel today because he couldn't make it to DrupalCon, but he was going to if he had made it here. I've left him up here because he was significant in the development of the plugin system, so he's still up there. Great music. Hi. I'm Alex Bronstein. I'm a software engineer for Acquia. I work for Akto, our office of the CTO, and that actually gives me a lot of time to work on Drupal 8 core. I'm Tim Plunkett. I work at Stanford, the Graduate School of Business as a developer, and I'm on the views in core team. So I've got a handful of slides here that I'm just going to kind of walk through real quickly, and this is an attempt at a visual explanation of what plugins really is. I gave this same talk at Drupal Camp Dallas, and it went really, really long because I had definitions for everything, so we're not going to do that. We're going to talk about the Drupal, like, specific stuff here and then acknowledge what's really just like plain old PHP, as Larry Garfield says, and we'll kind of take it from there. Our attempt here is probably going to be to spend the first half telling you what this is, and then maybe the last half doing question and answer and maybe showing some code examples or things like that. So this is very much designed to be an interactive session. Start getting your questions ready. So really quickly, we'll run through just kind of a glossary of terms. We have a whole bunch of things that we throw around when we start talking about plugins, and we have plugin types and managers and discovery and factory and mappers and plugins themselves, and all of this can be kind of daunting. So I've tried to put it together into what I'm hoping will be a fairly concise visual representation of how this code flows, and we'll talk about what really is specific to Drupal and what would have worked anywhere, anyhow, right? So the first and really one of the most important things that we're going to talk about here is the manager. The manager is a class. It does some stuff. It does three major things and can be used as a really great place to attach various helper functions for your plugin types. If you dig through, say, the entity types manager, it has all sorts of helpers on it for getting the controllers and various other things like that. One of the responsibilities of the manager is to do discovery. Discovery is the clear Drupalism in what we're doing here. Drupal has an awful lot of configurableness in it, and plugins is really kind of an answer to that. In many ways, plugins is designed to replace what we've traditionally thought of as being info hooks. So any sort of info hook that you might have in your own contrib or any that we may not have killed in Drupal 8 yet, and I'll get to that topic, could likely be replaced with plugins. So Discovery's job is to go out and discover plugins. If you've ever implemented an info hook, you've functionally done what Discovery is trying to do through a different mechanism. And so there is this metadata out there which it finds and parses and brings back one way or another. There's some really cool stuff around metadata that Tim has worked very, very hard on, and we'll show you that if we have time and what it's meant to do and how you can do some really cool stuff with it. But for purposes of kind of the low level conversation that we've started here, it's the info hook implementation. And unlike the way previous versions of Drupal have done this, where a single module might have many of these sitting in its info hook implementation, each one of these generally stands alone. And we'll cover that topic a little bit as well. And you guys feel free to jump in on this at any time. Once the metadata is returned back to Discovery, we have a methodology through which we can wrap decorators around the Discovery mechanism and the metadata that comes back. We are in process of kind of disassembling some of those right now in favor of more direct establishment of what we want to happen inside the manager. So a great example of this is, who in here has used an altar hook? Amen, brother. Okay. Everyone raised their hand. Yeah. So, yeah, yeah, exactly. So we have an altar decorator that takes all of the various collected metadata and gives you an altar hook for it. And we're probably going to kill that before it's all out. And you'll be able to just, in your manager, do that. And we're going to provide a default manager that does that. And if you want to use it, then great, the default manager works for you. Another example of this might be caching or derivatives, which is a topic that we may lightly cover. But this concept exists at least. We're likely to reduce it down as much as possible in favor of letting the manager handle most of that, which means probably just derivatives as a decorator. But we'll see what actually happens come release. And then we have a factory. This, again, is the manager's responsibility. The three things that will be close to the manager are all its responsibilities. And the factory is really just plain old PHP. Who here has done enough OO that you've ever written a factory for instantiating classes? Yeah, this is exact same thing. And so the manager can either use a factory class that exists or it can be a factory class itself. I'm not going to get into that topic because it's mildly contentious, but it can happen. And what happens from there is you instantiate a plug-in or perhaps multiple plug-ins, and this is, again, plain old PHP. We are just instantiating a class. Generally speaking, all plug-ins of a type are instantiated the same way. There are some plug-in types in Drupal who code around this in certain ways. We probably won't cover that topic unless some of those people are here and want to discuss it further. But we will show you some examples of exactly how this happens. And most importantly, plug-in and metadata for virtually all, not all, but virtually all plug-ins in Drupal 8 right now, those are the same class. So the class that you are instantiating also has the metadata on it in the form of annotations, okay? And finally, there's this thing called a mapper. The mapper is really just business logic. You can hand, say, an array of values to it, and it can parse that array of values and determine which plug-in configured how should be handed back to you. And we do have an example of that actually in core at this point. It's not used. Yeah, it is. We have one that is actively used now. Archiver. Yeah. I am. Yay, chicks. I killed the other one. And so a quick code example. And we're really close to the end of my slides, so we are going to be digging into questions real quick here. I have two managers here. I just grabbed code snippets from two different managers. This one doesn't actually look this way. If you look in head right now, I reformatted it so that it would fit on my slide. But this is the block manager. And that is the entirety of the code in the block manager, from class beginning to class end. It has one function that's the construct method wherein it sets the various discovery and discovery decorators it needs and sets the particular factory it needs. There are methods implemented on the managers, which are in the interface, that do the active discovery when you ask for it and do the class instantiation when you ask for it and mapping if you ever have need for that. We aren't really going to cover that today. But I want you to be aware that it exists. And by contrast, this is the archiver manager. It's a little bit larger. It uses the create instance method here, which you may or may not be able to read. The font was a little bit smaller for this one because there's more code. And it also has the get instance. These are the two methods that do factory instantiation and mapping accordingly. So with that, there are a whole bunch of plug-in managers in core. These are all but one of them, excluding the test ones. Editors, there's two editor managers. And I didn't really feel like trying to differentiate them on the screen, but there are two. And they're used for totally different things. Who's the, whoa, the edit module is what for inline editing. And they're going to rename it the in-place editor module. And the other one's editor, which is for WYSIWYG. And yeah, they both have the same class. They both have editor manager. And it's one of the more confusing things when you're debugging. So they'll fix it. But that's a good list. I was very surprised, frankly. So we wrote this just the system. Actually, like a year ago it got in maybe at this point. Something like that. And we had no clue whether core was really going to use it. Obviously core did. And this actually, this is an even every plug-in type. If we go through here, Views Plugins and Views Handlers are two plug-in managers that actually handle multiple plug-in types. 22. It's a lot. It's a double-digit number, which would double what I have on screen here. And so they did some interesting things there so that they only had to write one manager and they can get away with some cool stuff there. So within all of these, you have quite a list of cool stuff to dig through and see how people implemented it. Not everybody implemented stuff the way I would have wanted them to, but plenty are implemented very nicely and work very well. I'm sure Contrib will do things that make me unhappy too. But who cares? We have an awesome system. So with that, I think, yeah, no, no. You're on this panel, but you can't talk. So there's also some that aren't on here yet. Like, for example, image effects are not on this list, but could be. Actions, text filters. Text filters went in. Yay. I guess I didn't pull from head, sorry. So yeah, so if anyone here is inspired to want to kind of convert whatever is left in core that can use plugins that isn't, there's a code sprint Friday and there's another four weeks before code freeze. Yeah, which takes us back to into hooks. So actually, some of these, I don't even know if all of these were necessarily info hooks. Some of these are new things. Some aren't. OK, so as you said, a lot of this stuff is new to core. So like conditions and constraints and REST type data seekator. So field formatters and field widgets were the one thing I know in D7 was my least favorite info hooks. But blocks, anything where you have an info hook and then you have another hook that it called. So hook block info, hook block view, hook field formatter info, field formatter view. But yeah, a lot of these were all info hooks, I don't think, or their new code to begin with. And I think there's only like two or three info hooks left that would even make sense. As of it stands right now, the only info hooks we will probably ship with will be hook menu or its derivatives. And hook library info, because we're not going to make our JavaScript things into plugins, because that makes no sense. OK, so that's actually the end of the slides I have. I'm just going to start pulling up code and hopefully digging through stuff. But really, I think I want to open it up for questions. Is there anybody who's actively working with plugins right now in Contrib or in Core who's running into stuff? And just come up to the mic. Yeah. And we'll start answering questions. I'm going to bring up probably, I mean, Blocks is what I know best, but we have an awful lot of knowledge up here with regard to some of these various plugin systems. So we can show some cool stuff. If you have questions, just come up to the mic. But you have to come up to the mic. Really? Come on. So I was trying to help out with the responsive toolbar. And initially, it only took links in that top level toolbar. And now it can take render elements. And I was feeling pretty good. And then someone said, oh, but you should really make it a plugin in Do Blocks. And I said, oh, I have no idea how to do that. And so I'm hoping to get some answers from this session. And for a specific question for you, can you name one module, maybe two, that would be a good model to work off of? Something not too complicated that gives me an idea of how I can get started in plugins, something I can emulate? The Tor module, TOUR, they provide tips plugins. So if anyone hasn't seen the module, it uses the JoyRide jQuery plugin. And it shows you what different parts of your page do. And each of those, you can provide these tips, they're called. And the Tor module, since it's new code and it's very one purpose, it has really, really clear steps that you can see what does what. And there's not all this baggage from previous systems. I mean, the Blocks and Views are really good examples for doing hard things, but that's after you've already figured out the baseline. So I'd recommend using the tips plugin manager in the Tor module as an example. OK, thanks. That wasn't on my radar. Another one worth looking at. This is easily the simplest plugin conversion in all of core was Archivers. Who in here is familiar with Archiver? Yeah, we can unzip crap. Who knew? I ran into this because one of my coworkers was using it on a Drupal 7 system. And I was like, how are you doing that? So I went and I figured out what he was doing. And I was like, that's an info hook. We need to replace it. And the whole thing was already classes. If you go and you look at the code that's in Drupal 8 and the code that's in Drupal 7, it didn't change. It's the same code. We just threw away the info hook and put a manager in place. Literally, that's what the conversion was. No other conversion has been that simple. But this was all already classes and objects. And like I said, from the factory forward, it's plain old PHP. So CHX actually did that conversion. And I mean, it's stupid simple. So if you want a before-after, look at that in Drupal 7. Look at it in Drupal 8. You're going to be like, ooh, OK. It's very, very straightforward and obvious. In addition to that, I believe it's possible to use a manager to invoke hooks, right? To still have hook-based plugins. You would have won that probably. But you probably could just in addition. My question was about the hard work. I had some interesting discussions about plugins with Tim on IRC. Say you have an entity that I'm going to make this abstract, Tim, so don't worry. That uses a plugin to do something. But it also needs to use configuration for that particular plugin. Because the plugin itself contains logic. And if you save the entity, you only want to specify. It uses that plugin. And this is the configuration. It's probably use case that is going to be required a lot in contrib. Can you give a short demonstration or an overview of schema of how that should be done in a good way? I mean, we can walk through blocks. No? Can I try plugging in real quick? I mean, well, I don't think it's going to work, but I can't see the screen. So everyone tell me if it works. It's very Drupal blue. Too bad. Sorry. Are you wanting actions or what? Yeah. I'll go get it and apply that. OK, yeah, I'll talk while you do that. So the block module got ported. And then it got rewritten. And then it got rewritten again. And like three times, like 200 plus k each time. It is a really good example of that, what you just described. An entity that needs a plugin to do a thing and it wants to store it, et cetera. But the block module has been around for a little while. And it has a lot of baggage. So it's not a real concise example of that. But just the other last weekend, I was working on porting the action module to make it not useless, but not quite as crazy as rules. And it actually followed the same exact architecture that we used for blocks, where you have an entity that needs configuration to store for its plugin. And now that we have two of them, I mean, it's not in Core yet. It will be. But now that we have two of them, I think we can take some steps to make that easier and more obvious and documented. So, oh, I have this set up. What do I, you know, I just extend this base class instead of figuring out, again, from scratch. Because I ended up doing the same exact things from each example. So OK. Well, no. Take another question. Yeah, let's take another question. We'll come back to the action stuff then. Hello. I would like to ask you to go briefly about standard discovery decorators and factories that are used and what are they aimed for if you can. The factories in what? Yeah, discovery. Oh, discovery. OK, yeah. So there are two main types of discovery right now, just the info hook and the annotations, right? Oh, yeah, yeah, yeah. So there's one for tests. OK, right now there's a discovery class that just uses, like, module and vocall so that you don't have to actually do any conversions. And you can leave your info hooks in place. But the resulting code will be plugins, not just procedural functions. That's the one. The other one is the static discovery, and that's mostly just for tests. And you just hand it a list of, like, this maps to this class. And that's, it's not intelligent. It doesn't do anything. You just, it's for testing purposes. The third and the actually, you know, useful one is this annotated class discovery. And that's the thing that we mentioned and haven't shown yet, which is how to, your plugin will have this metadata that gets read out and processed and stored. And we'll get there, I guess. But so those are the three kinds of discovery. Really, you're just going to use annotated classes. The info hun's basically just for backwards compatibility. Factories, we have two main kinds of factories. Excluding the, like, specialized ones. The one is just, it calls new dollar class, and dollar class is a string. And that's it. The other one calls a method and passes it the dependency injection container. And you can use that to do all your dependency injection stuff. And that's called container factory. But they, what? That went in. Like, yeah, two weeks ago, something. I was looking at the. Stop using the internet so we can work on that. Yeah, container factory is recent to core. So now your plugins can have services injected into them. Please don't do that. Well, views doesn't. So, yeah. I don't know if I answered any of your actual questions. Yes, and the decorators. Decorators. Yeah. I'm good to say. Yeah, so the decorators that we currently have are, we have an alter decorator. So that's basically, once you read, for example, let's say you're using the annotated class discovery and you get back the values of the annotations from the class. It invokes alter hooks so that modules can alter that. We also have a cache decorator. So that's, and a very important one. We have a derivative decorator. So the idea behind derivatives is, let's say you have something like a menu block. And your system has a bunch of different menus. You have the main menu, the administration menu, the tools menu, whatever user menu, whatever custom menus there are out there. So you only have a single class called menu block. But for every menu that is administrator configured, you sort of expose, in the blocks UI, a separate block. So that's the use case for derivatives, anything like that. It's not just for blocks, that same use case exists in other plugins. Right, yeah. So if discovery within plugins replaces info hooks, derivatives replace for each loops within info hooks. So that's another kind of decorator that's in use. One thing that Chris mentioned is that we're currently in progress of setting up a base class. So now that we have all of these different managers, when the plugin system first went in, we weren't sure how similar the different core managers would end up being. So now that we have 20 or so plugin managers in core, we see how similar they are. And so we're actually working to make them more similar to each other. And then instead of them duplicating all those decisions, like instead of 18 of the 20 core managers saying, we want annotated class discovery with an altered decorator and a cast decorator and such and such, that we can have a base class that sort of makes all those decisions. And once we do that, then there's also some argument for moving away from the decorator architecture and putting some of that logic directly on the manager. There's some pros and cons of each approach. So it may be the case that that same functionality that currently exists in decorators will move to just functionality on the base manager class, if depending on how the issue queue debate goes on that. Okay, thank you. Who has ever used trigger module? Okay, you've used it more than I have. The trigger module is removed from Drupal 8 and it was the only thing that really actually used the action module. And action modules just dumb down rules module. So, but the idea was you have an info hook called hook action info and you provide a list of actions. And it's sort of, it's not exactly used, but it's like on the content listing or the admin people, you can block users and publish nodes and whatnot. So you just had a list here and Drupal style just a massive array. And so the node publish action is one of the actions. And this is also met, it's the name of the function it should call later. It only works on nodes. It publishes your content. It's not configurable. And then this stuff is still just left over from trigger module. And the actual function is node publish action and it takes a node and it sets its status to published and then it writes the watchdog. And it doesn't actually even call save. Save is managed somewhere else. But that's the basic setup of just plain actions. So, yeah. Can you guys see that? Eh? That's blurry. Is it like fuzzy and then stop? And then fuzzy and stop? Fuzzy, it could be a little bigger. Well, okay, let's see. For a while. Yeah, just feel free to hijack that one. I'll just make it like 20. Oh, 20. How's that? All right. How do I make that go away? Whatever. Okay, cool. So instead of having, so the equivalent of this function and its info hook is all contained right here. So you're in this publish node class. It has a method that takes an entity, sets its status and calls save. And instead of having an info hook, it's right here. So you have your ID, you have a label that gets translated and it works on nodes. And that's it. So instead of having to write out annotation class, yeah, yeah. So, yeah, right. So instead of every time you wanna add a new action before you had to go find your node hook and add a new, like 10 lines to this and then go somewhere else and put another procedural function. Now you can just drop in a file and it just gets picked up. And this is the info hook path and this is the rest of it. So you'll notice this says at action. This is an annotation and we use doctrine to parse our annotations. And this just maps to another class that is hidden right here called Drupal core annotation action. So this is just, this provides the default values as well as documentation. So this shows you what you can and should use to create a new action and how to document it. So the plugin ID, the human readable name and a URL. So now you know you can use a URL. And if you don't specify one, it'll give you an empty string. Right, and then the action manager is, yeah, okay. So we use annotated classes and then we have an alter hook and then we're using this thing called container factory. And that's the factory just looks like this, container, yeah. And it just calls a create method and passes in the dependency injection container. And you mentioned earlier that you can, the managers are where you put useful methods. So for example, very often you wanna get a list of all your actions. But more often than that, you wanna get all the actions for a specific type. So I want all the node actions now. So I just tack on a new method, get definitions by type. It just gets all the definitions and then uses array filter and anonymous function and filters it all out. So then in code somewhere else, you'd just be like, this is VimMode in an IDE, it's tricky. You'd just be like manager, get definitions by type, node, and then you'd have all of your, it'd just be like calling the info hook yourself. Okay, so, yeah. Therefore, you now know everything about plugins. The actual question though is about configurable plugins. So, action. So this is going a little off topic because it's config entity. So we have these concept of configuration entities, like a view or an image style and it gets written out to YAML. And this is the entity that has the configuration of a plugin. So this one has an ID, it has a label, it has a UD, et cetera. And then it has a plugin. And an actual, let's see if this, cool. Action.action, there we go. So this is the YAML file for that configured plugin. It knows, this is what plugin to call, it's in English, it works on a node. A more complex one would be like, where'd it go? Oh, you don't have it. Oh, right, you didn't install. You didn't reinstall Drupal, okay. Damn. Well, yeah. These, no, it's not worth it. Some of these actions are configured in a way that you can just do this and you'll just have settings and it's like, oh yeah, yeah, yeah, yeah, what am I thinking? Locked up, lock. Looks like this, where you just have a settings array. And then this gets, this whole array gets passed to the plugin. So you use the one system to store the configuration for the other one and it just gets instantiated when you need it. Like in, you talk. So like the important point on that is that the config entity in this case actually has a settings property and only the stuff in the settings property, the array that sits in there is what's used to actually bootstrap and configure the plugin, right? You don't want to pass the whole entity in. There are a whole bunch of reasons for that that we could spend literally hours discussing much less days we have. But the point being, like those settings are, they're isolated from everything else in the entity. In the case of block, like blocks are a really good example because the region that a block exists in and its weight aren't really things that matter to the plugin. They're things that matter when it's rendered on screen when you're dealing with a whole bunch of block entities, their various configuration. But it's not at the same level as say, how many users are we gonna show in the, who's online block, right? That's something the plugin cares about. And so, I mean, this is something that you kind of have to go over it with a fine tooth comb when you run into one of these and make sure that you're really appropriately separating your entity from your plugin configuration. And it can be quite tricky, but it's also well worth it in the end. So do you pass on the settings when creating a plugin, like creating a plugin instance, or only when the plugin actually needs it? Because then you have a lot of, you could potentially end up with a lot of instances of the same plugin, but every one of them would have their own few configuration. So because, okay, so in views, a view is just a wrapper around displays. So you have your page display, you have your block display, you have a feed display. And those are all plugins. And the idea was if you want to just display a block on your page, you don't wanna have to load the entire page display of that view that's used somewhere else. So we added a little layer to lazily instantiate them, and I named it plugin bag. Named after, the symphony stuff, it was like a parameter bag. It's like a bag. It's a collection that the order doesn't matter, and you just reach in and then it's like Mary Poppins, you know. So, it's a bag of holding. It's a, yeah. So this is the action bag, and the action bag, that sounds awesome. Where's my other class? Okay, so in my entity, whoa, in the construct, all it does is just call parent construct, and then stores my bag. And I pass in the plugin manager, I pass in the plugin, and I pass in the configuration I know about. So that's basically taking that file and saying, okay, here's what I know, and go forth and give me plugins later. So action bag in its constructor takes the plugin manager, it takes a list of possible instance IDs that it may eventually instantiate, and then any configuration needed, and stores it for later. And then when it comes time to initialize, it calls manager create instance with the configuration. In short, until the entity, in this case the configuration entity needs the plugin, it doesn't exist. And then once it needs it, it instantiates it, and does pass the entirety of the configuration that the plugin needs at that point. But if you aren't necessarily going to be using config entities and plugins in conjunction all the time, it's likely to happen a lot, but it's, wow, I'm getting feedback. It's not, okay, it's you. It's not something that absolutely has to be done by any stretch of the imagination. There are plenty of ways to do it without. It's also very likely that you're going to end up with a configuration entity that might actually compose many plugins together. Views do this. Rules will do that. Rules, page manager. Views does that. Yeah, I mean. There are only maybe four that do it like this right now where you have a plugin views filters and form, like a text format configuration contains filter plugins now. So there is a model, there's a lot of code there that you can like copy and paste from and read and learn. But I do think we can now take the steps to codify that and make it easier to do that and contribute because it's gonna happen. So. Yeah, but the harder part on that is actually gonna come down to you as a developer identifying what's relevant to the entity, what's relevant to the plugin. Next question. Actually, while we wait for more people to come to the mic, just curious, who here is familiar with what config entities are and why we have them and what purpose they serve? Okay, I'd say. That was like a dozen people. Less than 10, way less than 10%. Yeah. Okay, so there was a question at an sort of an earlier call about sort of when to use config entities, when to use plugins and sort of what that whole distinction is. So here's a quick summary. So when the configuration system went in, we just had this concept of configuration files. So great, we have, and we could get rid of things like the variable table and variable get and variable set. So if you wanna store something like the site front page, you put that in system.settings.yaml. So that's a one, that's a single configuration file. But then we also sort of know that we have some configuration files that sort of follow a particular pattern but that the specific instances get created depending on what the user does. So for example, for image styles, if the user adds a large image style, that's a whole set of configuration and then if the administrator adds a medium image style, that's a whole another set of configuration and so on and so on, same for views, right, every view you make. So there's this idea of like, there's a particular kind of schema of configuration, like that defines an image style in the abstract and then there's the specific instances of like a large image style, a medium image style. And at first those were just sort of configuration files that weren't treated in a special way but for various reasons it actually became really useful to codify those kinds of configurations as entities, they're instantiated objects that get stored, which is pretty much what entities are. So that's the config entity system. So a config entity represents basically a piece of configuration that gets stored and that can exist in multiple instantiations. In contrast, a plugin is a piece of behavior. It exists, you instantiate it within a particular request to accomplish some action and then once the process stops, it's out of memory and it's not stored. So for example, if you look at an image effect, as part of an image style, you're gonna instantiate like a resize effect, but you're instantiating that in PHP code, telling it to run and then you don't need that effect object anymore. So there's the distinction between for example, the configuration that represents an image style and each plugin that represents an image effect. And so it's really like sort of a unit of configuration storage versus a unit of behavior that you pass configuration to. And that's a really good example of a config entity that it's got n plugins that it's configuring. Yeah. So when it's an n to one situation or one to n situation, like an image style contains an n image effect or a view contains n displays or a text format contains n filters, it's pretty easy to conceptualize about what goes in which one. With things like block, it becomes a bit harder because the way our current block system works, one block config entity, one unit of block configuration storage maps to a single block plugin. So now you have a one to one relationship, it becomes a little harder to reason about which goes where, but you follow the same sort of principles of what represents the unit of storage and what represents the behavior. And one way to start thinking about that separation is to think what other situations can that plugin be useful for. So for example, in core, currently, blocks are stored as individual units of configuration. Each block is stored as its own configuration entity, its own configuration file. But maybe panels wants to introduce a concept of displays that store multiple block configurations as panes within a single unit of configuration. So if you start thinking in terms of like, okay, so now the behavior of rendering a block can be potentially via contrived like panels, the configuration for that plugin or for a set of those plugins can actually be stored in a different config entity, that's where sort of separating those two becomes useful because then as long as the block plugin only acts on past in configuration rather than making assumptions about how that configuration is stored, it allows a module like panels to allow the configurations of blocks to be stored in a different way than what core defines us, than what core provides. And that's really useful when you start talking about if you've got a situation where you're building a plugin that you know is gonna be useful outside of your own circumstances, you can build a single manager that makes the assumptions you need made for your implementation, but if you take care of your plugins appropriately, then someone else can come along and reuse them in a completely different situation. So in the case of blocks, yes, core currently has this block manager that assumes a one-to-one relationship between block entities and block plugins, but it's not a requirement of using it. You could go out and do something totally different. We also have a condition system that could be done the same way and frankly actions. Yeah, that was the logic behind the actions, plugins versus the config is that rules is obviously gonna run and reuse these and not have to rewrite all of it again. So I mean the rules module completely duplicates what's in core because it's inadequate and now ideally it will be able to just swap out the parts it doesn't like and the rest will, you write an action and it'll work anywhere. Which brings us to an interesting topic. These managers, within core at least, all the managers are actually registered within the dependency injection container. Anybody in the room have the foggiest clue what I'm talking about there? Dependency injection container. Okay, that's not trivial. So the dependency injection container currently knows about basically any class within the system that's likely to be asked for on its own and needs to have some sort of dependency fulfilled. In the case of most plugin managers, they currently need a list of all of the modules that exist because they're using the annotation based discovery system. And so they get that injected into them when you ask for one. But because they exist in the dependency injection container by virtue of that fact, it actually means you could replace the block manager with your own class that may do different things. And this gives you a level of flexibility in core that you've not really had before because you can replace core's actual implementation, the code that is making these decisions. If you take that and go really crazy with it, I'm not suggesting this. I'm just going crazy for a moment. You could look at, say, the entity system and throw away the entity manager, which is likely a really bad idea, but you could, right? And then you could get at your entities or their controllers or something like that in different ways and through different methodologies. It is unlikely that you need to do that. More likely you'll end up creating new managers for existing plugin types when you just need a slightly different implementation, but the old one needs to continue functioning as well. There are a lot of possibilities there. And while we're talking about the swappability of this, the alter decorator that we have talked about with regard to the metadata, when that comes back, it actually comes back with the class that it's going to invoke, which means that if you use the alter decorator, people could actually swap out your plugin class whole hog. So if we use the menu block example, if you aren't, say, thrilled with the output that menu block has and you wanted to change the output completely, you could extend the menu block class to some custom class, use the alter decorator to put it in place for menu blocks and then from there, you would be in a position to completely rewrite the output of all menu blocks on the entire system simultaneously. Just write a single method over write our build, right? And so this is a level of power that I don't know if the front-enders are likely to use it. I know the developers are likely to use it, but I don't know if the front-enders are likely to use it, but really whole hog. And since that class contains everything, it contains the configuration form, the validation for that form, the submission for that form, all of that stuff, you really have the whole world at your fingertips there. You can just replace it. Yeah, for the menu block example, a module like menu block would of course follow best practices and make sure that all HTML markup that was output was done via a template, right? So for front-end developers to customize the markup of a menu block, it would be overriding a template just like normal theming, but the example that Chris was giving was, like let's say the, you know, something more, not necessarily the markup, but let's say the render array structure or some of the internal logic that the menu block implements for whatever reason you decide doesn't suit your needs, then that would be the kind of functionality you could replace with the class. That's not a tool that's meant for theming, it would be more for a tool meant for changing the actual sort of functionality of the menu block. But any plugin manager that implements alterations like this, you're gonna have that ability on. So, I mean, and the vast majority of them do. So you can do some really cool. They all do, yeah. I don't know if type data does. Oh, well, I, oh, that's true. Okay, all the annotated ones now have alters. Type data still uses info hooks for some other reasons. We'll fix that. If you wanna come help fix that, find us on Friday, which is tomorrow. What are you pulling up right now? Oh, I was just showing that you could take over menu block and decide that they don't get a form anymore. You could do that. You could do that. You could totally do that. No form for you. One of the other things that we haven't really touched on at all is that plugins actually have this notion of contextuality. And so there are a set of base classes which you can extend and use, which make your plugins context aware. And at that point they're actually consuming various objects, say like a node or a string or a user or something like that. And so you can actually define what sort of constraints are on that object. And so like, can you pull up the node type condition? Yeah, so just look at the annotation. So in this annotation there's actually an array of contexts. It currently says node. Node is just the name that I chose for it there. But underneath node it actually specifies the type of type data that it is and any constraints on that. So it says we are going to have an entity type data and the constraint of entity type node. So you can only pass nodes through here. If you handed it a user it would actually like throw an exception and say you can't do that. So what's really cool about this is that this gives us kind of a, if you've used C tools or panels or anything like that this gives us the same sort of structure. Rules does these same sort of things where there are certain conditions or certain blocks or certain actions that only work if you have a node available or they only work on a node. And so for example, you can't very well show a node title if you don't have a node. So why would we give you a block to show a node title? These sorts of things. The only plugins in core that are using it right now is conditions. We are likely to give blocks the ability to do it but might not have an implementation of it in core but the base system for doing it does have test coverage so we can do that with pretty good surety of what's going on there. We got a question. So with all these classes being used throughout system and modules incorporating some of the base classes are there any visual tools that would just give us a snapshot of what some modules are using and all the methods available in those classes? I mean, this is not an endorsement. I don't work for JetBrains but get PHPStorm. It's worth it. Or IntelliJ, which is a big brother. The same thing, but yeah, I'm a Vim guy but I'm using PHPStorm now because there's too much. I mean, api.jp.org, I pulled this up earlier shows you what, these are all the config entities and stuff but it is hard to see and it's hard to discover what is this module doing because the file structure is verbose, to say the least. And you've been working really hard to trim that down lately. Yeah, I deleted two levels of directories but it's still like eight. Yeah, so that's worth talking about. You can see it up here at the top. This is in core modules node, lib, drupal, node, plugin, condition, node type. Those are directories, that's a lot. Yeah, I mean it's PSR0, most of it is PSR0 and some of it is our convention so that we are protecting against namespace clashes. I mean we don't want to do all this work and then have it not work and contribute. So we're kind of being a little paranoid. If you were at the keynote this morning you kind of talked about that. We're, it's for the best, I swear. So when annotations went in, I was very adamant that we needed to know about who was the owner, right? What module or subsystem declared this plugin type exists and then what plugin type is it because a single subsystem or module could declare multiples, say I don't know, views. And so when you look at that you want to know that this is a views field. This is views cache. You don't just want to know this is cache because guess what? Everybody in their dog might have a cache plugin type so you can't just squat the cache namespace, right? And so I was very adamant that we had to have these two directories worth of separation. Tim has worked really hard on giving us better annotations so you've seen the action annotation and it sets defaults. The entity type annotation is a really great example of this. It sets default controllers and some default base keys and things like that for various things. And so it's really smart stuff but we didn't have that initially. We just had an at plugin annotation which basically gave you an annotation as an array that you could then treat kind of like you might have an info hooks array and that sort of stuff. But because we have these annotations now we could in a worst case scenario if two different plugin types ended up in the same cache directory they should have different annotation classes on them so we'll still have a separation even if we don't have one that's separated by directory. So we're still being paranoid. We've just figured out how to be paranoid without as many directories. Also two of those directories as Tim mentioned come from just sort of having to follow PSR0 standard just because that's sort of the only standard that's available now but there is an issue in the queue to move to what may end up becoming a PSR4 standard. Is it four or five? It'll be, well depends on the timing. Depends on which one lands first. But it's currently a proposal but basically allows it's sort of a new auto loading standard that's proposed by different PHP projects that allows shallower directories for use cases like we have. So potentially we'll be able to get two directory shallower for all classes implemented by modules not just plugins. Yeah, the F, was it framework interoperability group? I think, if the Google does a thing. But yeah, PSR4, if you're interested in that kind of stuff it's a pretty interesting read. If the Google does the thing. I'm waiting for your browser. Yeah, and it's on GitHub which is cool too and mailing lists and whatnot but yeah. So we've thrown an awful lot at you from the perspective of what's sitting here. I think like what would be good that we haven't really done yet and we don't have a lot of time left is can we just, let's just pull up the plugin manager interface real quick. The plugin manager interface is, I mean, yeah. So discovery and the manager are really the two clear Drupalisms here. There are four methods on the manager that we're going to talk about. There are no methods on the manager interface. It's just remember. Oh yeah, okay. All right, nope, even better. Okay, so it implements, yeah, I guess pull up base or pull up those interfaces, one of the two. So the plugin manager interface actually extends three other interfaces, the factory interface, the discovery interface and the mapper interface. And these have one, one and two accordingly. So the discovery interface has two methods. The factory interface has one and the mapper interface has one. And so discovery is, as you might suspect, responsible for discovery. And it has the methods of get definitions and get definition. And so you can get individual plugin definitions or you can get all of them simultaneously. The factory oftentimes calls the get definition for whatever ID was passed to it and it finds out the class and then instantiates that class and hands it off to you. And then, as I said, the mapper is kind of a clear use case for specific business logic that you might have. We were using it in lieu of config entities for a while until those landed and we converted over to them. The archiver manager is using it for determining which archiver to use. So you handed a file name and it goes, oh, that's a zip file. And then it loads up the zip plugin and unzips it and gives you stuff, right? So that's kind of the idea there. But managers really at their core are just these four methods. Get definition, get definitions, create instance, get instance. That's all that has to be in a manager. And actually, there are some managers that don't even implement all of that because they extend the base manager class that we provided, which tries to give you some same defaults. So we've tried to keep these as simple as possible. The one thing I would encourage you to do is if you find yourself writing a custom factory class, stop and go, am I ever going to reuse this? If the answer is no, write your logic in the manager's create instance. It will solve a lot of headaches for you in the long term. And one other point I just wanna come back to with the question around, there's a lot of classes in Drupal 8 and how do we sort of navigate them either if we don't wanna use PHPStorm or if we wanna navigate them some way other than through PHPStorm? And that's a question that's a broader than just plugins. Plugins is just one area in which we're using object-oriented programming within Drupal 8. We're using object-oriented programming within Drupal 8 in lots of other areas. So we have a lot of classes and a lot of interfaces. And so I think it's sort of a community challenge. So I guess I point it to challenge all of us to find out how we can improve our documentation on d.o, improve tools and sort of what are the best practices that if we're becoming an object-oriented project, how do we make that friendly for people? Yeah, I hate to turn this into an advertisement for JetBrains, but their product is really good. It is really, really good. So if you haven't stopped by their booth, they are here and they have yo-yos. I would encourage you to. Their product's reasonably priced and has been really helpful in development of D8, just so you know. Yeah, that's time. So we'll be here and available to answer questions, but yeah, you are officially dismissed.