 Welcome everyone. So today I'm going to give you a talk about some of the new APIs or some of the new methods of extending Drupal that are available now in Drupal 8. Really, it's a bit of a high level discussion. I'm trying to look at why would you use one tool over another in Drupal? So we're going to be looking at a session that's targeted at people who are familiar with Drupal 7. So that means that you've written some custom modules in Drupal 7. You've probably implemented hooks, which is a very common way of what you typically need when you're implementing a module in Drupal 7. And we want to learn about best practices for Drupal 8. So I'll try to keep it at a fairly high level, but there will be a lot of code examples in there where I sort of try to delve in and explain some of the concepts. So just to illustrate some of the details there. So we'll go through in this order. So we're going to be looking at hooks, a bit of a review of what they are and what goal they're trying to achieve. Then I'll look at plugins. And then I'll delve into something that you might not be as familiar with, which is tagged services. And then finally, I'll look at events. So I'm Kim Pepper. I'm the co-founder and technical director at Previous Next, based in Australia, where Australia's biggest Drupal shop down there. These are my contact details. Feel free to get in touch with me. I've been a member of Drupal.org for about seven years and five months. I had to check before this session. And I've worked on Drupal call quite a bit. With Larry a few years ago, we were doing a lot of the whiskey work, which is basically converting a lot of the kind of hook menu implementations over to symphony controllers. And that's where I kind of cut my teeth in Drupal 8 and got to learn about some of those concepts. So before we dive into the new APIs that are available in Drupal 8, we sort of have to go back in time a little bit just to look at where hooks came from in the beginning, what goal they're trying to achieve. So in the beginning, there were hooks. They're actually around before Drupal 1.0, believe it or not. I had to go through the Git log to find exactly where Dries has actually done the first commit and added the concept of hooks. And it was pretty much like in the very beginning. So that's around 15 years ago. So this is the message that was in the commit that I found. Basically, the idea is to be able to run, to decouple the implementation, the different implementation details from the code that's actually executing at that time. So we wanted to decouple in a loose way and be able to execute that code. And this was a weird concept. I actually had a Java background before I got into Drupal. So I just wait till everyone filters into the room. There's a couple of spare chairs up on the end here. If you're looking for a chair. Cool packed house. Yeah, so I mean, this is the original goal of hooks. And actually, it's an architecture that really defines the code base of Drupal and what made it actually a very flexible framework to work with. I think that's why you've got a lot of adoption by developers. Even in the days before ObjectDoran to PHP was around, this was a mechanism that provided a bit more of an event-based mechanism for executing code in systems where you could decouple the listeners of the code from the event triggers, if you like. So just a brief explanation if you're not familiar. So essentially, hooks are discovered in your .module file. Drupal, in Drupal 7 and 8, an early version of the Drupal, look in the module file, they're trying to find something that matches a pattern. So it's based on a function naming convention. And the code that calls a hook basically says, if this function exists, then call it. Passing whatever data it might have. And PHP is actually pretty efficient at doing that kind of looking up if a function name exists. So it actually works. There's different types of hooks. So in Drupal 7, there's a lot of these things called info hooks. And really, all it's doing is providing a declarative metadata about what that bit of code is, how it is implementing and passing that back. And hook block info is a really classic example of that. A lot of this information is caged, of course, by Drupal, so it doesn't have to do it every time. And of course, there's the concept of alter hooks. So this is really just adding the ability to modify data. And the classic case is hook form alter, where you can modify a form before it gets rendered. There are plenty of hooks still in Drupal 8. I think the alter hooks are the most common case that you'll find in Drupal 8. So actually, I had to ask Larry about this before I put this slide up. But basically, there is a big move away from hooks in general in Drupal 8. So almost all of the info hooks are gone. We replace those with other mechanisms, either yaml file, annotations, those kinds of things. All the alter hooks are still there, most of them. Actually, I think there's actually a few more in the word before. But there's a trend to move them and replace them with event listeners. Which I'll go into a bit later in the talk. So they will replace, but it's not Drupal 8. It might be Drupal 9. But it depends on the effort of whether people are interested in moving everything over to event listener. So should you be defining your own hooks? Well, I'd argue not. Because when hooks were invented, it was basically an aversion of PHP, which didn't have the concept of object-oriented programming. And there's actually a lot of better ways to do it now. And if you're writing a new custom module and you're deciding on how you're going to allow other modules to extend that functionality, then I would avoid hooks, personally. So what is wrong with hooks? So in this example, this is an example from Drupal 7. It's really hard to understand what it is that you actually need to implement. So this is a very simple example. There's much more complicated examples than this. But if you want to define a hook, how do you know what it is that you actually need to do? Only the top two are actually required. The others are only if you have configuration with your block. But using object-oriented PHP, we can actually build very clear contracts or definitions of what it is they actually need to provide. So this is an example from Drupal 8. And it's very clear exactly what you need to implement. So we need to implement a build method. If we've got a form, we need to implement block form and block submit. It really makes a clear definition about what's required. And because we can use inheritance, if you have some default implementations that everything can use, then you can just extend from a base class and get all that stuff. You don't have to duplicate all of the code. So procedural, I think, has got a lot of negatives to it. First of all, all of those functions are global. So why is that bad? Well, it basically means you're tightly coupled to the code that you're executing. There isn't a clear separation there. And one of the key things, I think, is testability. So if you're using object-directed code, what you can do is you can mock out the dependencies of that code and then test that code in isolation. And if you're thinking about whether you need to have end-to-end tests versus unit tests, I'd say maybe 80, 90% of your tests in any particular project or code base that you're doing should be unit tests. Doesn't mean that you shouldn't have functional tests or end-to-end web tests. But you should be focusing a majority of your tests as unit tests. OK, so the reason is because with object-directed PHP, we can actually code to interfaces. We don't actually have to code to concrete classes or explicit implementations of class. We can use patterns like dependency injection to avoid understanding how dependencies actually need to be created. They can just be passed into the constructor. And then we can actually do things like mock out those interfaces when we're doing our unit tests. So if you're not familiar with dependent, who knows what dependency injection is? A few people? All right, so it's a weird name, but it's actually a very simple concept. And this is a basic example of what dependency injection is. So you can see that in my class here, I want to do something, rather than understand what my dependency is or how it gets implemented, all I'm doing is just passing in the dependency in the constructor, setting it to this local property here. And then when I'm actually running my code, I just call the dependency. But you can see how I never really need to know how my dependency is created. All I care about is that I've got an interface. I can expect that whatever methods are defined on that interface, I can call. And whatever implementations there will be respecting that interface. So that's the concept of dependency injection. It's not too complicated, right? The alternative would be if I were trying to create, say, the database connection, I'd need to understand what its dependencies are. So its dependencies might be, OK, well, I need a connection object, or I need all these credentials, all those kinds of things. You want to essentially abstract your code away from all of the underlying technical details of that dependency. And of course, this makes it easy to test, right? Because we've got an interface here. We can provide a mock. We can test that that code gets executed, provide stub code to return data, or whatever. OK, so the rest of this talk really is about extending Drupal 8 with object-oriented programming. So we're going to be focusing on some of those things that avoid this procedural code. So the first one is plugins. So plugins as a concept essentially existed in Drupal 7 with C tools. Many modules took advantage of C tools plugins in Drupal 7. Essentially what they are is small pieces of code which you can define an interface for. And then multiple implementations of those can exist, either within your own module or other modules that might want to provide an implementation as well. Plugins typically have configuration. So each implementation can define its own configuration. They can be completely different types of configuration per plug-in instance or plug-in implementation. And you'd see applications providing admin form support. Typically they would. If they've got configuration, typically they would expose that in an admin form to let you modify that and then export that as confident. And they also support the concept which is a little bit more advanced, which is a concept of derivatives, which is basically having multiple instances of a plug-in time. So a good example of that in Drupal Core is blocks, where you can kind of have multiple instances of a block placed around the site. All right, so how does Drupal 8 actually discover plug-ins? So this is a new concept in Drupal. We didn't have this before. But it's actually what's called an annotation. So we need the annotation. We also need to use the PSR4 namespace, the correct folder structure and namespacing class, namespacing declaration in our class. And it's got to typically implement an interface. It's not strictly enforced, but it's best practice to actually have an interface for your plug-in, for all about the reasons that I explained before. So this is what an annotation looks like. It's very simple for blocks. Essentially it's a comment that sits above your class declaration. In the case of blocks, you can see here we've got a special annotation called block. And then it's just a bunch of properties that define the metadata for this plug-in. In this case, we only need a unique ID for the plug-in. And then the label that we want to appear in the admin screen when we're viewing all the blocks that are available. And then in terms of the PSR4 namespace, this is a common standard across all PHP. It's not a Drupal-specific thing. But we can basically make sure that it has to live under the plug-in folder and the block folder, and then with the namespace that actually matches that pattern. That's it, right? Drupal will then be able to discover that. It's different to how Drupal works with module code, where it basically will load the .module file and every page load. Here it will use PSR4 discovery to find that. So this is the full implementation of a block. So essentially you can see you've got our annotation at the top. And here, our custom block implementation is extending this block base. So we're taking advantage of inheritance here. We've got a base class which defines a lot of the basic standard methods. And the only thing that's still on the interface that hasn't been implemented is this build method, which just means that we need to return a render array. So that's a simple example of a plug-in implementation. The other concept you need to be aware of is the idea of plug-in managers. So this is essentially the entry point for dealing with plug-ins, because essentially you don't know what plug-ins are available. You are queried plug-in manager to provide that information for you. And they're used for doing things like show me all the plug-ins that are available, or create an instance, or get me the definition of that plug-in. And a few of the other concepts that you get with plug-ins, you're able to do dependency injection, like I explained before, to pass in services. So for example, if your plug-in needs to query the database, you can use implement a method on there, which will query the container, grab the database, and pass it to your plug-in. And as I mentioned before, there's other things like derivatives, which allow you to create multiple instances of a plug-in. So that's just an example of how you would implement existing plug-in types in Drupal. So Drupal Core provides a whole list of different plug-in types. So how do we define our own type? So you're building your own custom module. You've got to make a decision about how you're going to allow other people to extend code. You've been told by me that hooks are bad. So how do you build your own plug-in type? So essentially, when would you build it? So you would do this when you've got typically configuration required for a number of different plug-in implementations. So you want to allow users to provide configuration for them, or they need certain settings. And you might want to expose that as an admin form. So in actually to create your own plug-in type, there is a fair amount of boilerplate that you need. So first of all, you saw before with the block annotation, that's actually a class. So you need to create your own annotation class that defines the properties that you can configure with your annotation. You'll need to write a plug-in interface that all of the plug-ins must implement. And then of course, you need to build in some of your plug-in implementations. Typically, you might implement a couple yourself that are part of your module and then assume that other third-party modules will be able to add additional one. And you also need to create a plug-in manager. So plug-in manager is the thing that why is it all together? So plug-in manager, it's responsible for defining the directory and the namespace, where the plug-ins live, where to look for them, what annotation class to use, what the interface is that your plug-in will need to implement, and things like a plug-in case. So plug-in case basically keeps those things in case so it doesn't have to do the look-up every time, and also what all the hooks are available. So a fair amount of stuff in a plug-in manager. And this is a very simple example of a plug-in manager. The simplest one I could find, which is from the search module, and you can see here, essentially, I stripped out most of the comments just to fit it on the screen. But you can see I need to be defining the namespace that it lives under, this is the search plug-in, the interface that the plug-in types must implement, and what annotation class to use. I'm setting the cache namespace here and what the altar hook is. There's a fair amount in there. But there's a lot of flexibility in the plug-in system. So there's lots of areas where you can go in and override things and customize things, how you might want to do that. And there's actually lots of good examples in Dripper Core of this being done. So things like how plug-ins actually get created. So that search plug-in manager is just using the default creation method. But if you need to do additional functionality, when your plug-ins get created, then you can customize that in your plug-in manager. How they're executed, and also just things like listing what plug-ins are available. So there's way too many of plug-in types in core to list on the screen. But just to give you an idea, plug-ins as a concept is one of those things that just got spread throughout Dripper Core, which I think is a good thing because there was actually lots of different ways of doing the same thing in Dripper 7. And we kind of consolidated on a single approach for a lot of this. So you might be thinking, oh my god, like I need to create a plug-in type. It's like there's a lot of stuff there. Like I need to learn all these concepts. Is there a simpler way? And I think there is. I think if you don't need configuration for each instance type, you might be able to look at something like tag services, which is a much simpler way of doing that. And I'll go and explain what services are and then what tag services are. So who's here familiar with symphony and symphony container? Just a few people. OK, so Dripalate adopted a lot of symphony components. And one of the most important ones was the dependency injection container. But before I want to show you an example of dependency injection where all you're doing in your constructor is passing in the interface. You don't know how it got created. Well, the dependency injection container is the thing that creates all of the instances for you. And it does that by looking at YAML files to work out what class to call new on. And you can do things like passing arguments. It's a whole bunch of options there. So the benefit of that is that essentially it's declarative information, you're passing. You just be able to do that in YAML. And you can just assume that all of the classes will be there in your code when it gets called. And in your own custom module, you just define a module named dot services dot YAML file. And Dripalate automatically load that up and add that to the list of services. So this is a simple example of defining a service. We have a YAML file here. And essentially, we just need this high level services. We've got my services. It's essentially your unique name. It should be, usually, it would be prefixed with the name of your module just to avoid a name clash. And then here, we're just defining what the class is that the container is going to create. And we can also do things like passing arguments. So here, we're passing in the config factory. And this at symbol means it's basically another service that's been defined somewhere else. But this could easily be, say, the database connection or anything like that. So these will get passed into your class. So once you've defined these services, to get them is actually pretty straightforward. So as I said before, if you're defining a service, you can pass other services in and they'll automatically be there. If you want to, if you're forced to use a procedural method, you can use this Dripal class here in Dripalate that basically will find the service by its unique name. And it will just return you the instance that's already been created. There's probably too much of this being used at the moment in Dripalate call. So I see this as a bit of an anti-pattern. For the reasons I explained before around problems with procedural code, it's actually much harder to kind of mock these kinds of calls out in your code. So the benefits of services, essentially, we get a lot of benefit out of that pattern of dependency injection. Loose coupling, decoupled from the implementation details. We're programming interfaces. And we can allow our plugins or even our root controllers, the symphony root controllers that are in Dripalate as well, to actually be free of a bit of that domain logic. We can push that out into kind of well-defined services. So now I kind of understand the concept of services. So what are tag services? So tag services is essentially a way of letting the container, the symphony container, take care of the work of discovering what implementations are available. So what you're doing in your service definition, you're giving it a tag. And the container will go through and say, find everything that's tagged with this. And I'll take you through how this kind of works. So the first thing is we need an interface for a service. We're always using interfaces to just have that decoupling and a manager. So a manager is probably not always a good term, but it's essentially what is calling these services. So whatever your domain logic is, be it a manager or a bit or a repository or whatever it might be that you call it, it's essentially the thing that will get past all those services that can get to them. And then we need to add some tags to our service definitions. So this is just a simple example of an interface that I would create. You can see I've got one method called applies. And the idea with that is that I wanna build in some logic to be able to say, should this service be called or not? I mean, you don't have to do that. For example, if you've got services that every single one of your services, you just wanna be called all the time, then you don't need this. This just gives you a little bit more flexibility. And then just something that I've called do something which is essentially the thing that's actually gonna be called. And then this is our manager class. So this is basically where the instances of those services will get added. So we've got two methods on here. One is add handler. And what this is doing, this is the method that gets called by the container to pass the service in. And all it's doing is collecting them. So every time the symphony container finds something with that tag, it'll call this add handler method and it will add to this list of services. So what you end up with is just that property is just a big long list of all of the things that have had those tags. And then the manager is really where the business logic takes place. So in my example here, all I'm doing is that when I wanted to invoke these services, I looped through each of them. I check if it applies or not. And then if it does, I'll just call it. So this is obviously where you could customize whatever functionality that you want to happen. Be it you could call every single one. You don't need to check if things apply or not. Or you could do things like, if it actually applies, then jump out at that point. Don't call anything further down the list. Really depends on how you actually want to implement it. And so the last thing we need to do is add those tags. So this is again, it's a symphony container concept where essentially we've got two things. First of all, we're tagging our manager class as a service collector. And I think Larry might be able to correct me. This is actually a Drupal concept where essentially we build up some logic to avoid kind of reproducing like the same things that it's just to remove some of the boilerplate. And this here is, we're telling it, this is the tag I want you to look for to collect all of those services. And then down here we've got another example of a service. And it's something that we want to be collected by this manager. So we just have to give it the tag that we've defined up here. And then it will get found by the container and passed in. There's also the other concept of priority which is supported by this service collector, which means it will automatically rank them in order. So if you want something to higher up in the list, when it loops through those things, it will basically respect this priority order. So what are the benefits of tag service as well? We're still defining interfaces. We're using cleared service definitions and we're actually using a lot less boilerplate than plugins. When you don't need configuration for each instance type, this could be a much simpler way, albeit it's much more to do with the container definition. And it provides, I think, a pretty simple way to third parties to extend. So it doesn't have configuration support. It doesn't support the concept of admin forms. And of course we don't have things like derivatives or multi-instance support. So there's quite a few examples of tag services in Drupal Core already. If you're familiar with, did anyone ever struggle in Drupal 7 kind of dealing with breadcrumbs and what order things? Yeah, okay. So this kind of solves that problem. So basically it's got the concept of, you've got a number of different breadcrumb builders. You might have one for taxonomies. You might have one for nodes. And you can actually go and create your own breadcrumb builder to override certain kind of conditions and say, okay, when it's this kind of node or it's this taxonomy term, instead of the default behavior, I actually want to override that and you can specify all the menu links that you want to be in your breadcrumb and it'll get used. There's also things like authentication providers. All of the twig extensions are actually tag services. And then something that kind of came in right at the end before Drupal 8 was released was the idea of placeholder strategies which if you heard Dree's keynote this morning, he was talking about big pipe. Was actually like a few different strategies that could be used. So one of them is big pipe, which is basically using placeholders and then filling in the slow bits later on. But there's also other concepts like edge site includes, which is using a CDN to do that for you. I think there's another JavaScript one as well. So that's all basically tag services as well. So lastly, I want to talk about events and this kind of ties it back into where I started, which is basically hooks. So it's events are essentially the same concept as hooks. What happens is something gets triggered and we want some code to be able to kind of listen in for those events when they get triggered and then do some work. And we don't really know what they are. So we don't know what implementations exist and we don't have a list of them what we're calling. We just want to say, go and fire that event and then whoever's listening can go and do what they want to do. And it's using another symphony to component, which is the event dispatcher component. And it all kind of happens inside the container as well. So we can leverage the container that we've already got in DRIPLE 8 to achieve some of this. And it can be the actual thing that gets fired can be any callable, so PHP callable, so method or whatnot, or even a service method. So they support in DRIPLE 8 call for being able to just say, load this service and call that method on the service. All right, so what do we need in order to be able to set up and use an event? So first thing is an event class. And this is really a simple data object that will get passed around to the events. So the event handlers as they're called. This could be just something for them to read that information out of that event and then do whatever they need to do. Or in the case of alter hooks, modify some of that data and then pass it back to the next one. Of course, we need some business logic. So maybe a manager or something to trigger the event. And then each of the individual events subscribe us to do the work. So it's a very simple example. I've got an event class. I need to extend this event class here. And then I can pass whatever it is I want. So in my example, I've just kind of got this abstract concept of data, but this might be actually something that's actually more meaningful to the events that you're creating. And then something to actually be able to get the data back. This would be an event manager. So this is essentially the thing that notifies the event implementations of something and says, okay, go and do your work. And you can see it. All I need is this, I need the symphony event dispatch object, which I can inject using the container. And then all I need to do is say dispatch. And here I'm basically, I've got a unique name for the event that I'm dispatching. And then I'm passing in the event object with the data that I want to pass into it. Very, very simple to trigger an event with using the event dispatcher. And then in my event subscriber, I need two things. First thing, I need to actually define what events my subscriber is listening to. So up here I've got this, I implement this interface, event subscriber interface. And it has this method on it called get subscribed events. And then essentially it's just returning this array here of, which is basically keyed by the unique event name. So that's on the left hand side. And then on the right hand side, I'm telling it what method to call. And by default, it will call a method with that name on the same class. But if I want to, if I want to call a service from the container, I can actually give it a service definition and it will go and call that service definition as well. And the last thing I need to do is just using the container definition to wire it all together. So, first thing is the event manager, all it needs was to have that event dispatcher service passed into it to be able to call dispatch on. And that is actually something that's already available in Drupal 8 Core. So that's just, you just put that definition and it will get passed in. And then I'm defining my event subscriber. And the only thing you need to know about this is that you just need to pass a tag to tell it that it's an event subscriber. And then the symphony container goes, okay, you're an event subscriber and it will look for that method that says get subscribed events and it will do all the wiring up for you. Right, everyone's still with me. Okay, so when do we want to use events? So you can see it's very similar model to hooks in Drupal 7. It's basically anywhere where Drupal's actually saying module invoke all or whatever it might be. It's just triggering an event and then it's using the mechanism of a function name in order to define how to be discovered and how to be registered to be called when that event happens. You can use events for altering as well like much like Drupal alter does because we're passing that event around. If we wanted to, we could modify the data in that and that's our option to do hook form alters or hook whatever alters that we want to do. And it could be a good replacement for a lot of the Drupal hooks that are there. And I guess one of the main reasons that you'd want to use events is that we get all the benefits of object-oriented PHP code. So we're writing to interfaces, we've got loosely coupled components. It just means that we can write unit tests around our code and have much better, more granular kind of code quality. All right, so summing up, avoid hooks. The procedure, they're hard to test. If you want to create something that is like hooks where you want something to be able to react to code or things that you're doing, then you can use events that will support that. If you need configuration for multiple instances and you need admin forms and you need users to be able to add some settings, then plugins are probably your best option. However, if you don't need that and you want something really simple or simpler with less boilerplate, then you can use tag services. And with that, are there any questions? Events and tag services inside plugins. In my, whatever my plugins are doing, they're like, I could have events and tag services. Yeah, there's nothing stopping you from doing that. Yeah, that would work. Because essentially, your event handlers have access, can have access to the container and they can do whatever they want. So you could probably wire it up in a couple of different ways. Yeah. What is the ideal scenario to use all these things? Is it a good, concrete example of using all these things because it's too confusing? One is a tag service, one is a service. Yeah, so I think concrete examples. So a good example might be for search, for example, where you might have multiple implementations. So search API, right? Search API in 777 is a very popular module. You might have a solar module and you might have an elastic search module. And each of them, they have different configuration. You have different configuration options for each of those. But in terms of like trying to decouple your code, you know, you probably just want to implement a plugin for each of those. I think the core system is actually using plugins, search plugins for that reason because they're different things. They need configuration. An example of using tag services was breadcrumbs, which they don't have any configuration. And all it is really is like a list of different implementations and whoever gets in first, that code gets run. You don't really care about, there's nothing that's user-facing for those people to actually configure. And then I think, lastly, events are the thing, it really is a replacement for hooks. So if you've got a situation where you think, oh, I need to implement a hook, it'd be like, okay, well, maybe an event's a better way of doing that in object-oriented way. So if we implement hooks in bread, we get an error? No, no, hooks are still supported. So you can implement hooks if you like. I would discourage them. I mean, you're gonna have to implement hooks from core modules. So if you want to do a form alter, you still have to do form alter. That's the only way of doing it at the moment. But I'm just talking about if you're building a custom module and you're wanting to extend, allowing other modules to extend your custom module, then you have a choice about how you implement that. Standard, whether it will be like, if you're implementing hooks, it will say that it's recommended to implement plug-in or... Look, I don't, I mean, really it depends on how much community support we get around the idea of using events versus hooks. I mean, it's a very ingrained, and then there's still gallons of hooks in Drupal. So it's just a case of like, okay, this is something that we think is worthwhile doing and then it's doing the work to actually get that implemented. Yep. So with this latest drop-series, we'll be talking about progressive decoupling as such and decoupling the front end and the back end end. There are multiple ways of doing that. You could also create your custom services, your custom events, your custom plug-ins, or custom, your custom management. What do you think is your recommendation if you had to do something like give an evening conference, in which you would let's say handlebar or angular or something else, you know, within the teaming system? Oh, I mean, that's a little bit out of the scope of what I'm talking about today, because that's really a decoupling, not at a PHP code level, it's decoupling at a system level, you know, like this system's talking to that web service and those kinds of things, so, yeah, that's a, that's a difficult... At the teaming layer, I guess what are the hooks or events or, you know, what should we use if we have to customize the teaming layer as such? So in terms of customizing the team layer, there's still a lot of hooks in there for, you know, hook pre-process, that's all, that hasn't changed, so I don't think you can actually use events in the teaming layer if you want to do things like modify variables before they get passed to tweak templates, you still have to use the hooks. Sure, and plug-ins obviously with blocks and things like that. Yeah, you have to use, if you want to write a block, you have to write a plug-in implementation. Thank you. Tell me about the handling of the breadcrumbs. Handling the, sorry? Breadcrumbs. Breadcrumbs, yeah? So, I can use it as a multiple package. Suppose like, I created that as a block, the breadcrumbs. It's changing, it's tight, so... There's a couple of different concepts there, so, there's, so the breadcrumbs, how to work out, work out what the links are going to be in the breadcrumbs, that's a tag service. The block that gets placed on the breadcrumbs, that's a block, which is a plug-in. Yeah, yeah, so I want to add it just in the plug-in, in a block, separate, separate, so we can add it. You do it as a block plug-in. Yeah, so we can add it and keep it in the separate candidates. You should automatically click out. Yeah. It works? Yeah, like you want to basically write your own... Yeah, I have like two, three candidates. So it has to become like this. So I define that as a service. Like this URL has to be, this breadcrumbs has to become like this. That's a service that comes in a block. That's what the breadcrumbs... Yeah, that's right. The plug-in? That would just come in the normal breadcrumbs block. So, yeah, I can add the plug-ins anywhere, multiple times, right? Yeah, you can. Okay, thanks. You can have multiple instances of that. Yeah. Any other questions? Yeah? Do you have a microphone? Sorry, I can't hear. How to do a core kind of altering with events, like farm alter, those kinds of art? Well, I mean, that's not supported. So changing, like, hook form, alter is not something that would need to be supported in Drip or Core. What I'm referring to is if you write your own custom module and you're not just implementing a core hook, you want to basically use the concept of hooks in your module for other modules to extend your module, then you would use events, rather than hooks. You still need to implement some of the hooks that are in Drip or Core. Thanks. I think we're probably out of time. Yeah, one more, yep. What is the role of the annotation class? So the annotation class, essentially, the annotation class is the metadata for your plug-in. So it allows each plug-in type can define the kinds of things that you can set. In the case of blocks, it's really just a unique block ID and the label that appears in the admin screen. But there's much bigger examples like the entities system. It defines all the controllers and all of those kinds of things as a big, long list of those. And then what happens is the plug-in manager, essentially, when it discovers the plug-ins, reads those annotations, then it stores that metadata with each of the plug-in implementations so that you can do things like query that and work out what to do. OK, thank you. And what is the use of build method in block-based class, actually, build method? What is the build method for? Yes, block-based. So suppose we are creating a custom block. So in plug-in folder, there is a block folder. And there is a module named block.php file. So if we are going to create our own block, then we have to create a class and we have to extend the block-based class into our own class. So there is a method build and access block. So what is the role of build and access block method? The build is essentially the equivalent of hook block view in Drupal 7. So it just returns a render array. And it's exactly what you had in Drupal 7. It's just that now it's on an interface instead of just a method with a magical name. And the same with our access. So that's just this equivalent to the Drupal 7 version. Can we use services in our custom form? Yes. And how to create our own event in custom form? Well, I'll share the slides. It's got some examples later on. Thank you, sir. All right. Thanks, everyone. Yeah, if you want to rate the session, that's the link. Thank you. You can say if you're wrong. I think it's fine.