Created
October 3, 2018 13:56
-
-
Save milo/94313f1cf9a5c4c499cd1cd173df5984 to your computer and use it in GitHub Desktop.
Nette DI service collections
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App; | |
use Nette\DI\CompilerExtension; | |
/** | |
* Nette DI extension (https://nette.org/). | |
* | |
* Creates collections of services in DI container. Usage in NEON: | |
* extensions: | |
* serviceCollections: App\ServiceCollectionsExtension | |
* | |
* serviceCollections: | |
* - MyInterfaceCollection | |
* - OtherClassCollection | |
* | |
* With such configuration, two new services of MyInterfaceCollection and OtherClassCollection type are created. | |
* By convention, they must declare add() method with one typed parameter. A type of this parameter is taken and | |
* every service from DI container of the type is passed to add() method in setup phase. | |
*/ | |
class ServiceCollectionsExtension extends CompilerExtension | |
{ | |
private const METHOD = 'add'; | |
/** @var string[] */ | |
private $services = []; | |
public function loadConfiguration() | |
{ | |
$config = $this->getConfig(); | |
$builder = $this->getContainerBuilder(); | |
foreach ($config as $key => $class) { | |
if (!class_exists($class)) { | |
throw new \LogicException("Cannot create service collection. Collection class '$class' does not exist."); | |
} | |
$rc = new \ReflectionClass($class); | |
if (!$rc->hasMethod(self::METHOD)) { | |
throw new \LogicException("Cannot create service collection. Missing '$class::" . self::METHOD . "()' method."); | |
} | |
$params = $rc->getMethod(self::METHOD)->getParameters(); | |
if (count($params) !== 1) { | |
throw new \LogicException("Cannot create service collection. Method '$class::" . self::METHOD . "()' must have exactly one parameter, but has " . count($params) . '.'); | |
} elseif (!$params[0]->hasType()) { | |
throw new \LogicException("Cannot create service collection. Missing type of '$class::" . self::METHOD . "(\${$params[0]->getName()})' parameter."); | |
} elseif ($params[0]->getType()->isBuiltin()) { | |
throw new \LogicException("Cannot create service collection. Parameter '$class::" . self::METHOD . "(\${$params[0]->getName()})' has builtin type. It is not supported."); | |
} | |
$type = $params[0]->getType()->getName(); | |
$builder | |
->addDefinition($name = $this->prefix($key)) | |
->setFactory($class); | |
$this->services[$name] = $type; | |
} | |
} | |
public function beforeCompile() | |
{ | |
$builder = $this->getContainerBuilder(); | |
foreach ($this->services as $name => $type) { | |
$service = $builder->getDefinition($name); | |
foreach ($builder->findByType($type) as $add) { | |
$service->addSetup(self::METHOD, [$add]); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment