-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[DI] Add "PHP fluent format" for configuring the container #23834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\DependencyInjection\Loader\Configurator; | ||
|
||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; | ||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | ||
use Symfony\Component\DependencyInjection\Parameter; | ||
use Symfony\Component\DependencyInjection\Reference; | ||
use Symfony\Component\ExpressionLanguage\Expression; | ||
|
||
abstract class AbstractConfigurator | ||
{ | ||
const FACTORY = 'unknown'; | ||
|
||
public function __call($method, $args) | ||
{ | ||
if (method_exists($this, 'set'.$method)) { | ||
return call_user_func_array(array($this, 'set'.$method), $args); | ||
} | ||
|
||
throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', get_class($this), $method)); | ||
} | ||
|
||
/** | ||
* Checks that a value is valid, optionally replacing Definition and Reference configurators by their configure value. | ||
* | ||
* @param mixed $value | ||
* @param bool $allowServices whether Definition and Reference are allowed; by default, only scalars and arrays are | ||
* | ||
* @return mixed the value, optionaly cast to a Definition/Reference | ||
*/ | ||
public static function processValue($value, $allowServices = false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any usage where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should it be protected? |
||
{ | ||
if (is_array($value)) { | ||
foreach ($value as $k => $v) { | ||
$value[$k] = static::processValue($v, $allowServices); | ||
} | ||
|
||
return $value; | ||
} | ||
|
||
if ($value instanceof ReferenceConfigurator) { | ||
static $refCast; | ||
|
||
if (!$refCast) { | ||
$refCast = \Closure::bind(function ($value) { | ||
return new Reference($value->id, $value->invalidBehavior); | ||
}, null, $value); | ||
} | ||
|
||
// cast ReferenceConfigurator to Reference | ||
return $refCast($value); | ||
} | ||
|
||
if ($value instanceof InlineServiceConfigurator) { | ||
static $defCast; | ||
|
||
if (!$defCast) { | ||
$defCast = \Closure::bind(function ($value) { | ||
$def = $value->definition; | ||
$value->definition = null; | ||
|
||
return $def; | ||
}, null, $value); | ||
} | ||
|
||
// cast InlineServiceConfigurator to Definition | ||
return $defCast($value); | ||
} | ||
|
||
if ($value instanceof self) { | ||
throw new InvalidArgumentException(sprintf('"%s()" can be used only at the root of service configuration files.', $value::FACTORY)); | ||
} | ||
|
||
switch (true) { | ||
case null === $value: | ||
case is_scalar($value): | ||
return $value; | ||
|
||
case $value instanceof ArgumentInterface: | ||
case $value instanceof Definition: | ||
case $value instanceof Expression: | ||
case $value instanceof Parameter: | ||
case $value instanceof Reference: | ||
if ($allowServices) { | ||
return $value; | ||
} | ||
} | ||
|
||
throw new InvalidArgumentException(sprintf('Cannot use values of type "%s" in service configuration files.', is_object($value) ? get_class($value) : gettype($value))); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\DependencyInjection\Loader\Configurator; | ||
|
||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; | ||
|
||
abstract class AbstractServiceConfigurator extends AbstractConfigurator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @author tags are not required. |
||
{ | ||
protected $parent; | ||
protected $definition; | ||
protected $id; | ||
protected $defaultTags = array(); | ||
|
||
public function __construct(ServicesConfigurator $parent, Definition $definition, $id = null, array $defaultTags = array()) | ||
{ | ||
$this->parent = $parent; | ||
$this->definition = $definition; | ||
$this->id = $id; | ||
$this->defaultTags = $defaultTags; | ||
} | ||
|
||
public function __destruct() | ||
{ | ||
// default tags should be added last | ||
foreach ($this->defaultTags as $name => $attributes) { | ||
foreach ($attributes as $attributes) { | ||
$this->definition->addTag($name, $attributes); | ||
} | ||
} | ||
$this->defaultTags = array(); | ||
} | ||
|
||
/** | ||
* Registers a service. | ||
* | ||
* @param string $id | ||
* @param string|null $class | ||
* | ||
* @return ServiceConfigurator | ||
*/ | ||
final public function set($id, $class = null) | ||
{ | ||
$this->__destruct(); | ||
|
||
return $this->parent->set($id, $class); | ||
} | ||
|
||
/** | ||
* Creates an alias. | ||
* | ||
* @param string $id | ||
* @param string $ref | ||
* | ||
* @return AliasConfigurator | ||
*/ | ||
final public function alias($id, $referencedId) | ||
{ | ||
$this->__destruct(); | ||
|
||
return $this->parent->alias($id, $referencedId); | ||
} | ||
|
||
/** | ||
* Registers a PSR-4 namespace using a glob pattern. | ||
* | ||
* @param string $namespace | ||
* @param string $resource | ||
* | ||
* @return PrototypeConfigurator | ||
*/ | ||
final public function load($namespace, $resource) | ||
{ | ||
$this->__destruct(); | ||
|
||
return $this->parent->load($namespace, $resource); | ||
} | ||
|
||
/** | ||
* Gets an already defined service definition. | ||
* | ||
* @param string $id | ||
* | ||
* @return ServiceConfigurator | ||
* | ||
* @throws ServiceNotFoundException if the service definition does not exist | ||
*/ | ||
final public function get($id) | ||
{ | ||
$this->__destruct(); | ||
|
||
return $this->parent->get($id); | ||
} | ||
|
||
/** | ||
* Registers a service. | ||
* | ||
* @param string $id | ||
* @param string|null $class | ||
* | ||
* @return ServiceConfigurator | ||
*/ | ||
final public function __invoke($id, $class = null) | ||
{ | ||
$this->__destruct(); | ||
|
||
return $this->parent->set($id, $class); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. $this-parent is defined as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch, parent is now a |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\DependencyInjection\Loader\Configurator; | ||
|
||
use Symfony\Component\DependencyInjection\Alias; | ||
|
||
/** | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
class AliasConfigurator extends AbstractServiceConfigurator | ||
{ | ||
const FACTORY = 'alias'; | ||
|
||
use Traits\PublicTrait; | ||
|
||
public function __construct(ServicesConfigurator $parent, Alias $alias) | ||
{ | ||
$this->parent = $parent; | ||
$this->definition = $alias; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\DependencyInjection\Loader\Configurator; | ||
|
||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument; | ||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Definition; | ||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; | ||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; | ||
use Symfony\Component\ExpressionLanguage\Expression; | ||
|
||
/** | ||
* @author Nicolas Grekas <p@tchwork.com> | ||
*/ | ||
class ContainerConfigurator extends AbstractConfigurator | ||
{ | ||
const FACTORY = 'container'; | ||
|
||
private $container; | ||
private $loader; | ||
private $instanceof; | ||
private $path; | ||
private $file; | ||
|
||
public function __construct(ContainerBuilder $container, PhpFileLoader $loader, &$instanceof, $path, $file) | ||
{ | ||
$this->container = $container; | ||
$this->loader = $loader; | ||
$this->instanceof = &$instanceof; | ||
$this->path = $path; | ||
$this->file = $file; | ||
} | ||
|
||
final public function extension($namespace, array $config) | ||
{ | ||
if (!$this->container->hasExtension($namespace)) { | ||
$extensions = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions())); | ||
throw new InvalidArgumentException(sprintf( | ||
'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s', | ||
$namespace, | ||
$this->file, | ||
$namespace, | ||
$extensions ? sprintf('"%s"', implode('", "', $extensions)) : 'none' | ||
)); | ||
} | ||
|
||
$this->container->loadFromExtension($namespace, static::processValue($config)); | ||
} | ||
|
||
final public function import($resource, $type = null, $ignoreErrors = false) | ||
{ | ||
$this->loader->setCurrentDir(dirname($this->path)); | ||
$this->loader->import($resource, $type, $ignoreErrors, $this->file); | ||
} | ||
|
||
/** | ||
* @return ParametersConfigurator | ||
*/ | ||
public function parameters() | ||
{ | ||
return new ParametersConfigurator($this->container); | ||
} | ||
|
||
/** | ||
* @return ServicesConfigurator | ||
*/ | ||
public function services() | ||
{ | ||
return new ServicesConfigurator($this->container, $this->loader, $this->instanceof); | ||
} | ||
} | ||
|
||
/** | ||
* Creates a service reference. | ||
* | ||
* @param string $id | ||
* | ||
* @return ReferenceConfigurator | ||
*/ | ||
function ref($id) | ||
{ | ||
return new ReferenceConfigurator($id); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to keep the functions? If functions aren't the official way of doing things, nobody will use them. So I'd prefer less options things to maintain, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see #23834 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I disagree with keeping them, but not very heavily. So it's ok for me :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would remove the functions as well :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with Ryan and Fabien. It's better to provide just one solution. |
||
|
||
/** | ||
* Creates an inline service. | ||
* | ||
* @param string|null $class | ||
* | ||
* @return InlineServiceConfigurator | ||
*/ | ||
function inline($class = null) | ||
{ | ||
return new InlineServiceConfigurator(new Definition($class)); | ||
} | ||
|
||
/** | ||
* Creates a lazy iterator. | ||
* | ||
* @param ReferenceConfigurator[] $values | ||
* | ||
* @return IteratorArgument | ||
*/ | ||
function iterator(array $values) | ||
{ | ||
return new IteratorArgument(AbstractConfigurator::processValue($values, true)); | ||
} | ||
|
||
/** | ||
* Creates an expression. | ||
* | ||
* @param string $expression an expression | ||
* | ||
* @return Expression | ||
*/ | ||
function expr($expression) | ||
{ | ||
return new Expression($expression); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing
@author
tag