Skip to content

Commit 2840e75

Browse files
authored
Merge pull request #11 from ceford/patch-2
Converted from existing J4 Document
2 parents f6972fa + 0936e34 commit 2840e75

File tree

1 file changed

+164
-4
lines changed

1 file changed

+164
-4
lines changed
Lines changed: 164 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,168 @@
11
Dependencies
22
============
3-
Description of dependency injection in Joomla
4-
:::caution TODO
53

6-
This page is unfinished, please use the **Edit this Page** link at the bottom of this page to help make it more useful.
4+
## Introduction
75

8-
:::
6+
Joomla 4 introduces the practice of Dependency Injection Containers
7+
(DIC's) into Joomla. This article aims to explain why we are introducing
8+
them and how to use them in Joomla.
9+
10+
DIC's have been around in the PHP ecosystem for a long time now to
11+
support the goals of dependency injection. For example Symfony
12+
[introduced the concept
13+
in 2009](http://fabien.potencier.org/do-you-need-a-dependency-injection-container.html).
14+
15+
There's a variety of reasons why now is the right time to introduce
16+
these into Joomla 4:
17+
18+
1. **Testing** - one of the themes of Joomla 3 has been buggy releases.
19+
We need to be able to test classes and components in an easier
20+
fashion. Dependency injection allows significantly easier injection
21+
of Mock classes hopefully allowing us to reduce the amount of bugs.
22+
2. **Reduce the amount of magic in Joomla** - Joomla has a large number
23+
of magic files you need to guess the names of. This increases the
24+
amount of time people new to Joomla have to take researching these
25+
conventions. Exposing a concrete class in extensions allows us to
26+
easily test extensions compatibility with other extensions (for
27+
example categories and associations).
28+
29+
## The global container
30+
31+
The Global Dependency injection is very loosely a replacement for the
32+
JFactory class. However it shouldn't be mistaken for a direct
33+
replacement.
34+
35+
So for example in your Controllers in the CMS instead of substituting
36+
37+
``` php
38+
\Joomla\CMS\Factory::getDocument()
39+
```
40+
41+
consider using
42+
43+
``` php
44+
$this->app->getDocument()
45+
```
46+
47+
. This uses the injected application and therefore allows for easier
48+
testing.
49+
50+
### Creating an object in a container
51+
52+
To place something in the Global DIC the most simple way is to pass in
53+
an anonymous function. An example for a logger is below
54+
55+
``` php
56+
// Assuming we have an instance of a Joomla Container
57+
$container->share(
58+
LoggerInterface::class,
59+
function (Container $container)
60+
{
61+
return \Joomla\CMS\Log\Log::createDelegatedLogger();
62+
},
63+
true
64+
);
65+
```
66+
67+
The share function takes two compulsory parameters and an optional third
68+
parameter.
69+
70+
- A name for the service is nearly always the class name that you're
71+
creating
72+
- An anonymous function takes a single parameter - the container
73+
instance (this allows you to retrieve any dependencies out the
74+
container). The return is the service that you want to place into
75+
the container
76+
- (optional) This boolean controls whether the service is protected
77+
(i.e. whether anyone else is allowed to override it in the
78+
container). Generally for Joomla core services, such as session
79+
objects, this is true.
80+
81+
Let's now look at a more complicated
82+
example:
83+
84+
``` php
85+
$container->alias('AmazingApiRouter', Joomla\CMS\Router\ApiRouter::class)
86+
->share(
87+
\Joomla\CMS\Router\ApiRouter::class,
88+
function (Container $container)
89+
{
90+
return new \Joomla\CMS\Router\ApiRouter($container->get(\Joomla\CMS\Application\ApiApplication::class));
91+
},
92+
true
93+
);
94+
```
95+
96+
Here you can see we've done two extra things - we've started using
97+
dependencies (the api router gets the api application out the container)
98+
and we've also created an alias for the ApiRouter. That means whilst the
99+
container recognises that if it needs to build an ApiRouter instance it
100+
can do that. But in our code to keep things simple we can also run
101+
102+
``` php
103+
Factory::getContainer()->get('AmazingApiRouter')
104+
```
105+
106+
to retrieve our router.
107+
108+
Whilst in Joomla our providers can look more complicated than this
109+
because the logic to create objects inside the anonymous function is
110+
more complicated - all of them follow this base idea.
111+
112+
### Providers
113+
114+
Providers in Joomla are a way of registering a dependency into a service
115+
container. To do this create a class that implements
116+
117+
``` php
118+
Joomla\DI\ServiceProviderInterface
119+
```
120+
121+
. This gives you a register method which contains the container. You can
122+
then use the share method again to add any number of objects into the
123+
container. You can then register this into the container with the
124+
\`\\Joomla\\DI\\Container::registerServiceProvider\` method in the
125+
container. You can see where we register all the core service providers
126+
[here in the \\Joomla\\CMS\\Factory::createContainer
127+
method](https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/Factory.php#L570-L594)
128+
129+
## Component Containers
130+
131+
Every component also has its own container (which is located in the
132+
administrator section of Joomla). However this container is not exposed.
133+
It's just there to get the system dependencies and allow a class to
134+
represent your extension. This class is the Extension class and at a
135+
minimum must implement the relevant extensions type interface. For
136+
example a component must implement the
137+
138+
``` php
139+
\Joomla\CMS\Extension\ComponentInterface
140+
```
141+
142+
(found on [here on
143+
GitHub](https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/Extension/ComponentInterface.php)).
144+
For full information on implementing this in your extension, we
145+
recommend reading [Developing an MVC
146+
Component](https://docs.joomla.org/S:MyLanguage/J4.x:Developing_an_MVC_Component "wikilink")
147+
148+
### Using a component container in another extension
149+
150+
You can easily grab the container of another extension through the
151+
CMSApplication object. For
152+
example
153+
154+
``` php
155+
Factory::getApplication()->bootComponent('com_content')->getMVCFactory()->createModel('Articles', 'Site');
156+
```
157+
158+
Will get the com\_content container, get the MVC Factory and get the
159+
ArticlesModel from the frontend of Joomla. And this will work in any
160+
extension in frontend, backend or the API of Joomla (unlike the old
161+
LegacyModel::getInstance() method)
162+
163+
## Read More
164+
165+
There's a great example in the Joomla Framework docs on why Dependency
166+
Injection is good for your Application and how DIC's help structure it.
167+
[Read it
168+
here](https://github.com/joomla-framework/di/blob/2.0-dev/docs/why-dependency-injection.md)

0 commit comments

Comments
 (0)