> For the complete documentation index, see [llms.txt](https://senens-organization.gitbook.io/senenhermida.docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://senens-organization.gitbook.io/senenhermida.docs/symfony/service-container.md).

# Service container

## Service container

## Service container

Tool for managing class dependencies and performing dependency injection.

#### Automatic Service Loading

Thanks to this configuration, you can automatically use any classes from the src/ directory as a service, without needing to manually configure it.

If you'd prefer to manually wire your service, that's totally possible

```yaml
# config/services.yaml
services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      
        # Automatically injects dependencies in your services.
        autoconfigure: true 
        # Automatically registers your services as commands, event subscribers, etc.
        # When a service is autoconfigured, it means that Symfony 
        # will automatically tag it when possible.

    # makes classes in src/ available to be used as services
    # this creates a service per class whose id is the fully-qualified class name
    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'

    # order is important in this file because service definitions
    # always *replace* previous ones; add your own service configuration below

    # ...
```

#### Injecting services/config into a service

The container will *automatically* know to pass the `logger` service when instantiating the `MessageGenerator` thanks to`autowiring`. autowire:true in services.yml

#### Configure arguments

```php
class MessageGenerator
{
    public function __construct(
        private LoggerInterface $logger,
    ) {
    }
}
```

```yaml
# config/services.yaml
services:
    # ... same as before

    # explicitly configure the service
    App\Service\SiteUpdateManager:
        arguments:
            $adminEmail: 'manager@example.com'
```

#### Tags

**Service tags** are a way to tell Symfony or other third-party bundles that your service should be registered in some special way. Take the following example:

```yaml
# config/services.yaml
services:
    App\Twig\AppExtension:
        tags: ['twig.extension']
```

Services tagged with the `twig.extension` tag are collected during the initialization of TwigBundle and added to Twig as extensions.

**Service parameters**

```yaml
services:
    App\Service\SomeService:
        arguments:
            $emailSender: '%email_sender%'
```

**#\[Required] in setter**

same as

```yaml
services:
    App\Service\MessageGenerator:
        # ...
        calls:
            - setLogger: ['@logger']
```

**Choose a specific service**

We inject `LoggerInterface` but it has multiple implementations such as `logger`,  `monolog.logger.request`,  `monolog.logger.php`

In these situations, the container is usually configured to automatically choose one of the service

But, you can control this and pass in a different logger:

```yaml
# config/services.yaml
services:
    # ... same code as before

    # explicitly configure the service
    App\Service\MessageGenerator:
        arguments:
            # the '@' symbol is important: that's what tells the container
            # you want to pass the *service* whose id is 'monolog.logger.request',
            # and not just the *string* 'monolog.logger.request'
            $logger: '@monolog.logger.request'
```

**public vs private services**

By default every service is private. You cannot access them using $container->get()

As a best practice, you should only create *private* services and you should fetch services using dependency injection instead of using `$container->get()`.

**bind arguments globally**

```yaml
services:
    _defaults:
        bind:
            $emailNotificationsEnabled: '%email_notifications_enabled%'
```

```php
namespace App\Service;

class EmailSender
{
    private $mailer;
    private $emailNotificationsEnabled;

    public function __construct(\Swift_Mailer $mailer, bool $emailNotificationsEnabled)
    {
        $this->mailer = $mailer;
        $this->emailNotificationsEnabled = $emailNotificationsEnabled;
    }

}
```

Later

* more

  service subscriber and locator

  decorator service

  factory service

  service closures

  Injecting a Closure as an Argument ??

  **Container Building Workflow**

  Binding Arguments by Name or Type ??

A **Compiler Pass** in Symfony is a way to manipulate or modify service definitions within the dependency injection container before it is fully compiled and used by the application.

#### What It's Useful For:

* **Customizing Service Definitions:** You can add, remove, or alter services and their dependencies programmatically.
* **Tag Processing:** It allows you to find all services tagged with a specific label and apply custom logic, such as registering them in a registry service.
* **Advanced Dependency Injection:** You can dynamically modify service configurations that can't be predefined in static YAML or XML files.

#### Example Use Case:

Suppose you have multiple services tagged as `app.custom_logger`. You can use a compiler pass to collect these services and inject them into a logger manager.

#### How It Works:

1. **Create the Compiler Pass Class:** Extend `CompilerPassInterface` and implement the `process` method.
2. **Modify Service Container:** Use the `ContainerBuilder` object to access and modify service definitions.
3. **Register the Compiler Pass:** Add it to the `Kernel` in the `build` method.

#### Code Example:

```php
php
Copy code
namespace App\DependencyInjection;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class CustomLoggerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->has('app.logger_manager')) {
            return;
        }

        $definition = $container->findDefinition('app.logger_manager');
        $taggedServices = $container->findTaggedServiceIds('app.custom_logger');

        foreach ($taggedServices as $id => $tags) {
            $definition->addMethodCall('addLogger', [new Reference($id)]);
        }
    }
}

```

Register it in `Kernel`:

```php
php
Copy code
use App\DependencyInjection\CustomLoggerPass;

class Kernel extends BaseKernel
{
    protected function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new CustomLoggerPass());
    }
}

```

#### Summary:

Compiler Passes are powerful for customizing and optimizing service definitions during the container compilation process, providing flexibility for complex dependency injection scenarios.
