8000 [DI] Allow using a class factory · Issue #23819 · symfony/symfony · GitHub 647F
[go: up one dir, main page]

Skip to content
[DI] Allow using a class factory #23819
Closed
@GuilhemN

Description

@GuilhemN
Q A
Bug report? no
Feature request? yes
BC Break report? no
RFC? yes
Symfony version 3.4

Here's a proposal coming mostly from @nicolas-grekas (I helped a bit making the example :)).
Would you like to be able use a class factory to define your services?

Main benefits:

  • service names based on the methods return type (or @Alias)
  • arguments injection based on autowiring
  • access to php functions at runtime (no need anymore of the expression language), that also means access to getenv()
  • possibility to manually inline simple services

An example of how it could be used:

// services.yaml
imports:
    - type: service_factory
      resource: App\MyServicesFactory
// src/MyServicesFactory.php
<?php

namespace App;

use App\Entity\Product;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Psr\Logger\LoggerInterface;

class MyServicesFactory
{
    private static $apiKey = 'foo';
    private $database;

    public function __construct()
    {
        // Constructor called with *no* argument
    }

    /**
     * @Tag(name="monolog.logger", channel="my_channel")
     * @Alias(id="my_service")
     * @Alias // when used with no id, the return type is used
     * @Param("strategies", tag="app.strategies")
     * 
     * @param StrategyInterface[] $strategies // it's the responsibility of a DI extension to populate this
     */
    public function myService(LoggerInterface $logger, iterable $strategies): MyServiceInterface
    {
      	$myService = new MyService($logger);
      	$myService->setSecret(self::$apiKey); // the service can be easily configured
      	$myService->setSecret(getenv('API_KEY')); // even dynamically
      	foreach ($strategies as $strategy) {
            $myService->addStrategy();
     	}

    	// Less flexible than an injected dep, but still a nice shortcut for private apps
        // benefits from type hinting (return type vs argument type can be verified by IDEs)
      	$myService->setDatabase($this->myDatabase()); 
  
      	return $myService;
    }

    /**
     * ExpressionLanguage not needed anymore.
     */
    public function myController(MyService $myService, Repository $doctrine): MyController
    {
      	return new MyController($myService, $doctrine->getRepository(Product::class));
    }

    protected function myDatabase(): DatabaseInterface
    {
      	return $this->database ?? $this->database = new Database('dns://...');
    }
}

Wdyt? This could be an alternative to #22407.

< 56A0 div>

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0