From the
article you can find out how the Symfony2 application starts and works. I would like to continue the cycle of articles about this modern framework and pay more attention to such a component as Dependency Injection (DI - dependency injection) also known as Service Container.
Foreword
I would like to first briefly describe the architecture of Symfony2. The core application consists of components (Component), which are independent elements between themselves and perform certain functions. The business logic of the application is enclosed in a so-called.
bandlach . Along with the built-in Symfony2 components, you can connect any other components of third-party vendor libraries (including the popular Zend), without forgetting to register them correctly in the autoloader. As a rule, along with the Symfony2 kernel, components such as
Twig (template engine),
Doctrine2 (ORM),
SwiftMailer (mailer) are supplied.
Service Oriented Architecture
The ideology of separation of functions into modules that stand out as independent services is commonly called a
service-oriented architecture (SOA). It is the basis of symfony2.
Dependency Injection and Inversion of Control
In an application using OOP, the developer operates and works with objects. Each object is aimed at performing certain functions (service) and it is possible that other objects are encapsulated inside it. It turns out the dependence of one object on another, as a result of which the parent object will manage the state of the instances of the children. The
dependency injection pattern (DI) is designed to get rid of this need and provide dependency management to external code. Those. the object will always work with a ready-made instance of another object (descendant) and will not know how this object is created, by whom and what other dependencies exist. The parent object simply provides a substitution mechanism for the dependent object, usually through a constructor or setter method. This transfer of control is called Inversion of Control. Inversion is that the object itself no longer controls the state of its descendant objects.
In Symfony2, the Dependency Injection component relies on a container, manages all registered services and tracks the connections between them, creates instances of services, and uses a substitution mechanism.
')
IoC container
The DI component needs to know the dependencies between the service objects and which services it can manage. For this, Symfony2 has a ContainerBuilder, which is formed on the basis of an xml-map or direct dependency formation in a bundle. As it happens in symfony2. Let's say the app has App \ HelloBundle. To form a container and add it with your own services (at the framework level the container already exists and is filled with services defined in standard bundles), you need to create a DependencyInjection directory in the root directory of the bundle and override the load method of the \ Symfony \ Component \ HttpKernel \ DependencyInjection \ Extension class (according to the rules of the Symfony2 class should be called AppHelloBundleExtension (i.e. [namespace] [name of the bundle] Extension).
Application Services
After when you already have AppHelloBundleExtension, you can start adding your services. It is necessary to take into account that in this case you operate not with the objects-services themselves, but only with their definitions (Definition). Because in this context the container as such is still missing, it is only formed on the basis of definitions.
In addition to such a “manual” code creation, you can use the import xml-card services, which is created according to certain rules. Obviously, it is more convenient and clearer.
However, nothing prevents us from using both ways of creating definitions.
This is useful when the definition structure is specified in the xml file, and the values ​​of the necessary arguments are substituted in the extension for the definition, for example, from the configuration file. Creating your own configuration is a bit beyond the current article and can be considered later. It is assumed that there is currently a collection with data from the configuration.
Now let's see how to create definitions of future services in xml. The file has the following root structure
< container xmlns ="http://symfony.com/schema/dic/services" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://symfony.com/schema/dic/services symfony.com/schema/dic/services/services-1.0.xsd" >
< parameters >
< parameter > ... </ parameter >
...
</ parameters >
< services >
< service > ... </ service >
...
</ services >
</ container >
* This source code was highlighted with Source Code Highlighter .
Each service definition is defined by a service tag. It has the following attributes
- id - the name of the service (the one by which this service can be obtained from the container)
- class - the name of the service class, if it will be created through the new construction (if the service is created through a factory, the class name can be an interface or abstract class reference)
- scope
- public - true or false - service visibility
- syntetic - true or false
- abstract - true or false - is this service definition abstract, i.e. a template for use in defining other services
- factory-class - the name of the factory class for the static method call
- factory-service - the name of the existing service-factory for calling the public method
- factory-method - the name of the factory method to which the container refers
- alias - service alias
- parent
Attributes of the set
parametersThe following elements can be nested inside the service tag.
< argument />
< tag />
< call />
* This source code was highlighted with Source Code Highlighter .
argument - the transmission as a parameter of an argument, or it is a link to an existing service, or a collection of arguments.
tag - tag assigned to the service.
call - call the service method after its initialization. When calling a method, the parameters passed are listed using the nested argument tag.
The values ​​of attributes and tags (for example, the names of classes) are most often put into parameters, then use the substitution of this parameter into an attribute or tag. A parameter can always be distinguished by the presence of a% sign at the beginning and end. for example
< parameters >
< parameter key ="some_service.class" > App\HelloBundle\Service </ parameter >
</ parameters >
< services >
< service id ="some_service" class ="%some_service.class%" />
</ services >
* This source code was highlighted with Source Code Highlighter .
It is convenient in this case to list all the parameters in one place, and then use them more than once in the service definitions.
Examples of service definitions
Now, more clearly described above can be presented with examples:
< service id ="some_service_name" class ="App\HelloBundle\Service\Class" >
< argument > some_text </ argument >
< argument type ="service" id ="reference_service" /><! -- -- >
< argument type ="collection" >
< argument key ="key" > value </ argument >
</ argument >
< call method ="setRequest" >
< argument type ="service" id ="request" />
</ call >
</ service >
* This source code was highlighted with Source Code Highlighter .
The container service described above, when first accessed, “turns” into approximately the following
The same, but in the definitions of symfony2
To get this service, for example, in the MVC controller, you can
$this->container->get('some_service_name');
I think that more illustrative examples of creating service definitions can be viewed in the standard bundles that come with the Symfony2 core.
Conclusion
As a conclusion, it is worth noting that the Service Container in Symfony2 is very convenient, it allows you once to configure all the necessary services for an application and use them for its intended purpose. It is also worth noting that in Symfony2 there is a “smart” caching system, including for service definitions, so every time you add or change them, do not forget to clear the cache.
Related Links
Martin Fawler: Inversion of Control Containers and the Dependency Injection patternDependency injectionAppeal control (inversion control)Symfony2 - The Service Container