 Yeah, yeah, yeah, I did that already. I saw the last guy came up here, tried to use the Wi-Fi, so I was like, oh, I will preload every page. I'm already there. Alright, so it is officially 215. Hi everybody, I'm Adam Englender, and I'm here to talk to you, believe it or not, about the infinite wonder of the Symphony Event Dispatcher. And it may sound like a flowery title, but if you're a Drupal or getting used to the Symphony stuff, I got used to the Symphony 2 stuff when it first came out, and it was really hard and really difficult, but once I got it, the potential was endless on what you could do with it. So the first thing I want to try and figure out from everybody is why you're here. So how many are Drupal developers trying to learn about the Symphony nonsense? Alright, Symphony developer trying to learn about Drupal? Okay, okay. PHP developer trying to learn about Drupal, okay, and you just thought it was a cool presentation title. Alright, alright, alright, okay. Anybody here for none of the above? Alright, alright, honest man, I appreciate that. So this should be interesting for you, .NET. C sharp? Okay, so it's not so terrible. So how do we get here? So how I got here is that I started PHP with PHP 3, didn't do a whole lot in it because you couldn't do a whole lot in it, but then found Drupal. I've been building web pages and websites for myself, for people, and I'm a terrible designer, and I was terrible at HTML, and I got sick and tired of constantly changing content for people, and I found someone hooked me up with Drupal. I was like, this is amazing, this is the most amazing thing I've ever seen. I can stop doing content for these idiots who change it every 10 minutes. I can put in a database, put in the website, not have to write a whole lot of code and customize it a little bit. So the way that you would customize Drupal in the long, long ago is you would copy core or template code to your site code, hack around it for what you needed, beam with the pleasure of customizing Drupal, break things unknowingly, and only patch them required because you changed core code. This is the before time. How many people remember those times? Quite a few of you. Then came Drupal 5 through 7, right? And you still kind of copy core to customize true core functionality, but then hooks came about, right? And hooks are kind of cool so you can do things without having to go modify core code and you can make modules and all this kind of fun stuff. Use global functions to access everything. And upgrade was fairly simple as long as the hooks or global functions didn't really change. So if they didn't change how a hook worked, you were still cool, but if they did, then you had problems, right? How many people are in this boat? Probably most of you, right? Drupal 7? Yeah, most of you. And unit tests? You can kind of do it. Not too many boos, but I actually also write WordPress plugins, because I have to. And it's all the same thing, it's global functions and you have to write, there's a way you can write unit tests and it's a terrible way to go about it, but I did it, I'm not proud of it, but it works. So Drupal 8 was symphony. How many people have used Drupal 8 in an actual project? Okay, okay, that's not bad. How many people would love to, but it's too hard to figure out at this point? So it's not a whole lot different, but it uses event subscribers for hooks, which is what this whole talk is about, right? It uses dependency injection for core services, so you're not using those global functions anymore. It uses portable code in an open ecosystem, right? It allows you through all the composer stuff, the dependency injection talk from the last guy, Ashwini, is that you can use code from somewhere else. You don't have to write everything yourself. One of the hardest problems that I had with PHP before the revolution started with composer is that you had to write everything yourself because people were not writing good portable code, because they didn't need to, because nobody else used it, right? You would use pair and it was terrible and it was horrible. But that's changed, right? And Drupal has changed for it, and what you're going to be able to do is you're going to be able to, oh, I don't have to go write a mail module, use somebody's terrible mail module, I can just go use somebody else's stuff, stick it in there with a dependency injection container and get it running, which is awesome. And the other big thing is that it is fully unit testable, fully unit testable, right? If you use the dependency injection stuff from the last talk, you'll be able to understand how easy it is to test. How many people write unit tests? All right, all right, all right. And those of you who don't is probably because it's hard and doesn't make a whole lot of sense, because it's really hard if you're module developers, any module developers? Okay. So in writing your modules, right, it's super hard to find out when stuff breaks, because everything is a global function, and how do you mock a global function? Tell it it's a bad person, but that doesn't help. So when you're actually using dependency injection, and you're using all this stuff, it allows for full unit testable. And one of the nice things about this as you can also upgrade it will, because you know things aren't going to break, right? When you're hooking into with the dependency injection container, you're just kind of grabbing stuff that's in there and using it. And since people is using interfaces now, they can't really change that. They can't change how that works just kind of willy nilly, because it's a function that can do whatever they want. Right now, it's an interface, and there's a contract there that says this is what it is, and this is what it does. And this is how you call it. So you'll know very quickly when stuff doesn't work, because you'll try to access a function that doesn't exist, not why isn't it calling my callback? Why is my hook not running? Why is my hook broken? That's a big difference. So why do you want to use an event dispatcher? Is anyone here familiar with the concept of a design pattern called PubSub? Okay. So when you want to use an event subscriber, you want to use it because it creates highly modular code. Build you modules. Build modules and templates like building blocks. Once again, reusable code and open ecosystem and proven libraries inside the Drupal ecosystem. And so what you're doing here is you're actually listening for events. So the old world was a hook, right? You get a hook, it does something, you do a couple things and it goes out. The one thing that you really didn't do, and I mean, I haven't seen a whole lot of it, is nobody really hooks into the hook system, right? From your own module to call your own hook. How does someone knows they can do that, right? How does someone know where to do that to hook into your stuff? And modular code creates highly testable code at the unit level, right? I think that's kind of just to repeat what we talked about. It's going to allow you to do decoupled code and highly decoupled code is part of an event manager, right? In the Drupal stuff, you're injecting services in the connection container and it doesn't require you to know knowledge of the core systems. You don't have to instantiate an object, right? You don't have to use the new keyword, right? To build something and know how to build it. You don't have to. You just have to know, oh, it's got this function I need. So I need to call it. And it allows for a mix and match of components providing services based on events. And that's the big thing of events. So if there's something that you wanted to jam into Drupal core, how would you know where to do it? The example that I'm going to show you in a bit actually stops it before it processes anything. And I don't have to know where that's going on in Drupal core. I don't have to know what piece I have to copy out and change and replace inside of Drupal core to do this. What I can do is I can listen for an event. All I need to know is that event and what I can do with the structure of that event. And so that's a huge power there in that I can register an event. I'm going to get an object back similar to a hook. But the difference when the hook is, is that I'm going to actually get an object that I can deal with that's very, very specific about what it can do. I'm going to be able to make changes or pull data out. So one of the big things is a lot of the events in there, the same thing with the hooks with the note events and things like that. You're going to be able to modify a note as it comes through. That's a little powerful. But the other thing that you can do that I do inside of my modules is that you can now trigger events. So I can put that event handler inside of my module and I can trigger an event that I did something. And so if you care about it, you can do something about that too. So it allows you to have all these different modules that can talk to each other through kind of a single standard interface without having to know anything about each other or whether they're installed or not, is you're basically just saying, hey, I'm module A. I did this. You might care. You might not. But I'm going to tell the world that I did it so they can do something about it if they want to. Which is allowing you to act like Drupal core, right? You can go and just make your things extensible. So if you have a very popular module, people don't have to contribute all of your module to add functionality. They can just make a module that uses your module and says, oh, I'm going to listen to your module's event and I'm going to do this other super special thing that, you know, one-tenth of the population cares about instead of having to slam it all into one giant monolithic module. It allows you to build modules like building blocks. So you can say, I don't care about that functionality. I don't want all that extra junk. I don't want the database hits. I don't want the external calls. All I really want is the core piece. But I might want this other thing. So you can install one module and install a module based on that module that's going to listen for events. And basically, you're creating your own hook system, but you're using the embedded internal system to do that, which is pretty sweet. And that's how you do, like, the mixing and matching of components. And it allows for highly extensible code. So, like I was just talking about, you can take something very core, a very simple module that is listening to very specific events and doing something and saying, hey, I've done this. Do you care if you do do something about it? And so you can just build on top of each other without having to basically extend somebody else's module. Because the way you do it now is you kind of extend their module or just copy their stuff into your stuff or do whatever you do to add somebody's functionality to your code. And with the way that you do it with events and event-driven development is you don't have to do that. If someone writes their module well, they can just trigger an event. And hopefully, you're always triggering events. The two things that you can do super easy doesn't cost you anything, but gives you a lot is to log everything and trigger an event for everything. One of the things I do constantly is I'm doing, I have debug logs, right? You can inject the logger super easy and just debug log debug log debug log debug log. So I don't have to write print statements when something's going wrong. I can go look at the Drupal logs and say, hey, what happened? Which I actually had to do for my test thing because I couldn't figure out what's wrong because I had a bug in my code that I missed in the tests. Logic can be extracted to services. So in a hook, everything exists in that hook. And it's a function and it has access to what it has in the function, right? So it's this big kind of junk chunk that has to do everything by itself. When you're using the event manager, you're getting an event that's being called and it's calling a service that's registered inside the injection container. So I've got all the things that I need that are inside of there and I've got it already pre-built and it's pre-cached and it's super fast and I can do whatever I need to do as well as using things that other people wrote, right? I can inject the logger. I didn't have to write a logger. I don't have to know if it's going to work if I do error log or if I do a print statement what's going to happen. I don't have to figure that stuff out. I can inject all that stuff in. I know it works and I can test I'm actually doing the logging that I should be doing. And your logic can be extracted outside the Drupal environment. If you write something super cool for Drupal, nobody else can use it, right? Because it kind of works inside of Drupal. That's really all that it does. What you can do now is you can go, oh, people really like this functionality. The Drupal world really loves it and I'm making some money off of this or some notoriety. Why don't I take it and I port it to WordPress or I port it to Symphony or I port it to Laravel or cake or whatever you might want to do some other framework that might use it. Magento, right? Anything that's using the Symphony Core, you can throw cake out because it doesn't do that. But you can use that same event model or you can package up your code and split it out so that you're using it inside of your things that are doing the hooks, right? Always have to check time. Services can register and trigger their own investor extensibility, right? That's what we're talking about. You've got this service, it's listening to hooks, it's doing things, it's got these events, it's interacting, it's doing whatever it does, interacting with the core, but it's also allowing other modules to interact with it or other custom code to interact with it so that you might want to send an email every time this thing happens or pop up something on an admin or stick it in a log or do whatever you feel like, create a custom node or do something crazy. So up to this point, are there any questions before we get into the crazy stuff? Yeah. Yeah, so you can create, so the question is, can you create custom events, can you trigger your own events? Absolutely. So in the event dispatcher, all you do is you give it an event name, you say trigger event, and you give it a name, and that needs to be unique, otherwise people are listening to the wrong stuff, but usually you prepend it with your, your module name, dot, something, so you know what type of event it is. A lot of times you'll see using class constants for that, so that other people can know what it is without having to look at your docs. And then you just pass something that implements the event. So if you need to pass along another object, you extend event with another object, and it has accessors for these other pieces. And I have a, there's a demonstration that'll show you how you do that to some extent, at least to access the other pieces. That's your question? Yeah, so, and the whole thing is that you can do whatever you want, right? All you have to do is call the event dispatcher with a name that's unique, and an object that extends event. That's it. Any other questions? Yeah. Yes, it's nearly identical. Yeah, it's PubSub. It's standard PubSub. What you'll find if you're a Java developer, you'll find that symphony is a lot like Java. So the symphony dependency injection container is very similar to spring, spring dependency injection. And so, like, I was a Java developer for a while before I came into symphony, and I was, it made, I was like, oh, this makes so much sense. I totally get this. PHP developers were like, what? It is very different. It is very different, right? It's using some of the, one of the things I really like about symphony is that they took a lot of things from a lot of languages that aren't PHP and said, this is really popular. Let's port it to PHP, right? And the dependency injection container was probably the first one I'd ever seen in PHP. Before that, everything was using static methods, right? Zend used their static methods for their repository pattern and all this kind of crazy stuff. This is literally kind of building it all, and it even does a compiler pass where it actually takes all of these things, which is, by the way, when you do this development, always remember to run update.php or whatever you're using to basically reload your whole system because it compiles it all down to one giant file. Your dependency injection container becomes one giant file that has all of your classes in it and all that stuff, so it just loads one page, it gets cached one time, so that's what makes it super fast, but it also means that you have to reload it when you make changes. I discovered that when I was developing. I know how to do it in symphony, I didn't know how to do it inside of Drupal, and update PHP does that. It also does it whenever you install a module, it reloads all that, which kind of makes sense, because your modules are using the container and it's got to rebuild everything. So how to use the event dispatcher? So here's an oversimplified overview on how to use the event dispatcher. You create a service in your module that implements the event subscriber interface. All the Drupal docs have this, it's nothing super surprising, but the event subscriber interface basically is just one method that gets subscribed events, and you return an array. You write handlers for those events in your service, so the way that event subscribers work is that it's going to be the object that you're going to use needs to have the methods, and you just tell it what method it is. And then to get subscribed events method, you return a list of handled events. So it's an array, key value, the value can just be a string, or the value can be an array if you want to basically tell it what order you want it to be in, because you can specify priority for events that, oh, I need to fire before this other thing, so give me a higher priority. And then register the service with a tag event subscriber in your services YAML for your module. That's it, that's all it takes. And you are listening to events that you've registered for and it's going to call a function, just like registering for the hooks, right? Same process, although it's not in code, right? Some of it's in code, but it's not just I'm going to, on the load, you know, when I'm bootstrapping my module, I'm telling it, here's the events I care about, call these functions for these hooks, right? It's very similar, but it's a, it's a little cleaner and it's a lot easier to test. So in my opinion an example is worth a thousand slides. There's an example that I have up on GitHub, which I have here. So I created a Drupal module that basically what it does is it goes and gets an event. It registers for the getResponse event on the kernel. And if you don't know what the kernel is, that is the very core of symphony that says, oh, I got an HTTP request. I'm going to turn it into an object and then I'm going to call an event that says, get me a response to this request. And that's how all of symphony is event-based, right? Every piece of it is event-based from the kernel down. I can't say every piece of symphony because symphony is bigger than just the kernel. But inside of Drupal it's going to basically say you have the kernel that's going to say, hey, I need a response to this request. Get me a response, here's the request and it goes on. And it's basically a blacklist, right? So it says, is the IP in the white list? No? Tell them they can't, they're unauthorized. Right? I have no idea how you would do that in Drupal Core. I figured out how to do it using the event manager in like 10 minutes. And I know that there are a lot of security plugins, right? So you can jack right at everything and be fairly safe that you're not rewriting a bunch of core to write a security plugin. You can actually just get the request before everything else and do what you want to do with it. And there's basically four files. Can everybody read that by the way? Yeah, yeah. Okay. And there's four files. So I have a blacklist service and this is my separate service that performs all of the functionality. I have an event subscriber which is the piece that is going to tell Drupal slash Symphony, I want to read this event. It's going to get the request and then it's going to call the service and see if it's one of the pieces that are there. And it's separating the functionality in that the event subscriber is handling all the Drupal type stuff, like get me the Drupal or Symphony type stuff, get me the request, get me the IP address and then it calls a service and says hey, is this IP address blocked? Right? So it's subtracting all that functionality that's not specific to deterring what the blacklist is to another service. Instead of having to do that all in one giant function or other global functions inside of a hook. And so it also has the services YAML file, which if you're doing Drupal 8, you'll module building, you'll get very familiar with it. It's a little overwhelming at first having to write all this nonsense. But once you understand it, it's a little easier and if you use the Symphony documentation, it's there's a lot of documentation, right? Ryan, who may or may not be here but he's speaking next, he wrote most of the documentation for Symphony and it's fantastic. There's a lot of documentation for Symphony and it's really good. Examples on how to do this, examples on how to do that, it makes a lot of sense. And then there's the ever-popular info.yaml for the file, right? So we all know the info.yaml has basically nothing in it. It just says hi, this is my module. It's a custom package and it needs, you know, core 8 or better. And what are my configuration settings? This is the services file. This can be confusing. Can everybody see that? No? Figure? Better? Okay. Yeah, so basically for this talk I couldn't figure out how to get the configuration stuff to work inside the container. So I'm setting a parameter which is hard coding the addresses that are whitelisted. And then I'm setting up my services. So I have a blacklist service that is the thing that's determining if you're blacklisted and it gets the whitelist, right? So it's just saying, hey, build this, build this service. Here's the pieces that it needs which is the number of the IPs that are whitelisted. And then we have, I wanted to, like I said, I log everything so I can figure out what's going on instead of having to like inject print statements and code and nonsense like that. So I created a logger channel for the Drupal event dispatch, for example. And then I injected that logger channel into my event subscriber. So I've got the subscriber, I've got the service. The really super important part here is that. That is what tells the container this thing wants to subscribe to events. It's tags. And tags are just a way for you to find things that you care about that are identifying themselves to you for another service in the container. Basically it's what's called a compiler pass. And it goes through and it says, oh, I want to add a compiler pass because I care about tags like this and I want to do something special for them because we're awesome. And so that's really what's kind of happening there. Is it's got a tag looking for event dispatcher and says, oh great, I need to know what these service names are and I need to know what the functions are. I'm going to call this thing and figure out what events that I have to trigger. Any questions about that? No? Are we too confused yet? Yeah. So event subscriber, again, this right here, my object has to implement the event subscriber interface which has a function called get subscribed events. So it's going to go, oh, and it's a it's also it's a static class. It's a static method on the class. So actually let me just, is this it? Yes. So, can we see that? Make it a little bit better. Okay. So get subscribed events, right? This is the actual thing that I have to implement in order to implement the interface event subscriber. And so I'm returning kernel event request, right? So static class attributes are awesome when you're using event names because I don't have to remember what your event name is. I just know that I'm looking for something on kernel events and looking for the request. And if you change that, my code doesn't break, right? Because my code is still using whatever you're calling it behind that that static thing. And then so I just have a super awesome named on kernel quest event, right? And so on kernel quest event, one thing that you have to know is that you're going to whatever objects or other method that you register, it's going to get an event. It's guaranteed to get something that implements the event interface. Beyond that is dependent on the particular event that you're listening for. And if you're listening to multiple events, the same function, you have to, you can kind of figure it out once you get it. But I happen to know because I looked at the documentation that on kernel quest returns a getResponse event, right? And so I'm doing some logic here that I know about because I'm a symphony guy and you might not know about because you're not symphony people. Is that there's two types of requests. There are master requests and there are sub requests, right? Which means and you're both good, both can get the same data but all I really care about is the master request, which is the incoming request and going out. You can do sub requests as it does sub routes and all this kind of nonsense in your routing scheme and all that kind of junk that I don't care about, right? All I care about is I want the master request. So basically it checks to see if it's a master request, logs that it's checking that or which it is that it's not master not processing, right? So if I'm not a master, just log it. The other thing I want to do that you probably would do the opposite most times with a security plugin, I'm checking to make sure it's not admin so that it works out really well for my demo. Because when you get an unauthorized you have to actually uninstall it manually and reload, upload to get it to be able to uninstall it and turn it off. So in this one it basically says, hey, the event, the get requests or getResponse event has a method only called getRequest which is the incoming request and getPathInfo tells me what the path is. And so if it's admin I'm not going to process it because the path is admin so I'm not going to process for the blacklist because it doesn't work well for my demo. Otherwise it's not an admin and it's the master request so I actually want to see if this is supposed to be blacklisted. So I log that that's what I'm doing. I get the client IP from the request. There's one of the things that is super awesome for old school object oriented programmers like myself. In Drupal 8 is that everything is objects. Drupal 7 and almost every PHP based content management system out there nowadays you're using either standard class for the most part or using some sort of multi dimensional array to get all of your data and you've always got to check to make sure stuff is there. So if you're not flipping off warnings everywhere that to me is just a little annoying because they also change what is up in that object from time to time. There's no way to know what's going on. In the Drupal 8 world as far as I've seen so far everything's an object and it's a defined object and it's going to have a defined interface. They may add stuff later but the stuff that you was supposed to be there is always there and even on the symphony side they have probably the best migration thing I've ever seen. I've actually, the company I work at we're actually implementing that as well is that you deprecate it and then up to the next major release you put in deprecation notices and once you fix the deprecation notices you can move to the next major release with no problems. So the symphony stuff is going to be the least of your problems with Drupal upgrades I promise you. It is super, super, super stable. So basically I get the client IP from the request, I call my blacklist service and I ask is this IP blacklisted? If it is then I log a notice not a debug because sometimes people want to know why can't I access your system and if you're not looking at, if you're looking if you're not reporting debug logs you don't know. And then I throw an access denied HTTP exception. Now the one thing that I'm not doing here which I should be doing here is I should have been triggering another event to make this extensible. Because I could have said that oh IP blacklisted event. And you could do something about that if you really cared too. But I did not have time to do that for this particular piece here. And then more debug logging. So in honesty besides all the debug logging and all this kind of nonsense I have one function with one line. In the beginning this was all like three lines of code to say if it's the master request and it's not the admin path and it's blacklisted return denied. It's not the income request. There's a bunch of other stuff in there. And then the last piece is the actual blacklist service which basically gets an array of whitelisted and just returns if it's in the whitelisted array. There's no functionality really in there either. So but the thing that this actually does do is it shows some really core concepts specific to symphony which is dependency injection. Right. Building a modular module. Right. You're not just building a modular Drupal you're building a modular module that you're going to in theory if you wanted to find some other really cool library out there that did blacklisting way more sophisticated than I have you could just pull that library in and you could use that in your module and you could inject it into your event subscriber and you could just use that. Right. Instead of having to write everything. Right. I worked at a company for six years writing big PHP apps and we wrote everything and it was tiring and exhausting to have to be amazing at everything. Right. I have to write a really good logger otherwise my logs get filled up with crap I don't care about and I've got to write a request processor and a response cacher and a database accessor because the ones that are out there aren't so great and they don't do what I need them to do. And you wrote everything. Right. And there are there are Drupal modules out there that do a lot of very cool things but they're missing one piece here or one piece there because they're trying to be everything and what's happened a lot in the general PHP community. How many people here are familiar with packages. OK. Before pack how many people were here before packages. OK. Before packages life. So. It's. If you wanted to get your code if you had a really cool library. The only way that I could use your library is I would have to go know who you were. I'd have to go find where you put your code download a zip file or a tar ball and stick it inside my code. Now if you made any fixes to that I would have to somehow magically know that and update the code in my code because you made a change in yours or you could use pair. And pair. I understand why they did it but basically you would submit your code to pair they would decide if it was good enough to be put in there. And most stuff wasn't. And then. I don't know which came first. I've never asked Jordy or Fabian which came first symphony or composer. But when symphony came out there's so many modules that it used. You needed something to install all that stuff. And they had their own crazy little module builder thing. And all of a sudden this thing called composer showed up and it was the most amazing thing ever because packages didn't exist yet but you could basically say oh this git repository I want this tagged version. It was amazing. It changed my life forever. And then packages came out and now I can publish my library there and you can use it and know what it requires. And it will resolve all that stuff magically for you so that you can start including libraries. And what ended up happening is now there are tens of thousands of good libraries out there to do stuff that I don't want to write. I work for a security company. We write security software. We don't write logs. We don't write HTTP parsers. We write super secure with a lot of encryption. SDKs to access our security API. I don't want to have to write the rest. And I don't have to. Because I use a ton of libraries. I use PHP seclib even though I know a lot about crypto. I'm not an expert at crypto but there are people that are mathematicians that write PHP seclibs that I don't have to. And there are people that write monologue so I don't have to. And there are people that write the symphony event dispatcher so I don't have to. And that's my soapbox. Sorry. But I think that one thing to take away about and I know that it's actually going to be talked about a lot by Ryan in the next talk is that Drupal 8 opens up the world for Drupal developers. You can include anything from anywhere of the tens, not even up to hundreds of thousands of packages, on packages. Into your code. It's a little kind of weird how you have to do it but you can still do it in your module. So you can build these super awesome modules that do this super cool stuff that is super secure and super safe and you didn't have to write it. You just had to put the pieces together so it could be done. And then you can make it extensible because you can use the event manager so that people can build on top of yours without having to commit to your project. Right? Because there's some stuff where someone says they have this bizarre thing and they're like, oh, I want to add this to your module and you're like, no. That's not really what my module's for. And no, that's not cool. But what they can do now, if you trigger events, is that they can build their own module that listens to the events from your module and does the crazy whack-out stuff you don't want in your core stuff. Makes it super awesome. Any questions about the example? Yeah. So in my example, is there a way for me to set priority for the event? And no. It's not doing that right now. So where you would do that is right here. This would just be an array and it would have two attributes or two items in the array and it would be the name and you would give it the priority. It's integer. Yeah. Can you see how it's doing that? Yeah. And offhand, I don't remember if higher or lower is better because there's so many of these things that some of them higher is better, some of them lower is better. But the documentation is in the symphony event dispatcher and how to do all that crazy stuff. And there's a few other things that you can do. Like you can actually tell it to call multiple functions and you can give an array of an array of... Yeah. So it allows you to do some fairly complex stuff but that's basically what it does. And you had a question? Yeah, I did. So what you would do is you would inside of whatever service you wanted, you would inject the event dispatcher. All right. It's another service that's in the container and I believe it's actually event underscore dispatcher. And so you would go into your services YAML file and you would inject it there. And then in here, when you got done, you would just say... You would trigger you would event dispatcher, trigger event, give it a name, give it an event object. That's it. That's all there is to it. Because that's all that the core is doing underneath, right? That's all that the symphony kernel is doing. It's going, oh, I got a request in. I've parsed the request and turned into this request object. I'm going to tell the world I need a response. Because what I'm doing here is I could actually set a response, but it actually works a whole lot better. If I set the response, it actually just returns a blank page that just has a 400, 401 response. If I do the access denied exception, it actually does a nice Drupal page. And what that actually looks like in an example, make sure it's still working. So I have this nice little Drupal page, Drupal site, running a little docker on my box. And the instructions are actually on the thing on how to do this that basically you just go into Extends. Sorry for the tapping noises. Drupal event dispatcher example, install. It's going to rebuild the container. It's all done. And so now, if I go to the site, I've got access tonight, right? I've completely circumvented everything except for the template layer. And I'm just saying, you cannot access this site. Because I'm actually, and you're saying, but wait a minute, you're on localhost. Why can't you access it? And the actual reason for that is, is because I'm not on localhost. My address is 172.1701. So if you use this locally, you'll probably find and try to extra for somewhere else to be there. But because I'm in, I'm using docker. Thank you. Because I'm using docker, it picks its own IP addresses and everything's all happy. And here's all the logs, right? So I'm a real big believer in logging for people that aren't you, that don't know how your code works, to find out what's going on and why things are terrible. Because sometimes stuff just doesn't work. There's the things you don't think of, the things you don't expect. When you build a module and it's used out there by a million people that speak 12 different languages, sometimes you didn't think of everything. So logging is always really good. And so any more questions about the example? And I'll have a thing at the end if you want to take a look at it. And so in the last little bit of the talk, I want to talk about how this is only the beginning, right? Drupal 8 is the beginning, right? I promise you, it's just the beginning. It is such a change from Drupal 7, right? I mean, if you're an old Drupal developer, you're like, whoa, this is blowing my mind. I don't understand it. I don't want to figure it out. I just want to make money using Drupal. And I totally get it. But if you're a module developer, it's going to make your life a lot easier. You're going to write better modules. You're going to write them faster. You're going to be able to test them. You're going to be able to put them under continuous integration to make sure that if somebody else commits to your module, that they don't break your stuff because you can just write tests around it. And that was the other thing that I didn't show is that I actually have unit tests around every one of those things. Because I can, it's just an object, right? It's not some global method calling another global method using a static method on a global object. That is really hard to test. And if you love unit tests, like I love unit tests, you'd be excited. But like I said, it's going to help you build a better model, module, right? You're going to have modular modules. I know that does make a lot of sense, but it allows you to just build on top of what someone else has done, right? Instead of worrying about, you know, oh, can I get this accepted by this thing or do I have to fork it and write it myself and make all the changes, right? Because that's old school dribble. Just take what they wrote, steal it, copy it, change a couple of things. And you've got your own module. But you don't get their bug fixes, right? When you do it that way, when they find something broken and they fix it, you don't get it because you copy their stuff. Loosely coupled, right? So you can build modules that aren't dependent, that can work with other modules. But all they know about is that you, there's an event dispatcher and an event. They have no idea how your module works and they don't need to, right? You don't have to know how anything else works to build on top of it. And that's an amazing bit of power, right? I don't have to, I didn't have to know anything about symphony or Drupal to intercept the request and give an unauthorized response. I just had to know that the first thing it does is it fires off a getResponse event and that event has a request and I can throw an exception and it's done, right? I didn't have to learn anything about Drupal for that. I didn't have to learn anything about symphony for that. I just had to know about the events, right? That's really powerful. Highly extensible because it's loosely coupled. Highly configurable as you're building things for the events. You can configure it based on events. You can trigger it. You can basically have things, oh, I've got this event, this event, this event. So now I know as I'm trying to process my piece, I know the state that's going on from the other events. Now I can react in a way that I care about. And you can make it bulletproof, right? When you can test everything. When you can have reliable tests using mocked objects inside of your modules, you can make them bulletproof, right? You can find all the bugs. You can find all the edge cases, right? You can write really good code that people will look at and go, wow, that's pretty cool. I like what you did there. That's rare in a CMS, right? That someone's going to look at your code from something you built for a CMS and went, that's a really good instance of object-oriented code. That's pretty cool stuff. You can do that now, right? Drupal 8 allows that. And external libraries, right? Not having to write everything lets you concentrate on what you're doing, right? And you can build a better Drupal. So my hope is that there are a limited number of events that are out there, right? There's stuff from the symphony world that's already been sent and there's a few things, but for a security company, I'm trying to write a Drupal module. I can't, there's no event that says someone has submitted a login request, right? I have to go write my own login form and process that and replace the existing login form, right? So I still have to go do the stuff that I've always done in Drupal, which is copy it from core, change the piece I need, register it for my module and replace the existing one that's used by Drupal. But not too many boos, but on WordPress, it's actually triggers, right? I get a callback, which is a hook that says someone's trying to log in. If you return me a user object, then I'll assume they're logged in. Hopefully Drupal gets there, right? To get away from the copy, core and modify and be able to utilize more non-Drupal stuff, right? Inside of Drupal. There's probably a lot more code in there that is doing your own thing, which you're not, you know, depending on how important that is to that specific, that specific maintainer, you may get new stuff, you may not. And accelerate platform growth. When you don't have to write everything and you don't have to have intimate knowledge of the system to extend it, you can build things very quickly. And when they're under test, you can have a lot of people working on it and know it's not going to break. So this is my contact information. If you have any further questions, I think we actually have three minutes for questions or 13 minutes, okay. Just want to put that up there. Twitter, email, please rate my talk. There'll be another one up here. And then the example is already up there. The slides are at the speaker rate address. So if you want to get it there, which is there. I really, really appreciate any input people give me on these talks. I think I'm halfway decent at them. Some people say I suck, some people say I'm great. I would like to know what you think and what you'd like to see different. This is my first talk to Drupal folks. So, I'd like to know how you guys feel about it. Any questions? Question? Anyway, so you were talking about, okay, like if you want to have a login event, right? That's an event that's handled by core out of the box. What is your philosophy about, okay, well, if I wanted to do that the right way, maybe I'll do a form alter, right? I can hook in using the existing hooks, right? And create a place for me to shove in an event listener, right, I can fire off an event and then do it that way. What's your philosophy on sort of creating those event listeners for core? Right, so the event listeners are there for form actions, right? But I don't have a form action. What I want to do is I want to hook in to the login system, right? I want to hook into the off system, not the form. I don't want to change your form. I just want to add my service as a secondary factor to login to protect Drupal sites from hackers with multi-factor authentication, right? So what I have to do is I have to actually replace that form handler entirely so that I can do the login. So basically it's like I have to replace the form because that's what generates the form and listens to the form so that I can call the existing functionality and then do that. What I would prefer to have is you have prioritized events that is pre-off, post-off. Like in the best world, you have a pre and post of everything, right? So that I can pre this if I want to change the data that you're working with, I will affect it on a pre event. And if I want to know what you did, I can deal with that on a post event. But being able to just kind of slide yourself in there on a chain is a whole lot simpler than having to inject yourself in the middle because what happens when somebody else wants to do something with the form as well, right? So now they're replacing, so I've got to get in there first or last depending on how it works because if they replace the form, then my stuff is gone, right? So there's no way, you can't have like two people interacting with an override on the same form because you have to replace the form in the form handler. So are you aware of an initiative to get rid of hooks and replace all of them for Drupal 9 with event, is that where this is going then? Well, Drupal 8, I don't know if the hooks are there, I know that all the hooks are available as events. I don't know if the hooks are actually there, are they? Some are still there? Right, right, right. Right, and I think a lot of it is because you take a look at how many Drupal modules are we gonna destroy, right? That people use at every single Drupal site. Like this was a massive change, but I can imagine that there is a lot of, how do we not just piss everybody off, right? Well, I know, but you guys are still here, right? They didn't piss everybody off. Like if you took a look at the difference between Symphony 1 and Symphony 2, they are not even similar, right? I'm grateful, right? Because I never used Symphony 1, but I gladly used Symphony 2. So sometimes you need this massive change, but I imagine some of the stuff just still needed to be there because there's just too much code to change, like I said, I don't know if there's a movement or not, like I'm not super into the Drupal community, that's just my hope, right? Is that you start exposing more of this so that you can extend the platform more, you can extend it quicker, you've got a better opportunity to do so. So what you do is you extend the event object or you implement the event interface with another object and you put in centers or getters for that data. You inject it in the constructor, then you have getters to go get the things that you need, and it's passed with that event. So in the actual, in here, see I take the event, I'm getting the request type, right? So the event itself has whether or not this is a, it's very specific data to that event, right? All the event actually has, the only methods that it implements is propagation stopped and stop propagation, right? There's some other methods that are deprecated, but that's the only thing left in event, right? That's the only thing that's part of the actual event itself. Everything else has been added on afterwards. And that's how you put it in there, is you extend it with your own object that allows you to get the data out. Correct, you're gonna pass an event object, when it gets triggered, you're gonna trigger it and pass your event object that's gonna implement the event interface and then give those people who are listening to that event access to the data they need to react appropriately. Usually it's done with getters, not so much properties, like global or public properties. Yeah, it depends. So when you trigger your event, you may have pass it an object that you already have or reference to that it's gonna change. So like I could set the response to that event and then it would actually use that response that I gave it in the event handler. So it's gonna trigger the event and then get the data back from the event and it uses that response. Actually that's not correct. It's gonna be the, I'm trying to remember how the kernel request works. There's one at the very bottom that gets the response out and if it doesn't have anything, it builds its own unhandled response, right? Because nothing took care of this so I'm just gonna tell you nothing took care of it. So there's an event at the very bottom that gets all the data passed along in the event and says, oh, now I need to do something with it. But you also, if it passed in a response, you could get the response object, modify it and it would have that object if it passed it in. Question. I'm sorry, can you code the event from what? Can you code it, I mean, can you trigger it? I mean, you could build, if you have the event manager and an event subscriber inside of like symphony command, you could. I mean, it's not something where, so if you want to trigger it manually, you would have something listening to the request that says, oh, this URL wants me to trigger something and you could do that in theory. Like I'm listening for things that aren't admin that are the master request and trigger and dealing with that. So you could do that if you wanted to, but it's not, you couldn't really do it from the command line unless you access the Drupal app, right? I mean, in theory, there are command line stuff where you could hook into Drupal and do that, but it's not so much where you could just magically make it trigger from the command line. Any other questions? All right, thank you for your time.