Skip to content

Instantly share code, notes, and snippets.

@milo
Created October 3, 2018 13:56
Show Gist options
  • Save milo/94313f1cf9a5c4c499cd1cd173df5984 to your computer and use it in GitHub Desktop.
Save milo/94313f1cf9a5c4c499cd1cd173df5984 to your computer and use it in GitHub Desktop.
Nette DI service collections
<?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