# 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://senens-organization.gitbook.io/senenhermida.docs/symfony/service-container.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
