The Service Container

All about Dependency Injection!

## Introduction ---
This demonstration assumes you have already got a good grasp of the "Service Container" and "Dependency Injection" concepts. If not, please read our Service Container introduction first.
The ABC Manager 6 [Service Container](https://docs.angrybytes.com/p/abc-manager/6.0/docs/container/introduction/index.html) is a powerful component adopting the Dependency Injection concept and will hold almost all knowledge about your bundle components and their parameters. Almost all of the ABC Manager 6 core *bundles* already register their components as **services** in the service container, as well as the **parameters** used by them. In addition to that, we have added some features on top of the service container to add more flexibility when developing applications. In this demonstration, we will not lay the focus on the service container itself, since there is already more than enough proper [reading material](http://symfony.com/doc/current/book/service_container.html) out there. Instead, we will focus on some of the additional features that we've added: * Automatic conversion of `application` and `project` YAML configuration parameters into service container parameters. * The ability to define a single service definition for each applications uses the bundle (via [Kernel registration](https://docs.angrybytes.com/p/abc-manager/6.0/docs/kernel/introduction/index.html)), thus making them **application aware**.
Note - all demonstrations occur in realtime! Open this project in your IDE to view and/or modify the actual sourcecode used in the demonstrations.
### YAML Configuration to Service Container Parameters --- Before ABC Manager 6, you had fewer possibilities to expose application or project wide configuration values to your application logic. YAML configuration, placed inside the `sitebased` or `site` YAML files needed to be retrieved directly from inside your components and there was no way to automatically inject configuration values into components. In ABC Manager 6, having the service container and using dependency injection, it becomes fairly easy to inject these values into your components, by defining them as service container **parameters** in the `services.yml` file on a per bundle basis. In addition to that we will parse the YAML configuration files and inject the configuration nodes/values as parameters into the service container when [compiling the container](http://symfony.com/doc/current/components/dependency_injection/compilation.html). Read More about YAML to parameter conversion [here](https://docs.angrybytes.com/p/abc-manager/6.0/docs/container/configuration/index.html#configuration-to-container-parameters). #### YAML Configuration To demonstrate this, a dummy node has been added to the `demo` application's YAML configuration: ```yml ### file: applications/demo/applications/Resources/config/config.yml url: 'https://demo.abc-demo.test' ``` #### Service Definition By defining an [application aware parameter](https://docs.angrybytes.com/p/abc-manager/6.0/docs/container/application/index.html) in the `Demo\ServiceContainerBundle` bundle, we are now able to automatically inject the `` configuration value as a service container parameter into components. Keep the following rules in mind: * Container parameters derived from `applications//Resources/config/config.yml` config values will be prefixed with the application id: "`[application-id].`". * Container parameters derived from `project/Resources/config/config.yml` config values will be prefixed with "`abc.`". * Nested YAML configuration values are imploded and separated by a dot [`.`] value. * Example: ```yml foo: bar: 'baz' ``` equals `foo.bar: 'baz'`. The `services-application.yml` file inside the `ServiceContainerBundle` bundle registers a parameter with the same name used in the YAML configuration and injects the parameter value into a service definition: ```yaml # file: src/Demo/ServiceContainerBundle/Resources/config/services-application.yml parameters: # Overwritable by application configuration node: ... $application.url: '' services: # Container demo component $application.container: class: Demo\ServiceContainerBundle\Container calls: # Inject the application url parameter - [set, [%$application.url%]] # By using $application, a service or parameter is created for 'every' application that registers this bundle ``` By fetching the service `$application.container` for this application, with application id "`demo`", we can now retrieve the `url` value derived from the configuration and use it to our liking:

The `` configured for this application is: https://demo.abc-demo.test

```php // file: src/Demo/PublicationBundle/Controller/Demo.php:#27 /** * Demo the service container * * @return Response **/ public function serviceContainerAction() { // Retrieve the url via the contaioner service // Uses "Abc\HttpBundle\Controller\ContainerAware::get()" to retrieve a service from the container $appUrl = $this->get('demo.container')->getValue(); ... } ```

We have now successfully converted, used and displayed a service container parameter that has been derived from the YAML configuration.

### Application Aware Services --- In addition to regular services, defined in `services.yml` files, ABC Manager 6 allows bundles to register container services and parameters that will automatically be registered inside the container during compilation **for each application** the bundle is registered for in the project Kernel. These application aware services are registered in a file called `services-application.yml` and are automatically picked up by our core. These services especially come in handy when they act upon any given application, not for one application in particular. For example, the ABC Manager dispatcher, retrieved from the service container in every front controller (`index.php`) file does this. The service definition is registered for each application: ```yaml # file: vendor/angrybytes/abc-maanger/src/HttpBundle/Resources/config/services-application.yml services: # Dispatcher component for every application $application.dispatcher: class: Abc\HttpBundle\Dispatcher\Routed ``` The application aware service files are be parsed by a [Compiler Pass](http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html) during container compilation and are registered inside the container for every application added in the project Kernel (and the `cms` application). For every application, the `$application` part gets replaced with the actual application id to create a new, unique, service id for that application. To demonstrate this effect, we will register an application aware service, inject the current (dispatched) application instance into the service (made available by the ABC core under id `@$application`) and retrieve some values from it. First, we register an application aware service: ```yaml # file: src/Demo/ServiceContainerBundle/Resources/config/services-application.yml services: # Container Demonstration Service $application.app_aware_service: class: Demo\ServiceContainerBundle\Container calls: - [setValue, [@$application]] ``` And now we can retrieve this service in our application logic based on a given application id and retrieve its values:

**Demo App** Some application properties: * The application has id: `demo` * The application's frontend url is: https://abc-demo.angrybytes.com * The applicaiton's webroot is: `/var/www/html/project/includes/../../applications/demo/public`

```php // file: src/Demo/PublicationBundle/Controller/Demo.php:#27 /** * Demo the service container * * @return Response **/ public function serviceContainerAction() { // Second demo; retrieve an application aware service $dispatchedApp = $this->get('demo.app_aware_service'); // Render template w/ $dispatchedApp } ```

```twig # file: service-container.html.twig {{ dispatchedApp.getName() }} Some application properties: * The application has id: {{ dispatchedApp.getId() }} * The application's frontend url is: {{ dispatchedApp.getUrl() }} * The applicaiton's webroot is: {{ dispatchedApp.getDirectoryLayout().getPublic() }} ```

This demonstrates how generic services are created that are able to work on any given ABC Application.