 So yeah, so this is the dependency injection presentation. So all my code and slides are there. If you need it, that's where you'll find it. If you're doing a dependency injection, you need to look up certain services and stuff like that. You can find them at this address. And also if you are interested in learning more about dependency injection as well as other development-related stuff, there's a couple of podcasts I would recommend. There's one about talk and called Talking Drupal. It basically talks about all the various changes coming in and going in Drupal. It's really interesting. Then there's a complete developer podcast which goes into a lot of textual stuff. So it's really, really cool. So what are we talking about today? So we're going to basically cover what is dependency injection? We're going to cover why do we use it? How do we use it? We're going to talk a little bit about symphony because Drupal is a symphony application. And then we're going to talk about how exactly we use dependency injection in Drupal 8. And it's time for us to do a demo as well. Okay, so what is dependency injection? To define that, first we are going to look at this which is basically we need to define what exactly a dependency is. And dependency exists when there's one class that requires another class to do something. Right? So if you need something from another class to do your work, then there's a dependency. And dependency injection, that's the name in first, is that it's like we're basically pushing a dependency into an object so that they can use it. Right? It's basically, instead of them asking for it during runtime, we're giving it to them before they even call the actual function. Right? Because if you want to build a house, you will want to have all the parts before you build it. Otherwise, if you're building it as you go along, you may need to, it'll be very complicated and it could break things. Dependency injection is also a decoupling of objects. So what that means is that if you have two objects, one lies on the other, right? But you need to make it so that if that object can be replaced with something else later on, that you can do that, right? And dependency injection allows for that. And we'll see exactly how that's done. So the purpose of dependency injection is to create objects. Its main purpose is to know which classes this object requires, right? And then basically provide those objects with those classes. It's basically a middleman, right? Between the two objects, and it basically asks the one that's requiring something, what exactly are you requiring? Here, I'll give it to you. That's basically what it does, right? You just need to set up a few things and then it basically does it for you. So why do we use dependency injection? We use it because Drupal 8 basically needs it. That's how Drupal 8 works. If you look at any classes within Drupal 8 or any services, they all use Drupal and dependency injection to actually get what they need, right? If you try to do an outside of that, you'll find that you're running into errors and you can't debug them because you're trying to find something that the stack trace doesn't show. Also, unlike Drupal 7, where all the code is bootstrapped in Drupal 8, it's not. You can call the Drupal instance to call a particular function or whatever, but do you really want to bootstrap Drupal? No, you just want to call exactly what you need. So the advantage of using it is that at least two self-contained code that's easy to unit test. What that means is that basically you're setting up your classes and services. Okay, so before I do that, classes, services, objects, they're exactly the same thing, right? So for now, I'm just going to say their services because in Drupal 8's lingo, they're basically all services. So basically the advantage of using it is that it leads to self-contained code that's easy to unit test because the service knows exactly what its dependencies are and as soon as you call it, that's exactly what it's going to receive. The code requirements are self-documented because you have a standard structure of required dependencies. When you go to it, you can see exactly what it needs to function. And it allows for more automation as well because everything is self-contained. The disadvantage is it's more complex because you kind of have to understand how Drupal's interfaces work and how services work. So there's a huge, there's a bit of a learning curve. I wouldn't say it's huge, but there is a bit of learning curve and it can't be difficult to debug because if you have a service that depends on another service, that depends on another service, that depends on another service, right? And there's like a null happening up top somewhere. You only need to know what's causing that. So it's kind of a little bit difficult to debug. So how do we use dependency injection? So as I said, the objects, classes, services, they're always the old services now, right? You basically break up the code into separate functions, separate classes to do things and separate things and you call them using services. And we'll look exactly what that is. So just like classes are, services are basically reusable. They're unit testable and they're self-documented by their nature. Here's an example of a class. If you're self-dating database connection, you're calling that class database connection. You can also instantiate Drupal to basically call that function to get a big connection and there's a bunch of methods associated with it. What if our services has dependencies? So like if you're calling the database connection and it has a bunch of services, how do we get them and what exactly do we need to recall the show? We could possibly just run this and get the connection, right? But then if you're using this in multiple places, then that's gonna cause a lot of duplications, right? And let's say we are not using that get connection anymore and we're using a completely different data source, for example. That would mean a lot of refactoring. And it doesn't really really be coupling. We could define a global one and basically we start with global variable that basically defines that connection. But then now anytime that our service needs to be set up, you need to know that you need to set this up. Otherwise it's a complaint, right? And that's not really documentable. You could just require it as a parameter, right? As an argument, right? Set up a constructor and have it as an argument there. Now your class will use this connection throughout its execution. And whoever will be using your service knows exactly that you need this. So that's basically Drupal injection, right? Is that basically you're providing the exact requirements for your service to run, right? So the various types of dependency injections are there's a constructor one that you just looked at. There's also set of injections and property injections. So the center injections, which are basically optional dependencies, or these are things that need to change within your service. And like let's say you're reusing the service to do multiple things on different entries. So you can set up a center function that basically sets a local dependency. It could be just a variable or it could be an actual service as well or a class. Then there's the property dependencies. These are things you extend. Like you're extending it to another class or service. So you're inheriting all their functions. So you can extend them. This is called a property dependency. You can also be implementing other interfaces into yours. So just to recap, services are some code that does something in a class. That's basically what it is, right? Dependency injection explicitly requiring any dependencies. So you're basically telling everyone around you that this is what I need to run and that's what dependency injection does. Again, I'll be showing some code later to show exactly how that's done. So now let's look at the symphony connection. Because as you know, Drupal is a symphony application. And as such, we inherit a lot of the symphony principles as well. Anytime we're setting up a plugin or any time we're setting up a plugin, field, type, whatever, but all based on symphony architecture, right? As such, they follow the same way that are developed and set up. So symphony introduces something called containers into dependency injection. That's something that symphony provides us. So container is basically our dependency injection middleman, right? It basically knows exactly what services are available and will grab them for us and provide it to us. So here, for example, we're saying a container equals new container builder. So we're asking this from symphony and it will get us the database object. You know, so it basically knows exactly what this library is and all the things that it depends on, right? And it will grab that for us and basically give it to us. And we can use it for whatever we want in our service or class. So service containers are basically set up in this manner. And since we're using Drupal, we're gonna look at only the YAML format, right? Because in Drupal, services are set up within the services.yaml files. So here's an example of a couple of services that have been set up. The first service basically says that we're just gonna call this service and it has service one. And this is the class that it calls, right? To get that service. Service two calls this class, but it also takes in an argument, which is service one, right? So it basically depends on service one being there. Yeah, so basically just building on the previous one, we just have three services here and services two and three require on the previous service. And when you say container builder gets service three, it knows to get service one, two and three, right? When it's actually returning that object because it depends on those. And because the YAML set up in that way, it knows exactly what those are as well. And again, we'll look at exactly how this looks like. Then there's also a service tag which can apply. So these tags would allow it to need it. Yeah, so basically you can tag different services and they can be called by those names as well. So just to recap, services are just some code that does something in a class, right? Classes are services, dependency injection basically requires any explicitly required dependencies. Service containers are metadata about the services and dependencies and service tags allow you to name, categorize and query services. So how does Drupal use dependency injection? In Drupal 7, all code is bootstrapped. So it's available globally, right? And you use something called hooks to actually like respond to events. In Drupal 8, everything is not that way. It's more obvi-oriented. And as such, you'll implement classes or you'll look at interfaces to react upon different things, right? And so basically we need to allow for dependency injection to play a role in here. So how does that look? Service classes are named this. So you have a module, you have a source directory, then you have a folder inside there, whatever that folder is, that's your namespace. And then you'll have a class name, a WSP. Service containers can be defined inside of the mymoduleservice.yaml file. Let's look at some code right now. Any questions so far? Yes. Actually for the, we can go back to the previous slide. It's just for the interval best practices where you store your service like you put like namespace and then name of the service. Yeah. Yeah, yeah. Yes. I don't know. We usually just create a service for the center in there. Is there any kind of best practice? Best practice is normally the, so everything there will be inside your module, right? So these services are local to your module, right? So technically you call us anything you want. You call services. I call you customer services, but. Most of the modules in Drupal Core that offer services don't actually like stick them inside folders anyways. Yeah, they just leave it in the module name space at the root. So I don't, I don't know if there is a best practice. Yeah. I put them inside the folder, but again. So I guess there is no real best practice, but it's just that your module's gonna be part of the namespace anyways. All right, so it really doesn't matter. As long as your module name is unique, I guess that's all that matters. Yeah, unless it's like, what? So that is super important. Yeah, exactly. Any other questions? Okay. First let's dive into some code. Kind of small. Is that visible? Okay, so here I have to have a custom module that I've set up. It just sets up a service, which is called custom. I'm basically calling it a custom service. It's just, this looks kind of now. I've worked on a mailing thing. I've stripped up a lot of stuff from this. But basically what's going on here is that I'm basically creating a new service within Drupal and I'm calling it mailer.subscribablemail. And it's basically referencing this class, right? First thing always is you have Drupal, then you have the name of your module, then you have your namespace, and then you have the actual service. And it accepts two arguments. One is entity type.manager, and one is entity repository. I'll show you exactly what those do. So here I have my service. I have my custom service I've set up. It's inside, it's hard to see it, but it's inside a custom services directory within the source. And it basically says that I want to place all the stuff within this namespace, right? So anything that's using the same namespace can reference me, all right? And then it's using a whole bunch of dependencies. But so we have a class subscriber mail, and inside of it we have a whole bunch of detective functions, which I forgot to delete. And then we have a constructor. So the constructor is basically saying that we need to, we need two parameters passed into us in order for us to work. It's basically saying that listen, we need the config factory, and we need entity type manager interface to do some work later on. So we're basically setting them up as local variables within this class, and so that we can use it wherever we need it. That way we don't have to reinstation it to that class, and it also speeds up and reduces memory usage as well. Then we have a create function. Now create function actually browse us that particular dependency. This is using a container interface, which is coming from symphony. And we can see that up here that container interface is coming from symphony. So symphony component, dependency injection. And basically it knows exactly where all our services are because we set them up through the services.yaml file, right? And it basically can grab us exactly what those energies are as to why config.factory has been used. So these names identify each of those parameters. Now they vary depending on, yes. Sorry, are these the two arguments you passed in the services.yaml? Yes. From the create function? Yeah, so they're exactly the same wording as well. And they come from, on Drupal.org, there's a Drupal API. So here, if you need to look up any particular service within Drupal, you can do that here. So if you wanted to config factory, for example, you can type in config and it'll give us a whole bunch of items and here's the config factory, right? That's the name that we apply to this, right? Because we want, okay, before I even went on to explain the extra class, I should have explained what the class does. So, this class was set up to basically send a test email. And it was gonna load some configuration to get some presets like the sender name, sender email and some other arbitrary items. And then it was going to do was it was gonna look up the latest content that's on the site and basically attach it to the email to be sent out. So, I figured that I needed at least two dependencies for this, right? One was the config factory, which handles all the configuration. And the other one was the entity type manager, which actually lets me load content. All right, this lets me actually grab content. So, I started basically building my class up this way. And I passed in those two variables and then I had to set up a create function. That create is very important because it lets us actually cast this on this into our class. Services will tell us exactly what those parameters are, but it won't tell us exactly. It's not actually, it's passing it in, but this is telling us that this is exactly what we need to pass in. This is important when it comes to unit testing, right? Because for unit testing, it's not gonna bootstrap Drupal or anything like that. It's going to basically call our class and the class will be able to create these variables for us and that way we don't have to do a lot of lookups. And in here, I also have a node interface, which I'm basically passing in from the previous one. Actually, that's trouble. Forgot to leave that. Okay, so going back, how exactly do you look up what exactly you need to put inside your constructor? I knew that I needed to look up what do you call it, the config, so I looked up config and I went through and found that the one thing that everything uses is config factory, that's the main interface, to basically look up any service within any configuration within Drupal. So I can see here that this is where config factory is located, so I would include that, I would use this, what do you call it, I would use that as part of my code. So up top, I would set up Drupal core config factory, that's the class I'm using here, and then I would say that in my constructor that this is of type config factory, I just called it config factory just for naming sake, but I also set up a protected function within my class called config factory, you can call this anything you want. Well, not everything, but you should make it specific to what you're actually looking at. And yeah, so that's basically how that is passed in, same thing with any type manager interface. You can just look that up on the API page and it'll add it there. Now, exactly how do you use this? So anywhere within your function, within your service, you can have a, you can call that function like using this, and then the actual variable, and then you can actually call whatever function on that interface that you wish. So here I'm calling getStoriesNote and I'm loading the campaign ID that we got passed in. Yeah, so this is just doing config factory workloads. Now, you can, now dependency injection works for classes. In regards to the Duplic module files, because there's no class, there's no construct, you can't really call the service that way. So one way you can do that is by basically calling Drupal to grab that service, right? And if you grab that service, because all the procedures are already set up, you don't need to pass in any parameters, right? Because already knows exactly what it needs. And then of course you can just basically use it by calling various functions as that. So I have a setter function within it to basically set the node ID that I want to start using for this. And then I have a generateMail function which basically generates mail from you. You can also, so I also have another function here. There's another service here called sendMail. This is another class that I set up to basically use my newly created service, subscribing mail to basically send emails. Because all that does right now is that it just sets up a class that can basically generate mail and send it out. But it doesn't really know exactly what it needs to be sending out. That has to be done outside. So I set up a class that basically extends the control base, right? Control base basically lets me set up a route to any specific point which I can execute over the code, right? And this is basically a property injection, right? Because basically we're extending control base so we're basically inheriting all the control base functionality. And, oh, I almost forgot. So one thing that Drupal does a little bit different is translations. So if you're using translations within Drupal, you have to basically set up a string translation trait. You have to use that class. And within your class, you actually have to use a string translation trait. This tells us, this is a little bit different than most other things, and I find a little weird. But you're not really putting this inside this construct or you're not actually injecting it somewhere. You're just saying, I just want to use this trait. And what this will let us do is this will let us use this T. If you know the T function from Drupal, I will show you translate strings. Well, if you want to do that outside your services or inside your classes that has the injection, this is the way you do it, all right? T is being deprecated for Drupal 9 so this is really how you do it. Yeah. So going back to this class here. So I set up this class which is send mail and extends the control base. What this class does is that it basically accepts a bunch of parameters and then it says, okay, I'm going to call the subscriber mail class and I'm going to generate emails for particular node IDs and send them out. That's all I'm going to be doing. So I set up a controller which is going to be executed through a route and it basically accepts two parameters. One is the subscriber mail and the other one is a messenger. Messenger, for those that don't know, is basically how you set up status messages within Drupal, all right? So if you want to set up a status message, error message, or info message, whatever, that's how you do it. How you do it through the messenger interface. And then again, I created a create function for it to basically pass those in. For custom services like this, you can just use your mail or dot which is the service I set up. Where's my service? Mail, we love to subscribe and mail, right? That's how you get that name because that's the service I've set up. Then of course I'm passing in messenger which it knows about from Drupal itself. Then I have a function here which is sent as mail and it basically receives a endowed interface or parameter. This is being passed in from my outside function which I'll show you in a second. And it basically does a bunch of things like it calls the subscriber, calls the mailer that I've just set up and sets the campaign to be the current node and language and basically it sets, okay, generates a mail and then once it's done generating the mail, it sets the status and this is where you use this T, right, it could be set up the trade already and it basically sets the status and then does a bunch of things in versus loading the campaign, setting, updating the last task run and saves it. Do I pass it in the message here? No, I did not. Okay, okay, so yeah, I forgot to pass in one. One interface interface into my constructor which is the entity manager and so I'll just do that right now. I'll just copy one of these. If you guys have any questions just ask. If I'm confusing anyone, I'd like to clarify things. Yeah, so this is my self-documenting thing going on here so everyone knows exactly what each one does and then of course in here we'll just do container yet and I don't know exactly what it is so I'll just look it up and just do entity manager, it is called entity manager. Is it the entity manager or entity type? It is entity manager. That's good. It's just different. Oh yeah? Yeah, it's usually. Oh yeah, you're right. Shoot. You're stunning, you can point to your dogs. Well, I did use that anyway. That's funny. Apricot. Apricot? I know you're fine, sorry, you're heavy on the set. Thank you, you're good. Yeah. Okay, so that basically adds entity manager into our... Online 30. What? Online 38. Yes, you're right. Okay. So there we have entity manager and I think I'm using an entity manager to basically load that particular node and getting a translation of that and then doing some functions. So at the bottom here, I'm calling URL from route. Since I'm not, I'm calling this dynamically, I guess I could have injected this, but I didn't. But I'm not using it, I wasn't planning on using URL, so I think it's fine for that. Okay, so then we have the functionality above this. It's actually calling that send mail class and this basically is just using hook cron, which we all use. And it's saying, okay, get me some campaigns to run, then we have a campaign runner which calls a service and then basically goes through and runs that service. So this is how you kind of do it inside your top module file, right? And you could also use, do a use statement up here, so you can do use triple mail or custom services and then subscribe in the mail to do that. But if you do that, then you also need to do, pass in all the dependencies into it, which if you call the class specifically, you'll have to do. But if you just call the services here, that basically injects all the services for you. Yeah, I just hard coded a bunch of random values down here. I'm not going to run this because I don't have a working site, but everything has been committed and pushed up. Anyone have any questions? I think I'm confused about some confused phrases. Yeah, you were talking previously about the trade for translation. Yes. I remember that what I did in the code recently, I did the injection for that. I didn't know there was a trade. So is there a page where it lists all the trades? I actually found it in Dave, but there's a trade for me, you can tell me. So referring to like get the T function, it's documented somewhere in the Drupal 8 documentation. You get like T, the support translation in the classes. The correct way is to use the string translation trade, but there's other language features, like if you actually memorize the languages and translate things, like content stuff, then there are services that you need for those. There are trades in the API docs, but unfortunately with most things in Drupal 8, you kind of have to do Drupal 8's source in Drupal 8 Core and they have their doing things and they learn all kinds of fun stuff. Yeah, actually, when you're actually using a lot of this, the reason it gets complicated is because a lot of stuff is in the old document and you kind of have to go through the core source to actually find examples of some of the dependency requirements. So yeah, you kind of dig through code to get that as well. But if everything you're looking for is available in the API doc, then that's really low. But then again, even that, like searching is not very good, because how do I know that I need to fix actually a new configuration? I mean, we have to go through a single config, the API I mentioned, you know, we need to find that, right? And that's basically, well, what I did initially was go through the core source and like I was like, oh, we're going to be using config factory. So it is a little confusing and a little bit complicated in the beginning, but once you start using it, then it gets easier and easier. Hey, any other questions? Yes. Yeah, I can talk a little bit about interfaces and they seem to be like. Yes, so interfaces are interesting because and if you're setting up services, you kind of want to use an interface, right? Basically interface around it. And the way they work is that basically your service will call, will reference a, well, no, will ask for a dependency injection of an interface. And the reason you want that is because that is what allows for your code to be decoupled, right? It needs, an interface basically allows you to implement multiple classes to represent it, right? It works like a middleman between multiple classes that do similar things but might do it with different things, right? For example, database. You could have a MySQL database, you got a Postgres database, you could have a flat poly, the hierarchy, right? All that sort of stuff would basically use the same interface to talk to all your things, right? And in that way, basically if you need to change your functionality later on, you're not rebinding your main service. Instead, you just basically change the dependency on it. And I don't have an example right now. Yeah, I think it's like a best practice, but I don't find myself writing them very often and I don't think you have one there. No, and it is best practice, but I also don't like it, so. Because every time I need to do something customerless, this needs to put something specific. But then again, I'm later on, that if someone needs to change it and point to something else, maybe someone else can also better mediate about us, then they have to go back and change a lot of stuff in one. Yeah, because we should make our code so that it's not dependent on the dependency. It requires it, but it doesn't care exactly how that code gets executed, right? Yeah, it's an abstraction. Yeah, it's an abstraction, exactly. So that's very basically we should do it. It is difficult, but that's how it should be done. Any other questions? Thank you.