PHPackages                             sbuerk/typo3-symfony-di-test - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. sbuerk/typo3-symfony-di-test

ActiveTypo3-cms-extension[Utility &amp; Helpers](/categories/utility)

sbuerk/typo3-symfony-di-test
============================

Provides proof-of-concept implementation for Symfony DI techniques as TYPO3 extension

0.0.2(1y ago)01GPL-2.0-or-laterPHP

Since Sep 8Pushed 1y ago1 watchersCompare

[ Source](https://github.com/sbuerk/typo3-symfony-di-test)[ Packagist](https://packagist.org/packages/sbuerk/typo3-symfony-di-test)[ RSS](/packages/sbuerk-typo3-symfony-di-test/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (3)Versions (3)Used By (0)

sbuerk/typo3-symfony-di-test
============================

[](#sbuerktypo3-symfony-di-test)

Preamble
--------

[](#preamble)

This repository and package is just a `proof-of-concept` implementation and not meant to be a longtime example or demonstration. At lest not yet. Thus, this package lacks for now CGL, code analyzers and test and is not maintained in any case.

Take this into account if you want to contribute, as literally this may be a waste of time because it is not meant to be maintained.

However, while talking about this contribution may be added (pull-request) to co-work on this to have something testable at hand to talk and decide if the included pattern(s) may be used and documented within the TYPO3 core and/or extensions.

Note that this TYPO3 extension will not be released in the TYPO3 Extension repository - either download it/check it out for non-composer installations or monorepo. However, it is registered in public packagist and can be required in composer based installations with:

```
composer require --dev sbuerk/typo3-symfony-di-test

```

Introduction
------------

[](#introduction)

This package contains a TYPO3 extension which demonstrates different Symfony DI techniques.

### Using Symfony Service decoration for extendable service factories

[](#using-symfony-service-decoration-for-extendable-service-factories)

It's a common way to use the service factory pattern to create a instance based on different configuration parameters. In these cases the `ServiceFactory` is used within consumer classes (injected service factory) to retrieve the matching service.

The usual TYPO3 Core way to use service factory forces extension authors to replace the DI definition with the extended service factory which is only possible if the service factory is not final or the factory implements a factory interface and the interface is used as type annotation in core code. Extension authors adopted the same technique for their own extensions.

In cases multiple extension wants to influence the factory to retrieve adjusted (custom) services based on some context data but still keep prior service factory in place this was not possible.

Symfony DI supports service decoration, which can be used to provide a more flexible way for extension authors to influence service creation based on context data. This package contains a demonstration for that technique.

#### Scenario introduction

[](#scenario-introduction)

For the demonstration scenario we assume, that a way is needed to create specialized service based on a `string value` as context data with a default service.

That means, that we need a `ServiceInterface` which can be used for PHP type declarations in methods and return types and ensure that required methods exists. The service itself should be able to retrieve autowired dependencies.

To be able to create service instance based on that context value, a service factory is a good way to archieve that:

```
final class ServiceFactory {
    public function create(string $context): ServiceInterface
    {
        return match($context) {
          'special' => new SpecialService(),
          default => new DefaultService(),
        };
    }
}
```

If the service factory class is final like in the example above, extension authors are not able to extend the service factory and replace (alias) them in the Symfony DI configuration. Using a registry (injected) or tagged services array could be used to replace the match/context determination by calling a method on all retrieved tagged service to determine the service to use and return.

For the sake of this scenario, it would be nice that extension authors may be able to simple add custom service factories retrieving the prior service factory, so it can fallback to the parent factory:

```
final class ServiceFactory {
    public function __construct(
        private DefaultServiceFactory $serviceFactory,
    ) {}

    public function create(string $context): ServiceInterface
    {
        return match($context) {
          'special' => new SpecialService(),
          default => $this->serviceFactory->create($context),
        };
    }
}
```

This is possible in general, but nearly impossible for extension when multiple extension want to do that because the type hint in the constructor.

Given that we introduce a `ServiceFactoryInterface` it is still a configuration nightmare and instances (developer/maintainer) needs to adjust the chain through multiple extensions which is quite a horrible way.

Combining the use of an interface with the `Decorator Pattern` this would be more suitable:

```
final class ServiceFactory implements ServiceFactoryInterface  {
    public function __construct(
        private ServiceFactoryInterface $serviceFactory,
    ) {}

    public function create(string $context): ServiceInterface
    {
        return match($context) {
          'special' => new SpecialService(),
          default => $this->serviceFactory->create($context),
        };
    }
}
```

we could provide a chain. How to use the decorator pattern with Symfony DI is the background for this example.

#### Symfony DI service decorator pattern - what is needed ?

[](#symfony-di-service-decorator-pattern---what-is-needed-)

From the TYPO3 Core side (or a extension providing this) following basic parts are needed:

- `ServiceInterface`: Define the required methods and helps with type declaration
- `ServiceFactoryInterface`: Define the factory method with context data, for example `ServiceFactoryInterface->create(string $context): ServiceInterface;`
- `DefaultService` implementing the `ServiceInterface` is the default service.
- `DefaultServiceFactory` implementing the `ServiceFactoryInterface` is the default service factory retrieved for the `ServiceFactoryInterface` -

Implementation of the aforementioned requirement are explained in detail in next sections.

Based on that, extension authors would

- implement a custom service based on `ServiceInterface` =&gt; `CustomService`
- implement a custom service factory based on the `ServiceFactoryInterface`, configured as decorator for the default service factory implementation `DefaultServiceFactory`

The example implementation for extension authors are also explained later.

Note that default extension `Configuration/Services.yaml` snippet is assumed for explained explanation using Symfony PHP attributes:

```
services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false

  SBUERK\DiTests\:
    resource: '../Classes/*'
```

Readup:

- [Symfony ServiceContainer: How to Decorate Services](https://symfony.com/doc/current/service_container/service_decoration.html)

##### BASE: ServiceInterface

[](#base-serviceinterface)

The service interface defines the required public facing methods all services requires to implement, for the demonstration purpose a simple `ping()` method:

```
