julienfalque/symfony-service-replacer

Allows replacing services in a Symfony Dependency Injection Container at runtime

1.0.x-dev 2021-10-02 16:22 UTC

This package is auto-updated.

Last update: 2024-03-29 04:32:54 UTC


README

Provides a way to replace services in a Symfony Dependency Injection Container at runtime for testing purposes.

Installation

Install the package using Composer:

$ composer require --dev julienfalque/symfony-service-replacer

Then enable the bundle in your Symfony application:

<?php // config/bundles.php

return [
    // ...
    JulienFalque\SymfonyServiceReplacer\Bridge\Symfony\Bundle::class => ['test' => true],
];

The bundle decorates Symfony's test container (test.service_container) so make sure it is available by enabling FrameworkBundle's test mode:

# config/packages/test/framework.yaml
framework:
  test: true

Usage

To make a service replaceable at runtime, add the replaceable tag to it:

# config/services.yaml
services:
  replaceable_service:
    # ...
    tags: [replaceable]

Each tagged service is decorated with a proxy that forwards calls to the original service and returns their results unchanged. Tagged services don't need to be public to be replaced.

At runtime, the test container (test.service_container) now allows you to use the set() method to replace your service and the restore() method to use the original service again:

$service = $container->get('replaceable_service');

echo "{$service->foo()}\n";

$container->get('test.service_container')->set('replaceable_service', new class() {
    public function foo(): string
    {
        return 'Bar';
    }
});

echo "{$service->foo()}\n";

$replacer->restore('replaceable_service');

echo "{$service->foo()}\n";

Assuming that the original service's method returns "Foo", this will output:

Foo
Bar
Foo