initial commit
This commit is contained in:
2
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/.gitignore
vendored
Normal file
2
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
71
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Alias.php
vendored
Normal file
71
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Alias.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
class Alias
|
||||
{
|
||||
private $id;
|
||||
private $public;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $id Alias identifier
|
||||
* @param Boolean $public If this alias is public
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($id, $public = true)
|
||||
{
|
||||
$this->id = strtolower($id);
|
||||
$this->public = $public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this DI Alias should be public or not.
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isPublic()
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this Alias is public.
|
||||
*
|
||||
* @param Boolean $boolean If this Alias should be public
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setPublic($boolean)
|
||||
{
|
||||
$this->public = (Boolean) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id of this alias.
|
||||
*
|
||||
* @return string The alias id
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
15
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/CHANGELOG.md
vendored
Normal file
15
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added IntrospectableContainerInterface (to be able to check if a service
|
||||
has been initialized or not)
|
||||
* added ConfigurationExtensionInterface
|
||||
* added Definition::clearTag()
|
||||
* component exceptions that inherit base SPL classes are now used exclusively
|
||||
(this includes dumped containers)
|
||||
* [BC BREAK] fixed unescaping of class arguments, method
|
||||
ParameterBag::unescapeValue() was made public
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Run this pass before passes that need to know more about the relation of
|
||||
* your services.
|
||||
*
|
||||
* This class will populate the ServiceReferenceGraph with information. You can
|
||||
* retrieve the graph in other passes from the compiler.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class AnalyzeServiceReferencesPass implements RepeatablePassInterface
|
||||
{
|
||||
private $graph;
|
||||
private $container;
|
||||
private $currentId;
|
||||
private $currentDefinition;
|
||||
private $repeatedPass;
|
||||
private $onlyConstructorArguments;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Boolean $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
|
||||
*/
|
||||
public function __construct($onlyConstructorArguments = false)
|
||||
{
|
||||
$this->onlyConstructorArguments = (Boolean) $onlyConstructorArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setRepeatedPass(RepeatedPass $repeatedPass)
|
||||
{
|
||||
$this->repeatedPass = $repeatedPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a ContainerBuilder object to populate the service reference graph.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->graph = $container->getCompiler()->getServiceReferenceGraph();
|
||||
$this->graph->clear();
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isSynthetic() || $definition->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->currentId = $id;
|
||||
$this->currentDefinition = $definition;
|
||||
$this->processArguments($definition->getArguments());
|
||||
|
||||
if (!$this->onlyConstructorArguments) {
|
||||
$this->processArguments($definition->getMethodCalls());
|
||||
$this->processArguments($definition->getProperties());
|
||||
if ($definition->getConfigurator()) {
|
||||
$this->processArguments(array($definition->getConfigurator()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
$this->graph->connect($id, $alias, (string) $alias, $this->getDefinition((string) $alias), null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes service definitions for arguments to find relationships for the service graph.
|
||||
*
|
||||
* @param array $arguments An array of Reference or Definition objects relating to service definitions
|
||||
*/
|
||||
private function processArguments(array $arguments)
|
||||
{
|
||||
foreach ($arguments as $argument) {
|
||||
if (is_array($argument)) {
|
||||
$this->processArguments($argument);
|
||||
} elseif ($argument instanceof Reference) {
|
||||
$this->graph->connect(
|
||||
$this->currentId,
|
||||
$this->currentDefinition,
|
||||
$this->getDefinitionId((string) $argument),
|
||||
$this->getDefinition((string) $argument),
|
||||
$argument
|
||||
);
|
||||
} elseif ($argument instanceof Definition) {
|
||||
$this->processArguments($argument->getArguments());
|
||||
$this->processArguments($argument->getMethodCalls());
|
||||
$this->processArguments($argument->getProperties());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a service definition given the full name or an alias.
|
||||
*
|
||||
* @param string $id A full id or alias for a service definition.
|
||||
*
|
||||
* @return Definition|null The definition related to the supplied id
|
||||
*/
|
||||
private function getDefinition($id)
|
||||
{
|
||||
$id = $this->getDefinitionId($id);
|
||||
|
||||
return null === $id ? null : $this->container->getDefinition($id);
|
||||
}
|
||||
|
||||
private function getDefinitionId($id)
|
||||
{
|
||||
while ($this->container->hasAlias($id)) {
|
||||
$id = (string) $this->container->getAlias($id);
|
||||
}
|
||||
|
||||
if (!$this->container->hasDefinition($id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Checks your services for circular references
|
||||
*
|
||||
* References from method calls are ignored since we might be able to resolve
|
||||
* these references depending on the order in which services are called.
|
||||
*
|
||||
* Circular reference from method calls will only be detected at run-time.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckCircularReferencesPass implements CompilerPassInterface
|
||||
{
|
||||
private $currentId;
|
||||
private $currentPath;
|
||||
|
||||
/**
|
||||
* Checks the ContainerBuilder object for circular references.
|
||||
*
|
||||
* @param ContainerBuilder $container The ContainerBuilder instances
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$graph = $container->getCompiler()->getServiceReferenceGraph();
|
||||
|
||||
foreach ($graph->getNodes() as $id => $node) {
|
||||
$this->currentId = $id;
|
||||
$this->currentPath = array($id);
|
||||
|
||||
$this->checkOutEdges($node->getOutEdges());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for circular references.
|
||||
*
|
||||
* @param array $edges An array of Nodes
|
||||
*
|
||||
* @throws ServiceCircularReferenceException When a circular reference is found.
|
||||
*/
|
||||
private function checkOutEdges(array $edges)
|
||||
{
|
||||
foreach ($edges as $edge) {
|
||||
$node = $edge->getDestNode();
|
||||
$this->currentPath[] = $id = $node->getId();
|
||||
|
||||
if ($this->currentId === $id) {
|
||||
throw new ServiceCircularReferenceException($this->currentId, $this->currentPath);
|
||||
}
|
||||
|
||||
$this->checkOutEdges($node->getOutEdges());
|
||||
array_pop($this->currentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* This pass validates each definition individually only taking the information
|
||||
* into account which is contained in the definition itself.
|
||||
*
|
||||
* Later passes can rely on the following, and specifically do not need to
|
||||
* perform these checks themselves:
|
||||
*
|
||||
* - non synthetic, non abstract services always have a class set
|
||||
* - synthetic services are always public
|
||||
* - synthetic services are always of non-prototype scope
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckDefinitionValidityPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Processes the ContainerBuilder to validate the Definition.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*
|
||||
* @throws RuntimeException When the Definition is invalid
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
// synthetic service is public
|
||||
if ($definition->isSynthetic() && !$definition->isPublic()) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'A synthetic service ("%s") must be public.',
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
// synthetic service has non-prototype scope
|
||||
if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'A synthetic service ("%s") cannot be of scope "prototype".',
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
// non-synthetic, non-abstract service has class
|
||||
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
|
||||
if ($definition->getFactoryClass() || $definition->getFactoryService()) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'Please add the class to service "%s" even if it is constructed by a factory '
|
||||
.'since we might need to add method calls based on compile-time checks.',
|
||||
$id
|
||||
));
|
||||
}
|
||||
|
||||
throw new RuntimeException(sprintf(
|
||||
'The definition for "%s" has no class. If you intend to inject '
|
||||
.'this service dynamically at runtime, please mark it as synthetic=true. '
|
||||
.'If this is an abstract definition solely used by child definitions, '
|
||||
.'please add abstract=true, otherwise specify a class to get rid of this error.',
|
||||
$id
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Checks that all references are pointing to a valid service.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckExceptionOnInvalidReferenceBehaviorPass implements CompilerPassInterface
|
||||
{
|
||||
private $container;
|
||||
private $sourceId;
|
||||
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$this->sourceId = $id;
|
||||
$this->processDefinition($definition);
|
||||
}
|
||||
}
|
||||
|
||||
private function processDefinition(Definition $definition)
|
||||
{
|
||||
$this->processReferences($definition->getArguments());
|
||||
$this->processReferences($definition->getMethodCalls());
|
||||
$this->processReferences($definition->getProperties());
|
||||
}
|
||||
|
||||
private function processReferences(array $arguments)
|
||||
{
|
||||
foreach ($arguments as $argument) {
|
||||
if (is_array($argument)) {
|
||||
$this->processReferences($argument);
|
||||
} elseif ($argument instanceof Definition) {
|
||||
$this->processDefinition($argument);
|
||||
} elseif ($argument instanceof Reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $argument->getInvalidBehavior()) {
|
||||
$destId = (string) $argument;
|
||||
|
||||
if (!$this->container->has($destId)) {
|
||||
throw new ServiceNotFoundException($destId, $this->sourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ScopeCrossingInjectionException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ScopeWideningInjectionException;
|
||||
|
||||
/**
|
||||
* Checks the validity of references
|
||||
*
|
||||
* The following checks are performed by this pass:
|
||||
* - target definitions are not abstract
|
||||
* - target definitions are of equal or wider scope
|
||||
* - target definitions are in the same scope hierarchy
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class CheckReferenceValidityPass implements CompilerPassInterface
|
||||
{
|
||||
private $container;
|
||||
private $currentId;
|
||||
private $currentDefinition;
|
||||
private $currentScope;
|
||||
private $currentScopeAncestors;
|
||||
private $currentScopeChildren;
|
||||
|
||||
/**
|
||||
* Processes the ContainerBuilder to validate References.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
$children = $this->container->getScopeChildren();
|
||||
$ancestors = array();
|
||||
|
||||
$scopes = $this->container->getScopes();
|
||||
foreach ($scopes as $name => $parent) {
|
||||
$ancestors[$name] = array($parent);
|
||||
|
||||
while (isset($scopes[$parent])) {
|
||||
$ancestors[$name][] = $parent = $scopes[$parent];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isSynthetic() || $definition->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->currentId = $id;
|
||||
$this->currentDefinition = $definition;
|
||||
$this->currentScope = $scope = $definition->getScope();
|
||||
|
||||
if (ContainerInterface::SCOPE_CONTAINER === $scope) {
|
||||
$this->currentScopeChildren = array_keys($scopes);
|
||||
$this->currentScopeAncestors = array();
|
||||
} elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
|
||||
$this->currentScopeChildren = $children[$scope];
|
||||
$this->currentScopeAncestors = $ancestors[$scope];
|
||||
}
|
||||
|
||||
$this->validateReferences($definition->getArguments());
|
||||
$this->validateReferences($definition->getMethodCalls());
|
||||
$this->validateReferences($definition->getProperties());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an array of References.
|
||||
*
|
||||
* @param array $arguments An array of Reference objects
|
||||
*
|
||||
* @throws RuntimeException when there is a reference to an abstract definition.
|
||||
*/
|
||||
private function validateReferences(array $arguments)
|
||||
{
|
||||
foreach ($arguments as $argument) {
|
||||
if (is_array($argument)) {
|
||||
$this->validateReferences($argument);
|
||||
} elseif ($argument instanceof Reference) {
|
||||
$targetDefinition = $this->getDefinition((string) $argument);
|
||||
|
||||
if (null !== $targetDefinition && $targetDefinition->isAbstract()) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'The definition "%s" has a reference to an abstract definition "%s". '
|
||||
.'Abstract definitions cannot be the target of references.',
|
||||
$this->currentId,
|
||||
$argument
|
||||
));
|
||||
}
|
||||
|
||||
$this->validateScope($argument, $targetDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the scope of a single Reference.
|
||||
*
|
||||
* @param Reference $reference
|
||||
* @param Definition $definition
|
||||
*
|
||||
* @throws ScopeWideningInjectionException when the definition references a service of a narrower scope
|
||||
* @throws ScopeCrossingInjectionException when the definition references a service of another scope hierarchy
|
||||
*/
|
||||
private function validateScope(Reference $reference, Definition $definition = null)
|
||||
{
|
||||
if (ContainerInterface::SCOPE_PROTOTYPE === $this->currentScope) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$reference->isStrict()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $definition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->currentScope === $scope = $definition->getScope()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id = (string) $reference;
|
||||
|
||||
if (in_array($scope, $this->currentScopeChildren, true)) {
|
||||
throw new ScopeWideningInjectionException($this->currentId, $this->currentScope, $id, $scope);
|
||||
}
|
||||
|
||||
if (!in_array($scope, $this->currentScopeAncestors, true)) {
|
||||
throw new ScopeCrossingInjectionException($this->currentId, $this->currentScope, $id, $scope);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Definition given an id.
|
||||
*
|
||||
* @param string $id Definition identifier
|
||||
*
|
||||
* @return Definition
|
||||
*/
|
||||
private function getDefinition($id)
|
||||
{
|
||||
if (!$this->container->hasDefinition($id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->container->getDefinition($id);
|
||||
}
|
||||
}
|
||||
122
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/Compiler.php
vendored
Normal file
122
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/Compiler.php
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
|
||||
/**
|
||||
* This class is used to remove circular dependencies between individual passes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Compiler
|
||||
{
|
||||
private $passConfig;
|
||||
private $log;
|
||||
private $loggingFormatter;
|
||||
private $serviceReferenceGraph;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->passConfig = new PassConfig();
|
||||
$this->serviceReferenceGraph = new ServiceReferenceGraph();
|
||||
$this->loggingFormatter = new LoggingFormatter();
|
||||
$this->log = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PassConfig.
|
||||
*
|
||||
* @return PassConfig The PassConfig instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getPassConfig()
|
||||
{
|
||||
return $this->passConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ServiceReferenceGraph.
|
||||
*
|
||||
* @return ServiceReferenceGraph The ServiceReferenceGraph instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getServiceReferenceGraph()
|
||||
{
|
||||
return $this->serviceReferenceGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logging formatter which can be used by compilation passes.
|
||||
*
|
||||
* @return LoggingFormatter
|
||||
*/
|
||||
public function getLoggingFormatter()
|
||||
{
|
||||
return $this->loggingFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pass to the PassConfig.
|
||||
*
|
||||
* @param CompilerPassInterface $pass A compiler pass
|
||||
* @param string $type The type of the pass
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
|
||||
{
|
||||
$this->passConfig->addPass($pass, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a log message.
|
||||
*
|
||||
* @param string $string The log message
|
||||
*/
|
||||
public function addLogMessage($string)
|
||||
{
|
||||
$this->log[] = $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the log.
|
||||
*
|
||||
* @return array Log array
|
||||
*/
|
||||
public function getLog()
|
||||
{
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the Compiler and process all Passes.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function compile(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($this->passConfig->getPasses() as $pass) {
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by compilation passes
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* You can modify the container here before it is dumped to PHP code.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function process(ContainerBuilder $container);
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Inline service definitions where this is possible.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class InlineServiceDefinitionsPass implements RepeatablePassInterface
|
||||
{
|
||||
private $repeatedPass;
|
||||
private $graph;
|
||||
private $compiler;
|
||||
private $formatter;
|
||||
private $currentId;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setRepeatedPass(RepeatedPass $repeatedPass)
|
||||
{
|
||||
$this->repeatedPass = $repeatedPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the ContainerBuilder for inline service definitions.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->compiler = $container->getCompiler();
|
||||
$this->formatter = $this->compiler->getLoggingFormatter();
|
||||
$this->graph = $this->compiler->getServiceReferenceGraph();
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$this->currentId = $id;
|
||||
|
||||
$definition->setArguments(
|
||||
$this->inlineArguments($container, $definition->getArguments())
|
||||
);
|
||||
|
||||
$definition->setMethodCalls(
|
||||
$this->inlineArguments($container, $definition->getMethodCalls())
|
||||
);
|
||||
|
||||
$definition->setProperties(
|
||||
$this->inlineArguments($container, $definition->getProperties())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes inline arguments.
|
||||
*
|
||||
* @param ContainerBuilder $container The ContainerBuilder
|
||||
* @param array $arguments An array of arguments
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function inlineArguments(ContainerBuilder $container, array $arguments)
|
||||
{
|
||||
foreach ($arguments as $k => $argument) {
|
||||
if (is_array($argument)) {
|
||||
$arguments[$k] = $this->inlineArguments($container, $argument);
|
||||
} elseif ($argument instanceof Reference) {
|
||||
if (!$container->hasDefinition($id = (string) $argument)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) {
|
||||
$this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));
|
||||
|
||||
if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
|
||||
$arguments[$k] = $definition;
|
||||
} else {
|
||||
$arguments[$k] = clone $definition;
|
||||
}
|
||||
}
|
||||
} elseif ($argument instanceof Definition) {
|
||||
$argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
|
||||
$argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
|
||||
$argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the definition is inlineable.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
* @param string $id
|
||||
* @param Definition $definition
|
||||
*
|
||||
* @return Boolean If the definition is inlineable
|
||||
*/
|
||||
private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
|
||||
{
|
||||
if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($definition->isPublic()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->graph->hasNode($id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
|
||||
$ids[] = $edge->getSourceNode()->getId();
|
||||
}
|
||||
|
||||
if (count(array_unique($ids)) > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $container->getDefinition(reset($ids))->getScope() === $definition->getScope();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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\Compiler;
|
||||
|
||||
/**
|
||||
* Used to format logging messages during the compilation.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class LoggingFormatter
|
||||
{
|
||||
public function formatRemoveService(CompilerPassInterface $pass, $id, $reason)
|
||||
{
|
||||
return $this->format($pass, sprintf('Removed service "%s"; reason: %s', $id, $reason));
|
||||
}
|
||||
|
||||
public function formatInlineService(CompilerPassInterface $pass, $id, $target)
|
||||
{
|
||||
return $this->format($pass, sprintf('Inlined service "%s" to "%s".', $id, $target));
|
||||
}
|
||||
|
||||
public function formatUpdateReference(CompilerPassInterface $pass, $serviceId, $oldDestId, $newDestId)
|
||||
{
|
||||
return $this->format($pass, sprintf('Changed reference of service "%s" previously pointing to "%s" to "%s".', $serviceId, $oldDestId, $newDestId));
|
||||
}
|
||||
|
||||
public function formatResolveInheritance(CompilerPassInterface $pass, $childId, $parentId)
|
||||
{
|
||||
return $this->format($pass, sprintf('Resolving inheritance for "%s" (parent: %s).', $childId, $parentId));
|
||||
}
|
||||
|
||||
public function format(CompilerPassInterface $pass, $message)
|
||||
{
|
||||
return sprintf('%s: %s', get_class($pass), $message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Merges extension configs into the container builder
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class MergeExtensionConfigurationPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$parameters = $container->getParameterBag()->all();
|
||||
$definitions = $container->getDefinitions();
|
||||
$aliases = $container->getAliases();
|
||||
|
||||
foreach ($container->getExtensions() as $name => $extension) {
|
||||
if (!$config = $container->getExtensionConfig($name)) {
|
||||
// this extension was not called
|
||||
continue;
|
||||
}
|
||||
$config = $container->getParameterBag()->resolveValue($config);
|
||||
|
||||
$tmpContainer = new ContainerBuilder($container->getParameterBag());
|
||||
$tmpContainer->addObjectResource($extension);
|
||||
|
||||
$extension->load($config, $tmpContainer);
|
||||
|
||||
$container->merge($tmpContainer);
|
||||
}
|
||||
|
||||
$container->addDefinitions($definitions);
|
||||
$container->addAliases($aliases);
|
||||
$container->getParameterBag()->add($parameters);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Compiler Pass Configuration
|
||||
*
|
||||
* This class has a default configuration embedded.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class PassConfig
|
||||
{
|
||||
const TYPE_AFTER_REMOVING = 'afterRemoving';
|
||||
const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization';
|
||||
const TYPE_BEFORE_REMOVING = 'beforeRemoving';
|
||||
const TYPE_OPTIMIZE = 'optimization';
|
||||
const TYPE_REMOVE = 'removing';
|
||||
|
||||
private $mergePass;
|
||||
private $afterRemovingPasses;
|
||||
private $beforeOptimizationPasses;
|
||||
private $beforeRemovingPasses;
|
||||
private $optimizationPasses;
|
||||
private $removingPasses;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->mergePass = new MergeExtensionConfigurationPass();
|
||||
|
||||
$this->afterRemovingPasses = array();
|
||||
$this->beforeOptimizationPasses = array();
|
||||
$this->beforeRemovingPasses = array();
|
||||
|
||||
$this->optimizationPasses = array(
|
||||
new ResolveDefinitionTemplatesPass(),
|
||||
new ResolveParameterPlaceHoldersPass(),
|
||||
new CheckDefinitionValidityPass(),
|
||||
new ResolveReferencesToAliasesPass(),
|
||||
new ResolveInvalidReferencesPass(),
|
||||
new AnalyzeServiceReferencesPass(true),
|
||||
new CheckCircularReferencesPass(),
|
||||
new CheckReferenceValidityPass(),
|
||||
);
|
||||
|
||||
$this->removingPasses = array(
|
||||
new RemovePrivateAliasesPass(),
|
||||
new RemoveAbstractDefinitionsPass(),
|
||||
new ReplaceAliasByActualDefinitionPass(),
|
||||
new RepeatedPass(array(
|
||||
new AnalyzeServiceReferencesPass(),
|
||||
new InlineServiceDefinitionsPass(),
|
||||
new AnalyzeServiceReferencesPass(),
|
||||
new RemoveUnusedDefinitionsPass(),
|
||||
)),
|
||||
new CheckExceptionOnInvalidReferenceBehaviorPass(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all passes in order to be processed.
|
||||
*
|
||||
* @return array An array of all passes to process
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getPasses()
|
||||
{
|
||||
return array_merge(
|
||||
array($this->mergePass),
|
||||
$this->beforeOptimizationPasses,
|
||||
$this->optimizationPasses,
|
||||
$this->beforeRemovingPasses,
|
||||
$this->removingPasses,
|
||||
$this->afterRemovingPasses
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pass.
|
||||
*
|
||||
* @param CompilerPassInterface $pass A Compiler pass
|
||||
* @param string $type The pass type
|
||||
*
|
||||
* @throws InvalidArgumentException when a pass type doesn't exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION)
|
||||
{
|
||||
$property = $type.'Passes';
|
||||
if (!isset($this->$property)) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type));
|
||||
}
|
||||
|
||||
$passes = &$this->$property;
|
||||
$passes[] = $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the AfterRemoving pass.
|
||||
*
|
||||
* @return array An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getAfterRemovingPasses()
|
||||
{
|
||||
return $this->afterRemovingPasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the BeforeOptimization pass.
|
||||
*
|
||||
* @return array An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getBeforeOptimizationPasses()
|
||||
{
|
||||
return $this->beforeOptimizationPasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the BeforeRemoving pass.
|
||||
*
|
||||
* @return array An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getBeforeRemovingPasses()
|
||||
{
|
||||
return $this->beforeRemovingPasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the Optimization pass.
|
||||
*
|
||||
* @return array An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getOptimizationPasses()
|
||||
{
|
||||
return $this->optimizationPasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the Removing pass.
|
||||
*
|
||||
* @return array An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getRemovingPasses()
|
||||
{
|
||||
return $this->removingPasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all passes for the Merge pass.
|
||||
*
|
||||
* @return array An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getMergePass()
|
||||
{
|
||||
return $this->mergePass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Merge Pass.
|
||||
*
|
||||
* @param CompilerPassInterface $pass The merge pass
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setMergePass(CompilerPassInterface $pass)
|
||||
{
|
||||
$this->mergePass = $pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the AfterRemoving passes.
|
||||
*
|
||||
* @param array $passes An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setAfterRemovingPasses(array $passes)
|
||||
{
|
||||
$this->afterRemovingPasses = $passes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BeforeOptimization passes.
|
||||
*
|
||||
* @param array $passes An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setBeforeOptimizationPasses(array $passes)
|
||||
{
|
||||
$this->beforeOptimizationPasses = $passes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the BeforeRemoving passes.
|
||||
*
|
||||
* @param array $passes An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setBeforeRemovingPasses(array $passes)
|
||||
{
|
||||
$this->beforeRemovingPasses = $passes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Optimization passes.
|
||||
*
|
||||
* @param array $passes An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setOptimizationPasses(array $passes)
|
||||
{
|
||||
$this->optimizationPasses = $passes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Removing passes.
|
||||
*
|
||||
* @param array $passes An array of passes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setRemovingPasses(array $passes)
|
||||
{
|
||||
$this->removingPasses = $passes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Removes abstract Definitions
|
||||
*
|
||||
*/
|
||||
class RemoveAbstractDefinitionsPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Removes abstract definitions from the ContainerBuilder
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$compiler = $container->getCompiler();
|
||||
$formatter = $compiler->getLoggingFormatter();
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isAbstract()) {
|
||||
$container->removeDefinition($id);
|
||||
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'abstract'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Remove private aliases from the container. They were only used to establish
|
||||
* dependencies between services, and these dependencies have been resolved in
|
||||
* one of the previous passes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RemovePrivateAliasesPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Removes private aliases from the ContainerBuilder
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$compiler = $container->getCompiler();
|
||||
$formatter = $compiler->getLoggingFormatter();
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
if ($alias->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$container->removeAlias($id);
|
||||
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'private alias'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Removes unused service definitions from the container.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RemoveUnusedDefinitionsPass implements RepeatablePassInterface
|
||||
{
|
||||
private $repeatedPass;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setRepeatedPass(RepeatedPass $repeatedPass)
|
||||
{
|
||||
$this->repeatedPass = $repeatedPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the ContainerBuilder to remove unused definitions.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$compiler = $container->getCompiler();
|
||||
$formatter = $compiler->getLoggingFormatter();
|
||||
$graph = $compiler->getServiceReferenceGraph();
|
||||
|
||||
$hasChanged = false;
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($graph->hasNode($id)) {
|
||||
$edges = $graph->getNode($id)->getInEdges();
|
||||
$referencingAliases = array();
|
||||
$sourceIds = array();
|
||||
foreach ($edges as $edge) {
|
||||
$node = $edge->getSourceNode();
|
||||
$sourceIds[] = $node->getId();
|
||||
|
||||
if ($node->isAlias()) {
|
||||
$referencingAliases[] = $node->getValue();
|
||||
}
|
||||
}
|
||||
$isReferenced = (count(array_unique($sourceIds)) - count($referencingAliases)) > 0;
|
||||
} else {
|
||||
$referencingAliases = array();
|
||||
$isReferenced = false;
|
||||
}
|
||||
|
||||
if (1 === count($referencingAliases) && false === $isReferenced) {
|
||||
$container->setDefinition((string) reset($referencingAliases), $definition);
|
||||
$definition->setPublic(true);
|
||||
$container->removeDefinition($id);
|
||||
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'replaces alias '.reset($referencingAliases)));
|
||||
} elseif (0 === count($referencingAliases) && false === $isReferenced) {
|
||||
$container->removeDefinition($id);
|
||||
$compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'unused'));
|
||||
$hasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasChanged) {
|
||||
$this->repeatedPass->setRepeat();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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\Compiler;
|
||||
|
||||
/**
|
||||
* Interface that must be implemented by passes that are run as part of an
|
||||
* RepeatedPass.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface RepeatablePassInterface extends CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Sets the RepeatedPass interface.
|
||||
*
|
||||
* @param RepeatedPass $repeatedPass
|
||||
*/
|
||||
public function setRepeatedPass(RepeatedPass $repeatedPass);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* A pass that might be run repeatedly.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RepeatedPass implements CompilerPassInterface
|
||||
{
|
||||
private $repeat;
|
||||
private $passes;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $passes An array of RepeatablePassInterface objects
|
||||
*
|
||||
* @throws InvalidArgumentException when the passes don't implement RepeatablePassInterface
|
||||
*/
|
||||
public function __construct(array $passes)
|
||||
{
|
||||
foreach ($passes as $pass) {
|
||||
if (!$pass instanceof RepeatablePassInterface) {
|
||||
throw new InvalidArgumentException('$passes must be an array of RepeatablePassInterface.');
|
||||
}
|
||||
|
||||
$pass->setRepeatedPass($this);
|
||||
}
|
||||
|
||||
$this->passes = $passes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the repeatable passes that run more than once.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->repeat = false;
|
||||
foreach ($this->passes as $pass) {
|
||||
$pass->process($container);
|
||||
}
|
||||
|
||||
if ($this->repeat) {
|
||||
$this->process($container);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the pass should repeat
|
||||
*/
|
||||
public function setRepeat()
|
||||
{
|
||||
$this->repeat = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the passes
|
||||
*
|
||||
* @return array An array of RepeatablePassInterface objects
|
||||
*/
|
||||
public function getPasses()
|
||||
{
|
||||
return $this->passes;
|
||||
}
|
||||
}
|
||||
@@ -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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Replaces aliases with actual service definitions, effectively removing these
|
||||
* aliases.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
|
||||
{
|
||||
private $compiler;
|
||||
private $formatter;
|
||||
private $sourceId;
|
||||
|
||||
/**
|
||||
* Process the Container to replace aliases with service definitions.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->compiler = $container->getCompiler();
|
||||
$this->formatter = $this->compiler->getLoggingFormatter();
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
$aliasId = (string) $alias;
|
||||
|
||||
$definition = $container->getDefinition($aliasId);
|
||||
|
||||
if ($definition->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition->setPublic(true);
|
||||
$container->setDefinition($id, $definition);
|
||||
$container->removeDefinition($aliasId);
|
||||
|
||||
$this->updateReferences($container, $aliasId, $id);
|
||||
|
||||
// we have to restart the process due to concurrent modification of
|
||||
// the container
|
||||
$this->process($container);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates references to remove aliases.
|
||||
*
|
||||
* @param ContainerBuilder $container The container
|
||||
* @param string $currentId The alias identifier being replaced
|
||||
* @param string $newId The id of the service the alias points to
|
||||
*/
|
||||
private function updateReferences($container, $currentId, $newId)
|
||||
{
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
if ($currentId === (string) $alias) {
|
||||
$container->setAlias($id, $newId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$this->sourceId = $id;
|
||||
|
||||
$definition->setArguments(
|
||||
$this->updateArgumentReferences($definition->getArguments(), $currentId, $newId)
|
||||
);
|
||||
|
||||
$definition->setMethodCalls(
|
||||
$this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId)
|
||||
);
|
||||
|
||||
$definition->setProperties(
|
||||
$this->updateArgumentReferences($definition->getProperties(), $currentId, $newId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates argument references.
|
||||
*
|
||||
* @param array $arguments An array of Arguments
|
||||
* @param string $currentId The alias identifier
|
||||
* @param string $newId The identifier the alias points to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function updateArgumentReferences(array $arguments, $currentId, $newId)
|
||||
{
|
||||
foreach ($arguments as $k => $argument) {
|
||||
if (is_array($argument)) {
|
||||
$arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId);
|
||||
} elseif ($argument instanceof Reference) {
|
||||
if ($currentId === (string) $argument) {
|
||||
$arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
|
||||
$this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* This replaces all DefinitionDecorator instances with their equivalent fully
|
||||
* merged Definition instance.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ResolveDefinitionTemplatesPass implements CompilerPassInterface
|
||||
{
|
||||
private $container;
|
||||
private $compiler;
|
||||
private $formatter;
|
||||
|
||||
/**
|
||||
* Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->compiler = $container->getCompiler();
|
||||
$this->formatter = $this->compiler->getLoggingFormatter();
|
||||
|
||||
foreach (array_keys($container->getDefinitions()) as $id) {
|
||||
// yes, we are specifically fetching the definition from the
|
||||
// container to ensure we are not operating on stale data
|
||||
$definition = $container->getDefinition($id);
|
||||
if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->resolveDefinition($id, $definition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the definition
|
||||
*
|
||||
* @param string $id The definition identifier
|
||||
* @param DefinitionDecorator $definition
|
||||
*
|
||||
* @return Definition
|
||||
*
|
||||
* @throws \RuntimeException When the definition is invalid
|
||||
*/
|
||||
private function resolveDefinition($id, DefinitionDecorator $definition)
|
||||
{
|
||||
if (!$this->container->hasDefinition($parent = $definition->getParent())) {
|
||||
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id));
|
||||
}
|
||||
|
||||
$parentDef = $this->container->getDefinition($parent);
|
||||
if ($parentDef instanceof DefinitionDecorator) {
|
||||
$parentDef = $this->resolveDefinition($parent, $parentDef);
|
||||
}
|
||||
|
||||
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent));
|
||||
$def = new Definition();
|
||||
|
||||
// merge in parent definition
|
||||
// purposely ignored attributes: scope, abstract, tags
|
||||
$def->setClass($parentDef->getClass());
|
||||
$def->setArguments($parentDef->getArguments());
|
||||
$def->setMethodCalls($parentDef->getMethodCalls());
|
||||
$def->setProperties($parentDef->getProperties());
|
||||
$def->setFactoryClass($parentDef->getFactoryClass());
|
||||
$def->setFactoryMethod($parentDef->getFactoryMethod());
|
||||
$def->setFactoryService($parentDef->getFactoryService());
|
||||
$def->setConfigurator($parentDef->getConfigurator());
|
||||
$def->setFile($parentDef->getFile());
|
||||
$def->setPublic($parentDef->isPublic());
|
||||
|
||||
// overwrite with values specified in the decorator
|
||||
$changes = $definition->getChanges();
|
||||
if (isset($changes['class'])) {
|
||||
$def->setClass($definition->getClass());
|
||||
}
|
||||
if (isset($changes['factory_class'])) {
|
||||
$def->setFactoryClass($definition->getFactoryClass());
|
||||
}
|
||||
if (isset($changes['factory_method'])) {
|
||||
$def->setFactoryMethod($definition->getFactoryMethod());
|
||||
}
|
||||
if (isset($changes['factory_service'])) {
|
||||
$def->setFactoryService($definition->getFactoryService());
|
||||
}
|
||||
if (isset($changes['configurator'])) {
|
||||
$def->setConfigurator($definition->getConfigurator());
|
||||
}
|
||||
if (isset($changes['file'])) {
|
||||
$def->setFile($definition->getFile());
|
||||
}
|
||||
if (isset($changes['public'])) {
|
||||
$def->setPublic($definition->isPublic());
|
||||
}
|
||||
|
||||
// merge arguments
|
||||
foreach ($definition->getArguments() as $k => $v) {
|
||||
if (is_numeric($k)) {
|
||||
$def->addArgument($v);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (0 !== strpos($k, 'index_')) {
|
||||
throw new RuntimeException(sprintf('Invalid argument key "%s" found.', $k));
|
||||
}
|
||||
|
||||
$index = (integer) substr($k, strlen('index_'));
|
||||
$def->replaceArgument($index, $v);
|
||||
}
|
||||
|
||||
// merge properties
|
||||
foreach ($definition->getProperties() as $k => $v) {
|
||||
$def->setProperty($k, $v);
|
||||
}
|
||||
|
||||
// append method calls
|
||||
if (count($calls = $definition->getMethodCalls()) > 0) {
|
||||
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
|
||||
}
|
||||
|
||||
// these attributes are always taken from the child
|
||||
$def->setAbstract($definition->isAbstract());
|
||||
$def->setScope($definition->getScope());
|
||||
$def->setTags($definition->getTags());
|
||||
|
||||
// set new definition on container
|
||||
$this->container->setDefinition($id, $def);
|
||||
|
||||
return $def;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Emulates the invalid behavior if the reference is not found within the
|
||||
* container.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ResolveInvalidReferencesPass implements CompilerPassInterface
|
||||
{
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* Process the ContainerBuilder to resolve invalid references.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
foreach ($container->getDefinitions() as $definition) {
|
||||
if ($definition->isSynthetic() || $definition->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition->setArguments(
|
||||
$this->processArguments($definition->getArguments())
|
||||
);
|
||||
|
||||
$calls = array();
|
||||
foreach ($definition->getMethodCalls() as $call) {
|
||||
try {
|
||||
$calls[] = array($call[0], $this->processArguments($call[1], true));
|
||||
} catch (RuntimeException $ignore) {
|
||||
// this call is simply removed
|
||||
}
|
||||
}
|
||||
$definition->setMethodCalls($calls);
|
||||
|
||||
$properties = array();
|
||||
foreach ($definition->getProperties() as $name => $value) {
|
||||
try {
|
||||
$value = $this->processArguments(array($value), true);
|
||||
$properties[$name] = reset($value);
|
||||
} catch (RuntimeException $ignore) {
|
||||
// ignore property
|
||||
}
|
||||
}
|
||||
$definition->setProperties($properties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes arguments to determine invalid references.
|
||||
*
|
||||
* @param array $arguments An array of Reference objects
|
||||
* @param Boolean $inMethodCall
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \RuntimeException When the config is invalid
|
||||
*/
|
||||
private function processArguments(array $arguments, $inMethodCall = false)
|
||||
{
|
||||
foreach ($arguments as $k => $argument) {
|
||||
if (is_array($argument)) {
|
||||
$arguments[$k] = $this->processArguments($argument, $inMethodCall);
|
||||
} elseif ($argument instanceof Reference) {
|
||||
$id = (string) $argument;
|
||||
|
||||
$invalidBehavior = $argument->getInvalidBehavior();
|
||||
$exists = $this->container->has($id);
|
||||
|
||||
// resolve invalid behavior
|
||||
if ($exists && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
|
||||
$arguments[$k] = new Reference($id);
|
||||
} elseif (!$exists && ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
$arguments[$k] = null;
|
||||
} elseif (!$exists && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
if ($inMethodCall) {
|
||||
throw new RuntimeException('Method shouldn\'t be called.');
|
||||
}
|
||||
|
||||
$arguments[$k] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
|
||||
/**
|
||||
* Resolves all parameter placeholders "%somevalue%" to their real values.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ResolveParameterPlaceHoldersPass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* Processes the ContainerBuilder to resolve parameter placeholders.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*
|
||||
* @throws ParameterNotFoundException When an invalid parameter is referenced
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$parameterBag = $container->getParameterBag();
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
try {
|
||||
$definition->setClass($parameterBag->resolveValue($definition->getClass()));
|
||||
$definition->setFile($parameterBag->resolveValue($definition->getFile()));
|
||||
$definition->setArguments($parameterBag->resolveValue($definition->getArguments()));
|
||||
|
||||
$calls = array();
|
||||
foreach ($definition->getMethodCalls() as $name => $arguments) {
|
||||
$calls[$parameterBag->resolveValue($name)] = $parameterBag->resolveValue($arguments);
|
||||
}
|
||||
$definition->setMethodCalls($calls);
|
||||
|
||||
$definition->setProperties($parameterBag->resolveValue($definition->getProperties()));
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
$e->setSourceId($id);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$aliases = array();
|
||||
foreach ($container->getAliases() as $name => $target) {
|
||||
$aliases[$parameterBag->resolveValue($name)] = $parameterBag->resolveValue($target);
|
||||
}
|
||||
$container->setAliases($aliases);
|
||||
|
||||
$parameterBag->resolve();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Replaces all references to aliases with references to the actual service.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ResolveReferencesToAliasesPass implements CompilerPassInterface
|
||||
{
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* Processes the ContainerBuilder to replace references to aliases with actual service references.
|
||||
*
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
foreach ($container->getDefinitions() as $definition) {
|
||||
if ($definition->isSynthetic() || $definition->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition->setArguments($this->processArguments($definition->getArguments()));
|
||||
$definition->setMethodCalls($this->processArguments($definition->getMethodCalls()));
|
||||
$definition->setProperties($this->processArguments($definition->getProperties()));
|
||||
}
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
$aliasId = (string) $alias;
|
||||
if ($aliasId !== $defId = $this->getDefinitionId($aliasId)) {
|
||||
$container->setAlias($id, new Alias($defId, $alias->isPublic()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the arguments to replace aliases.
|
||||
*
|
||||
* @param array $arguments An array of References
|
||||
*
|
||||
* @return array An array of References
|
||||
*/
|
||||
private function processArguments(array $arguments)
|
||||
{
|
||||
foreach ($arguments as $k => $argument) {
|
||||
if (is_array($argument)) {
|
||||
$arguments[$k] = $this->processArguments($argument);
|
||||
} elseif ($argument instanceof Reference) {
|
||||
$defId = $this->getDefinitionId($id = (string) $argument);
|
||||
|
||||
if ($defId !== $id) {
|
||||
$arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an alias into a definition id.
|
||||
*
|
||||
* @param string $id The definition or alias id to resolve
|
||||
*
|
||||
* @return string The definition id with aliases resolved
|
||||
*/
|
||||
private function getDefinitionId($id)
|
||||
{
|
||||
while ($this->container->hasAlias($id)) {
|
||||
$id = (string) $this->container->getAlias($id);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* This is a directed graph of your services.
|
||||
*
|
||||
* This information can be used by your compiler passes instead of collecting
|
||||
* it themselves which improves performance quite a lot.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ServiceReferenceGraph
|
||||
{
|
||||
private $nodes;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->nodes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the graph has a specific node.
|
||||
*
|
||||
* @param string $id Id to check
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function hasNode($id)
|
||||
{
|
||||
return isset($this->nodes[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a node by identifier.
|
||||
*
|
||||
* @param string $id The id to retrieve
|
||||
*
|
||||
* @return ServiceReferenceGraphNode The node matching the supplied identifier
|
||||
*
|
||||
* @throws InvalidArgumentException if no node matches the supplied identifier
|
||||
*/
|
||||
public function getNode($id)
|
||||
{
|
||||
if (!isset($this->nodes[$id])) {
|
||||
throw new InvalidArgumentException(sprintf('There is no node with id "%s".', $id));
|
||||
}
|
||||
|
||||
return $this->nodes[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all nodes.
|
||||
*
|
||||
* @return array An array of all ServiceReferenceGraphNode objects
|
||||
*/
|
||||
public function getNodes()
|
||||
{
|
||||
return $this->nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all nodes.
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->nodes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects 2 nodes together in the Graph.
|
||||
*
|
||||
* @param string $sourceId
|
||||
* @param string $sourceValue
|
||||
* @param string $destId
|
||||
* @param string $destValue
|
||||
* @param string $reference
|
||||
*/
|
||||
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null)
|
||||
{
|
||||
$sourceNode = $this->createNode($sourceId, $sourceValue);
|
||||
$destNode = $this->createNode($destId, $destValue);
|
||||
$edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference);
|
||||
|
||||
$sourceNode->addOutEdge($edge);
|
||||
$destNode->addInEdge($edge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a graph node.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $value
|
||||
*
|
||||
* @return ServiceReferenceGraphNode
|
||||
*/
|
||||
private function createNode($id, $value)
|
||||
{
|
||||
if (isset($this->nodes[$id]) && $this->nodes[$id]->getValue() === $value) {
|
||||
return $this->nodes[$id];
|
||||
}
|
||||
|
||||
return $this->nodes[$id] = new ServiceReferenceGraphNode($id, $value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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\Compiler;
|
||||
|
||||
/**
|
||||
* Represents an edge in your service graph.
|
||||
*
|
||||
* Value is typically a reference.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ServiceReferenceGraphEdge
|
||||
{
|
||||
private $sourceNode;
|
||||
private $destNode;
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ServiceReferenceGraphNode $sourceNode
|
||||
* @param ServiceReferenceGraphNode $destNode
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null)
|
||||
{
|
||||
$this->sourceNode = $sourceNode;
|
||||
$this->destNode = $destNode;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the edge
|
||||
*
|
||||
* @return ServiceReferenceGraphNode
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source node
|
||||
*
|
||||
* @return ServiceReferenceGraphNode
|
||||
*/
|
||||
public function getSourceNode()
|
||||
{
|
||||
return $this->sourceNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the destination node
|
||||
*
|
||||
* @return ServiceReferenceGraphNode
|
||||
*/
|
||||
public function getDestNode()
|
||||
{
|
||||
return $this->destNode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?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\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
|
||||
/**
|
||||
* Represents a node in your service graph.
|
||||
*
|
||||
* Value is typically a definition, or an alias.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ServiceReferenceGraphNode
|
||||
{
|
||||
private $id;
|
||||
private $inEdges;
|
||||
private $outEdges;
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $id The node identifier
|
||||
* @param mixed $value The node value
|
||||
*/
|
||||
public function __construct($id, $value)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->value = $value;
|
||||
$this->inEdges = array();
|
||||
$this->outEdges = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an in edge to this node.
|
||||
*
|
||||
* @param ServiceReferenceGraphEdge $edge
|
||||
*/
|
||||
public function addInEdge(ServiceReferenceGraphEdge $edge)
|
||||
{
|
||||
$this->inEdges[] = $edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an out edge to this node.
|
||||
*
|
||||
* @param ServiceReferenceGraphEdge $edge
|
||||
*/
|
||||
public function addOutEdge(ServiceReferenceGraphEdge $edge)
|
||||
{
|
||||
$this->outEdges[] = $edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value of this node is an Alias.
|
||||
*
|
||||
* @return Boolean True if the value is an Alias instance
|
||||
*/
|
||||
public function isAlias()
|
||||
{
|
||||
return $this->value instanceof Alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value of this node is a Definition.
|
||||
*
|
||||
* @return Boolean True if the value is a Definition instance
|
||||
*/
|
||||
public function isDefinition()
|
||||
{
|
||||
return $this->value instanceof Definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the in edges.
|
||||
*
|
||||
* @return array The in ServiceReferenceGraphEdge array
|
||||
*/
|
||||
public function getInEdges()
|
||||
{
|
||||
return $this->inEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the out edges.
|
||||
*
|
||||
* @return array The out ServiceReferenceGraphEdge array
|
||||
*/
|
||||
public function getOutEdges()
|
||||
{
|
||||
return $this->outEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this Node
|
||||
*
|
||||
* @return mixed The value
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
477
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Container.php
vendored
Normal file
477
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Container.php
vendored
Normal file
@@ -0,0 +1,477 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
||||
|
||||
/**
|
||||
* Container is a dependency injection container.
|
||||
*
|
||||
* It gives access to object instances (services).
|
||||
*
|
||||
* Services and parameters are simple key/pair stores.
|
||||
*
|
||||
* Parameter and service keys are case insensitive.
|
||||
*
|
||||
* A service id can contain lowercased letters, digits, underscores, and dots.
|
||||
* Underscores are used to separate words, and dots to group services
|
||||
* under namespaces:
|
||||
*
|
||||
* <ul>
|
||||
* <li>request</li>
|
||||
* <li>mysql_session_storage</li>
|
||||
* <li>symfony.mysql_session_storage</li>
|
||||
* </ul>
|
||||
*
|
||||
* A service can also be defined by creating a method named
|
||||
* getXXXService(), where XXX is the camelized version of the id:
|
||||
*
|
||||
* <ul>
|
||||
* <li>request -> getRequestService()</li>
|
||||
* <li>mysql_session_storage -> getMysqlSessionStorageService()</li>
|
||||
* <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li>
|
||||
* </ul>
|
||||
*
|
||||
* The container can have three possible behaviors when a service does not exist:
|
||||
*
|
||||
* * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
|
||||
* * NULL_ON_INVALID_REFERENCE: Returns null
|
||||
* * IGNORE_ON_INVALID_REFERENCE: Ignores the wrapping command asking for the reference
|
||||
* (for instance, ignore a setter if the service does not exist)
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Container implements IntrospectableContainerInterface
|
||||
{
|
||||
protected $parameterBag;
|
||||
protected $services;
|
||||
protected $scopes;
|
||||
protected $scopeChildren;
|
||||
protected $scopedServices;
|
||||
protected $scopeStacks;
|
||||
protected $loading = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ParameterBagInterface $parameterBag A ParameterBagInterface instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
$this->parameterBag = null === $parameterBag ? new ParameterBag() : $parameterBag;
|
||||
|
||||
$this->services = array();
|
||||
$this->scopes = array();
|
||||
$this->scopeChildren = array();
|
||||
$this->scopedServices = array();
|
||||
$this->scopeStacks = array();
|
||||
|
||||
$this->set('service_container', $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the container.
|
||||
*
|
||||
* This method does two things:
|
||||
*
|
||||
* * Parameter values are resolved;
|
||||
* * The parameter bag is frozen.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function compile()
|
||||
{
|
||||
$this->parameterBag->resolve();
|
||||
|
||||
$this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the container parameter bag are frozen.
|
||||
*
|
||||
* @return Boolean true if the container parameter bag are frozen, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isFrozen()
|
||||
{
|
||||
return $this->parameterBag instanceof FrozenParameterBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service container parameter bag.
|
||||
*
|
||||
* @return ParameterBagInterface A ParameterBagInterface instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getParameterBag()
|
||||
{
|
||||
return $this->parameterBag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws InvalidArgumentException if the parameter is not defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getParameter($name)
|
||||
{
|
||||
return $this->parameterBag->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a parameter exists.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return Boolean The presence of parameter in container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasParameter($name)
|
||||
{
|
||||
return $this->parameterBag->has($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
* @param mixed $value The parameter value
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setParameter($name, $value)
|
||||
{
|
||||
$this->parameterBag->set($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a service.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param object $service The service instance
|
||||
* @param string $scope The scope of the service
|
||||
*
|
||||
* @throws \RuntimeException When trying to set a service in an inactive scope
|
||||
* @throws \InvalidArgumentException When trying to set a service in the prototype scope
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
|
||||
{
|
||||
if (self::SCOPE_PROTOTYPE === $scope) {
|
||||
throw new InvalidArgumentException('You cannot set services of scope "prototype".');
|
||||
}
|
||||
|
||||
$id = strtolower($id);
|
||||
|
||||
if (self::SCOPE_CONTAINER !== $scope) {
|
||||
if (!isset($this->scopedServices[$scope])) {
|
||||
throw new RuntimeException('You cannot set services of inactive scopes.');
|
||||
}
|
||||
|
||||
$this->scopedServices[$scope][$id] = $service;
|
||||
}
|
||||
|
||||
$this->services[$id] = $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given service is defined.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Boolean true if the service is defined, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($id)
|
||||
{
|
||||
$id = strtolower($id);
|
||||
|
||||
return isset($this->services[$id]) || method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_')).'Service');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a service.
|
||||
*
|
||||
* If a service is defined both through a set() method and
|
||||
* with a get{$id}Service() method, the former has always precedence.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param integer $invalidBehavior The behavior when the service does not exist
|
||||
*
|
||||
* @return object The associated service
|
||||
*
|
||||
* @throws InvalidArgumentException if the service is not defined
|
||||
* @throws ServiceCircularReferenceException When a circular reference is detected
|
||||
* @throws ServiceNotFoundException When the service is not defined
|
||||
*
|
||||
* @see Reference
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
|
||||
{
|
||||
$id = strtolower($id);
|
||||
|
||||
if (isset($this->services[$id])) {
|
||||
return $this->services[$id];
|
||||
}
|
||||
|
||||
if (isset($this->loading[$id])) {
|
||||
throw new ServiceCircularReferenceException($id, array_keys($this->loading));
|
||||
}
|
||||
|
||||
if (method_exists($this, $method = 'get'.strtr($id, array('_' => '', '.' => '_')).'Service')) {
|
||||
$this->loading[$id] = true;
|
||||
|
||||
try {
|
||||
$service = $this->$method();
|
||||
} catch (\Exception $e) {
|
||||
unset($this->loading[$id]);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
unset($this->loading[$id]);
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
throw new ServiceNotFoundException($id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given service has actually been initialized
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Boolean true if service has already been initialized, false otherwise
|
||||
*/
|
||||
public function initialized($id)
|
||||
{
|
||||
return isset($this->services[strtolower($id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all service ids.
|
||||
*
|
||||
* @return array An array of all defined service ids
|
||||
*/
|
||||
public function getServiceIds()
|
||||
{
|
||||
$ids = array();
|
||||
$r = new \ReflectionClass($this);
|
||||
foreach ($r->getMethods() as $method) {
|
||||
if (preg_match('/^get(.+)Service$/', $method->name, $match)) {
|
||||
$ids[] = self::underscore($match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique(array_merge($ids, array_keys($this->services)));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when you enter a scope
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @throws RuntimeException When the parent scope is inactive
|
||||
* @throws InvalidArgumentException When the scope does not exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function enterScope($name)
|
||||
{
|
||||
if (!isset($this->scopes[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
if (self::SCOPE_CONTAINER !== $this->scopes[$name] && !isset($this->scopedServices[$this->scopes[$name]])) {
|
||||
throw new RuntimeException(sprintf('The parent scope "%s" must be active when entering this scope.', $this->scopes[$name]));
|
||||
}
|
||||
|
||||
// check if a scope of this name is already active, if so we need to
|
||||
// remove all services of this scope, and those of any of its child
|
||||
// scopes from the global services map
|
||||
if (isset($this->scopedServices[$name])) {
|
||||
$services = array($this->services, $name => $this->scopedServices[$name]);
|
||||
unset($this->scopedServices[$name]);
|
||||
|
||||
foreach ($this->scopeChildren[$name] as $child) {
|
||||
$services[$child] = $this->scopedServices[$child];
|
||||
unset($this->scopedServices[$child]);
|
||||
}
|
||||
|
||||
// update global map
|
||||
$this->services = call_user_func_array('array_diff_key', $services);
|
||||
array_shift($services);
|
||||
|
||||
// add stack entry for this scope so we can restore the removed services later
|
||||
if (!isset($this->scopeStacks[$name])) {
|
||||
$this->scopeStacks[$name] = new \SplStack();
|
||||
}
|
||||
$this->scopeStacks[$name]->push($services);
|
||||
}
|
||||
|
||||
$this->scopedServices[$name] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called to leave the current scope, and move back to the parent
|
||||
* scope.
|
||||
*
|
||||
* @param string $name The name of the scope to leave
|
||||
*
|
||||
* @throws InvalidArgumentException if the scope is not active
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function leaveScope($name)
|
||||
{
|
||||
if (!isset($this->scopedServices[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
|
||||
}
|
||||
|
||||
// remove all services of this scope, or any of its child scopes from
|
||||
// the global service map
|
||||
$services = array($this->services, $this->scopedServices[$name]);
|
||||
unset($this->scopedServices[$name]);
|
||||
foreach ($this->scopeChildren[$name] as $child) {
|
||||
if (!isset($this->scopedServices[$child])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$services[] = $this->scopedServices[$child];
|
||||
unset($this->scopedServices[$child]);
|
||||
}
|
||||
$this->services = call_user_func_array('array_diff_key', $services);
|
||||
|
||||
// check if we need to restore services of a previous scope of this type
|
||||
if (isset($this->scopeStacks[$name]) && count($this->scopeStacks[$name]) > 0) {
|
||||
$services = $this->scopeStacks[$name]->pop();
|
||||
$this->scopedServices += $services;
|
||||
|
||||
array_unshift($services, $this->services);
|
||||
$this->services = call_user_func_array('array_merge', $services);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a scope to the container.
|
||||
*
|
||||
* @param ScopeInterface $scope
|
||||
*
|
||||
* @throws \InvalidArgumentException When the scope is invalid
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addScope(ScopeInterface $scope)
|
||||
{
|
||||
$name = $scope->getName();
|
||||
$parentScope = $scope->getParentName();
|
||||
|
||||
if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
|
||||
throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
|
||||
}
|
||||
if (isset($this->scopes[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('A scope with name "%s" already exists.', $name));
|
||||
}
|
||||
if (self::SCOPE_CONTAINER !== $parentScope && !isset($this->scopes[$parentScope])) {
|
||||
throw new InvalidArgumentException(sprintf('The parent scope "%s" does not exist, or is invalid.', $parentScope));
|
||||
}
|
||||
|
||||
$this->scopes[$name] = $parentScope;
|
||||
$this->scopeChildren[$name] = array();
|
||||
|
||||
// normalize the child relations
|
||||
while ($parentScope !== self::SCOPE_CONTAINER) {
|
||||
$this->scopeChildren[$parentScope][] = $name;
|
||||
$parentScope = $this->scopes[$parentScope];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this container has a certain scope
|
||||
*
|
||||
* @param string $name The name of the scope
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasScope($name)
|
||||
{
|
||||
return isset($this->scopes[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this scope is currently active
|
||||
*
|
||||
* This does not actually check if the passed scope actually exists.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isScopeActive($name)
|
||||
{
|
||||
return isset($this->scopedServices[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Camelizes a string.
|
||||
*
|
||||
* @param string $id A string to camelize
|
||||
*
|
||||
* @return string The camelized string
|
||||
*/
|
||||
public static function camelize($id)
|
||||
{
|
||||
return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A string to underscore.
|
||||
*
|
||||
* @param string $id The string to underscore
|
||||
*
|
||||
* @return string The underscored string
|
||||
*/
|
||||
public static function underscore($id)
|
||||
{
|
||||
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($id, '_', '.')));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* A simple implementation of ContainerAwareInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
abstract class ContainerAware implements ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Sets the Container associated with this Controller.
|
||||
*
|
||||
* @param ContainerInterface $container A ContainerInterface instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* ContainerAwareInterface should be implemented by classes that depends on a Container.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Sets the Container.
|
||||
*
|
||||
* @param ContainerInterface $container A ContainerInterface instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container = null);
|
||||
}
|
||||
881
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php
vendored
Normal file
881
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php
vendored
Normal file
@@ -0,0 +1,881 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\Compiler;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* ContainerBuilder is a DI container that provides an API to easily describe services.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
{
|
||||
private $extensions = array();
|
||||
private $extensionsByNs = array();
|
||||
private $definitions = array();
|
||||
private $aliases = array();
|
||||
private $resources = array();
|
||||
private $extensionConfigs = array();
|
||||
private $compiler;
|
||||
|
||||
/**
|
||||
* Registers an extension.
|
||||
*
|
||||
* @param ExtensionInterface $extension An extension instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function registerExtension(ExtensionInterface $extension)
|
||||
{
|
||||
$this->extensions[$extension->getAlias()] = $extension;
|
||||
|
||||
if (false !== $extension->getNamespace()) {
|
||||
$this->extensionsByNs[$extension->getNamespace()] = $extension;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an extension by alias or namespace.
|
||||
*
|
||||
* @param string $name An alias or a namespace
|
||||
*
|
||||
* @return ExtensionInterface An extension instance
|
||||
*
|
||||
* @throws \LogicException if the extension is not registered
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getExtension($name)
|
||||
{
|
||||
if (isset($this->extensions[$name])) {
|
||||
return $this->extensions[$name];
|
||||
}
|
||||
|
||||
if (isset($this->extensionsByNs[$name])) {
|
||||
return $this->extensionsByNs[$name];
|
||||
}
|
||||
|
||||
throw new LogicException(sprintf('Container extension "%s" is not registered', $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all registered extensions.
|
||||
*
|
||||
* @return array An array of ExtensionInterface
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getExtensions()
|
||||
{
|
||||
return $this->extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we have an extension.
|
||||
*
|
||||
* @param string $name The name of the extension
|
||||
*
|
||||
* @return Boolean If the extension exists
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasExtension($name)
|
||||
{
|
||||
return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of resources loaded to build this configuration.
|
||||
*
|
||||
* @return ResourceInterface[] An array of resources
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getResources()
|
||||
{
|
||||
return array_unique($this->resources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a resource for this configuration.
|
||||
*
|
||||
* @param ResourceInterface $resource A resource instance
|
||||
*
|
||||
* @return ContainerBuilder The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addResource(ResourceInterface $resource)
|
||||
{
|
||||
$this->resources[] = $resource;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the object class hierarchy as resources.
|
||||
*
|
||||
* @param object $object An object instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addObjectResource($object)
|
||||
{
|
||||
$parent = new \ReflectionObject($object);
|
||||
do {
|
||||
$this->addResource(new FileResource($parent->getFileName()));
|
||||
} while ($parent = $parent->getParentClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configuration for an extension.
|
||||
*
|
||||
* @param string $extension The extension alias or namespace
|
||||
* @param array $values An array of values that customizes the extension
|
||||
*
|
||||
* @return ContainerBuilder The current instance
|
||||
* @throws BadMethodCallException When this ContainerBuilder is frozen
|
||||
*
|
||||
* @throws \LogicException if the container is frozen
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function loadFromExtension($extension, array $values = array())
|
||||
{
|
||||
if ($this->isFrozen()) {
|
||||
throw new BadMethodCallException('Cannot load from an extension on a frozen container.');
|
||||
}
|
||||
|
||||
$namespace = $this->getExtension($extension)->getAlias();
|
||||
|
||||
$this->extensionConfigs[$namespace][] = $values;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a compiler pass.
|
||||
*
|
||||
* @param CompilerPassInterface $pass A compiler pass
|
||||
* @param string $type The type of compiler pass
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
|
||||
{
|
||||
if (null === $this->compiler) {
|
||||
$this->compiler = new Compiler();
|
||||
}
|
||||
|
||||
$this->compiler->addPass($pass, $type);
|
||||
|
||||
$this->addObjectResource($pass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compiler pass config which can then be modified.
|
||||
*
|
||||
* @return PassConfig The compiler pass config
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getCompilerPassConfig()
|
||||
{
|
||||
if (null === $this->compiler) {
|
||||
$this->compiler = new Compiler();
|
||||
}
|
||||
|
||||
return $this->compiler->getPassConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compiler.
|
||||
*
|
||||
* @return Compiler The compiler
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getCompiler()
|
||||
{
|
||||
if (null === $this->compiler) {
|
||||
$this->compiler = new Compiler();
|
||||
}
|
||||
|
||||
return $this->compiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Scopes.
|
||||
*
|
||||
* @return array An array of scopes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
return $this->scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Scope children.
|
||||
*
|
||||
* @return array An array of scope children.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getScopeChildren()
|
||||
{
|
||||
return $this->scopeChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a service.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param object $service The service instance
|
||||
* @param string $scope The scope
|
||||
*
|
||||
* @throws BadMethodCallException When this ContainerBuilder is frozen
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
|
||||
{
|
||||
if ($this->isFrozen()) {
|
||||
throw new BadMethodCallException('Setting service on a frozen container is not allowed');
|
||||
}
|
||||
|
||||
$id = strtolower($id);
|
||||
|
||||
unset($this->definitions[$id], $this->aliases[$id]);
|
||||
|
||||
parent::set($id, $service, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a service definition.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function removeDefinition($id)
|
||||
{
|
||||
unset($this->definitions[strtolower($id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given service is defined.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Boolean true if the service is defined, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($id)
|
||||
{
|
||||
$id = strtolower($id);
|
||||
|
||||
return isset($this->definitions[$id]) || isset($this->aliases[$id]) || parent::has($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a service.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param integer $invalidBehavior The behavior when the service does not exist
|
||||
*
|
||||
* @return object The associated service
|
||||
*
|
||||
* @throws InvalidArgumentException if the service is not defined
|
||||
* @throws LogicException if the service has a circular reference to itself
|
||||
*
|
||||
* @see Reference
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
|
||||
{
|
||||
$id = strtolower($id);
|
||||
|
||||
try {
|
||||
return parent::get($id, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
if (isset($this->loading[$id])) {
|
||||
throw new LogicException(sprintf('The service "%s" has a circular reference to itself.', $id), 0, $e);
|
||||
}
|
||||
|
||||
if (!$this->hasDefinition($id) && isset($this->aliases[$id])) {
|
||||
return $this->get($this->aliases[$id]);
|
||||
}
|
||||
|
||||
try {
|
||||
$definition = $this->getDefinition($id);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->loading[$id] = true;
|
||||
|
||||
$service = $this->createService($definition, $id);
|
||||
|
||||
unset($this->loading[$id]);
|
||||
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a ContainerBuilder with the current ContainerBuilder configuration.
|
||||
*
|
||||
* Service definitions overrides the current defined ones.
|
||||
*
|
||||
* But for parameters, they are overridden by the current ones. It allows
|
||||
* the parameters passed to the container constructor to have precedence
|
||||
* over the loaded ones.
|
||||
*
|
||||
* $container = new ContainerBuilder(array('foo' => 'bar'));
|
||||
* $loader = new LoaderXXX($container);
|
||||
* $loader->load('resource_name');
|
||||
* $container->register('foo', new stdClass());
|
||||
*
|
||||
* In the above example, even if the loaded resource defines a foo
|
||||
* parameter, the value will still be 'bar' as defined in the ContainerBuilder
|
||||
* constructor.
|
||||
*
|
||||
* @param ContainerBuilder $container The ContainerBuilder instance to merge.
|
||||
*
|
||||
*
|
||||
* @throws BadMethodCallException When this ContainerBuilder is frozen
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function merge(ContainerBuilder $container)
|
||||
{
|
||||
if ($this->isFrozen()) {
|
||||
throw new BadMethodCallException('Cannot merge on a frozen container.');
|
||||
}
|
||||
|
||||
$this->addDefinitions($container->getDefinitions());
|
||||
$this->addAliases($container->getAliases());
|
||||
$this->getParameterBag()->add($container->getParameterBag()->all());
|
||||
|
||||
foreach ($container->getResources() as $resource) {
|
||||
$this->addResource($resource);
|
||||
}
|
||||
|
||||
foreach ($this->extensions as $name => $extension) {
|
||||
if (!isset($this->extensionConfigs[$name])) {
|
||||
$this->extensionConfigs[$name] = array();
|
||||
}
|
||||
|
||||
$this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration array for the given extension.
|
||||
*
|
||||
* @param string $name The name of the extension
|
||||
*
|
||||
* @return array An array of configuration
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getExtensionConfig($name)
|
||||
{
|
||||
if (!isset($this->extensionConfigs[$name])) {
|
||||
$this->extensionConfigs[$name] = array();
|
||||
}
|
||||
|
||||
return $this->extensionConfigs[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the container.
|
||||
*
|
||||
* This method passes the container to compiler
|
||||
* passes whose job is to manipulate and optimize
|
||||
* the container.
|
||||
*
|
||||
* The main compiler passes roughly do four things:
|
||||
*
|
||||
* * The extension configurations are merged;
|
||||
* * Parameter values are resolved;
|
||||
* * The parameter bag is frozen;
|
||||
* * Extension loading is disabled.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function compile()
|
||||
{
|
||||
if (null === $this->compiler) {
|
||||
$this->compiler = new Compiler();
|
||||
}
|
||||
|
||||
foreach ($this->compiler->getPassConfig()->getPasses() as $pass) {
|
||||
$this->addObjectResource($pass);
|
||||
}
|
||||
|
||||
$this->compiler->compile($this);
|
||||
|
||||
$this->extensionConfigs = array();
|
||||
|
||||
parent::compile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all service ids.
|
||||
*
|
||||
* @return array An array of all defined service ids
|
||||
*/
|
||||
public function getServiceIds()
|
||||
{
|
||||
return array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliases), parent::getServiceIds()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the service aliases.
|
||||
*
|
||||
* @param array $aliases An array of aliases
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addAliases(array $aliases)
|
||||
{
|
||||
foreach ($aliases as $alias => $id) {
|
||||
$this->setAlias($alias, $id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service aliases.
|
||||
*
|
||||
* @param array $aliases An array of service definitions
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setAliases(array $aliases)
|
||||
{
|
||||
$this->aliases = array();
|
||||
$this->addAliases($aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an alias for an existing service.
|
||||
*
|
||||
* @param string $alias The alias to create
|
||||
* @param string|Alias $id The service to alias
|
||||
*
|
||||
* @throws \InvalidArgumentException if the id is not a string or an Alias
|
||||
* @throws \InvalidArgumentException if the alias is for itself
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setAlias($alias, $id)
|
||||
{
|
||||
$alias = strtolower($alias);
|
||||
|
||||
if (is_string($id)) {
|
||||
$id = new Alias($id);
|
||||
} elseif (!$id instanceof Alias) {
|
||||
throw new InvalidArgumentException('$id must be a string, or an Alias object.');
|
||||
}
|
||||
|
||||
if ($alias === strtolower($id)) {
|
||||
throw new InvalidArgumentException('An alias can not reference itself, got a circular reference on "'.$alias.'".');
|
||||
}
|
||||
|
||||
unset($this->definitions[$alias]);
|
||||
|
||||
$this->aliases[$alias] = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an alias.
|
||||
*
|
||||
* @param string $alias The alias to remove
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function removeAlias($alias)
|
||||
{
|
||||
unset($this->aliases[strtolower($alias)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an alias exists under the given identifier.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Boolean true if the alias exists, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasAlias($id)
|
||||
{
|
||||
return isset($this->aliases[strtolower($id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all defined aliases.
|
||||
*
|
||||
* @return Alias[] An array of aliases
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an alias.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Alias An Alias instance
|
||||
*
|
||||
* @throws InvalidArgumentException if the alias does not exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getAlias($id)
|
||||
{
|
||||
$id = strtolower($id);
|
||||
|
||||
if (!$this->hasAlias($id)) {
|
||||
throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
|
||||
}
|
||||
|
||||
return $this->aliases[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a service definition.
|
||||
*
|
||||
* This methods allows for simple registration of service definition
|
||||
* with a fluid interface.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param string $class The service class
|
||||
*
|
||||
* @return Definition A Definition instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function register($id, $class = null)
|
||||
{
|
||||
return $this->setDefinition(strtolower($id), new Definition($class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the service definitions.
|
||||
*
|
||||
* @param Definition[] $definitions An array of service definitions
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addDefinitions(array $definitions)
|
||||
{
|
||||
foreach ($definitions as $id => $definition) {
|
||||
$this->setDefinition($id, $definition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service definitions.
|
||||
*
|
||||
* @param array $definitions An array of service definitions
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDefinitions(array $definitions)
|
||||
{
|
||||
$this->definitions = array();
|
||||
$this->addDefinitions($definitions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all service definitions.
|
||||
*
|
||||
* @return Definition[] An array of Definition instances
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getDefinitions()
|
||||
{
|
||||
return $this->definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a service definition.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param Definition $definition A Definition instance
|
||||
*
|
||||
* @return Definition the service definition
|
||||
*
|
||||
* @throws BadMethodCallException When this ContainerBuilder is frozen
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setDefinition($id, Definition $definition)
|
||||
{
|
||||
if ($this->isFrozen()) {
|
||||
throw new BadMethodCallException('Adding definition to a frozen container is not allowed');
|
||||
}
|
||||
|
||||
$id = strtolower($id);
|
||||
|
||||
unset($this->aliases[$id]);
|
||||
|
||||
return $this->definitions[$id] = $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a service definition exists under the given identifier.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Boolean true if the service definition exists, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasDefinition($id)
|
||||
{
|
||||
return array_key_exists(strtolower($id), $this->definitions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a service definition.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Definition A Definition instance
|
||||
*
|
||||
* @throws InvalidArgumentException if the service definition does not exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getDefinition($id)
|
||||
{
|
||||
$id = strtolower($id);
|
||||
|
||||
if (!$this->hasDefinition($id)) {
|
||||
throw new InvalidArgumentException(sprintf('The service definition "%s" does not exist.', $id));
|
||||
}
|
||||
|
||||
return $this->definitions[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a service definition by id or alias.
|
||||
*
|
||||
* The method "unaliases" recursively to return a Definition instance.
|
||||
*
|
||||
* @param string $id The service identifier or alias
|
||||
*
|
||||
* @return Definition A Definition instance
|
||||
*
|
||||
* @throws InvalidArgumentException if the service definition does not exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function findDefinition($id)
|
||||
{
|
||||
while ($this->hasAlias($id)) {
|
||||
$id = (string) $this->getAlias($id);
|
||||
}
|
||||
|
||||
return $this->getDefinition($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a service for a service definition.
|
||||
*
|
||||
* @param Definition $definition A service definition instance
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return object The service described by the service definition
|
||||
*
|
||||
* @throws RuntimeException When the scope is inactive
|
||||
* @throws RuntimeException When the factory definition is incomplete
|
||||
* @throws InvalidArgumentException When configure callable is not callable
|
||||
*/
|
||||
private function createService(Definition $definition, $id)
|
||||
{
|
||||
$parameterBag = $this->getParameterBag();
|
||||
|
||||
if (null !== $definition->getFile()) {
|
||||
require_once $parameterBag->resolveValue($definition->getFile());
|
||||
}
|
||||
|
||||
$arguments = $this->resolveServices(
|
||||
$parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments()))
|
||||
);
|
||||
|
||||
if (null !== $definition->getFactoryMethod()) {
|
||||
if (null !== $definition->getFactoryClass()) {
|
||||
$factory = $parameterBag->resolveValue($definition->getFactoryClass());
|
||||
} elseif (null !== $definition->getFactoryService()) {
|
||||
$factory = $this->get($parameterBag->resolveValue($definition->getFactoryService()));
|
||||
} else {
|
||||
throw new RuntimeException('Cannot create service from factory method without a factory service or factory class.');
|
||||
}
|
||||
|
||||
$service = call_user_func_array(array($factory, $definition->getFactoryMethod()), $arguments);
|
||||
} else {
|
||||
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
|
||||
|
||||
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
|
||||
}
|
||||
|
||||
if (self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
|
||||
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
|
||||
throw new RuntimeException('You tried to create a service of an inactive scope.');
|
||||
}
|
||||
|
||||
$this->services[$lowerId = strtolower($id)] = $service;
|
||||
|
||||
if (self::SCOPE_CONTAINER !== $scope) {
|
||||
$this->scopedServices[$scope][$lowerId] = $service;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($definition->getMethodCalls() as $call) {
|
||||
$services = self::getServiceConditionals($call[1]);
|
||||
|
||||
$ok = true;
|
||||
foreach ($services as $s) {
|
||||
if (!$this->has($s)) {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ok) {
|
||||
call_user_func_array(array($service, $call[0]), $this->resolveServices($parameterBag->resolveValue($call[1])));
|
||||
}
|
||||
}
|
||||
|
||||
$properties = $this->resolveServices($parameterBag->resolveValue($definition->getProperties()));
|
||||
foreach ($properties as $name => $value) {
|
||||
$service->$name = $value;
|
||||
}
|
||||
|
||||
if ($callable = $definition->getConfigurator()) {
|
||||
if (is_array($callable) && is_object($callable[0]) && $callable[0] instanceof Reference) {
|
||||
$callable[0] = $this->get((string) $callable[0]);
|
||||
} elseif (is_array($callable)) {
|
||||
$callable[0] = $parameterBag->resolveValue($callable[0]);
|
||||
}
|
||||
|
||||
if (!is_callable($callable)) {
|
||||
throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
|
||||
}
|
||||
|
||||
call_user_func($callable, $service);
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces service references by the real service instance.
|
||||
*
|
||||
* @param mixed $value A value
|
||||
*
|
||||
* @return mixed The same value with all service references replaced by the real service instances
|
||||
*/
|
||||
public function resolveServices($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
foreach ($value as &$v) {
|
||||
$v = $this->resolveServices($v);
|
||||
}
|
||||
} elseif (is_object($value) && $value instanceof Reference) {
|
||||
$value = $this->get((string) $value, $value->getInvalidBehavior());
|
||||
} elseif (is_object($value) && $value instanceof Definition) {
|
||||
$value = $this->createService($value, null);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns service ids for a given tag.
|
||||
*
|
||||
* @param string $name The tag name
|
||||
*
|
||||
* @return array An array of tags
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function findTaggedServiceIds($name)
|
||||
{
|
||||
$tags = array();
|
||||
foreach ($this->getDefinitions() as $id => $definition) {
|
||||
if ($definition->getTag($name)) {
|
||||
$tags[$id] = $definition->getTag($name);
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Service Conditionals.
|
||||
*
|
||||
* @param mixed $value An array of conditionals to return.
|
||||
*
|
||||
* @return array An array of Service conditionals
|
||||
*/
|
||||
public static function getServiceConditionals($value)
|
||||
{
|
||||
$services = array();
|
||||
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $v) {
|
||||
$services = array_unique(array_merge($services, self::getServiceConditionals($v)));
|
||||
}
|
||||
} elseif (is_object($value) && $value instanceof Reference && $value->getInvalidBehavior() === ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
|
||||
$services[] = (string) $value;
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
|
||||
/**
|
||||
* ContainerInterface is the interface implemented by service container classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface ContainerInterface
|
||||
{
|
||||
const EXCEPTION_ON_INVALID_REFERENCE = 1;
|
||||
const NULL_ON_INVALID_REFERENCE = 2;
|
||||
const IGNORE_ON_INVALID_REFERENCE = 3;
|
||||
const SCOPE_CONTAINER = 'container';
|
||||
const SCOPE_PROTOTYPE = 'prototype';
|
||||
|
||||
/**
|
||||
* Sets a service.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param object $service The service instance
|
||||
* @param string $scope The scope of the service
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($id, $service, $scope = self::SCOPE_CONTAINER);
|
||||
|
||||
/**
|
||||
* Gets a service.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param int $invalidBehavior The behavior when the service does not exist
|
||||
*
|
||||
* @return object The associated service
|
||||
*
|
||||
* @throws InvalidArgumentException if the service is not defined
|
||||
* @throws ServiceCircularReferenceException When a circular reference is detected
|
||||
* @throws ServiceNotFoundException When the service is not defined
|
||||
*
|
||||
* @see Reference
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
|
||||
/**
|
||||
* Returns true if the given service is defined.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return Boolean true if the service is defined, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($id);
|
||||
|
||||
/**
|
||||
* Gets a parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws InvalidArgumentException if the parameter is not defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getParameter($name);
|
||||
|
||||
/**
|
||||
* Checks if a parameter exists.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return Boolean The presence of parameter in container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasParameter($name);
|
||||
|
||||
/**
|
||||
* Sets a parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
* @param mixed $value The parameter value
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setParameter($name, $value);
|
||||
|
||||
/**
|
||||
* Enters the given scope
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function enterScope($name);
|
||||
|
||||
/**
|
||||
* Leaves the current scope, and re-enters the parent scope
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function leaveScope($name);
|
||||
|
||||
/**
|
||||
* Adds a scope to the container
|
||||
*
|
||||
* @param ScopeInterface $scope
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addScope(ScopeInterface $scope);
|
||||
|
||||
/**
|
||||
* Whether this container has the given scope
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasScope($name);
|
||||
|
||||
/**
|
||||
* Determines whether the given scope is currently active.
|
||||
*
|
||||
* It does however not check if the scope actually exists.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isScopeActive($name);
|
||||
}
|
||||
659
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Definition.php
vendored
Normal file
659
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Definition.php
vendored
Normal file
@@ -0,0 +1,659 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Definition represents a service definition.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Definition
|
||||
{
|
||||
private $class;
|
||||
private $file;
|
||||
private $factoryClass;
|
||||
private $factoryMethod;
|
||||
private $factoryService;
|
||||
private $scope;
|
||||
private $properties;
|
||||
private $calls;
|
||||
private $configurator;
|
||||
private $tags;
|
||||
private $public;
|
||||
private $synthetic;
|
||||
private $abstract;
|
||||
|
||||
protected $arguments;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $class The service class
|
||||
* @param array $arguments An array of arguments to pass to the service constructor
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($class = null, array $arguments = array())
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->arguments = $arguments;
|
||||
$this->calls = array();
|
||||
$this->scope = ContainerInterface::SCOPE_CONTAINER;
|
||||
$this->tags = array();
|
||||
$this->public = true;
|
||||
$this->synthetic = false;
|
||||
$this->abstract = false;
|
||||
$this->properties = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the class that acts as a factory using the factory method,
|
||||
* which will be invoked statically.
|
||||
*
|
||||
* @param string $factoryClass The factory class name
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFactoryClass($factoryClass)
|
||||
{
|
||||
$this->factoryClass = $factoryClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory class.
|
||||
*
|
||||
* @return string The factory class name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFactoryClass()
|
||||
{
|
||||
return $this->factoryClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory method able to create an instance of this class.
|
||||
*
|
||||
* @param string $factoryMethod The factory method name
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFactoryMethod($factoryMethod)
|
||||
{
|
||||
$this->factoryMethod = $factoryMethod;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory method.
|
||||
*
|
||||
* @return string The factory method name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFactoryMethod()
|
||||
{
|
||||
return $this->factoryMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the service that acts as a factory using the factory method.
|
||||
*
|
||||
* @param string $factoryService The factory service id
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFactoryService($factoryService)
|
||||
{
|
||||
$this->factoryService = $factoryService;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory service id.
|
||||
*
|
||||
* @return string The factory service id
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFactoryService()
|
||||
{
|
||||
return $this->factoryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service class.
|
||||
*
|
||||
* @param string $class The service class
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setClass($class)
|
||||
{
|
||||
$this->class = $class;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service class.
|
||||
*
|
||||
* @return string The service class
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getClass()
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the arguments to pass to the service constructor/factory method.
|
||||
*
|
||||
* @param array $arguments An array of arguments
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function setProperties(array $properties)
|
||||
{
|
||||
$this->properties = $properties;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function getProperties()
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function setProperty($name, $value)
|
||||
{
|
||||
$this->properties[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an argument to pass to the service constructor/factory method.
|
||||
*
|
||||
* @param mixed $argument An argument
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addArgument($argument)
|
||||
{
|
||||
$this->arguments[] = $argument;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific argument
|
||||
*
|
||||
* @param integer $index
|
||||
* @param mixed $argument
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @throws \OutOfBoundsException When the replaced argument does not exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function replaceArgument($index, $argument)
|
||||
{
|
||||
if ($index < 0 || $index > count($this->arguments) - 1) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1));
|
||||
}
|
||||
|
||||
$this->arguments[$index] = $argument;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the arguments to pass to the service constructor/factory method.
|
||||
*
|
||||
* @return array The array of arguments
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an argument to pass to the service constructor/factory method.
|
||||
*
|
||||
* @param integer $index
|
||||
*
|
||||
* @return mixed The argument value
|
||||
*
|
||||
* @throws \OutOfBoundsException When the argument does not exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getArgument($index)
|
||||
{
|
||||
if ($index < 0 || $index > count($this->arguments) - 1) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1));
|
||||
}
|
||||
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the methods to call after service initialization.
|
||||
*
|
||||
* @param array $calls An array of method calls
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setMethodCalls(array $calls = array())
|
||||
{
|
||||
$this->calls = array();
|
||||
foreach ($calls as $call) {
|
||||
$this->addMethodCall($call[0], $call[1]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a method to call after service initialization.
|
||||
*
|
||||
* @param string $method The method name to call
|
||||
* @param array $arguments An array of arguments to pass to the method call
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @throws InvalidArgumentException on empty $method param
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addMethodCall($method, array $arguments = array())
|
||||
{
|
||||
if (empty($method)) {
|
||||
throw new InvalidArgumentException(sprintf('Method name cannot be empty.'));
|
||||
}
|
||||
$this->calls[] = array($method, $arguments);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a method to call after service initialization.
|
||||
*
|
||||
* @param string $method The method name to remove
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function removeMethodCall($method)
|
||||
{
|
||||
foreach ($this->calls as $i => $call) {
|
||||
if ($call[0] === $method) {
|
||||
unset($this->calls[$i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current definition has a given method to call after service initialization.
|
||||
*
|
||||
* @param string $method The method name to search for
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasMethodCall($method)
|
||||
{
|
||||
foreach ($this->calls as $call) {
|
||||
if ($call[0] === $method) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the methods to call after service initialization.
|
||||
*
|
||||
* @return array An array of method calls
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getMethodCalls()
|
||||
{
|
||||
return $this->calls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tags for this definition
|
||||
*
|
||||
* @param array $tags
|
||||
*
|
||||
* @return Definition the current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setTags(array $tags)
|
||||
{
|
||||
$this->tags = $tags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all tags.
|
||||
*
|
||||
* @return array An array of tags
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a tag by name.
|
||||
*
|
||||
* @param string $name The tag name
|
||||
*
|
||||
* @return array An array of attributes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getTag($name)
|
||||
{
|
||||
return isset($this->tags[$name]) ? $this->tags[$name] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tag for this definition.
|
||||
*
|
||||
* @param string $name The tag name
|
||||
* @param array $attributes An array of attributes
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addTag($name, array $attributes = array())
|
||||
{
|
||||
$this->tags[$name][] = $attributes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition has a tag with the given name
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function hasTag($name)
|
||||
{
|
||||
return isset($this->tags[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all tags for a given name.
|
||||
*
|
||||
* @param string $name The tag name
|
||||
*
|
||||
* @return Definition
|
||||
*/
|
||||
public function clearTag($name)
|
||||
{
|
||||
if (isset($this->tags[$name])) {
|
||||
unset($this->tags[$name]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the tags for this definition.
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function clearTags()
|
||||
{
|
||||
$this->tags = array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a file to require before creating the service.
|
||||
*
|
||||
* @param string $file A full pathname to include
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFile($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file to require before creating the service.
|
||||
*
|
||||
* @return string The full pathname to include
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scope of the service
|
||||
*
|
||||
* @param string $scope Whether the service must be shared or not
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setScope($scope)
|
||||
{
|
||||
$this->scope = $scope;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scope of the service
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getScope()
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of this service.
|
||||
*
|
||||
* @param Boolean $boolean
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setPublic($boolean)
|
||||
{
|
||||
$this->public = (Boolean) $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is public facing
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isPublic()
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this definition is synthetic, that is not constructed by the
|
||||
* container, but dynamically injected.
|
||||
*
|
||||
* @param Boolean $boolean
|
||||
*
|
||||
* @return Definition the current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setSynthetic($boolean)
|
||||
{
|
||||
$this->synthetic = (Boolean) $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is synthetic, that is not constructed by the
|
||||
* container, but dynamically injected.
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isSynthetic()
|
||||
{
|
||||
return $this->synthetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is abstract, that means it merely serves as a
|
||||
* template for other definitions.
|
||||
*
|
||||
* @param Boolean $boolean
|
||||
*
|
||||
* @return Definition the current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setAbstract($boolean)
|
||||
{
|
||||
$this->abstract = (Boolean) $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is abstract, that means it merely serves as a
|
||||
* template for other definitions.
|
||||
*
|
||||
* @return Boolean
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isAbstract()
|
||||
{
|
||||
return $this->abstract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a configurator to call after the service is fully initialized.
|
||||
*
|
||||
* @param callable $callable A PHP callable
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setConfigurator($callable)
|
||||
{
|
||||
$this->configurator = $callable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configurator to call after the service is fully initialized.
|
||||
*
|
||||
* @return callable The PHP callable to call
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getConfigurator()
|
||||
{
|
||||
return $this->configurator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* This definition decorates another definition.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class DefinitionDecorator extends Definition
|
||||
{
|
||||
private $parent;
|
||||
private $changes;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $parent The id of Definition instance to decorate.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($parent)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->parent = $parent;
|
||||
$this->changes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Definition being decorated.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all changes tracked for the Definition object.
|
||||
*
|
||||
* @return array An array of changes for this Definition
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getChanges()
|
||||
{
|
||||
return $this->changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setClass($class)
|
||||
{
|
||||
$this->changes['class'] = true;
|
||||
|
||||
return parent::setClass($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFactoryClass($class)
|
||||
{
|
||||
$this->changes['factory_class'] = true;
|
||||
|
||||
return parent::setFactoryClass($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFactoryMethod($method)
|
||||
{
|
||||
$this->changes['factory_method'] = true;
|
||||
|
||||
return parent::setFactoryMethod($method);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFactoryService($service)
|
||||
{
|
||||
$this->changes['factory_service'] = true;
|
||||
|
||||
return parent::setFactoryService($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setConfigurator($callable)
|
||||
{
|
||||
$this->changes['configurator'] = true;
|
||||
|
||||
return parent::setConfigurator($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setFile($file)
|
||||
{
|
||||
$this->changes['file'] = true;
|
||||
|
||||
return parent::setFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setPublic($boolean)
|
||||
{
|
||||
$this->changes['public'] = true;
|
||||
|
||||
return parent::setPublic($boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an argument to pass to the service constructor/factory method.
|
||||
*
|
||||
* If replaceArgument() has been used to replace an argument, this method
|
||||
* will return the replacement value.
|
||||
*
|
||||
* @param integer $index
|
||||
*
|
||||
* @return mixed The argument value
|
||||
*
|
||||
* @throws \OutOfBoundsException When the argument does not exist
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getArgument($index)
|
||||
{
|
||||
if (array_key_exists('index_'.$index, $this->arguments)) {
|
||||
return $this->arguments['index_'.$index];
|
||||
}
|
||||
|
||||
$lastIndex = count(array_filter(array_keys($this->arguments), 'is_int')) - 1;
|
||||
|
||||
if ($index < 0 || $index > $lastIndex) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, $lastIndex));
|
||||
}
|
||||
|
||||
return $this->arguments[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* You should always use this method when overwriting existing arguments
|
||||
* of the parent definition.
|
||||
*
|
||||
* If you directly call setArguments() keep in mind that you must follow
|
||||
* certain conventions when you want to overwrite the arguments of the
|
||||
* parent definition, otherwise your arguments will only be appended.
|
||||
*
|
||||
* @param integer $index
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return DefinitionDecorator the current instance
|
||||
* @throws InvalidArgumentException when $index isn't an integer
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function replaceArgument($index, $value)
|
||||
{
|
||||
if (!is_int($index)) {
|
||||
throw new InvalidArgumentException('$index must be an integer.');
|
||||
}
|
||||
|
||||
$this->arguments['index_'.$index] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
38
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/Dumper.php
vendored
Normal file
38
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/Dumper.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?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\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Dumper is the abstract class for all built-in dumpers.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
abstract class Dumper implements DumperInterface
|
||||
{
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ContainerBuilder $container The service container to dump
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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\Dumper;
|
||||
|
||||
/**
|
||||
* DumperInterface is the interface implemented by service container dumper classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface DumperInterface
|
||||
{
|
||||
/**
|
||||
* Dumps the service container.
|
||||
*
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @return string The representation of the service container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function dump(array $options = array());
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
<?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\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* GraphvizDumper dumps a service container as a graphviz file.
|
||||
*
|
||||
* You can convert the generated dot file with the dot utility (http://www.graphviz.org/):
|
||||
*
|
||||
* dot -Tpng container.dot > foo.png
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class GraphvizDumper extends Dumper
|
||||
{
|
||||
private $nodes;
|
||||
private $edges;
|
||||
private $options = array(
|
||||
'graph' => array('ratio' => 'compress'),
|
||||
'node' => array('fontsize' => 11, 'fontname' => 'Arial', 'shape' => 'record'),
|
||||
'edge' => array('fontsize' => 9, 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => 0.5),
|
||||
'node.instance' => array('fillcolor' => '#9999ff', 'style' => 'filled'),
|
||||
'node.definition' => array('fillcolor' => '#eeeeee'),
|
||||
'node.missing' => array('fillcolor' => '#ff9999', 'style' => 'filled'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Dumps the service container as a graphviz graph.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * graph: The default options for the whole graph
|
||||
* * node: The default options for nodes
|
||||
* * edge: The default options for edges
|
||||
* * node.instance: The default options for services that are defined directly by object instances
|
||||
* * node.definition: The default options for services that are defined via service definition instances
|
||||
* * node.missing: The default options for missing services
|
||||
*
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @return string The dot representation of the service container
|
||||
*/
|
||||
public function dump(array $options = array())
|
||||
{
|
||||
foreach (array('graph', 'node', 'edge', 'node.instance', 'node.definition', 'node.missing') as $key) {
|
||||
if (isset($options[$key])) {
|
||||
$this->options[$key] = array_merge($this->options[$key], $options[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->nodes = $this->findNodes();
|
||||
|
||||
$this->edges = array();
|
||||
foreach ($this->container->getDefinitions() as $id => $definition) {
|
||||
$this->edges[$id] = array_merge(
|
||||
$this->findEdges($id, $definition->getArguments(), true, ''),
|
||||
$this->findEdges($id, $definition->getProperties(), false, '')
|
||||
);
|
||||
|
||||
foreach ($definition->getMethodCalls() as $call) {
|
||||
$this->edges[$id] = array_merge(
|
||||
$this->edges[$id],
|
||||
$this->findEdges($id, $call[1], false, $call[0].'()')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->startDot().$this->addNodes().$this->addEdges().$this->endDot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all nodes.
|
||||
*
|
||||
* @return string A string representation of all nodes
|
||||
*/
|
||||
private function addNodes()
|
||||
{
|
||||
$code = '';
|
||||
foreach ($this->nodes as $id => $node) {
|
||||
$aliases = $this->getAliases($id);
|
||||
|
||||
$code .= sprintf(" node_%s [label=\"%s\\n%s\\n\", shape=%s%s];\n", $this->dotize($id), $id.($aliases ? ' ('.implode(', ', $aliases).')' : ''), $node['class'], $this->options['node']['shape'], $this->addAttributes($node['attributes']));
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all edges.
|
||||
*
|
||||
* @return string A string representation of all edges
|
||||
*/
|
||||
private function addEdges()
|
||||
{
|
||||
$code = '';
|
||||
foreach ($this->edges as $id => $edges) {
|
||||
foreach ($edges as $edge) {
|
||||
$code .= sprintf(" node_%s -> node_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $edge['name'], $edge['required'] ? 'filled' : 'dashed');
|
||||
}
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all edges belonging to a specific service id.
|
||||
*
|
||||
* @param string $id The service id used to find edges
|
||||
* @param array $arguments An array of arguments
|
||||
* @param Boolean $required
|
||||
* @param string $name
|
||||
*
|
||||
* @return array An array of edges
|
||||
*/
|
||||
private function findEdges($id, $arguments, $required, $name)
|
||||
{
|
||||
$edges = array();
|
||||
foreach ($arguments as $argument) {
|
||||
if (is_object($argument) && $argument instanceof Parameter) {
|
||||
$argument = $this->container->hasParameter($argument) ? $this->container->getParameter($argument) : null;
|
||||
} elseif (is_string($argument) && preg_match('/^%([^%]+)%$/', $argument, $match)) {
|
||||
$argument = $this->container->hasParameter($match[1]) ? $this->container->getParameter($match[1]) : null;
|
||||
}
|
||||
|
||||
if ($argument instanceof Reference) {
|
||||
if (!$this->container->has((string) $argument)) {
|
||||
$this->nodes[(string) $argument] = array('name' => $name, 'required' => $required, 'class' => '', 'attributes' => $this->options['node.missing']);
|
||||
}
|
||||
|
||||
$edges[] = array('name' => $name, 'required' => $required, 'to' => $argument);
|
||||
} elseif (is_array($argument)) {
|
||||
$edges = array_merge($edges, $this->findEdges($id, $argument, $required, $name));
|
||||
}
|
||||
}
|
||||
|
||||
return $edges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all nodes.
|
||||
*
|
||||
* @return array An array of all nodes
|
||||
*/
|
||||
private function findNodes()
|
||||
{
|
||||
$nodes = array();
|
||||
|
||||
$container = clone $this->container;
|
||||
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $this->container->getParameterBag()->resolveValue($definition->getClass())), 'attributes' => array_merge($this->options['node.definition'], array('style' => ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope() ? 'filled' : 'dotted')));
|
||||
|
||||
$container->setDefinition($id, new Definition('stdClass'));
|
||||
}
|
||||
|
||||
foreach ($container->getServiceIds() as $id) {
|
||||
$service = $container->get($id);
|
||||
|
||||
if (in_array($id, array_keys($container->getAliases()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$container->hasDefinition($id)) {
|
||||
$nodes[$id] = array('class' => str_replace('\\', '\\\\', get_class($service)), 'attributes' => $this->options['node.instance']);
|
||||
}
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start dot.
|
||||
*
|
||||
* @return string The string representation of a start dot
|
||||
*/
|
||||
private function startDot()
|
||||
{
|
||||
return sprintf("digraph sc {\n %s\n node [%s];\n edge [%s];\n\n",
|
||||
$this->addOptions($this->options['graph']),
|
||||
$this->addOptions($this->options['node']),
|
||||
$this->addOptions($this->options['edge'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end dot.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function endDot()
|
||||
{
|
||||
return "}\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds attributes
|
||||
*
|
||||
* @param array $attributes An array of attributes
|
||||
*
|
||||
* @return string A comma separated list of attributes
|
||||
*/
|
||||
private function addAttributes($attributes)
|
||||
{
|
||||
$code = array();
|
||||
foreach ($attributes as $k => $v) {
|
||||
$code[] = sprintf('%s="%s"', $k, $v);
|
||||
}
|
||||
|
||||
return $code ? ', '.implode(', ', $code) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options
|
||||
*
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @return string A space separated list of options
|
||||
*/
|
||||
private function addOptions($options)
|
||||
{
|
||||
$code = array();
|
||||
foreach ($options as $k => $v) {
|
||||
$code[] = sprintf('%s="%s"', $k, $v);
|
||||
}
|
||||
|
||||
return implode(' ', $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dotizes an identifier.
|
||||
*
|
||||
* @param string $id The identifier to dotize
|
||||
*
|
||||
* @return string A dotized string
|
||||
*/
|
||||
private function dotize($id)
|
||||
{
|
||||
return strtolower(preg_replace('/[^\w]/i', '_', $id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles an array of aliases for a specified service id.
|
||||
*
|
||||
* @param string $id A service id
|
||||
*
|
||||
* @return array An array of aliases
|
||||
*/
|
||||
private function getAliases($id)
|
||||
{
|
||||
$aliases = array();
|
||||
foreach ($this->container->getAliases() as $alias => $origin) {
|
||||
if ($id == $origin) {
|
||||
$aliases[] = $alias;
|
||||
}
|
||||
}
|
||||
|
||||
return $aliases;
|
||||
}
|
||||
}
|
||||
1145
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
vendored
Normal file
1145
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
305
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
vendored
Normal file
305
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
<?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\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* XmlDumper dumps a service container as an XML string.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class XmlDumper extends Dumper
|
||||
{
|
||||
/**
|
||||
* @var \DOMDocument
|
||||
*/
|
||||
private $document;
|
||||
|
||||
/**
|
||||
* Dumps the service container as an XML string.
|
||||
*
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @return string An xml string representing of the service container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function dump(array $options = array())
|
||||
{
|
||||
$this->document = new \DOMDocument('1.0', 'utf-8');
|
||||
$this->document->formatOutput = true;
|
||||
|
||||
$container = $this->document->createElementNS('http://symfony.com/schema/dic/services', 'container');
|
||||
$container->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
|
||||
$container->setAttribute('xsi:schemaLocation', 'http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd');
|
||||
|
||||
$this->addParameters($container);
|
||||
$this->addServices($container);
|
||||
|
||||
$this->document->appendChild($container);
|
||||
$xml = $this->document->saveXML();
|
||||
$this->document = null;
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds parameters.
|
||||
*
|
||||
* @param \DOMElement $parent
|
||||
*/
|
||||
private function addParameters(\DOMElement $parent)
|
||||
{
|
||||
$data = $this->container->getParameterBag()->all();
|
||||
if (!$data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->container->isFrozen()) {
|
||||
$data = $this->escape($data);
|
||||
}
|
||||
|
||||
$parameters = $this->document->createElement('parameters');
|
||||
$parent->appendChild($parameters);
|
||||
$this->convertParameters($data, 'parameter', $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds method calls.
|
||||
*
|
||||
* @param array $methodcalls
|
||||
* @param \DOMElement $parent
|
||||
*/
|
||||
private function addMethodCalls(array $methodcalls, \DOMElement $parent)
|
||||
{
|
||||
foreach ($methodcalls as $methodcall) {
|
||||
$call = $this->document->createElement('call');
|
||||
$call->setAttribute('method', $methodcall[0]);
|
||||
if (count($methodcall[1])) {
|
||||
$this->convertParameters($methodcall[1], 'argument', $call);
|
||||
}
|
||||
$parent->appendChild($call);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a service.
|
||||
*
|
||||
* @param Definition $definition
|
||||
* @param string $id
|
||||
* @param \DOMElement $parent
|
||||
*/
|
||||
private function addService($definition, $id, \DOMElement $parent)
|
||||
{
|
||||
$service = $this->document->createElement('service');
|
||||
if (null !== $id) {
|
||||
$service->setAttribute('id', $id);
|
||||
}
|
||||
if ($definition->getClass()) {
|
||||
$service->setAttribute('class', $definition->getClass());
|
||||
}
|
||||
if ($definition->getFactoryMethod()) {
|
||||
$service->setAttribute('factory-method', $definition->getFactoryMethod());
|
||||
}
|
||||
if ($definition->getFactoryService()) {
|
||||
$service->setAttribute('factory-service', $definition->getFactoryService());
|
||||
}
|
||||
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
|
||||
$service->setAttribute('scope', $scope);
|
||||
}
|
||||
if (!$definition->isPublic()) {
|
||||
$service->setAttribute('public', 'false');
|
||||
}
|
||||
|
||||
foreach ($definition->getTags() as $name => $tags) {
|
||||
foreach ($tags as $attributes) {
|
||||
$tag = $this->document->createElement('tag');
|
||||
$tag->setAttribute('name', $name);
|
||||
foreach ($attributes as $key => $value) {
|
||||
$tag->setAttribute($key, $value);
|
||||
}
|
||||
$service->appendChild($tag);
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition->getFile()) {
|
||||
$file = $this->document->createElement('file');
|
||||
$file->appendChild($this->document->createTextNode($definition->getFile()));
|
||||
$service->appendChild($file);
|
||||
}
|
||||
|
||||
if ($parameters = $definition->getArguments()) {
|
||||
$this->convertParameters($parameters, 'argument', $service);
|
||||
}
|
||||
|
||||
if ($parameters = $definition->getProperties()) {
|
||||
$this->convertParameters($parameters, 'property', $service, 'name');
|
||||
}
|
||||
|
||||
$this->addMethodCalls($definition->getMethodCalls(), $service);
|
||||
|
||||
if ($callable = $definition->getConfigurator()) {
|
||||
$configurator = $this->document->createElement('configurator');
|
||||
if (is_array($callable)) {
|
||||
$configurator->setAttribute((is_object($callable[0]) && $callable[0] instanceof Reference ? 'service' : 'class'), $callable[0]);
|
||||
$configurator->setAttribute('method', $callable[1]);
|
||||
} else {
|
||||
$configurator->setAttribute('function', $callable);
|
||||
}
|
||||
$service->appendChild($configurator);
|
||||
}
|
||||
|
||||
$parent->appendChild($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a service alias.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param string $id
|
||||
* @param \DOMElement $parent
|
||||
*/
|
||||
private function addServiceAlias($alias, $id, \DOMElement $parent)
|
||||
{
|
||||
$service = $this->document->createElement('service');
|
||||
$service->setAttribute('id', $alias);
|
||||
$service->setAttribute('alias', $id);
|
||||
if (!$id->isPublic()) {
|
||||
$service->setAttribute('public', 'false');
|
||||
}
|
||||
$parent->appendChild($service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds services.
|
||||
*
|
||||
* @param \DOMElement $parent
|
||||
*/
|
||||
private function addServices(\DOMElement $parent)
|
||||
{
|
||||
$definitions = $this->container->getDefinitions();
|
||||
if (!$definitions) {
|
||||
return;
|
||||
}
|
||||
|
||||
$services = $this->document->createElement('services');
|
||||
foreach ($definitions as $id => $definition) {
|
||||
$this->addService($definition, $id, $services);
|
||||
}
|
||||
|
||||
foreach ($this->container->getAliases() as $alias => $id) {
|
||||
$this->addServiceAlias($alias, $id, $services);
|
||||
}
|
||||
$parent->appendChild($services);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts parameters.
|
||||
*
|
||||
* @param array $parameters
|
||||
* @param string $type
|
||||
* @param \DOMElement $parent
|
||||
* @param string $keyAttribute
|
||||
*/
|
||||
private function convertParameters($parameters, $type, \DOMElement $parent, $keyAttribute = 'key')
|
||||
{
|
||||
$withKeys = array_keys($parameters) !== range(0, count($parameters) - 1);
|
||||
foreach ($parameters as $key => $value) {
|
||||
$element = $this->document->createElement($type);
|
||||
if ($withKeys) {
|
||||
$element->setAttribute($keyAttribute, $key);
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$element->setAttribute('type', 'collection');
|
||||
$this->convertParameters($value, $type, $element, 'key');
|
||||
} elseif (is_object($value) && $value instanceof Reference) {
|
||||
$element->setAttribute('type', 'service');
|
||||
$element->setAttribute('id', (string) $value);
|
||||
$behaviour = $value->getInvalidBehavior();
|
||||
if ($behaviour == ContainerInterface::NULL_ON_INVALID_REFERENCE) {
|
||||
$element->setAttribute('on-invalid', 'null');
|
||||
} elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
|
||||
$element->setAttribute('on-invalid', 'ignore');
|
||||
}
|
||||
} elseif (is_object($value) && $value instanceof Definition) {
|
||||
$element->setAttribute('type', 'service');
|
||||
$this->addService($value, null, $element);
|
||||
} else {
|
||||
if (in_array($value, array('null', 'true', 'false'), true)) {
|
||||
$element->setAttribute('type', 'string');
|
||||
}
|
||||
$text = $this->document->createTextNode(self::phpToXml($value));
|
||||
$element->appendChild($text);
|
||||
}
|
||||
$parent->appendChild($element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes arguments
|
||||
*
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function escape($arguments)
|
||||
{
|
||||
$args = array();
|
||||
foreach ($arguments as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$args[$k] = $this->escape($v);
|
||||
} elseif (is_string($v)) {
|
||||
$args[$k] = str_replace('%', '%%', $v);
|
||||
} else {
|
||||
$args[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts php types to xml types.
|
||||
*
|
||||
* @param mixed $value Value to convert
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws RuntimeException When trying to dump object or resource
|
||||
*/
|
||||
public static function phpToXml($value)
|
||||
{
|
||||
switch (true) {
|
||||
case null === $value:
|
||||
return 'null';
|
||||
case true === $value:
|
||||
return 'true';
|
||||
case false === $value:
|
||||
return 'false';
|
||||
case is_object($value) && $value instanceof Parameter:
|
||||
return '%'.$value.'%';
|
||||
case is_object($value) || is_resource($value):
|
||||
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
|
||||
default:
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
300
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
vendored
Normal file
300
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
<?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\Dumper;
|
||||
|
||||
use Symfony\Component\Yaml\Dumper as YmlDumper;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* YamlDumper dumps a service container as a YAML string.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class YamlDumper extends Dumper
|
||||
{
|
||||
private $dumper;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ContainerBuilder $container The service container to dump
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(ContainerBuilder $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
|
||||
$this->dumper = new YmlDumper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the service container as an YAML string.
|
||||
*
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @return string A YAML string representing of the service container
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function dump(array $options = array())
|
||||
{
|
||||
return $this->addParameters()."\n".$this->addServices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a service
|
||||
*
|
||||
* @param string $id
|
||||
* @param Definition $definition
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function addService($id, $definition)
|
||||
{
|
||||
$code = " $id:\n";
|
||||
if ($definition->getClass()) {
|
||||
$code .= sprintf(" class: %s\n", $definition->getClass());
|
||||
}
|
||||
|
||||
$tagsCode = '';
|
||||
foreach ($definition->getTags() as $name => $tags) {
|
||||
foreach ($tags as $attributes) {
|
||||
$att = array();
|
||||
foreach ($attributes as $key => $value) {
|
||||
$att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value));
|
||||
}
|
||||
$att = $att ? ', '.implode(' ', $att) : '';
|
||||
|
||||
$tagsCode .= sprintf(" - { name: %s%s }\n", $this->dumper->dump($name), $att);
|
||||
}
|
||||
}
|
||||
if ($tagsCode) {
|
||||
$code .= " tags:\n".$tagsCode;
|
||||
}
|
||||
|
||||
if ($definition->getFile()) {
|
||||
$code .= sprintf(" file: %s\n", $definition->getFile());
|
||||
}
|
||||
|
||||
if ($definition->getFactoryMethod()) {
|
||||
$code .= sprintf(" factory_method: %s\n", $definition->getFactoryMethod());
|
||||
}
|
||||
|
||||
if ($definition->getFactoryService()) {
|
||||
$code .= sprintf(" factory_service: %s\n", $definition->getFactoryService());
|
||||
}
|
||||
|
||||
if ($definition->getArguments()) {
|
||||
$code .= sprintf(" arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0));
|
||||
}
|
||||
|
||||
if ($definition->getProperties()) {
|
||||
$code .= sprintf(" properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0));
|
||||
}
|
||||
|
||||
if ($definition->getMethodCalls()) {
|
||||
$code .= sprintf(" calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
|
||||
}
|
||||
|
||||
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
|
||||
$code .= sprintf(" scope: %s\n", $scope);
|
||||
}
|
||||
|
||||
if ($callable = $definition->getConfigurator()) {
|
||||
if (is_array($callable)) {
|
||||
if (is_object($callable[0]) && $callable[0] instanceof Reference) {
|
||||
$callable = array($this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]);
|
||||
} else {
|
||||
$callable = array($callable[0], $callable[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$code .= sprintf(" configurator: %s\n", $this->dumper->dump($callable, 0));
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a service alias
|
||||
*
|
||||
* @param string $alias
|
||||
* @param Alias $id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function addServiceAlias($alias, $id)
|
||||
{
|
||||
if ($id->isPublic()) {
|
||||
return sprintf(" %s: @%s\n", $alias, $id);
|
||||
} else {
|
||||
return sprintf(" %s:\n alias: %s\n public: false", $alias, $id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds services
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function addServices()
|
||||
{
|
||||
if (!$this->container->getDefinitions()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$code = "services:\n";
|
||||
foreach ($this->container->getDefinitions() as $id => $definition) {
|
||||
$code .= $this->addService($id, $definition);
|
||||
}
|
||||
|
||||
foreach ($this->container->getAliases() as $alias => $id) {
|
||||
$code .= $this->addServiceAlias($alias, $id);
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds parameters
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function addParameters()
|
||||
{
|
||||
if (!$this->container->getParameterBag()->all()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($this->container->isFrozen()) {
|
||||
$parameters = $this->prepareParameters($this->container->getParameterBag()->all());
|
||||
} else {
|
||||
$parameters = $this->container->getParameterBag()->all();
|
||||
}
|
||||
|
||||
return $this->dumper->dump(array('parameters' => $parameters), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the value to YAML format
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws RuntimeException When trying to dump object or resource
|
||||
*/
|
||||
private function dumpValue($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$code = array();
|
||||
foreach ($value as $k => $v) {
|
||||
$code[$k] = $this->dumpValue($v);
|
||||
}
|
||||
|
||||
return $code;
|
||||
} elseif (is_object($value) && $value instanceof Reference) {
|
||||
return $this->getServiceCall((string) $value, $value);
|
||||
} elseif (is_object($value) && $value instanceof Parameter) {
|
||||
return $this->getParameterCall((string) $value);
|
||||
} elseif (is_object($value) || is_resource($value)) {
|
||||
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service call.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Reference $reference
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getServiceCall($id, Reference $reference = null)
|
||||
{
|
||||
if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
|
||||
return sprintf('@?%s', $id);
|
||||
}
|
||||
|
||||
return sprintf('@%s', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameter call.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getParameterCall($id)
|
||||
{
|
||||
return sprintf('%%%s%%', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares parameters
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function prepareParameters($parameters)
|
||||
{
|
||||
$filtered = array();
|
||||
foreach ($parameters as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$value = $this->prepareParameters($value);
|
||||
} elseif ($value instanceof Reference) {
|
||||
$value = '@'.$value;
|
||||
}
|
||||
|
||||
$filtered[$key] = $value;
|
||||
}
|
||||
|
||||
return $this->escape($filtered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes arguments
|
||||
*
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function escape($arguments)
|
||||
{
|
||||
$args = array();
|
||||
foreach ($arguments as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$args[$k] = $this->escape($v);
|
||||
} elseif (is_string($v)) {
|
||||
$args[$k] = str_replace('%', '%%', $v);
|
||||
} else {
|
||||
$args[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* Base BadMethodCallException for Dependency Injection component.
|
||||
*/
|
||||
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* Base ExceptionInterface for Dependency Injection component.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
|
||||
*/
|
||||
interface ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when you try to create a service of an inactive scope.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class InactiveScopeException extends RuntimeException
|
||||
{
|
||||
private $serviceId;
|
||||
private $scope;
|
||||
|
||||
public function __construct($serviceId, $scope)
|
||||
{
|
||||
parent::__construct(sprintf('You cannot create a service ("%s") of an inactive scope ("%s").', $serviceId, $scope));
|
||||
|
||||
$this->serviceId = $serviceId;
|
||||
$this->scope = $scope;
|
||||
}
|
||||
|
||||
public function getServiceId()
|
||||
{
|
||||
return $this->serviceId;
|
||||
}
|
||||
|
||||
public function getScope()
|
||||
{
|
||||
return $this->scope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* Base InvalidArgumentException for Dependency Injection component.
|
||||
*
|
||||
* @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* Base LogicException for Dependency Injection component.
|
||||
*/
|
||||
class LogicException extends \LogicException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* Base OutOfBoundsException for Dependency Injection component.
|
||||
*/
|
||||
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a circular reference in a parameter is detected.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ParameterCircularReferenceException extends RuntimeException
|
||||
{
|
||||
private $parameters;
|
||||
|
||||
public function __construct($parameters)
|
||||
{
|
||||
parent::__construct(sprintf('Circular reference detected for parameter "%s" ("%s" > "%s").', $parameters[0], implode('" > "', $parameters), $parameters[0]));
|
||||
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
public function getParameters()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a non-existent parameter is used.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ParameterNotFoundException extends InvalidArgumentException
|
||||
{
|
||||
private $key;
|
||||
private $sourceId;
|
||||
private $sourceKey;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $key The requested parameter key
|
||||
* @param string $sourceId The service id that references the non-existent parameter
|
||||
* @param string $sourceKey The parameter key that references the non-existent parameter
|
||||
*/
|
||||
public function __construct($key, $sourceId = null, $sourceKey = null)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->sourceId = $sourceId;
|
||||
$this->sourceKey = $sourceKey;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
public function updateRepr()
|
||||
{
|
||||
if (null !== $this->sourceId) {
|
||||
$this->message = sprintf('The service "%s" has a dependency on a non-existent parameter "%s".', $this->sourceId, $this->key);
|
||||
} elseif (null !== $this->sourceKey) {
|
||||
$this->message = sprintf('The parameter "%s" has a dependency on a non-existent parameter "%s".', $this->sourceKey, $this->key);
|
||||
} else {
|
||||
$this->message = sprintf('You have requested a non-existent parameter "%s".', $this->key);
|
||||
}
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
public function getSourceId()
|
||||
{
|
||||
return $this->sourceId;
|
||||
}
|
||||
|
||||
public function getSourceKey()
|
||||
{
|
||||
return $this->sourceKey;
|
||||
}
|
||||
|
||||
public function setSourceId($sourceId)
|
||||
{
|
||||
$this->sourceId = $sourceId;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
public function setSourceKey($sourceKey)
|
||||
{
|
||||
$this->sourceKey = $sourceKey;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* Base RuntimeException for Dependency Injection component.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the a scope crossing injection is detected.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ScopeCrossingInjectionException extends RuntimeException
|
||||
{
|
||||
private $sourceServiceId;
|
||||
private $sourceScope;
|
||||
private $destServiceId;
|
||||
private $destScope;
|
||||
|
||||
public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope)
|
||||
{
|
||||
parent::__construct(sprintf(
|
||||
'Scope Crossing Injection detected: The definition "%s" references the service "%s" which belongs to another scope hierarchy. '
|
||||
.'This service might not be available consistently. Generally, it is safer to either move the definition "%s" to scope "%s", or '
|
||||
.'declare "%s" as a child scope of "%s". If you can be sure that the other scope is always active, you can set the reference to strict=false to get rid of this error.',
|
||||
$sourceServiceId,
|
||||
$destServiceId,
|
||||
$sourceServiceId,
|
||||
$destScope,
|
||||
$sourceScope,
|
||||
$destScope
|
||||
));
|
||||
|
||||
$this->sourceServiceId = $sourceServiceId;
|
||||
$this->sourceScope = $sourceScope;
|
||||
$this->destServiceId = $destServiceId;
|
||||
$this->destScope = $destScope;
|
||||
}
|
||||
|
||||
public function getSourceServiceId()
|
||||
{
|
||||
return $this->sourceServiceId;
|
||||
}
|
||||
|
||||
public function getSourceScope()
|
||||
{
|
||||
return $this->sourceScope;
|
||||
}
|
||||
|
||||
public function getDestServiceId()
|
||||
{
|
||||
return $this->destServiceId;
|
||||
}
|
||||
|
||||
public function getDestScope()
|
||||
{
|
||||
return $this->destScope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when a scope widening injection is detected.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ScopeWideningInjectionException extends RuntimeException
|
||||
{
|
||||
private $sourceServiceId;
|
||||
private $sourceScope;
|
||||
private $destServiceId;
|
||||
private $destScope;
|
||||
|
||||
public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope)
|
||||
{
|
||||
parent::__construct(sprintf(
|
||||
'Scope Widening Injection detected: The definition "%s" references the service "%s" which belongs to a narrower scope. '
|
||||
.'Generally, it is safer to either move "%s" to scope "%s" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "%s" each time it is needed. '
|
||||
.'In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.',
|
||||
$sourceServiceId,
|
||||
$destServiceId,
|
||||
$sourceServiceId,
|
||||
$destScope,
|
||||
$destServiceId
|
||||
));
|
||||
|
||||
$this->sourceServiceId = $sourceServiceId;
|
||||
$this->sourceScope = $sourceScope;
|
||||
$this->destServiceId = $destServiceId;
|
||||
$this->destScope = $destScope;
|
||||
}
|
||||
|
||||
public function getSourceServiceId()
|
||||
{
|
||||
return $this->sourceServiceId;
|
||||
}
|
||||
|
||||
public function getSourceScope()
|
||||
{
|
||||
return $this->sourceScope;
|
||||
}
|
||||
|
||||
public function getDestServiceId()
|
||||
{
|
||||
return $this->destServiceId;
|
||||
}
|
||||
|
||||
public function getDestScope()
|
||||
{
|
||||
return $this->destScope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a circular reference is detected.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ServiceCircularReferenceException extends RuntimeException
|
||||
{
|
||||
private $serviceId;
|
||||
private $path;
|
||||
|
||||
public function __construct($serviceId, array $path)
|
||||
{
|
||||
parent::__construct(sprintf('Circular reference detected for service "%s", path: "%s".', $serviceId, implode(' -> ', $path)));
|
||||
|
||||
$this->serviceId = $serviceId;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function getServiceId()
|
||||
{
|
||||
return $this->serviceId;
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?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\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a non-existent service is requested.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ServiceNotFoundException extends InvalidArgumentException
|
||||
{
|
||||
private $id;
|
||||
private $sourceId;
|
||||
|
||||
public function __construct($id, $sourceId = null)
|
||||
{
|
||||
if (null === $sourceId) {
|
||||
$msg = sprintf('You have requested a non-existent service "%s".', $id);
|
||||
} else {
|
||||
$msg = sprintf('The service "%s" has a dependency on a non-existent service "%s".', $sourceId, $id);
|
||||
}
|
||||
|
||||
parent::__construct($msg);
|
||||
|
||||
$this->id = $id;
|
||||
$this->sourceId = $sourceId;
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getSourceId()
|
||||
{
|
||||
return $this->sourceId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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\Extension;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* ConfigurationExtensionInterface is the interface implemented by container extension classes.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
*/
|
||||
interface ConfigurationExtensionInterface
|
||||
{
|
||||
/**
|
||||
* Returns extension configuration
|
||||
*
|
||||
* @param array $config $config An array of configuration values
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
*
|
||||
* @return ConfigurationInterface|null The configuration or null
|
||||
*/
|
||||
public function getConfiguration(array $config, ContainerBuilder $container);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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\Extension;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* ExtensionInterface is the interface implemented by container extension classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface ExtensionInterface
|
||||
{
|
||||
/**
|
||||
* Loads a specific configuration.
|
||||
*
|
||||
* @param array $config An array of configuration values
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
*
|
||||
* @throws InvalidArgumentException When provided tag is not defined in this extension
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function load(array $config, ContainerBuilder $container);
|
||||
|
||||
/**
|
||||
* Returns the namespace to be used for this extension (XML namespace).
|
||||
*
|
||||
* @return string The XML namespace
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getNamespace();
|
||||
|
||||
/**
|
||||
* Returns the base path for the XSD files.
|
||||
*
|
||||
* @return string The XSD base path
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getXsdValidationBasePath();
|
||||
|
||||
/**
|
||||
* Returns the recommended alias to use in XML.
|
||||
*
|
||||
* This alias is also the mandatory prefix to use when using YAML.
|
||||
*
|
||||
* @return string The alias
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getAlias();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* IntrospectableContainerInterface defines additional introspection functionality
|
||||
* for containers, allowing logic to be implemented based on a Container's state.
|
||||
*
|
||||
* @author Evan Villemez <evillemez@gmail.com>
|
||||
*
|
||||
*/
|
||||
interface IntrospectableContainerInterface extends ContainerInterface
|
||||
{
|
||||
/**
|
||||
* Check for whether or not a service has been initialized.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return Boolean true if the service has been initialized, false otherwise
|
||||
*
|
||||
*/
|
||||
public function initialized($id);
|
||||
|
||||
}
|
||||
19
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LICENSE
vendored
Normal file
19
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2004-2012 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,61 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\Loader\Loader;
|
||||
|
||||
/**
|
||||
* ClosureLoader loads service definitions from a PHP closure.
|
||||
*
|
||||
* The Closure has access to the container as its first argument.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ClosureLoader extends Loader
|
||||
{
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
*/
|
||||
public function __construct(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a Closure.
|
||||
*
|
||||
* @param \Closure $closure The resource
|
||||
* @param string $type The resource type
|
||||
*/
|
||||
public function load($closure, $type = null)
|
||||
{
|
||||
call_user_func($closure, $this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean true if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return $resource instanceof \Closure;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
|
||||
use Symfony\Component\Config\FileLocatorInterface;
|
||||
|
||||
/**
|
||||
* FileLoader is the abstract class used by all built-in loaders that are file based.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class FileLoader extends BaseFileLoader
|
||||
{
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
* @param FileLocatorInterface $locator A FileLocator instance
|
||||
*/
|
||||
public function __construct(ContainerBuilder $container, FileLocatorInterface $locator)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
parent::__construct($locator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* IniFileLoader loads parameters from INI files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class IniFileLoader extends FileLoader
|
||||
{
|
||||
/**
|
||||
* Loads a resource.
|
||||
*
|
||||
* @param mixed $file The resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @throws InvalidArgumentException When ini file is not valid
|
||||
*/
|
||||
public function load($file, $type = null)
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
$this->container->addResource(new FileResource($path));
|
||||
|
||||
$result = parse_ini_file($path, true);
|
||||
if (false === $result || array() === $result) {
|
||||
throw new InvalidArgumentException(sprintf('The "%s" file is not valid.', $file));
|
||||
}
|
||||
|
||||
if (isset($result['parameters']) && is_array($result['parameters'])) {
|
||||
foreach ($result['parameters'] as $key => $value) {
|
||||
$this->container->setParameter($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean true if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return is_string($resource) && 'ini' === pathinfo($resource, PATHINFO_EXTENSION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
/**
|
||||
* PhpFileLoader loads service definitions from a PHP file.
|
||||
*
|
||||
* The PHP file is required and the $container variable can be
|
||||
* used form the file to change the container.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class PhpFileLoader extends FileLoader
|
||||
{
|
||||
/**
|
||||
* Loads a PHP file.
|
||||
*
|
||||
* @param mixed $file The resource
|
||||
* @param string $type The resource type
|
||||
*/
|
||||
public function load($file, $type = null)
|
||||
{
|
||||
// the container and loader variables are exposed to the included file below
|
||||
$container = $this->container;
|
||||
$loader = $this;
|
||||
|
||||
$path = $this->locator->locate($file);
|
||||
$this->setCurrentDir(dirname($path));
|
||||
$this->container->addResource(new FileResource($path));
|
||||
|
||||
include $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean true if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\SimpleXMLElement;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* XmlFileLoader loads XML files service definitions.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class XmlFileLoader extends FileLoader
|
||||
{
|
||||
/**
|
||||
* Loads an XML file.
|
||||
*
|
||||
* @param mixed $file The resource
|
||||
* @param string $type The resource type
|
||||
*/
|
||||
public function load($file, $type = null)
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
$xml = $this->parseFile($path);
|
||||
$xml->registerXPathNamespace('container', 'http://symfony.com/schema/dic/services');
|
||||
|
||||
$this->container->addResource(new FileResource($path));
|
||||
|
||||
// anonymous services
|
||||
$this->processAnonymousServices($xml, $path);
|
||||
|
||||
// imports
|
||||
$this->parseImports($xml, $path);
|
||||
|
||||
// parameters
|
||||
$this->parseParameters($xml, $path);
|
||||
|
||||
// extensions
|
||||
$this->loadFromExtensions($xml);
|
||||
|
||||
// services
|
||||
$this->parseDefinitions($xml, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean true if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses parameters
|
||||
*
|
||||
* @param SimpleXMLElement $xml
|
||||
* @param string $file
|
||||
*/
|
||||
private function parseParameters(SimpleXMLElement $xml, $file)
|
||||
{
|
||||
if (!$xml->parameters) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->container->getParameterBag()->add($xml->parameters->getArgumentsAsPhp('parameter'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses imports
|
||||
*
|
||||
* @param SimpleXMLElement $xml
|
||||
* @param string $file
|
||||
*/
|
||||
private function parseImports(SimpleXMLElement $xml, $file)
|
||||
{
|
||||
if (false === $imports = $xml->xpath('//container:imports/container:import')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($imports as $import) {
|
||||
$this->setCurrentDir(dirname($file));
|
||||
$this->import((string) $import['resource'], null, (Boolean) $import->getAttributeAsPhp('ignore-errors'), $file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses multiple definitions
|
||||
*
|
||||
* @param SimpleXMLElement $xml
|
||||
* @param string $file
|
||||
*/
|
||||
private function parseDefinitions(SimpleXMLElement $xml, $file)
|
||||
{
|
||||
if (false === $services = $xml->xpath('//container:services/container:service')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($services as $service) {
|
||||
$this->parseDefinition((string) $service['id'], $service, $file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an individual Definition
|
||||
*
|
||||
* @param string $id
|
||||
* @param SimpleXMLElement $service
|
||||
* @param string $file
|
||||
*/
|
||||
private function parseDefinition($id, $service, $file)
|
||||
{
|
||||
if ((string) $service['alias']) {
|
||||
$public = true;
|
||||
if (isset($service['public'])) {
|
||||
$public = $service->getAttributeAsPhp('public');
|
||||
}
|
||||
$this->container->setAlias($id, new Alias((string) $service['alias'], $public));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($service['parent'])) {
|
||||
$definition = new DefinitionDecorator((string) $service['parent']);
|
||||
} else {
|
||||
$definition = new Definition();
|
||||
}
|
||||
|
||||
foreach (array('class', 'scope', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'abstract') as $key) {
|
||||
if (isset($service[$key])) {
|
||||
$method = 'set'.str_replace('-', '', $key);
|
||||
$definition->$method((string) $service->getAttributeAsPhp($key));
|
||||
}
|
||||
}
|
||||
|
||||
if ($service->file) {
|
||||
$definition->setFile((string) $service->file);
|
||||
}
|
||||
|
||||
$definition->setArguments($service->getArgumentsAsPhp('argument'));
|
||||
$definition->setProperties($service->getArgumentsAsPhp('property'));
|
||||
|
||||
if (isset($service->configurator)) {
|
||||
if (isset($service->configurator['function'])) {
|
||||
$definition->setConfigurator((string) $service->configurator['function']);
|
||||
} else {
|
||||
if (isset($service->configurator['service'])) {
|
||||
$class = new Reference((string) $service->configurator['service'], ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
|
||||
} else {
|
||||
$class = (string) $service->configurator['class'];
|
||||
}
|
||||
|
||||
$definition->setConfigurator(array($class, (string) $service->configurator['method']));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($service->call as $call) {
|
||||
$definition->addMethodCall((string) $call['method'], $call->getArgumentsAsPhp('argument'));
|
||||
}
|
||||
|
||||
foreach ($service->tag as $tag) {
|
||||
$parameters = array();
|
||||
foreach ($tag->attributes() as $name => $value) {
|
||||
if ('name' === $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parameters[$name] = SimpleXMLElement::phpize($value);
|
||||
}
|
||||
|
||||
$definition->addTag((string) $tag['name'], $parameters);
|
||||
}
|
||||
|
||||
$this->container->setDefinition($id, $definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a XML file.
|
||||
*
|
||||
* @param string $file Path to a file
|
||||
*
|
||||
* @return SimpleXMLElement
|
||||
*
|
||||
* @throws \InvalidArgumentException When loading of XML file returns error
|
||||
*/
|
||||
private function parseFile($file)
|
||||
{
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
$disableEntities = libxml_disable_entity_loader(true);
|
||||
libxml_clear_errors();
|
||||
|
||||
$dom = new \DOMDocument();
|
||||
$dom->validateOnParse = true;
|
||||
if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
|
||||
libxml_disable_entity_loader($disableEntities);
|
||||
|
||||
throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors($internalErrors)));
|
||||
}
|
||||
$dom->normalizeDocument();
|
||||
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
libxml_disable_entity_loader($disableEntities);
|
||||
|
||||
foreach ($dom->childNodes as $child) {
|
||||
if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
|
||||
throw new \InvalidArgumentException('Document types are not allowed.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->validate($dom, $file);
|
||||
|
||||
return simplexml_import_dom($dom, 'Symfony\\Component\\DependencyInjection\\SimpleXMLElement');
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes anonymous services
|
||||
*
|
||||
* @param SimpleXMLElement $xml
|
||||
* @param string $file
|
||||
*/
|
||||
private function processAnonymousServices(SimpleXMLElement $xml, $file)
|
||||
{
|
||||
$definitions = array();
|
||||
$count = 0;
|
||||
|
||||
// anonymous services as arguments/properties
|
||||
if (false !== $nodes = $xml->xpath('//container:argument[@type="service"][not(@id)]|//container:property[@type="service"][not(@id)]')) {
|
||||
foreach ($nodes as $node) {
|
||||
// give it a unique name
|
||||
$node['id'] = sprintf('%s_%d', md5($file), ++$count);
|
||||
|
||||
$definitions[(string) $node['id']] = array($node->service, $file, false);
|
||||
$node->service['id'] = (string) $node['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// anonymous services "in the wild"
|
||||
if (false !== $nodes = $xml->xpath('//container:services/container:service[not(@id)]')) {
|
||||
foreach ($nodes as $node) {
|
||||
// give it a unique name
|
||||
$node['id'] = sprintf('%s_%d', md5($file), ++$count);
|
||||
|
||||
$definitions[(string) $node['id']] = array($node, $file, true);
|
||||
$node->service['id'] = (string) $node['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// resolve definitions
|
||||
krsort($definitions);
|
||||
foreach ($definitions as $id => $def) {
|
||||
// anonymous services are always private
|
||||
$def[0]['public'] = false;
|
||||
|
||||
$this->parseDefinition($id, $def[0], $def[1]);
|
||||
|
||||
$oNode = dom_import_simplexml($def[0]);
|
||||
if (true === $def[2]) {
|
||||
$nNode = new \DOMElement('_services');
|
||||
$oNode->parentNode->replaceChild($nNode, $oNode);
|
||||
$nNode->setAttribute('id', $id);
|
||||
} else {
|
||||
$oNode->parentNode->removeChild($oNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an XML document.
|
||||
*
|
||||
* @param \DOMDocument $dom
|
||||
* @param string $file
|
||||
*/
|
||||
private function validate(\DOMDocument $dom, $file)
|
||||
{
|
||||
$this->validateSchema($dom, $file);
|
||||
$this->validateExtensions($dom, $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a documents XML schema.
|
||||
*
|
||||
* @param \DOMDocument $dom
|
||||
* @param string $file
|
||||
*
|
||||
* @throws RuntimeException When extension references a non-existent XSD file
|
||||
* @throws InvalidArgumentException When xml doesn't validate its xsd schema
|
||||
*/
|
||||
private function validateSchema(\DOMDocument $dom, $file)
|
||||
{
|
||||
$schemaLocations = array('http://symfony.com/schema/dic/services' => str_replace('\\', '/', __DIR__.'/schema/dic/services/services-1.0.xsd'));
|
||||
|
||||
if ($element = $dom->documentElement->getAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation')) {
|
||||
$items = preg_split('/\s+/', $element);
|
||||
for ($i = 0, $nb = count($items); $i < $nb; $i += 2) {
|
||||
if (!$this->container->hasExtension($items[$i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (($extension = $this->container->getExtension($items[$i])) && false !== $extension->getXsdValidationBasePath()) {
|
||||
$path = str_replace($extension->getNamespace(), str_replace('\\', '/', $extension->getXsdValidationBasePath()).'/', $items[$i + 1]);
|
||||
|
||||
if (!is_file($path)) {
|
||||
throw new RuntimeException(sprintf('Extension "%s" references a non-existent XSD file "%s"', get_class($extension), $path));
|
||||
}
|
||||
|
||||
$schemaLocations[$items[$i]] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tmpfiles = array();
|
||||
$imports = '';
|
||||
foreach ($schemaLocations as $namespace => $location) {
|
||||
$parts = explode('/', $location);
|
||||
if (0 === stripos($location, 'phar://')) {
|
||||
$tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
|
||||
if ($tmpfile) {
|
||||
copy($location, $tmpfile);
|
||||
$tmpfiles[] = $tmpfile;
|
||||
$parts = explode('/', str_replace('\\', '/', $tmpfile));
|
||||
}
|
||||
}
|
||||
$drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
|
||||
$location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
|
||||
|
||||
$imports .= sprintf(' <xsd:import namespace="%s" schemaLocation="%s" />'."\n", $namespace, $location);
|
||||
}
|
||||
|
||||
$source = <<<EOF
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<xsd:schema xmlns="http://symfony.com/schema"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://symfony.com/schema"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
|
||||
$imports
|
||||
</xsd:schema>
|
||||
EOF
|
||||
;
|
||||
|
||||
$current = libxml_use_internal_errors(true);
|
||||
libxml_clear_errors();
|
||||
|
||||
$valid = @$dom->schemaValidateSource($source);
|
||||
|
||||
foreach ($tmpfiles as $tmpfile) {
|
||||
@unlink($tmpfile);
|
||||
}
|
||||
if (!$valid) {
|
||||
throw new InvalidArgumentException(implode("\n", $this->getXmlErrors($current)));
|
||||
}
|
||||
libxml_use_internal_errors($current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an extension.
|
||||
*
|
||||
* @param \DOMDocument $dom
|
||||
* @param string $file
|
||||
*
|
||||
* @throws InvalidArgumentException When no extension is found corresponding to a tag
|
||||
*/
|
||||
private function validateExtensions(\DOMDocument $dom, $file)
|
||||
{
|
||||
foreach ($dom->documentElement->childNodes as $node) {
|
||||
if (!$node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node->namespaceURI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// can it be handled by an extension?
|
||||
if (!$this->container->hasExtension($node->namespaceURI)) {
|
||||
$extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getNamespace(); }, $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',
|
||||
$node->tagName,
|
||||
$file,
|
||||
$node->namespaceURI,
|
||||
$extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of XML errors.
|
||||
*
|
||||
* @param Boolean $internalErrors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getXmlErrors($internalErrors)
|
||||
{
|
||||
$errors = array();
|
||||
foreach (libxml_get_errors() as $error) {
|
||||
$errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
|
||||
LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
|
||||
$error->code,
|
||||
trim($error->message),
|
||||
$error->file ? $error->file : 'n/a',
|
||||
$error->line,
|
||||
$error->column
|
||||
);
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads from an extension.
|
||||
*
|
||||
* @param SimpleXMLElement $xml
|
||||
*/
|
||||
private function loadFromExtensions(SimpleXMLElement $xml)
|
||||
{
|
||||
foreach (dom_import_simplexml($xml)->childNodes as $node) {
|
||||
if (!$node instanceof \DOMElement || $node->namespaceURI === 'http://symfony.com/schema/dic/services') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$values = static::convertDomElementToArray($node);
|
||||
if (!is_array($values)) {
|
||||
$values = array();
|
||||
}
|
||||
|
||||
$this->container->loadFromExtension($node->namespaceURI, $values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a \DomElement object to a PHP array.
|
||||
*
|
||||
* The following rules applies during the conversion:
|
||||
*
|
||||
* * Each tag is converted to a key value or an array
|
||||
* if there is more than one "value"
|
||||
*
|
||||
* * The content of a tag is set under a "value" key (<foo>bar</foo>)
|
||||
* if the tag also has some nested tags
|
||||
*
|
||||
* * The attributes are converted to keys (<foo foo="bar"/>)
|
||||
*
|
||||
* * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>)
|
||||
*
|
||||
* @param \DomElement $element A \DomElement instance
|
||||
*
|
||||
* @return array A PHP array
|
||||
*/
|
||||
public static function convertDomElementToArray(\DomElement $element)
|
||||
{
|
||||
$empty = true;
|
||||
$config = array();
|
||||
foreach ($element->attributes as $name => $node) {
|
||||
$config[$name] = SimpleXMLElement::phpize($node->value);
|
||||
$empty = false;
|
||||
}
|
||||
|
||||
$nodeValue = false;
|
||||
foreach ($element->childNodes as $node) {
|
||||
if ($node instanceof \DOMText) {
|
||||
if (trim($node->nodeValue)) {
|
||||
$nodeValue = trim($node->nodeValue);
|
||||
$empty = false;
|
||||
}
|
||||
} elseif (!$node instanceof \DOMComment) {
|
||||
if ($node instanceof \DOMElement && '_services' === $node->nodeName) {
|
||||
$value = new Reference($node->getAttribute('id'));
|
||||
} else {
|
||||
$value = static::convertDomElementToArray($node);
|
||||
}
|
||||
|
||||
$key = $node->localName;
|
||||
if (isset($config[$key])) {
|
||||
if (!is_array($config[$key]) || !is_int(key($config[$key]))) {
|
||||
$config[$key] = array($config[$key]);
|
||||
}
|
||||
$config[$key][] = $value;
|
||||
} else {
|
||||
$config[$key] = $value;
|
||||
}
|
||||
|
||||
$empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (false !== $nodeValue) {
|
||||
$value = SimpleXMLElement::phpize($nodeValue);
|
||||
if (count($config)) {
|
||||
$config['value'] = $value;
|
||||
} else {
|
||||
$config = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return !$empty ? $config : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
<?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;
|
||||
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* YamlFileLoader loads YAML files service definitions.
|
||||
*
|
||||
* The YAML format does not support anonymous services (cf. the XML loader).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class YamlFileLoader extends FileLoader
|
||||
{
|
||||
/**
|
||||
* Loads a Yaml file.
|
||||
*
|
||||
* @param mixed $file The resource
|
||||
* @param string $type The resource type
|
||||
*/
|
||||
public function load($file, $type = null)
|
||||
{
|
||||
$path = $this->locator->locate($file);
|
||||
|
||||
$content = $this->loadFile($path);
|
||||
|
||||
$this->container->addResource(new FileResource($path));
|
||||
|
||||
// empty file
|
||||
if (null === $content) {
|
||||
return;
|
||||
}
|
||||
|
||||
// imports
|
||||
$this->parseImports($content, $file);
|
||||
|
||||
// parameters
|
||||
if (isset($content['parameters'])) {
|
||||
foreach ($content['parameters'] as $key => $value) {
|
||||
$this->container->setParameter($key, $this->resolveServices($value));
|
||||
}
|
||||
}
|
||||
|
||||
// extensions
|
||||
$this->loadFromExtensions($content);
|
||||
|
||||
// services
|
||||
$this->parseDefinitions($content, $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string $type The resource type
|
||||
*
|
||||
* @return Boolean true if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses all imports
|
||||
*
|
||||
* @param array $content
|
||||
* @param string $file
|
||||
*/
|
||||
private function parseImports($content, $file)
|
||||
{
|
||||
if (!isset($content['imports'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($content['imports'] as $import) {
|
||||
$this->setCurrentDir(dirname($file));
|
||||
$this->import($import['resource'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false, $file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses definitions
|
||||
*
|
||||
* @param array $content
|
||||
* @param string $file
|
||||
*/
|
||||
private function parseDefinitions($content, $file)
|
||||
{
|
||||
if (!isset($content['services'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($content['services'] as $id => $service) {
|
||||
$this->parseDefinition($id, $service, $file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a definition.
|
||||
*
|
||||
* @param string $id
|
||||
* @param array $service
|
||||
* @param string $file
|
||||
*
|
||||
* @throws InvalidArgumentException When tags are invalid
|
||||
*/
|
||||
private function parseDefinition($id, $service, $file)
|
||||
{
|
||||
if (is_string($service) && 0 === strpos($service, '@')) {
|
||||
$this->container->setAlias($id, substr($service, 1));
|
||||
|
||||
return;
|
||||
} elseif (isset($service['alias'])) {
|
||||
$public = !array_key_exists('public', $service) || (Boolean) $service['public'];
|
||||
$this->container->setAlias($id, new Alias($service['alias'], $public));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($service['parent'])) {
|
||||
$definition = new DefinitionDecorator($service['parent']);
|
||||
} else {
|
||||
$definition = new Definition();
|
||||
}
|
||||
|
||||
if (isset($service['class'])) {
|
||||
$definition->setClass($service['class']);
|
||||
}
|
||||
|
||||
if (isset($service['scope'])) {
|
||||
$definition->setScope($service['scope']);
|
||||
}
|
||||
|
||||
if (isset($service['synthetic'])) {
|
||||
$definition->setSynthetic($service['synthetic']);
|
||||
}
|
||||
|
||||
if (isset($service['public'])) {
|
||||
$definition->setPublic($service['public']);
|
||||
}
|
||||
|
||||
if (isset($service['abstract'])) {
|
||||
$definition->setAbstract($service['abstract']);
|
||||
}
|
||||
|
||||
if (isset($service['factory_class'])) {
|
||||
$definition->setFactoryClass($service['factory_class']);
|
||||
}
|
||||
|
||||
if (isset($service['factory_method'])) {
|
||||
$definition->setFactoryMethod($service['factory_method']);
|
||||
}
|
||||
|
||||
if (isset($service['factory_service'])) {
|
||||
$definition->setFactoryService($service['factory_service']);
|
||||
}
|
||||
|
||||
if (isset($service['file'])) {
|
||||
$definition->setFile($service['file']);
|
||||
}
|
||||
|
||||
if (isset($service['arguments'])) {
|
||||
$definition->setArguments($this->resolveServices($service['arguments']));
|
||||
}
|
||||
|
||||
if (isset($service['properties'])) {
|
||||
$definition->setProperties($this->resolveServices($service['properties']));
|
||||
}
|
||||
|
||||
if (isset($service['configurator'])) {
|
||||
if (is_string($service['configurator'])) {
|
||||
$definition->setConfigurator($service['configurator']);
|
||||
} else {
|
||||
$definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($service['calls'])) {
|
||||
foreach ($service['calls'] as $call) {
|
||||
$args = isset($call[1]) ? $this->resolveServices($call[1]) : array();
|
||||
$definition->addMethodCall($call[0], $args);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($service['tags'])) {
|
||||
if (!is_array($service['tags'])) {
|
||||
throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s.', $id, $file));
|
||||
}
|
||||
|
||||
foreach ($service['tags'] as $tag) {
|
||||
if (!isset($tag['name'])) {
|
||||
throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
|
||||
}
|
||||
|
||||
$name = $tag['name'];
|
||||
unset($tag['name']);
|
||||
|
||||
foreach ($tag as $attribute => $value) {
|
||||
if (!is_scalar($value)) {
|
||||
throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s" in %s.', $id, $name, $file));
|
||||
}
|
||||
}
|
||||
|
||||
$definition->addTag($name, $tag);
|
||||
}
|
||||
}
|
||||
|
||||
$this->container->setDefinition($id, $definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a YAML file.
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return array The file content
|
||||
*/
|
||||
private function loadFile($file)
|
||||
{
|
||||
return $this->validate(Yaml::parse($file), $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a YAML file.
|
||||
*
|
||||
* @param mixed $content
|
||||
* @param string $file
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidArgumentException When service file is not valid
|
||||
*/
|
||||
private function validate($content, $file)
|
||||
{
|
||||
if (null === $content) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if (!is_array($content)) {
|
||||
throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
|
||||
}
|
||||
|
||||
foreach (array_keys($content) as $namespace) {
|
||||
if (in_array($namespace, array('imports', 'parameters', 'services'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->container->hasExtension($namespace)) {
|
||||
$extensionNamespaces = 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,
|
||||
$file,
|
||||
$namespace,
|
||||
$extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves services.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @return Reference
|
||||
*/
|
||||
private function resolveServices($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$value = array_map(array($this, 'resolveServices'), $value);
|
||||
} elseif (is_string($value) && 0 === strpos($value, '@')) {
|
||||
if (0 === strpos($value, '@?')) {
|
||||
$value = substr($value, 2);
|
||||
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
|
||||
} else {
|
||||
$value = substr($value, 1);
|
||||
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
}
|
||||
|
||||
if ('=' === substr($value, -1)) {
|
||||
$value = substr($value, 0, -1);
|
||||
$strict = false;
|
||||
} else {
|
||||
$strict = true;
|
||||
}
|
||||
|
||||
$value = new Reference($value, $invalidBehavior, $strict);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads from Extensions
|
||||
*
|
||||
* @param array $content
|
||||
*/
|
||||
private function loadFromExtensions($content)
|
||||
{
|
||||
foreach ($content as $namespace => $values) {
|
||||
if (in_array($namespace, array('imports', 'parameters', 'services'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_array($values)) {
|
||||
$values = array();
|
||||
}
|
||||
|
||||
$this->container->loadFromExtension($namespace, $values);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<xsd:schema xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://symfony.com/schema/dic/services"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Symfony XML Services Schema, version 1.0
|
||||
Authors: Fabien Potencier
|
||||
|
||||
This defines a way to describe PHP objects (services) and their
|
||||
dependencies.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:element name="container" type="container" />
|
||||
|
||||
<xsd:complexType name="container">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The root element of a service file.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="imports" type="imports" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="parameters" type="parameters" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="services" type="services" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="services">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enclosing element for the definition of all services
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:element name="service" type="service" />
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="imports">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enclosing element for the import elements
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:element name="import" type="import" />
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="import">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Import an external resource defining other services or parameters
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="resource" type="xsd:string" use="required" />
|
||||
<xsd:attribute name="ignore-errors" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="configurator">
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="service" type="xsd:string" />
|
||||
<xsd:attribute name="class" type="xsd:string" />
|
||||
<xsd:attribute name="method" type="xsd:string" />
|
||||
<xsd:attribute name="function" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="service">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="file" type="xsd:string" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="configurator" type="configurator" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="class" type="xsd:string" />
|
||||
<xsd:attribute name="scope" type="xsd:string" />
|
||||
<xsd:attribute name="public" type="boolean" />
|
||||
<xsd:attribute name="synthetic" type="boolean" />
|
||||
<xsd:attribute name="abstract" type="boolean" />
|
||||
<xsd:attribute name="factory-class" type="xsd:string" />
|
||||
<xsd:attribute name="factory-method" type="xsd:string" />
|
||||
<xsd:attribute name="factory-service" type="xsd:string" />
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="parent" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="tag">
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:anyAttribute namespace="##any" processContents="lax" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="parameters">
|
||||
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:element name="parameter" type="parameter" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="type" type="parameter_type" />
|
||||
<xsd:attribute name="key" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="parameter" mixed="true">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element name="parameter" type="parameter" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="type" type="parameter_type" />
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="key" type="xsd:string" />
|
||||
<xsd:attribute name="on-invalid" type="invalid_sequence" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="property" mixed="true">
|
||||
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||
<xsd:element name="service" type="service" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="type" type="argument_type" />
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="on-invalid" type="xsd:string" />
|
||||
<xsd:attribute name="strict" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="argument" mixed="true">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="service" type="service" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="type" type="argument_type" />
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="key" type="xsd:string" />
|
||||
<xsd:attribute name="index" type="xsd:integer" />
|
||||
<xsd:attribute name="on-invalid" type="xsd:string" />
|
||||
<xsd:attribute name="strict" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="call" mixed="true">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="service" type="service" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="method" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="parameter_type">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="collection" />
|
||||
<xsd:enumeration value="service" />
|
||||
<xsd:enumeration value="string" />
|
||||
<xsd:enumeration value="constant" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:simpleType name="argument_type">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="collection" />
|
||||
<xsd:enumeration value="service" />
|
||||
<xsd:enumeration value="string" />
|
||||
<xsd:enumeration value="constant" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:simpleType name="invalid_sequence">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="null" />
|
||||
<xsd:enumeration value="ignore" />
|
||||
<xsd:enumeration value="exception" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:simpleType name="boolean">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern value="(%.+%|true|false)" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:schema>
|
||||
44
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Parameter.php
vendored
Normal file
44
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Parameter.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Parameter represents a parameter reference.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Parameter
|
||||
{
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $id The parameter key
|
||||
*/
|
||||
public function __construct($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* __toString.
|
||||
*
|
||||
* @return string The parameter key
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?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\ParameterBag;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\LogicException;
|
||||
|
||||
/**
|
||||
* Holds read-only parameters.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class FrozenParameterBag extends ParameterBag
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* For performance reasons, the constructor assumes that
|
||||
* all keys are already lowercased.
|
||||
*
|
||||
* This is always the case when used internally.
|
||||
*
|
||||
* @param array $parameters An array of parameters
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(array $parameters = array())
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
$this->resolved = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
throw new LogicException('Impossible to call clear() on a frozen ParameterBag.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function add(array $parameters)
|
||||
{
|
||||
throw new LogicException('Impossible to call add() on a frozen ParameterBag.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
<?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\ParameterBag;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Holds parameters.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class ParameterBag implements ParameterBagInterface
|
||||
{
|
||||
protected $parameters;
|
||||
protected $resolved;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $parameters An array of parameters
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(array $parameters = array())
|
||||
{
|
||||
$this->parameters = array();
|
||||
$this->add($parameters);
|
||||
$this->resolved = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all parameters.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->parameters = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds parameters to the service container parameters.
|
||||
*
|
||||
* @param array $parameters An array of parameters
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function add(array $parameters)
|
||||
{
|
||||
foreach ($parameters as $key => $value) {
|
||||
$this->parameters[strtolower($key)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service container parameters.
|
||||
*
|
||||
* @return array An array of parameters
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a service container parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws ParameterNotFoundException if the parameter is not defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
if (!array_key_exists($name, $this->parameters)) {
|
||||
throw new ParameterNotFoundException($name);
|
||||
}
|
||||
|
||||
return $this->parameters[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a service container parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
* @param mixed $value The parameter value
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
$this->parameters[strtolower($name)] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a parameter name is defined.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return Boolean true if the parameter name is defined, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return array_key_exists(strtolower($name), $this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
unset($this->parameters[strtolower($name)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces parameter placeholders (%name%) by their values for all parameters.
|
||||
*/
|
||||
public function resolve()
|
||||
{
|
||||
if ($this->resolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parameters = array();
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
try {
|
||||
$value = $this->resolveValue($value);
|
||||
$parameters[$key] = $this->unescapeValue($value);
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
$e->setSourceKey($key);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$this->parameters = $parameters;
|
||||
$this->resolved = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces parameter placeholders (%name%) by their values.
|
||||
*
|
||||
* @param mixed $value A value
|
||||
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
|
||||
*
|
||||
* @return mixed The resolved value
|
||||
*
|
||||
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
|
||||
* @throws ParameterCircularReferenceException if a circular reference if detected
|
||||
* @throws RuntimeException when a given parameter has a type problem.
|
||||
*/
|
||||
public function resolveValue($value, array $resolving = array())
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$args = array();
|
||||
foreach ($value as $k => $v) {
|
||||
$args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving);
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
if (!is_string($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $this->resolveString($value, $resolving);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves parameters inside a string
|
||||
*
|
||||
* @param string $value The string to resolve
|
||||
* @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
|
||||
*
|
||||
* @return string The resolved string
|
||||
*
|
||||
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
|
||||
* @throws ParameterCircularReferenceException if a circular reference if detected
|
||||
* @throws RuntimeException when a given parameter has a type problem.
|
||||
*/
|
||||
public function resolveString($value, array $resolving = array())
|
||||
{
|
||||
// we do this to deal with non string values (Boolean, integer, ...)
|
||||
// as the preg_replace_callback throw an exception when trying
|
||||
// a non-string in a parameter value
|
||||
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
|
||||
$key = strtolower($match[1]);
|
||||
|
||||
if (isset($resolving[$key])) {
|
||||
throw new ParameterCircularReferenceException(array_keys($resolving));
|
||||
}
|
||||
|
||||
$resolving[$key] = true;
|
||||
|
||||
return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
|
||||
}
|
||||
|
||||
$self = $this;
|
||||
|
||||
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($self, $resolving, $value) {
|
||||
// skip %%
|
||||
if (!isset($match[1])) {
|
||||
return '%%';
|
||||
}
|
||||
|
||||
$key = strtolower($match[1]);
|
||||
if (isset($resolving[$key])) {
|
||||
throw new ParameterCircularReferenceException(array_keys($resolving));
|
||||
}
|
||||
|
||||
$resolved = $self->get($key);
|
||||
|
||||
if (!is_string($resolved) && !is_numeric($resolved)) {
|
||||
throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, gettype($resolved), $value));
|
||||
}
|
||||
|
||||
$resolved = (string) $resolved;
|
||||
$resolving[$key] = true;
|
||||
|
||||
return $self->isResolved() ? $resolved : $self->resolveString($resolved, $resolving);
|
||||
}, $value);
|
||||
}
|
||||
|
||||
public function isResolved()
|
||||
{
|
||||
return $this->resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function escapeValue($value)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
return str_replace('%', '%%', $value);
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$result = array();
|
||||
foreach ($value as $k => $v) {
|
||||
$result[$k] = $this->escapeValue($v);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function unescapeValue($value)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
return str_replace('%%', '%', $value);
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$result = array();
|
||||
foreach ($value as $k => $v) {
|
||||
$result[$k] = $this->unescapeValue($v);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?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\ParameterBag;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
|
||||
/**
|
||||
* ParameterBagInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface ParameterBagInterface
|
||||
{
|
||||
/**
|
||||
* Clears all parameters.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function clear();
|
||||
|
||||
/**
|
||||
* Adds parameters to the service container parameters.
|
||||
*
|
||||
* @param array $parameters An array of parameters
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function add(array $parameters);
|
||||
|
||||
/**
|
||||
* Gets the service container parameters.
|
||||
*
|
||||
* @return array An array of parameters
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function all();
|
||||
|
||||
/**
|
||||
* Gets a service container parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws ParameterNotFoundException if the parameter is not defined
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($name);
|
||||
|
||||
/**
|
||||
* Sets a service container parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
* @param mixed $value The parameter value
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function set($name, $value);
|
||||
|
||||
/**
|
||||
* Returns true if a parameter name is defined.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return Boolean true if the parameter name is defined, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($name);
|
||||
|
||||
/**
|
||||
* Replaces parameter placeholders (%name%) by their values for all parameters.
|
||||
*/
|
||||
public function resolve();
|
||||
|
||||
/**
|
||||
* Replaces parameter placeholders (%name%) by their values.
|
||||
*
|
||||
* @param mixed $value A value
|
||||
*
|
||||
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
|
||||
*/
|
||||
public function resolveValue($value);
|
||||
|
||||
/**
|
||||
* Escape parameter placeholders %
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function escapeValue($value);
|
||||
|
||||
/**
|
||||
* Unescape parameter placeholders %
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function unescapeValue($value);
|
||||
}
|
||||
76
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/README.md
vendored
Normal file
76
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/README.md
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
DependencyInjection Component
|
||||
=============================
|
||||
|
||||
DependencyInjection manages your services via a robust and flexible Dependency
|
||||
Injection Container.
|
||||
|
||||
Here is a simple example that shows how to register services and parameters:
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
$sc = new ContainerBuilder();
|
||||
$sc
|
||||
->register('foo', '%foo.class%')
|
||||
->addArgument(new Reference('bar'))
|
||||
;
|
||||
$sc->setParameter('foo.class', 'Foo');
|
||||
|
||||
$sc->get('foo');
|
||||
|
||||
Method Calls (Setter Injection):
|
||||
|
||||
$sc = new ContainerBuilder();
|
||||
|
||||
$sc
|
||||
->register('bar', '%bar.class%')
|
||||
->addMethodCall('setFoo', array(new Reference('foo')))
|
||||
;
|
||||
$sc->setParameter('bar.class', 'Bar');
|
||||
|
||||
$sc->get('bar');
|
||||
|
||||
Factory Class:
|
||||
|
||||
If your service is retrieved by calling a static method:
|
||||
|
||||
$sc = new ContainerBuilder();
|
||||
|
||||
$sc
|
||||
->register('bar', '%bar.class%')
|
||||
->setFactoryClass('%bar.class%')
|
||||
->setFactoryMethod('getInstance')
|
||||
->addArgument('Aarrg!!!')
|
||||
;
|
||||
$sc->setParameter('bar.class', 'Bar');
|
||||
|
||||
$sc->get('bar');
|
||||
|
||||
File Include:
|
||||
|
||||
For some services, especially those that are difficult or impossible to
|
||||
autoload, you may need the container to include a file before
|
||||
instantiating your class.
|
||||
|
||||
$sc = new ContainerBuilder();
|
||||
|
||||
$sc
|
||||
->register('bar', '%bar.class%')
|
||||
->setFile('/path/to/file')
|
||||
->addArgument('Aarrg!!!')
|
||||
;
|
||||
$sc->setParameter('bar.class', 'Bar');
|
||||
|
||||
$sc->get('bar');
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
phpunit
|
||||
|
||||
If you also want to run the unit tests that depend on other Symfony
|
||||
Components, install dev dependencies before running PHPUnit:
|
||||
|
||||
php composer.phar install --dev
|
||||
72
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Reference.php
vendored
Normal file
72
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Reference.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Reference represents a service reference.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Reference
|
||||
{
|
||||
private $id;
|
||||
private $invalidBehavior;
|
||||
private $strict;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
* @param int $invalidBehavior The behavior when the service does not exist
|
||||
* @param Boolean $strict Sets how this reference is validated
|
||||
*
|
||||
* @see Container
|
||||
*/
|
||||
public function __construct($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $strict = true)
|
||||
{
|
||||
$this->id = strtolower($id);
|
||||
$this->invalidBehavior = $invalidBehavior;
|
||||
$this->strict = $strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* __toString.
|
||||
*
|
||||
* @return string The service identifier
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the behavior to be used when the service does not exist.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getInvalidBehavior()
|
||||
{
|
||||
return $this->invalidBehavior;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when this Reference is strict
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isStrict()
|
||||
{
|
||||
return $this->strict;
|
||||
}
|
||||
}
|
||||
50
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Scope.php
vendored
Normal file
50
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Scope.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Scope class.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Scope implements ScopeInterface
|
||||
{
|
||||
private $name;
|
||||
private $parentName;
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function __construct($name, $parentName = ContainerInterface::SCOPE_CONTAINER)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->parentName = $parentName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function getParentName()
|
||||
{
|
||||
return $this->parentName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Scope Interface.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface ScopeInterface
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* @api
|
||||
*/
|
||||
public function getParentName();
|
||||
}
|
||||
127
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/SimpleXMLElement.php
vendored
Normal file
127
core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/SimpleXMLElement.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* SimpleXMLElement class.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class SimpleXMLElement extends \SimpleXMLElement
|
||||
{
|
||||
/**
|
||||
* Converts an attribute as a php type.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttributeAsPhp($name)
|
||||
{
|
||||
return self::phpize($this[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns arguments as valid php types.
|
||||
*
|
||||
* @param string $name
|
||||
* @param Boolean $lowercase
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getArgumentsAsPhp($name, $lowercase = true)
|
||||
{
|
||||
$arguments = array();
|
||||
foreach ($this->$name as $arg) {
|
||||
if (isset($arg['name'])) {
|
||||
$arg['key'] = (string) $arg['name'];
|
||||
}
|
||||
$key = isset($arg['key']) ? (string) $arg['key'] : (!$arguments ? 0 : max(array_keys($arguments)) + 1);
|
||||
|
||||
// parameter keys are case insensitive
|
||||
if ('parameter' == $name && $lowercase) {
|
||||
$key = strtolower($key);
|
||||
}
|
||||
|
||||
// this is used by DefinitionDecorator to overwrite a specific
|
||||
// argument of the parent definition
|
||||
if (isset($arg['index'])) {
|
||||
$key = 'index_'.$arg['index'];
|
||||
}
|
||||
|
||||
switch ($arg['type']) {
|
||||
case 'service':
|
||||
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
|
||||
if (isset($arg['on-invalid']) && 'ignore' == $arg['on-invalid']) {
|
||||
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
|
||||
} elseif (isset($arg['on-invalid']) && 'null' == $arg['on-invalid']) {
|
||||
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
|
||||
}
|
||||
|
||||
if (isset($arg['strict'])) {
|
||||
$strict = self::phpize($arg['strict']);
|
||||
} else {
|
||||
$strict = true;
|
||||
}
|
||||
|
||||
$arguments[$key] = new Reference((string) $arg['id'], $invalidBehavior, $strict);
|
||||
break;
|
||||
case 'collection':
|
||||
$arguments[$key] = $arg->getArgumentsAsPhp($name, false);
|
||||
break;
|
||||
case 'string':
|
||||
$arguments[$key] = (string) $arg;
|
||||
break;
|
||||
case 'constant':
|
||||
$arguments[$key] = constant((string) $arg);
|
||||
break;
|
||||
default:
|
||||
$arguments[$key] = self::phpize($arg);
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an xml value to a php type.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function phpize($value)
|
||||
{
|
||||
$value = (string) $value;
|
||||
$lowercaseValue = strtolower($value);
|
||||
|
||||
switch (true) {
|
||||
case 'null' === $lowercaseValue:
|
||||
return null;
|
||||
case ctype_digit($value):
|
||||
$raw = $value;
|
||||
$cast = intval($value);
|
||||
|
||||
return '0' == $value[0] ? octdec($value) : (((string) $raw == (string) $cast) ? $cast : $raw);
|
||||
case 'true' === $lowercaseValue:
|
||||
return true;
|
||||
case 'false' === $lowercaseValue:
|
||||
return false;
|
||||
case is_numeric($value):
|
||||
return '0x' == $value[0].$value[1] ? hexdec($value) : floatval($value);
|
||||
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $value):
|
||||
return floatval(str_replace(',', '', $value));
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* TaggedContainerInterface is the interface implemented when a container knows how to deals with tags.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
interface TaggedContainerInterface extends ContainerInterface
|
||||
{
|
||||
/**
|
||||
* Returns service ids for a given tag.
|
||||
*
|
||||
* @param string $name The tag name
|
||||
*
|
||||
* @return array An array of tags
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function findTaggedServiceIds($name);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\Compiler;
|
||||
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class AnalyzeServiceReferencesPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$a = $container
|
||||
->register('a')
|
||||
->addArgument($ref1 = new Reference('b'))
|
||||
;
|
||||
|
||||
$b = $container
|
||||
->register('b')
|
||||
->addMethodCall('setA', array($ref2 = new Reference('a')))
|
||||
;
|
||||
|
||||
$c = $container
|
||||
->register('c')
|
||||
->addArgument($ref3 = new Reference('a'))
|
||||
->addArgument($ref4 = new Reference('b'))
|
||||
;
|
||||
|
||||
$d = $container
|
||||
->register('d')
|
||||
->setProperty('foo', $ref5 = new Reference('b'))
|
||||
;
|
||||
|
||||
$e = $container
|
||||
->register('e')
|
||||
->setConfigurator(array($ref6 = new Reference('b'), 'methodName'))
|
||||
;
|
||||
|
||||
$graph = $this->process($container);
|
||||
|
||||
$this->assertCount(4, $edges = $graph->getNode('b')->getInEdges());
|
||||
|
||||
$this->assertSame($ref1, $edges[0]->getValue());
|
||||
$this->assertSame($ref4, $edges[1]->getValue());
|
||||
$this->assertSame($ref5, $edges[2]->getValue());
|
||||
$this->assertSame($ref6, $edges[3]->getValue());
|
||||
}
|
||||
|
||||
public function testProcessDetectsReferencesFromInlinedDefinitions()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('a')
|
||||
;
|
||||
|
||||
$container
|
||||
->register('b')
|
||||
->addArgument(new Definition(null, array($ref = new Reference('a'))))
|
||||
;
|
||||
|
||||
$graph = $this->process($container);
|
||||
|
||||
$this->assertCount(1, $refs = $graph->getNode('a')->getInEdges());
|
||||
$this->assertSame($ref, $refs[0]->getValue());
|
||||
}
|
||||
|
||||
public function testProcessDoesNotSaveDuplicateReferences()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('a')
|
||||
;
|
||||
$container
|
||||
->register('b')
|
||||
->addArgument(new Definition(null, array($ref1 = new Reference('a'))))
|
||||
->addArgument(new Definition(null, array($ref2 = new Reference('a'))))
|
||||
;
|
||||
|
||||
$graph = $this->process($container);
|
||||
|
||||
$this->assertCount(2, $graph->getNode('a')->getInEdges());
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new RepeatedPass(array(new AnalyzeServiceReferencesPass()));
|
||||
$pass->process($container);
|
||||
|
||||
return $container->getCompiler()->getServiceReferenceGraph();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckCircularReferencesPass;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class CheckCircularReferencesPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->addArgument(new Reference('b'));
|
||||
$container->register('b')->addArgument(new Reference('a'));
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessWithAliases()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->addArgument(new Reference('b'));
|
||||
$container->setAlias('b', 'c');
|
||||
$container->setAlias('c', 'a');
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessDetectsIndirectCircularReference()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->addArgument(new Reference('b'));
|
||||
$container->register('b')->addArgument(new Reference('c'));
|
||||
$container->register('c')->addArgument(new Reference('a'));
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
public function testProcessIgnoresMethodCalls()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->addArgument(new Reference('b'));
|
||||
$container->register('b')->addMethodCall('setA', array(new Reference('a')));
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$compiler = new Compiler();
|
||||
$passConfig = $compiler->getPassConfig();
|
||||
$passConfig->setOptimizationPasses(array(
|
||||
new AnalyzeServiceReferencesPass(true),
|
||||
new CheckCircularReferencesPass(),
|
||||
));
|
||||
$passConfig->setRemovingPasses(array());
|
||||
|
||||
$compiler->compile($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckDefinitionValidityPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class CheckDefinitionValidityPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessDetectsSyntheticNonPublicDefinitions()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->setSynthetic(true)->setPublic(false);
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessDetectsSyntheticPrototypeDefinitions()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->setSynthetic(true)->setScope(ContainerInterface::SCOPE_PROTOTYPE);
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessDetectsNonSyntheticNonAbstractDefinitionWithoutClass()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->setSynthetic(false)->setAbstract(false);
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a', 'class');
|
||||
$container->register('b', 'class')->setSynthetic(true)->setPublic(true);
|
||||
$container->register('c', 'class')->setAbstract(true);
|
||||
$container->register('d', 'class')->setSynthetic(true);
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new CheckDefinitionValidityPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckExceptionOnInvalidReferenceBehaviorPass;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class CheckExceptionOnInvalidReferenceBehaviorPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('b'))
|
||||
;
|
||||
$container->register('b', '\stdClass');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
|
||||
*/
|
||||
public function testProcessThrowsExceptionOnInvalidReference()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('b'))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
|
||||
*/
|
||||
public function testProcessThrowsExceptionOnInvalidReferenceFromInlinedDefinition()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$def = new Definition();
|
||||
$def->addArgument(new Reference('b'));
|
||||
|
||||
$container
|
||||
->register('a', '\stdClass')
|
||||
->addArgument($def)
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
private function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new CheckExceptionOnInvalidReferenceBehaviorPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Scope;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class CheckReferenceValidityPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcessIgnoresScopeWideningIfNonStrictReference()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->addArgument(new Reference('b', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false));
|
||||
$container->register('b')->setScope('prototype');
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessDetectsScopeWidening()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->addArgument(new Reference('b'));
|
||||
$container->register('b')->setScope('prototype');
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
public function testProcessIgnoresCrossScopeHierarchyReferenceIfNotStrict()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->addScope(new Scope('a'));
|
||||
$container->addScope(new Scope('b'));
|
||||
|
||||
$container->register('a')->setScope('a')->addArgument(new Reference('b', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false));
|
||||
$container->register('b')->setScope('b');
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessDetectsCrossScopeHierarchyReference()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->addScope(new Scope('a'));
|
||||
$container->addScope(new Scope('b'));
|
||||
|
||||
$container->register('a')->setScope('a')->addArgument(new Reference('b'));
|
||||
$container->register('b')->setScope('b');
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testProcessDetectsReferenceToAbstractDefinition()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('a')->setAbstract(true);
|
||||
$container->register('b')->addArgument(new Reference('a'));
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a')->addArgument(new Reference('b'));
|
||||
$container->register('b');
|
||||
|
||||
$this->process($container);
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new CheckReferenceValidityPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Scope;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\Compiler;
|
||||
use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class InlineServiceDefinitionsPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('inlinable.service')
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$container
|
||||
->register('service')
|
||||
->setArguments(array(new Reference('inlinable.service')))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $container->getDefinition('service')->getArguments();
|
||||
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $arguments[0]);
|
||||
$this->assertSame($container->getDefinition('inlinable.service'), $arguments[0]);
|
||||
}
|
||||
|
||||
public function testProcessDoesNotInlineWhenAliasedServiceIsNotOfPrototypeScope()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('foo')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container->setAlias('moo', 'foo');
|
||||
|
||||
$container
|
||||
->register('service')
|
||||
->setArguments(array($ref = new Reference('foo')))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $container->getDefinition('service')->getArguments();
|
||||
$this->assertSame($ref, $arguments[0]);
|
||||
}
|
||||
|
||||
public function testProcessDoesInlineServiceOfPrototypeScope()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('foo')
|
||||
->setScope('prototype')
|
||||
;
|
||||
$container
|
||||
->register('bar')
|
||||
->setPublic(false)
|
||||
->setScope('prototype')
|
||||
;
|
||||
$container->setAlias('moo', 'bar');
|
||||
|
||||
$container
|
||||
->register('service')
|
||||
->setArguments(array(new Reference('foo'), $ref = new Reference('moo'), new Reference('bar')))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $container->getDefinition('service')->getArguments();
|
||||
$this->assertEquals($container->getDefinition('foo'), $arguments[0]);
|
||||
$this->assertNotSame($container->getDefinition('foo'), $arguments[0]);
|
||||
$this->assertSame($ref, $arguments[1]);
|
||||
$this->assertEquals($container->getDefinition('bar'), $arguments[2]);
|
||||
$this->assertNotSame($container->getDefinition('bar'), $arguments[2]);
|
||||
}
|
||||
|
||||
public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$a = $container->register('a')->setPublic(false);
|
||||
$b = $container
|
||||
->register('b')
|
||||
->addArgument(new Reference('a'))
|
||||
->addArgument(new Definition(null, array(new Reference('a'))))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $b->getArguments();
|
||||
$this->assertSame($a, $arguments[0]);
|
||||
|
||||
$inlinedArguments = $arguments[1]->getArguments();
|
||||
$this->assertSame($a, $inlinedArguments[0]);
|
||||
}
|
||||
|
||||
public function testProcessInlinesOnlyIfSameScope()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->addScope(new Scope('foo'));
|
||||
$a = $container->register('a')->setPublic(false)->setScope('foo');
|
||||
$b = $container->register('b')->addArgument(new Reference('a'));
|
||||
|
||||
$this->process($container);
|
||||
$arguments = $b->getArguments();
|
||||
$this->assertEquals(new Reference('a'), $arguments[0]);
|
||||
$this->assertTrue($container->hasDefinition('a'));
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), new InlineServiceDefinitionsPass()));
|
||||
$repeatedPass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* This class tests the integration of the different compiler passes
|
||||
*/
|
||||
class IntegrationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests that the following dependencies are correctly processed:
|
||||
*
|
||||
* A is public, B/C are private
|
||||
* A -> C
|
||||
* B -> C
|
||||
*/
|
||||
public function testProcessRemovesAndInlinesRecursively()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$a = $container
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('c'))
|
||||
;
|
||||
|
||||
$b = $container
|
||||
->register('b', '\stdClass')
|
||||
->addArgument(new Reference('c'))
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$c = $container
|
||||
->register('c', '\stdClass')
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->assertTrue($container->hasDefinition('a'));
|
||||
$arguments = $a->getArguments();
|
||||
$this->assertSame($c, $arguments[0]);
|
||||
$this->assertFalse($container->hasDefinition('b'));
|
||||
$this->assertFalse($container->hasDefinition('c'));
|
||||
}
|
||||
|
||||
public function testProcessInlinesReferencesToAliases()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$a = $container
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('b'))
|
||||
;
|
||||
|
||||
$container->setAlias('b', new Alias('c', false));
|
||||
|
||||
$c = $container
|
||||
->register('c', '\stdClass')
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->assertTrue($container->hasDefinition('a'));
|
||||
$arguments = $a->getArguments();
|
||||
$this->assertSame($c, $arguments[0]);
|
||||
$this->assertFalse($container->hasAlias('b'));
|
||||
$this->assertFalse($container->hasDefinition('c'));
|
||||
}
|
||||
|
||||
public function testProcessInlinesWhenThereAreMultipleReferencesButFromTheSameDefinition()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('a', '\stdClass')
|
||||
->addArgument(new Reference('b'))
|
||||
->addMethodCall('setC', array(new Reference('c')))
|
||||
;
|
||||
|
||||
$container
|
||||
->register('b', '\stdClass')
|
||||
->addArgument(new Reference('c'))
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$container
|
||||
->register('c', '\stdClass')
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->assertTrue($container->hasDefinition('a'));
|
||||
$this->assertFalse($container->hasDefinition('b'));
|
||||
$this->assertFalse($container->hasDefinition('c'), 'Service C was not inlined.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\Compiler;
|
||||
use Symfony\Component\DependencyInjection\Compiler\RepeatedPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class RemoveUnusedDefinitionsPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('foo')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container
|
||||
->register('bar')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container
|
||||
->register('moo')
|
||||
->setArguments(array(new Reference('bar')))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertFalse($container->hasDefinition('foo'));
|
||||
$this->assertTrue($container->hasDefinition('bar'));
|
||||
$this->assertTrue($container->hasDefinition('moo'));
|
||||
}
|
||||
|
||||
public function testProcessRemovesUnusedDefinitionsRecursively()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('foo')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container
|
||||
->register('bar')
|
||||
->setArguments(array(new Reference('foo')))
|
||||
->setPublic(false)
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertFalse($container->hasDefinition('foo'));
|
||||
$this->assertFalse($container->hasDefinition('bar'));
|
||||
}
|
||||
|
||||
public function testProcessWorksWithInlinedDefinitions()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
->register('foo')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container
|
||||
->register('bar')
|
||||
->setArguments(array(new Definition(null, array(new Reference('foo')))))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertTrue($container->hasDefinition('foo'));
|
||||
$this->assertTrue($container->hasDefinition('bar'));
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), new RemoveUnusedDefinitionsPass()));
|
||||
$repeatedPass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class ReplaceAliasByActualDefinitionPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('a', '\stdClass');
|
||||
|
||||
$bDefinition = new Definition('\stdClass');
|
||||
$bDefinition->setPublic(false);
|
||||
$container->setDefinition('b', $bDefinition);
|
||||
|
||||
$container->setAlias('a_alias', 'a');
|
||||
$container->setAlias('b_alias', 'b');
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertTrue($container->has('a'), '->process() does nothing to public definitions.');
|
||||
$this->assertTrue($container->hasAlias('a_alias'));
|
||||
$this->assertFalse($container->has('b'), '->process() removes non-public definitions.');
|
||||
$this->assertTrue(
|
||||
$container->has('b_alias') && !$container->hasAlias('b_alias'),
|
||||
'->process() replaces alias to actual.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new ReplaceAliasByActualDefinitionPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('parent', 'foo')->setArguments(array('moo', 'b'))->setProperty('foo', 'moo');
|
||||
$container->setDefinition('child', new DefinitionDecorator('parent'))
|
||||
->replaceArgument(0, 'a')
|
||||
->setProperty('foo', 'bar')
|
||||
->setClass('bar')
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$def = $container->getDefinition('child');
|
||||
$this->assertNotInstanceOf('Symfony\Component\DependencyInjection\DefinitionDecorator', $def);
|
||||
$this->assertEquals('bar', $def->getClass());
|
||||
$this->assertEquals(array('a', 'b'), $def->getArguments());
|
||||
$this->assertEquals(array('foo' => 'bar'), $def->getProperties());
|
||||
}
|
||||
|
||||
public function testProcessAppendsMethodCallsAlways()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('parent')
|
||||
->addMethodCall('foo', array('bar'))
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('child', new DefinitionDecorator('parent'))
|
||||
->addMethodCall('bar', array('foo'))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$def = $container->getDefinition('child');
|
||||
$this->assertEquals(array(
|
||||
array('foo', array('bar')),
|
||||
array('bar', array('foo')),
|
||||
), $def->getMethodCalls());
|
||||
}
|
||||
|
||||
public function testProcessDoesNotCopyAbstract()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('parent')
|
||||
->setAbstract(true)
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('child', new DefinitionDecorator('parent'))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$def = $container->getDefinition('child');
|
||||
$this->assertFalse($def->isAbstract());
|
||||
}
|
||||
|
||||
public function testProcessDoesNotCopyScope()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('parent')
|
||||
->setScope('foo')
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('child', new DefinitionDecorator('parent'))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$def = $container->getDefinition('child');
|
||||
$this->assertEquals(ContainerInterface::SCOPE_CONTAINER, $def->getScope());
|
||||
}
|
||||
|
||||
public function testProcessDoesNotCopyTags()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('parent')
|
||||
->addTag('foo')
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('child', new DefinitionDecorator('parent'))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$def = $container->getDefinition('child');
|
||||
$this->assertEquals(array(), $def->getTags());
|
||||
}
|
||||
|
||||
public function testProcessHandlesMultipleInheritance()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('parent', 'foo')
|
||||
->setArguments(array('foo', 'bar', 'c'))
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('child2', new DefinitionDecorator('child1'))
|
||||
->replaceArgument(1, 'b')
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('child1', new DefinitionDecorator('parent'))
|
||||
->replaceArgument(0, 'a')
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$def = $container->getDefinition('child2');
|
||||
$this->assertEquals(array('a', 'b', 'c'), $def->getArguments());
|
||||
$this->assertEquals('foo', $def->getClass());
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new ResolveDefinitionTemplatesPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveInvalidReferencesPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class ResolveInvalidReferencesPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$def = $container
|
||||
->register('foo')
|
||||
->setArguments(array(new Reference('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE)))
|
||||
->addMethodCall('foo', array(new Reference('moo', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $def->getArguments();
|
||||
$this->assertNull($arguments[0]);
|
||||
$this->assertCount(0, $def->getMethodCalls());
|
||||
}
|
||||
|
||||
public function testProcessIgnoreNonExistentServices()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$def = $container
|
||||
->register('foo')
|
||||
->setArguments(array(new Reference('bar')))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $def->getArguments();
|
||||
$this->assertEquals('bar', (string) $arguments[0]);
|
||||
}
|
||||
|
||||
public function testProcessRemovesPropertiesOnInvalid()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$def = $container
|
||||
->register('foo')
|
||||
->setProperty('foo', new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertEquals(array(), $def->getProperties());
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new ResolveInvalidReferencesPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveReferencesToAliasesPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class ResolveReferencesToAliasesPassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setAlias('bar', 'foo');
|
||||
$def = $container
|
||||
->register('moo')
|
||||
->setArguments(array(new Reference('bar')))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $def->getArguments();
|
||||
$this->assertEquals('foo', (string) $arguments[0]);
|
||||
}
|
||||
|
||||
public function testProcessRecursively()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setAlias('bar', 'foo');
|
||||
$container->setAlias('moo', 'bar');
|
||||
$def = $container
|
||||
->register('foobar')
|
||||
->setArguments(array(new Reference('moo')))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$arguments = $def->getArguments();
|
||||
$this->assertEquals('foo', (string) $arguments[0]);
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new ResolveReferencesToAliasesPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,553 @@
|
||||
<?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\Tests;
|
||||
|
||||
require_once __DIR__.'/Fixtures/includes/classes.php';
|
||||
require_once __DIR__.'/Fixtures/includes/ProjectExtension.php';
|
||||
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
|
||||
class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::setDefinitions
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getDefinitions
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::setDefinition
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getDefinition
|
||||
*/
|
||||
public function testDefinitions()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$definitions = array(
|
||||
'foo' => new Definition('FooClass'),
|
||||
'bar' => new Definition('BarClass'),
|
||||
);
|
||||
$builder->setDefinitions($definitions);
|
||||
$this->assertEquals($definitions, $builder->getDefinitions(), '->setDefinitions() sets the service definitions');
|
||||
$this->assertTrue($builder->hasDefinition('foo'), '->hasDefinition() returns true if a service definition exists');
|
||||
$this->assertFalse($builder->hasDefinition('foobar'), '->hasDefinition() returns false if a service definition does not exist');
|
||||
|
||||
$builder->setDefinition('foobar', $foo = new Definition('FooBarClass'));
|
||||
$this->assertEquals($foo, $builder->getDefinition('foobar'), '->getDefinition() returns a service definition if defined');
|
||||
$this->assertTrue($builder->setDefinition('foobar', $foo = new Definition('FooBarClass')) === $foo, '->setDefinition() implements a fluid interface by returning the service reference');
|
||||
|
||||
$builder->addDefinitions($defs = array('foobar' => new Definition('FooBarClass')));
|
||||
$this->assertEquals(array_merge($definitions, $defs), $builder->getDefinitions(), '->addDefinitions() adds the service definitions');
|
||||
|
||||
try {
|
||||
$builder->getDefinition('baz');
|
||||
$this->fail('->getDefinition() throws an InvalidArgumentException if the service definition does not exist');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertEquals('The service definition "baz" does not exist.', $e->getMessage(), '->getDefinition() throws an InvalidArgumentException if the service definition does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::register
|
||||
*/
|
||||
public function testRegister()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('foo', 'FooClass');
|
||||
$this->assertTrue($builder->hasDefinition('foo'), '->register() registers a new service definition');
|
||||
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $builder->getDefinition('foo'), '->register() returns the newly created Definition instance');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::has
|
||||
*/
|
||||
public function testHas()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$this->assertFalse($builder->has('foo'), '->has() returns false if the service does not exist');
|
||||
$builder->register('foo', 'FooClass');
|
||||
$this->assertTrue($builder->has('foo'), '->has() returns true if a service definition exists');
|
||||
$builder->set('bar', new \stdClass());
|
||||
$this->assertTrue($builder->has('bar'), '->has() returns true if a service exists');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::get
|
||||
*/
|
||||
public function testGet()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
try {
|
||||
$builder->get('foo');
|
||||
$this->fail('->get() throws an InvalidArgumentException if the service does not exist');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertEquals('The service definition "foo" does not exist.', $e->getMessage(), '->get() throws an InvalidArgumentException if the service does not exist');
|
||||
}
|
||||
|
||||
$this->assertNull($builder->get('foo', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service does not exist and NULL_ON_INVALID_REFERENCE is passed as a second argument');
|
||||
|
||||
$builder->register('foo', 'stdClass');
|
||||
$this->assertInternalType('object', $builder->get('foo'), '->get() returns the service definition associated with the id');
|
||||
$builder->set('bar', $bar = new \stdClass());
|
||||
$this->assertEquals($bar, $builder->get('bar'), '->get() returns the service associated with the id');
|
||||
$builder->register('bar', 'stdClass');
|
||||
$this->assertEquals($bar, $builder->get('bar'), '->get() returns the service associated with the id even if a definition has been defined');
|
||||
|
||||
$builder->register('baz', 'stdClass')->setArguments(array(new Reference('baz')));
|
||||
try {
|
||||
@$builder->get('baz');
|
||||
$this->fail('->get() throws a ServiceCircularReferenceException if the service has a circular reference to itself');
|
||||
} catch (\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException $e) {
|
||||
$this->assertEquals('Circular reference detected for service "baz", path: "baz".', $e->getMessage(), '->get() throws a LogicException if the service has a circular reference to itself');
|
||||
}
|
||||
|
||||
$builder->register('foobar', 'stdClass')->setScope('container');
|
||||
$this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getServiceIds
|
||||
*/
|
||||
public function testGetServiceIds()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('foo', 'stdClass');
|
||||
$builder->bar = $bar = new \stdClass();
|
||||
$builder->register('bar', 'stdClass');
|
||||
$this->assertEquals(array('foo', 'bar', 'service_container'), $builder->getServiceIds(), '->getServiceIds() returns all defined service ids');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::setAlias
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::hasAlias
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getAlias
|
||||
*/
|
||||
public function testAliases()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('foo', 'stdClass');
|
||||
$builder->setAlias('bar', 'foo');
|
||||
$this->assertTrue($builder->hasAlias('bar'), '->hasAlias() returns true if the alias exists');
|
||||
$this->assertFalse($builder->hasAlias('foobar'), '->hasAlias() returns false if the alias does not exist');
|
||||
$this->assertEquals('foo', (string) $builder->getAlias('bar'), '->getAlias() returns the aliased service');
|
||||
$this->assertTrue($builder->has('bar'), '->setAlias() defines a new service');
|
||||
$this->assertTrue($builder->get('bar') === $builder->get('foo'), '->setAlias() creates a service that is an alias to another one');
|
||||
|
||||
try {
|
||||
$builder->getAlias('foobar');
|
||||
$this->fail('->getAlias() throws an InvalidArgumentException if the alias does not exist');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertEquals('The service alias "foobar" does not exist.', $e->getMessage(), '->getAlias() throws an InvalidArgumentException if the alias does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getAliases
|
||||
*/
|
||||
public function testGetAliases()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->setAlias('bar', 'foo');
|
||||
$builder->setAlias('foobar', 'foo');
|
||||
$builder->setAlias('moo', new Alias('foo', false));
|
||||
|
||||
$aliases = $builder->getAliases();
|
||||
$this->assertEquals('foo', (string) $aliases['bar']);
|
||||
$this->assertTrue($aliases['bar']->isPublic());
|
||||
$this->assertEquals('foo', (string) $aliases['foobar']);
|
||||
$this->assertEquals('foo', (string) $aliases['moo']);
|
||||
$this->assertFalse($aliases['moo']->isPublic());
|
||||
|
||||
$builder->register('bar', 'stdClass');
|
||||
$this->assertFalse($builder->hasAlias('bar'));
|
||||
|
||||
$builder->set('foobar', 'stdClass');
|
||||
$builder->set('moo', 'stdClass');
|
||||
$this->assertCount(0, $builder->getAliases(), '->getAliases() does not return aliased services that have been overridden');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::setAliases
|
||||
*/
|
||||
public function testSetAliases()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->setAliases(array('bar' => 'foo', 'foobar' => 'foo'));
|
||||
|
||||
$aliases = $builder->getAliases();
|
||||
$this->assertTrue(isset($aliases['bar']));
|
||||
$this->assertTrue(isset($aliases['foobar']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::addAliases
|
||||
*/
|
||||
public function testAddAliases()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->setAliases(array('bar' => 'foo'));
|
||||
$builder->addAliases(array('foobar' => 'foo'));
|
||||
|
||||
$aliases = $builder->getAliases();
|
||||
$this->assertTrue(isset($aliases['bar']));
|
||||
$this->assertTrue(isset($aliases['foobar']));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::addCompilerPass
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getCompilerPassConfig
|
||||
*/
|
||||
public function testAddGetCompilerPass()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$builder = new ContainerBuilder();
|
||||
$builderCompilerPasses = $builder->getCompiler()->getPassConfig()->getPasses();
|
||||
$builder->addCompilerPass($this->getMock('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface'));
|
||||
$this->assertEquals(sizeof($builderCompilerPasses) + 1, sizeof($builder->getCompiler()->getPassConfig()->getPasses()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
|
||||
*/
|
||||
public function testCreateService()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('foo1', 'FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
|
||||
$this->assertInstanceOf('\FooClass', $builder->get('foo1'), '->createService() requires the file defined by the service definition');
|
||||
$builder->register('foo2', 'FooClass')->setFile(__DIR__.'/Fixtures/includes/%file%.php');
|
||||
$builder->setParameter('file', 'foo');
|
||||
$this->assertInstanceOf('\FooClass', $builder->get('foo2'), '->createService() replaces parameters in the file provided by the service definition');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
|
||||
*/
|
||||
public function testCreateServiceClass()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('foo1', '%class%');
|
||||
$builder->setParameter('class', 'stdClass');
|
||||
$this->assertInstanceOf('\stdClass', $builder->get('foo1'), '->createService() replaces parameters in the class provided by the service definition');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
|
||||
*/
|
||||
public function testCreateServiceArguments()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('bar', 'stdClass');
|
||||
$builder->register('foo1', 'FooClass')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar'), '%%unescape_it%%'));
|
||||
$builder->setParameter('value', 'bar');
|
||||
$this->assertEquals(array('foo' => 'bar', 'bar' => 'foo', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->arguments, '->createService() replaces parameters and service references in the arguments provided by the service definition');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
|
||||
*/
|
||||
public function testCreateServiceFactoryMethod()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('bar', 'stdClass');
|
||||
$builder->register('foo1', 'FooClass')->setFactoryClass('FooClass')->setFactoryMethod('getInstance')->addArgument(array('foo' => '%value%', '%value%' => 'foo', new Reference('bar')));
|
||||
$builder->setParameter('value', 'bar');
|
||||
$this->assertTrue($builder->get('foo1')->called, '->createService() calls the factory method to create the service instance');
|
||||
$this->assertEquals(array('foo' => 'bar', 'bar' => 'foo', $builder->get('bar')), $builder->get('foo1')->arguments, '->createService() passes the arguments to the factory method');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
|
||||
*/
|
||||
public function testCreateServiceFactoryService()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('baz_service')->setFactoryService('baz_factory')->setFactoryMethod('getInstance');
|
||||
$builder->register('baz_factory', 'BazClass');
|
||||
|
||||
$this->assertInstanceOf('BazClass', $builder->get('baz_service'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
|
||||
*/
|
||||
public function testCreateServiceMethodCalls()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('bar', 'stdClass');
|
||||
$builder->register('foo1', 'FooClass')->addMethodCall('setBar', array(array('%value%', new Reference('bar'))));
|
||||
$builder->setParameter('value', 'bar');
|
||||
$this->assertEquals(array('bar', $builder->get('bar')), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
|
||||
*/
|
||||
public function testCreateServiceConfigurator()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('foo1', 'FooClass')->setConfigurator('sc_configure');
|
||||
$this->assertTrue($builder->get('foo1')->configured, '->createService() calls the configurator');
|
||||
|
||||
$builder->register('foo2', 'FooClass')->setConfigurator(array('%class%', 'configureStatic'));
|
||||
$builder->setParameter('class', 'BazClass');
|
||||
$this->assertTrue($builder->get('foo2')->configured, '->createService() calls the configurator');
|
||||
|
||||
$builder->register('baz', 'BazClass');
|
||||
$builder->register('foo3', 'FooClass')->setConfigurator(array(new Reference('baz'), 'configure'));
|
||||
$this->assertTrue($builder->get('foo3')->configured, '->createService() calls the configurator');
|
||||
|
||||
$builder->register('foo4', 'FooClass')->setConfigurator('foo');
|
||||
try {
|
||||
$builder->get('foo4');
|
||||
$this->fail('->createService() throws an InvalidArgumentException if the configure callable is not a valid callable');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertEquals('The configure callable for class "FooClass" is not a callable.', $e->getMessage(), '->createService() throws an InvalidArgumentException if the configure callable is not a valid callable');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::resolveServices
|
||||
*/
|
||||
public function testResolveServices()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder->register('foo', 'FooClass');
|
||||
$this->assertEquals($builder->get('foo'), $builder->resolveServices(new Reference('foo')), '->resolveServices() resolves service references to service instances');
|
||||
$this->assertEquals(array('foo' => array('foo', $builder->get('foo'))), $builder->resolveServices(array('foo' => array('foo', new Reference('foo')))), '->resolveServices() resolves service references to service instances in nested arrays');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::merge
|
||||
*/
|
||||
public function testMerge()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
|
||||
$config = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
|
||||
$container->merge($config);
|
||||
$this->assertEquals(array('bar' => 'foo', 'foo' => 'bar'), $container->getParameterBag()->all(), '->merge() merges current parameters with the loaded ones');
|
||||
|
||||
$container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
|
||||
$config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%')));
|
||||
$container->merge($config);
|
||||
////// FIXME
|
||||
$container->compile();
|
||||
$this->assertEquals(array('bar' => 'foo', 'foo' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
|
||||
|
||||
$container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));
|
||||
$config = new ContainerBuilder(new ParameterBag(array('foo' => '%bar%', 'baz' => '%foo%')));
|
||||
$container->merge($config);
|
||||
////// FIXME
|
||||
$container->compile();
|
||||
$this->assertEquals(array('bar' => 'foo', 'foo' => 'foo', 'baz' => 'foo'), $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo', 'FooClass');
|
||||
$container->register('bar', 'BarClass');
|
||||
$config = new ContainerBuilder();
|
||||
$config->setDefinition('baz', new Definition('BazClass'));
|
||||
$config->setAlias('alias_for_foo', 'foo');
|
||||
$container->merge($config);
|
||||
$this->assertEquals(array('foo', 'bar', 'baz'), array_keys($container->getDefinitions()), '->merge() merges definitions already defined ones');
|
||||
|
||||
$aliases = $container->getAliases();
|
||||
$this->assertTrue(isset($aliases['alias_for_foo']));
|
||||
$this->assertEquals('foo', (string) $aliases['alias_for_foo']);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo', 'FooClass');
|
||||
$config->setDefinition('foo', new Definition('BazClass'));
|
||||
$container->merge($config);
|
||||
$this->assertEquals('BazClass', $container->getDefinition('foo')->getClass(), '->merge() overrides already defined services');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::merge
|
||||
* @expectedException LogicException
|
||||
*/
|
||||
public function testMergeLogicException()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->compile();
|
||||
$container->merge(new ContainerBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::findTaggedServiceIds
|
||||
*/
|
||||
public function testfindTaggedServiceIds()
|
||||
{
|
||||
$builder = new ContainerBuilder();
|
||||
$builder
|
||||
->register('foo', 'FooClass')
|
||||
->addTag('foo', array('foo' => 'foo'))
|
||||
->addTag('bar', array('bar' => 'bar'))
|
||||
->addTag('foo', array('foofoo' => 'foofoo'))
|
||||
;
|
||||
$this->assertEquals($builder->findTaggedServiceIds('foo'), array(
|
||||
'foo' => array(
|
||||
array('foo' => 'foo'),
|
||||
array('foofoo' => 'foofoo'),
|
||||
)
|
||||
), '->findTaggedServiceIds() returns an array of service ids and its tag attributes');
|
||||
$this->assertEquals(array(), $builder->findTaggedServiceIds('foobar'), '->findTaggedServiceIds() returns an empty array if there is annotated services');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::findDefinition
|
||||
*/
|
||||
public function testFindDefinition()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setDefinition('foo', $definition = new Definition('FooClass'));
|
||||
$container->setAlias('bar', 'foo');
|
||||
$container->setAlias('foobar', 'bar');
|
||||
$this->assertEquals($definition, $container->findDefinition('foobar'), '->findDefinition() returns a Definition');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getResources
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::addResource
|
||||
*/
|
||||
public function testResources()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->addResource($a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml'));
|
||||
$container->addResource($b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml'));
|
||||
$resources = array();
|
||||
foreach ($container->getResources() as $resource) {
|
||||
if (false === strpos($resource, '.php')) {
|
||||
$resources[] = $resource;
|
||||
}
|
||||
}
|
||||
$this->assertEquals(array($a, $b), $resources, '->getResources() returns an array of resources read for the current configuration');
|
||||
$this->assertSame($container, $container->setResources(array()));
|
||||
$this->assertEquals(array(), $container->getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::registerExtension
|
||||
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::getExtension
|
||||
*/
|
||||
public function testExtension()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->registerExtension($extension = new \ProjectExtension());
|
||||
$this->assertTrue($container->getExtension('project') === $extension, '->registerExtension() registers an extension');
|
||||
|
||||
$this->setExpectedException('LogicException');
|
||||
$container->getExtension('no_registered');
|
||||
}
|
||||
|
||||
public function testRegisteredButNotLoadedExtension()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$extension = $this->getMock('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface');
|
||||
$extension->expects($this->once())->method('getAlias')->will($this->returnValue('project'));
|
||||
$extension->expects($this->never())->method('load');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->registerExtension($extension);
|
||||
$container->compile();
|
||||
}
|
||||
|
||||
public function testRegisteredAndLoadedExtension()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$extension = $this->getMock('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface');
|
||||
$extension->expects($this->exactly(2))->method('getAlias')->will($this->returnValue('project'));
|
||||
$extension->expects($this->once())->method('load')->with(array(array('foo' => 'bar')));
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->registerExtension($extension);
|
||||
$container->loadFromExtension('project', array('foo' => 'bar'));
|
||||
$container->compile();
|
||||
}
|
||||
|
||||
public function testPrivateServiceUser()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$fooDefinition = new Definition('BarClass');
|
||||
$fooUserDefinition = new Definition('BarUserClass', array(new Reference('bar')));
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$fooDefinition->setPublic(false);
|
||||
|
||||
$container->addDefinitions(array(
|
||||
'bar' => $fooDefinition,
|
||||
'bar_user' => $fooUserDefinition
|
||||
));
|
||||
|
||||
$container->compile();
|
||||
$this->assertInstanceOf('BarClass', $container->get('bar_user')->bar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException BadMethodCallException
|
||||
*/
|
||||
public function testThrowsExceptionWhenSetServiceOnAFrozenContainer()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->compile();
|
||||
$container->set('a', new \stdClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException BadMethodCallException
|
||||
*/
|
||||
public function testThrowsExceptionWhenSetDefinitionOnAFrozenContainer()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Resource\FileResource')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->compile();
|
||||
$container->setDefinition('a', new Definition());
|
||||
}
|
||||
}
|
||||
|
||||
class FooClass {}
|
||||
@@ -0,0 +1,450 @@
|
||||
<?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\Tests;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Scope;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
|
||||
class ContainerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::__construct
|
||||
*/
|
||||
public function testConstructor()
|
||||
{
|
||||
$sc = new Container();
|
||||
$this->assertSame($sc, $sc->get('service_container'), '__construct() automatically registers itself as a service');
|
||||
|
||||
$sc = new Container(new ParameterBag(array('foo' => 'bar')));
|
||||
$this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '__construct() takes an array of parameters as its first argument');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::compile
|
||||
*/
|
||||
public function testCompile()
|
||||
{
|
||||
$sc = new Container(new ParameterBag(array('foo' => 'bar')));
|
||||
$sc->compile();
|
||||
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag', $sc->getParameterBag(), '->compile() changes the parameter bag to a FrozenParameterBag instance');
|
||||
$this->assertEquals(array('foo' => 'bar'), $sc->getParameterBag()->all(), '->compile() copies the current parameters to the new parameter bag');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::isFrozen
|
||||
*/
|
||||
public function testIsFrozen()
|
||||
{
|
||||
$sc = new Container(new ParameterBag(array('foo' => 'bar')));
|
||||
$this->assertFalse($sc->isFrozen(), '->isFrozen() returns false if the parameters are not frozen');
|
||||
$sc->compile();
|
||||
$this->assertTrue($sc->isFrozen(), '->isFrozen() returns true if the parameters are frozen');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::getParameterBag
|
||||
*/
|
||||
public function testGetParameterBag()
|
||||
{
|
||||
$sc = new Container();
|
||||
$this->assertEquals(array(), $sc->getParameterBag()->all(), '->getParameterBag() returns an empty array if no parameter has been defined');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::setParameter
|
||||
* @covers Symfony\Component\DependencyInjection\Container::getParameter
|
||||
*/
|
||||
public function testGetSetParameter()
|
||||
{
|
||||
$sc = new Container(new ParameterBag(array('foo' => 'bar')));
|
||||
$sc->setParameter('bar', 'foo');
|
||||
$this->assertEquals('foo', $sc->getParameter('bar'), '->setParameter() sets the value of a new parameter');
|
||||
|
||||
$sc->setParameter('foo', 'baz');
|
||||
$this->assertEquals('baz', $sc->getParameter('foo'), '->setParameter() overrides previously set parameter');
|
||||
|
||||
$sc->setParameter('Foo', 'baz1');
|
||||
$this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase');
|
||||
$this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase');
|
||||
|
||||
try {
|
||||
$sc->getParameter('baba');
|
||||
$this->fail('->getParameter() thrown an \InvalidArgumentException if the key does not exist');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->getParameter() thrown an \InvalidArgumentException if the key does not exist');
|
||||
$this->assertEquals('You have requested a non-existent parameter "baba".', $e->getMessage(), '->getParameter() thrown an \InvalidArgumentException if the key does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::getServiceIds
|
||||
*/
|
||||
public function testGetServiceIds()
|
||||
{
|
||||
$sc = new Container();
|
||||
$sc->set('foo', $obj = new \stdClass());
|
||||
$sc->set('bar', $obj = new \stdClass());
|
||||
$this->assertEquals(array('service_container', 'foo', 'bar'), $sc->getServiceIds(), '->getServiceIds() returns all defined service ids');
|
||||
|
||||
$sc = new ProjectServiceContainer();
|
||||
$this->assertEquals(array('scoped', 'scoped_foo', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'service_container'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::set
|
||||
*/
|
||||
public function testSet()
|
||||
{
|
||||
$sc = new Container();
|
||||
$sc->set('foo', $foo = new \stdClass());
|
||||
$this->assertEquals($foo, $sc->get('foo'), '->set() sets a service');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testSetDoesNotAllowPrototypeScope()
|
||||
{
|
||||
$c = new Container();
|
||||
$c->set('foo', new \stdClass(), 'prototype');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testSetDoesNotAllowInactiveScope()
|
||||
{
|
||||
$c = new Container();
|
||||
$c->addScope(new Scope('foo'));
|
||||
$c->set('foo', new \stdClass(), 'foo');
|
||||
}
|
||||
|
||||
public function testSetAlsoSetsScopedService()
|
||||
{
|
||||
$c = new Container();
|
||||
$c->addScope(new Scope('foo'));
|
||||
$c->enterScope('foo');
|
||||
$c->set('foo', $foo = new \stdClass(), 'foo');
|
||||
|
||||
$services = $this->getField($c, 'scopedServices');
|
||||
$this->assertTrue(isset($services['foo']['foo']));
|
||||
$this->assertSame($foo, $services['foo']['foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::get
|
||||
*/
|
||||
public function testGet()
|
||||
{
|
||||
$sc = new ProjectServiceContainer();
|
||||
$sc->set('foo', $foo = new \stdClass());
|
||||
$this->assertEquals($foo, $sc->get('foo'), '->get() returns the service for the given id');
|
||||
$this->assertEquals($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id');
|
||||
$this->assertEquals($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined');
|
||||
$this->assertEquals($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined');
|
||||
|
||||
$sc->set('bar', $bar = new \stdClass());
|
||||
$this->assertEquals($bar, $sc->get('bar'), '->get() prefers to return a service defined with set() than one defined with a getXXXMethod()');
|
||||
|
||||
try {
|
||||
$sc->get('');
|
||||
$this->fail('->get() throws a \InvalidArgumentException exception if the service is empty');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty');
|
||||
}
|
||||
$this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE));
|
||||
}
|
||||
|
||||
public function testGetCircularReference()
|
||||
{
|
||||
|
||||
$sc = new ProjectServiceContainer();
|
||||
try {
|
||||
$sc->get('circular');
|
||||
$this->fail('->get() throws a ServiceCircularReferenceException if it contains circular reference');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException', $e, '->get() throws a ServiceCircularReferenceException if it contains circular reference');
|
||||
$this->assertStringStartsWith('Circular reference detected for service "circular"', $e->getMessage(), '->get() throws a \LogicException if it contains circular reference');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::has
|
||||
*/
|
||||
public function testHas()
|
||||
{
|
||||
$sc = new ProjectServiceContainer();
|
||||
$sc->set('foo', new \stdClass());
|
||||
$this->assertFalse($sc->has('foo1'), '->has() returns false if the service does not exist');
|
||||
$this->assertTrue($sc->has('foo'), '->has() returns true if the service exists');
|
||||
$this->assertTrue($sc->has('bar'), '->has() returns true if a get*Method() is defined');
|
||||
$this->assertTrue($sc->has('foo_bar'), '->has() returns true if a get*Method() is defined');
|
||||
$this->assertTrue($sc->has('foo.baz'), '->has() returns true if a get*Method() is defined');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Container::initialized
|
||||
*/
|
||||
public function testInitialized()
|
||||
{
|
||||
$sc = new ProjectServiceContainer();
|
||||
$sc->set('foo', new \stdClass());
|
||||
$this->assertTrue($sc->initialized('foo'), '->initialized() returns true if service is loaded');
|
||||
$this->assertFalse($sc->initialized('foo1'), '->initialized() returns false if service is not loaded');
|
||||
$this->assertFalse($sc->initialized('bar'), '->initialized() returns false if a service is defined, but not currently loaded');
|
||||
}
|
||||
|
||||
public function testEnterLeaveCurrentScope()
|
||||
{
|
||||
$container = new ProjectServiceContainer();
|
||||
$container->addScope(new Scope('foo'));
|
||||
|
||||
$container->enterScope('foo');
|
||||
$scoped1 = $container->get('scoped');
|
||||
$scopedFoo1 = $container->get('scoped_foo');
|
||||
|
||||
$container->enterScope('foo');
|
||||
$scoped2 = $container->get('scoped');
|
||||
$scoped3 = $container->get('scoped');
|
||||
$scopedFoo2 = $container->get('scoped_foo');
|
||||
|
||||
$container->leaveScope('foo');
|
||||
$scoped4 = $container->get('scoped');
|
||||
$scopedFoo3 = $container->get('scoped_foo');
|
||||
|
||||
$this->assertNotSame($scoped1, $scoped2);
|
||||
$this->assertSame($scoped2, $scoped3);
|
||||
$this->assertSame($scoped1, $scoped4);
|
||||
$this->assertNotSame($scopedFoo1, $scopedFoo2);
|
||||
$this->assertSame($scopedFoo1, $scopedFoo3);
|
||||
}
|
||||
|
||||
public function testEnterLeaveScopeWithChildScopes()
|
||||
{
|
||||
$container = new Container();
|
||||
$container->addScope(new Scope('foo'));
|
||||
$container->addScope(new Scope('bar', 'foo'));
|
||||
|
||||
$this->assertFalse($container->isScopeActive('foo'));
|
||||
|
||||
$container->enterScope('foo');
|
||||
$container->enterScope('bar');
|
||||
|
||||
$this->assertTrue($container->isScopeActive('foo'));
|
||||
$this->assertFalse($container->has('a'));
|
||||
|
||||
$a = new \stdClass();
|
||||
$container->set('a', $a, 'bar');
|
||||
|
||||
$services = $this->getField($container, 'scopedServices');
|
||||
$this->assertTrue(isset($services['bar']['a']));
|
||||
$this->assertSame($a, $services['bar']['a']);
|
||||
|
||||
$this->assertTrue($container->has('a'));
|
||||
$container->leaveScope('foo');
|
||||
|
||||
$services = $this->getField($container, 'scopedServices');
|
||||
$this->assertFalse(isset($services['bar']));
|
||||
|
||||
$this->assertFalse($container->isScopeActive('foo'));
|
||||
$this->assertFalse($container->has('a'));
|
||||
}
|
||||
|
||||
public function testLeaveScopeNotActive()
|
||||
{
|
||||
$container = new Container();
|
||||
$container->addScope(new Scope('foo'));
|
||||
|
||||
try {
|
||||
$container->leaveScope('foo');
|
||||
$this->fail('->leaveScope() throws a \LogicException if the scope is not active yet');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\LogicException', $e, '->leaveScope() throws a \LogicException if the scope is not active yet');
|
||||
$this->assertEquals('The scope "foo" is not active.', $e->getMessage(), '->leaveScope() throws a \LogicException if the scope is not active yet');
|
||||
}
|
||||
|
||||
try {
|
||||
$container->leaveScope('bar');
|
||||
$this->fail('->leaveScope() throws a \LogicException if the scope does not exist');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\LogicException', $e, '->leaveScope() throws a \LogicException if the scope does not exist');
|
||||
$this->assertEquals('The scope "bar" is not active.', $e->getMessage(), '->leaveScope() throws a \LogicException if the scope does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @dataProvider getBuiltInScopes
|
||||
*/
|
||||
public function testAddScopeDoesNotAllowBuiltInScopes($scope)
|
||||
{
|
||||
$container = new Container();
|
||||
$container->addScope(new Scope($scope));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testAddScopeDoesNotAllowExistingScope()
|
||||
{
|
||||
$container = new Container();
|
||||
$container->addScope(new Scope('foo'));
|
||||
$container->addScope(new Scope('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @dataProvider getInvalidParentScopes
|
||||
*/
|
||||
public function testAddScopeDoesNotAllowInvalidParentScope($scope)
|
||||
{
|
||||
$c = new Container();
|
||||
$c->addScope(new Scope('foo', $scope));
|
||||
}
|
||||
|
||||
public function testAddScope()
|
||||
{
|
||||
$c = new Container();
|
||||
$c->addScope(new Scope('foo'));
|
||||
$c->addScope(new Scope('bar', 'foo'));
|
||||
|
||||
$this->assertSame(array('foo' => 'container', 'bar' => 'foo'), $this->getField($c, 'scopes'));
|
||||
$this->assertSame(array('foo' => array('bar'), 'bar' => array()), $this->getField($c, 'scopeChildren'));
|
||||
}
|
||||
|
||||
public function testHasScope()
|
||||
{
|
||||
$c = new Container();
|
||||
|
||||
$this->assertFalse($c->hasScope('foo'));
|
||||
$c->addScope(new Scope('foo'));
|
||||
$this->assertTrue($c->hasScope('foo'));
|
||||
}
|
||||
|
||||
public function testIsScopeActive()
|
||||
{
|
||||
$c = new Container();
|
||||
|
||||
$this->assertFalse($c->isScopeActive('foo'));
|
||||
$c->addScope(new Scope('foo'));
|
||||
|
||||
$this->assertFalse($c->isScopeActive('foo'));
|
||||
$c->enterScope('foo');
|
||||
|
||||
$this->assertTrue($c->isScopeActive('foo'));
|
||||
$c->leaveScope('foo');
|
||||
|
||||
$this->assertFalse($c->isScopeActive('foo'));
|
||||
}
|
||||
|
||||
public function testGetThrowsException()
|
||||
{
|
||||
$c = new ProjectServiceContainer();
|
||||
|
||||
try {
|
||||
$c->get('throw_exception');
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Something went terribly wrong!', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$c->get('throw_exception');
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Something went terribly wrong!', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function getInvalidParentScopes()
|
||||
{
|
||||
return array(
|
||||
array(ContainerInterface::SCOPE_PROTOTYPE),
|
||||
array('bar'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getBuiltInScopes()
|
||||
{
|
||||
return array(
|
||||
array(ContainerInterface::SCOPE_CONTAINER),
|
||||
array(ContainerInterface::SCOPE_PROTOTYPE),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getField($obj, $field)
|
||||
{
|
||||
$reflection = new \ReflectionProperty($obj, $field);
|
||||
$reflection->setAccessible(true);
|
||||
|
||||
return $reflection->getValue($obj);
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectServiceContainer extends Container
|
||||
{
|
||||
public $__bar, $__foo_bar, $__foo_baz;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->__bar = new \stdClass();
|
||||
$this->__foo_bar = new \stdClass();
|
||||
$this->__foo_baz = new \stdClass();
|
||||
}
|
||||
|
||||
protected function getScopedService()
|
||||
{
|
||||
if (!isset($this->scopedServices['foo'])) {
|
||||
throw new \RuntimeException('Invalid call');
|
||||
}
|
||||
|
||||
return $this->services['scoped'] = $this->scopedServices['foo']['scoped'] = new \stdClass();
|
||||
}
|
||||
|
||||
protected function getScopedFooService()
|
||||
{
|
||||
if (!isset($this->scopedServices['foo'])) {
|
||||
throw new \RuntimeException('invalid call');
|
||||
}
|
||||
|
||||
return $this->services['scoped_foo'] = $this->scopedServices['foo']['scoped_foo'] = new \stdClass();
|
||||
}
|
||||
|
||||
protected function getBarService()
|
||||
{
|
||||
return $this->__bar;
|
||||
}
|
||||
|
||||
protected function getFooBarService()
|
||||
{
|
||||
return $this->__foo_bar;
|
||||
}
|
||||
|
||||
protected function getFoo_BazService()
|
||||
{
|
||||
return $this->__foo_baz;
|
||||
}
|
||||
|
||||
protected function getCircularService()
|
||||
{
|
||||
return $this->get('circular');
|
||||
}
|
||||
|
||||
protected function getThrowExceptionService()
|
||||
{
|
||||
throw new \Exception('Something went terribly wrong!');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?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\Tests;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
|
||||
class CrossCheckTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$fixturesPath = __DIR__.'/Fixtures/';
|
||||
|
||||
require_once self::$fixturesPath.'/includes/classes.php';
|
||||
require_once self::$fixturesPath.'/includes/foo.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider crossCheckLoadersDumpers
|
||||
*/
|
||||
public function testCrossCheck($fixture, $type)
|
||||
{
|
||||
$loaderClass = 'Symfony\\Component\\DependencyInjection\\Loader\\'.ucfirst($type).'FileLoader';
|
||||
$dumperClass = 'Symfony\\Component\\DependencyInjection\\Dumper\\'.ucfirst($type).'Dumper';
|
||||
|
||||
$tmp = tempnam('sf_service_container', 'sf');
|
||||
|
||||
file_put_contents($tmp, file_get_contents(self::$fixturesPath.'/'.$type.'/'.$fixture));
|
||||
|
||||
$container1 = new ContainerBuilder();
|
||||
$loader1 = new $loaderClass($container1, new FileLocator());
|
||||
$loader1->load($tmp);
|
||||
|
||||
$dumper = new $dumperClass($container1);
|
||||
file_put_contents($tmp, $dumper->dump());
|
||||
|
||||
$container2 = new ContainerBuilder();
|
||||
$loader2 = new $loaderClass($container2, new FileLocator());
|
||||
$loader2->load($tmp);
|
||||
|
||||
unlink($tmp);
|
||||
|
||||
$this->assertEquals($container2->getAliases(), $container1->getAliases(), 'loading a dump from a previously loaded container returns the same container');
|
||||
$this->assertEquals($container2->getDefinitions(), $container1->getDefinitions(), 'loading a dump from a previously loaded container returns the same container');
|
||||
$this->assertEquals($container2->getParameterBag()->all(), $container1->getParameterBag()->all(), '->getParameterBag() returns the same value for both containers');
|
||||
|
||||
$this->assertEquals(serialize($container2), serialize($container1), 'loading a dump from a previously loaded container returns the same container');
|
||||
|
||||
$services1 = array();
|
||||
foreach ($container1 as $id => $service) {
|
||||
$services1[$id] = serialize($service);
|
||||
}
|
||||
$services2 = array();
|
||||
foreach ($container2 as $id => $service) {
|
||||
$services2[$id] = serialize($service);
|
||||
}
|
||||
|
||||
unset($services1['service_container'], $services2['service_container']);
|
||||
|
||||
$this->assertEquals($services2, $services1, 'Iterator on the containers returns the same services');
|
||||
}
|
||||
|
||||
public function crossCheckLoadersDumpers()
|
||||
{
|
||||
return array(
|
||||
array('services1.xml', 'xml'),
|
||||
array('services2.xml', 'xml'),
|
||||
array('services6.xml', 'xml'),
|
||||
array('services8.xml', 'xml'),
|
||||
array('services9.xml', 'xml'),
|
||||
|
||||
array('services1.yml', 'yaml'),
|
||||
array('services2.yml', 'yaml'),
|
||||
array('services6.yml', 'yaml'),
|
||||
array('services8.yml', 'yaml'),
|
||||
array('services9.yml', 'yaml'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?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\Tests;
|
||||
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
|
||||
class DefinitionDecoratorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testConstructor()
|
||||
{
|
||||
$def = new DefinitionDecorator('foo');
|
||||
|
||||
$this->assertEquals('foo', $def->getParent());
|
||||
$this->assertEquals(array(), $def->getChanges());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getPropertyTests
|
||||
*/
|
||||
public function testSetProperty($property, $changeKey)
|
||||
{
|
||||
$def = new DefinitionDecorator('foo');
|
||||
|
||||
$getter = 'get'.ucfirst($property);
|
||||
$setter = 'set'.ucfirst($property);
|
||||
|
||||
$this->assertNull($def->$getter());
|
||||
$this->assertSame($def, $def->$setter('foo'));
|
||||
$this->assertEquals('foo', $def->$getter());
|
||||
$this->assertEquals(array($changeKey => true), $def->getChanges());
|
||||
}
|
||||
|
||||
public function getPropertyTests()
|
||||
{
|
||||
return array(
|
||||
array('class', 'class'),
|
||||
array('factoryClass', 'factory_class'),
|
||||
array('factoryMethod', 'factory_method'),
|
||||
array('factoryService', 'factory_service'),
|
||||
array('configurator', 'configurator'),
|
||||
array('file', 'file'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testSetPublic()
|
||||
{
|
||||
$def = new DefinitionDecorator('foo');
|
||||
|
||||
$this->assertTrue($def->isPublic());
|
||||
$this->assertSame($def, $def->setPublic(false));
|
||||
$this->assertFalse($def->isPublic());
|
||||
$this->assertEquals(array('public' => true), $def->getChanges());
|
||||
}
|
||||
|
||||
public function testSetArgument()
|
||||
{
|
||||
$def = new DefinitionDecorator('foo');
|
||||
|
||||
$this->assertEquals(array(), $def->getArguments());
|
||||
$this->assertSame($def, $def->replaceArgument(0, 'foo'));
|
||||
$this->assertEquals(array('index_0' => 'foo'), $def->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testReplaceArgumentShouldRequireIntegerIndex()
|
||||
{
|
||||
$def = new DefinitionDecorator('foo');
|
||||
|
||||
$def->replaceArgument('0', 'foo');
|
||||
}
|
||||
|
||||
public function testReplaceArgument()
|
||||
{
|
||||
$def = new DefinitionDecorator('foo');
|
||||
|
||||
$def->setArguments(array(0 => 'foo', 1 => 'bar'));
|
||||
$this->assertEquals('foo', $def->getArgument(0));
|
||||
$this->assertEquals('bar', $def->getArgument(1));
|
||||
|
||||
$this->assertSame($def, $def->replaceArgument(1, 'baz'));
|
||||
$this->assertEquals('foo', $def->getArgument(0));
|
||||
$this->assertEquals('baz', $def->getArgument(1));
|
||||
|
||||
$this->assertEquals(array(0 => 'foo', 1 => 'bar', 'index_1' => 'baz'), $def->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException OutOfBoundsException
|
||||
*/
|
||||
public function testGetArgumentShouldCheckBounds()
|
||||
{
|
||||
$def = new DefinitionDecorator('foo');
|
||||
|
||||
$def->setArguments(array(0 => 'foo'));
|
||||
$def->replaceArgument(0, 'foo');
|
||||
|
||||
$def->getArgument(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
<?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\Tests;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class DefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::__construct
|
||||
*/
|
||||
public function testConstructor()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertEquals('stdClass', $def->getClass(), '__construct() takes the class name as its first argument');
|
||||
|
||||
$def = new Definition('stdClass', array('foo'));
|
||||
$this->assertEquals(array('foo'), $def->getArguments(), '__construct() takes an optional array of arguments as its second argument');
|
||||
}
|
||||
|
||||
public function testSetGetFactoryClass()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertNull($def->getFactoryClass());
|
||||
$this->assertSame($def, $def->setFactoryClass('stdClass2'), "->setFactoryClass() implements a fluent interface.");
|
||||
$this->assertEquals('stdClass2', $def->getFactoryClass(), "->getFactoryClass() returns current class to construct this service.");
|
||||
}
|
||||
|
||||
public function testSetGetFactoryMethod()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertNull($def->getFactoryMethod());
|
||||
$this->assertSame($def, $def->setFactoryMethod('foo'), '->setFactoryMethod() implements a fluent interface');
|
||||
$this->assertEquals('foo', $def->getFactoryMethod(), '->getFactoryMethod() returns the factory method name');
|
||||
}
|
||||
|
||||
public function testSetGetFactoryService()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertNull($def->getFactoryService());
|
||||
$this->assertSame($def, $def->setFactoryService('foo.bar'), "->setFactoryService() implements a fluent interface.");
|
||||
$this->assertEquals('foo.bar', $def->getFactoryService(), "->getFactoryService() returns current service to construct this service.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setClass
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::getClass
|
||||
*/
|
||||
public function testSetGetClass()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertSame($def, $def->setClass('foo'), '->setClass() implements a fluent interface');
|
||||
$this->assertEquals('foo', $def->getClass(), '->getClass() returns the class name');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setArguments
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::getArguments
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::addArgument
|
||||
*/
|
||||
public function testArguments()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertSame($def, $def->setArguments(array('foo')), '->setArguments() implements a fluent interface');
|
||||
$this->assertEquals(array('foo'), $def->getArguments(), '->getArguments() returns the arguments');
|
||||
$this->assertSame($def, $def->addArgument('bar'), '->addArgument() implements a fluent interface');
|
||||
$this->assertEquals(array('foo', 'bar'), $def->getArguments(), '->addArgument() adds an argument');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setMethodCalls
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::addMethodCall
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::hasMethodCall
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::removeMethodCall
|
||||
*/
|
||||
public function testMethodCalls()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertSame($def, $def->setMethodCalls(array(array('foo', array('foo')))), '->setMethodCalls() implements a fluent interface');
|
||||
$this->assertEquals(array(array('foo', array('foo'))), $def->getMethodCalls(), '->getMethodCalls() returns the methods to call');
|
||||
$this->assertSame($def, $def->addMethodCall('bar', array('bar')), '->addMethodCall() implements a fluent interface');
|
||||
$this->assertEquals(array(array('foo', array('foo')), array('bar', array('bar'))), $def->getMethodCalls(), '->addMethodCall() adds a method to call');
|
||||
$this->assertTrue($def->hasMethodCall('bar'), '->hasMethodCall() returns true if first argument is a method to call registered');
|
||||
$this->assertFalse($def->hasMethodCall('no_registered'), '->hasMethodCall() returns false if first argument is not a method to call registered');
|
||||
$this->assertSame($def, $def->removeMethodCall('bar'), '->removeMethodCall() implements a fluent interface');
|
||||
$this->assertEquals(array(array('foo', array('foo'))), $def->getMethodCalls(), '->removeMethodCall() removes a method to call');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage Method name cannot be empty.
|
||||
*/
|
||||
public function testExceptionOnEmptyMethodCall()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$def->addMethodCall('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setFile
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::getFile
|
||||
*/
|
||||
public function testSetGetFile()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertSame($def, $def->setFile('foo'), '->setFile() implements a fluent interface');
|
||||
$this->assertEquals('foo', $def->getFile(), '->getFile() returns the file to include');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setScope
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::getScope
|
||||
*/
|
||||
public function testSetGetScope()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertEquals('container', $def->getScope());
|
||||
$this->assertSame($def, $def->setScope('foo'));
|
||||
$this->assertEquals('foo', $def->getScope());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setPublic
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::isPublic
|
||||
*/
|
||||
public function testSetIsPublic()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertTrue($def->isPublic(), '->isPublic() returns true by default');
|
||||
$this->assertSame($def, $def->setPublic(false), '->setPublic() implements a fluent interface');
|
||||
$this->assertFalse($def->isPublic(), '->isPublic() returns false if the instance must not be public.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setSynthetic
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::isSynthetic
|
||||
*/
|
||||
public function testSetIsSynthetic()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertFalse($def->isSynthetic(), '->isSynthetic() returns false by default');
|
||||
$this->assertSame($def, $def->setSynthetic(true), '->setSynthetic() implements a fluent interface');
|
||||
$this->assertTrue($def->isSynthetic(), '->isSynthetic() returns true if the instance must not be public.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setAbstract
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::isAbstract
|
||||
*/
|
||||
public function testSetIsAbstract()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertFalse($def->isAbstract(), '->isAbstract() returns false by default');
|
||||
$this->assertSame($def, $def->setAbstract(true), '->setAbstract() implements a fluent interface');
|
||||
$this->assertTrue($def->isAbstract(), '->isAbstract() returns true if the instance must not be public.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::setConfigurator
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::getConfigurator
|
||||
*/
|
||||
public function testSetGetConfigurator()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertSame($def, $def->setConfigurator('foo'), '->setConfigurator() implements a fluent interface');
|
||||
$this->assertEquals('foo', $def->getConfigurator(), '->getConfigurator() returns the configurator');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::clearTags
|
||||
*/
|
||||
public function testClearTags()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertSame($def, $def->clearTags(), '->clearTags() implements a fluent interface');
|
||||
$def->addTag('foo', array('foo' => 'bar'));
|
||||
$def->clearTags();
|
||||
$this->assertEquals(array(), $def->getTags(), '->clearTags() removes all current tags');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::clearTags
|
||||
*/
|
||||
public function testClearTag()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertSame($def, $def->clearTags(), '->clearTags() implements a fluent interface');
|
||||
$def->addTag('1foo1', array('foo1' => 'bar1'));
|
||||
$def->addTag('2foo2', array('foo2' => 'bar2'));
|
||||
$def->addTag('3foo3', array('foo3' => 'bar3'));
|
||||
$def->clearTag('2foo2');
|
||||
$this->assertTrue($def->hasTag('1foo1'));
|
||||
$this->assertFalse($def->hasTag('2foo2'));
|
||||
$this->assertTrue($def->hasTag('3foo3'));
|
||||
$def->clearTag('1foo1');
|
||||
$this->assertFalse($def->hasTag('1foo1'));
|
||||
$this->assertTrue($def->hasTag('3foo3'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::addTag
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::getTag
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::getTags
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::hasTag
|
||||
*/
|
||||
public function testTags()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertEquals(array(), $def->getTag('foo'), '->getTag() returns an empty array if the tag is not defined');
|
||||
$this->assertFalse($def->hasTag('foo'));
|
||||
$this->assertSame($def, $def->addTag('foo'), '->addTag() implements a fluent interface');
|
||||
$this->assertTrue($def->hasTag('foo'));
|
||||
$this->assertEquals(array(array()), $def->getTag('foo'), '->getTag() returns attributes for a tag name');
|
||||
$def->addTag('foo', array('foo' => 'bar'));
|
||||
$this->assertEquals(array(array(), array('foo' => 'bar')), $def->getTag('foo'), '->addTag() can adds the same tag several times');
|
||||
$def->addTag('bar', array('bar' => 'bar'));
|
||||
$this->assertEquals($def->getTags(), array(
|
||||
'foo' => array(array(), array('foo' => 'bar')),
|
||||
'bar' => array(array('bar' => 'bar')),
|
||||
), '->getTags() returns all tags');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Symfony\Component\DependencyInjection\Definition::replaceArgument
|
||||
*/
|
||||
public function testSetArgument()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
|
||||
$def->addArgument('foo');
|
||||
$this->assertSame(array('foo'), $def->getArguments());
|
||||
|
||||
$this->assertSame($def, $def->replaceArgument(0, 'moo'));
|
||||
$this->assertSame(array('moo'), $def->getArguments());
|
||||
|
||||
$def->addArgument('moo');
|
||||
$def
|
||||
->replaceArgument(0, 'foo')
|
||||
->replaceArgument(1, 'bar')
|
||||
;
|
||||
$this->assertSame(array('foo', 'bar'), $def->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException OutOfBoundsException
|
||||
*/
|
||||
public function testGetArgumentShouldCheckBounds()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
|
||||
$def->addArgument('foo');
|
||||
$def->getArgument(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException OutOfBoundsException
|
||||
*/
|
||||
public function testReplaceArgumentShouldCheckBounds()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
|
||||
$def->addArgument('foo');
|
||||
$def->replaceArgument(1, 'bar');
|
||||
}
|
||||
|
||||
public function testSetGetProperties()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
|
||||
$this->assertEquals(array(), $def->getProperties());
|
||||
$this->assertSame($def, $def->setProperties(array('foo' => 'bar')));
|
||||
$this->assertEquals(array('foo' => 'bar'), $def->getProperties());
|
||||
}
|
||||
|
||||
public function testSetProperty()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
|
||||
$this->assertEquals(array(), $def->getProperties());
|
||||
$this->assertSame($def, $def->setProperty('foo', 'bar'));
|
||||
$this->assertEquals(array('foo' => 'bar'), $def->getProperties());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?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\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Dumper\GraphvizDumper;
|
||||
|
||||
class GraphvizDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$fixturesPath = __DIR__.'/../Fixtures/';
|
||||
}
|
||||
|
||||
public function testDump()
|
||||
{
|
||||
$dumper = new GraphvizDumper($container = new ContainerBuilder());
|
||||
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services1.dot', $dumper->dump(), '->dump() dumps an empty container as an empty dot file');
|
||||
|
||||
$container = include self::$fixturesPath.'/containers/container9.php';
|
||||
$dumper = new GraphvizDumper($container);
|
||||
$this->assertEquals(str_replace('%path%', __DIR__, file_get_contents(self::$fixturesPath.'/graphviz/services9.dot')), $dumper->dump(), '->dump() dumps services');
|
||||
|
||||
$container = include self::$fixturesPath.'/containers/container10.php';
|
||||
$dumper = new GraphvizDumper($container);
|
||||
$this->assertEquals(str_replace('%path%', __DIR__, file_get_contents(self::$fixturesPath.'/graphviz/services10.dot')), $dumper->dump(), '->dump() dumps services');
|
||||
|
||||
$container = include self::$fixturesPath.'/containers/container10.php';
|
||||
$dumper = new GraphvizDumper($container);
|
||||
$this->assertEquals($dumper->dump(array(
|
||||
'graph' => array('ratio' => 'normal'),
|
||||
'node' => array('fontsize' => 13, 'fontname' => 'Verdana', 'shape' => 'square'),
|
||||
'edge' => array('fontsize' => 12, 'fontname' => 'Verdana', 'color' => 'white', 'arrowhead' => 'closed', 'arrowsize' => 1),
|
||||
'node.instance' => array('fillcolor' => 'green', 'style' => 'empty'),
|
||||
'node.definition' => array('fillcolor' => 'grey'),
|
||||
'node.missing' => array('fillcolor' => 'red', 'style' => 'empty'),
|
||||
)), str_replace('%path%', __DIR__, file_get_contents(self::$fixturesPath.'/graphviz/services10-1.dot')), '->dump() dumps services');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?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\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class PhpDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$fixturesPath = realpath(__DIR__.'/../Fixtures/');
|
||||
}
|
||||
|
||||
public function testDump()
|
||||
{
|
||||
$dumper = new PhpDumper($container = new ContainerBuilder());
|
||||
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services1.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class');
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services1-1.php', $dumper->dump(array('class' => 'Container', 'base_class' => 'AbstractContainer')), '->dump() takes a class and a base_class options');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
new PhpDumper($container);
|
||||
}
|
||||
|
||||
public function testDumpFrozenContainerWithNoParameter()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('foo', 'stdClass');
|
||||
|
||||
$container->compile();
|
||||
|
||||
$dumper = new PhpDumper($container);
|
||||
|
||||
$dumpedString = $dumper->dump();
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services11.php', $dumpedString, '->dump() does not add getDefaultParameters() method call if container have no parameters.');
|
||||
$this->assertNotRegexp("/function getDefaultParameters\(/", $dumpedString, '->dump() does not add getDefaultParameters() method definition.');
|
||||
}
|
||||
|
||||
public function testDumpOptimizationString()
|
||||
{
|
||||
$definition = new Definition();
|
||||
$definition->setClass('stdClass');
|
||||
$definition->addArgument(array(
|
||||
'only dot' => '.',
|
||||
'concatenation as value' => '.\'\'.',
|
||||
'concatenation from the start value' => '\'\'.',
|
||||
'.' => 'dot as a key',
|
||||
'.\'\'.' => 'concatenation as a key',
|
||||
'\'\'.' =>'concatenation from the start key',
|
||||
'optimize concatenation' => "string1%some_string%string2",
|
||||
'optimize concatenation with empty string' => "string1%empty_value%string2",
|
||||
'optimize concatenation from the start' => '%empty_value%start',
|
||||
'optimize concatenation at the end' => 'end%empty_value%',
|
||||
));
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->setDefinition('test', $definition);
|
||||
$container->setParameter('empty_value', '');
|
||||
$container->setParameter('some_string', '-');
|
||||
$container->compile();
|
||||
|
||||
$dumper = new PhpDumper($container);
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services10.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testExportParameters()
|
||||
{
|
||||
$dumper = new PhpDumper(new ContainerBuilder(new ParameterBag(array('foo' => new Reference('foo')))));
|
||||
$dumper->dump();
|
||||
}
|
||||
|
||||
public function testAddParameters()
|
||||
{
|
||||
$container = include self::$fixturesPath.'/containers/container8.php';
|
||||
$dumper = new PhpDumper($container);
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services8.php', $dumper->dump(), '->dump() dumps parameters');
|
||||
}
|
||||
|
||||
public function testAddService()
|
||||
{
|
||||
$container = include self::$fixturesPath.'/containers/container9.php';
|
||||
$dumper = new PhpDumper($container);
|
||||
$this->assertEquals(str_replace('%path%', str_replace('\\','\\\\',self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9.php')), $dumper->dump(), '->dump() dumps services');
|
||||
|
||||
$dumper = new PhpDumper($container = new ContainerBuilder());
|
||||
$container->register('foo', 'FooClass')->addArgument(new \stdClass());
|
||||
try {
|
||||
$dumper->dump();
|
||||
$this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\Symfony\Component\DependencyInjection\Exception\RuntimeException', $e, '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
$this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
}
|
||||
}
|
||||
|
||||
public function testOverrideServiceWhenUsingADumpedContainer()
|
||||
{
|
||||
require_once self::$fixturesPath.'/php/services9.php';
|
||||
require_once self::$fixturesPath.'/includes/foo.php';
|
||||
|
||||
$container = new \ProjectServiceContainer();
|
||||
$container->set('bar', $bar = new \stdClass());
|
||||
$container->setParameter('foo_bar', 'foo_bar');
|
||||
|
||||
$this->assertEquals($bar, $container->get('bar'), '->set() overrides an already defined service');
|
||||
}
|
||||
|
||||
public function testOverrideServiceWhenUsingADumpedContainerAndServiceIsUsedFromAnotherOne()
|
||||
{
|
||||
require_once self::$fixturesPath.'/php/services9.php';
|
||||
require_once self::$fixturesPath.'/includes/foo.php';
|
||||
require_once self::$fixturesPath.'/includes/classes.php';
|
||||
|
||||
$container = new \ProjectServiceContainer();
|
||||
$container->set('bar', $bar = new \stdClass());
|
||||
|
||||
$this->assertSame($bar, $container->get('foo')->bar, '->set() overrides an already defined service');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?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\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
|
||||
|
||||
class XmlDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$fixturesPath = realpath(__DIR__.'/../Fixtures/');
|
||||
}
|
||||
|
||||
public function testDump()
|
||||
{
|
||||
$dumper = new XmlDumper($container = new ContainerBuilder());
|
||||
|
||||
$this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/xml/services1.xml', $dumper->dump(), '->dump() dumps an empty container as an empty XML file');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$dumper = new XmlDumper($container);
|
||||
}
|
||||
|
||||
public function testExportParameters()
|
||||
{
|
||||
$container = include self::$fixturesPath.'//containers/container8.php';
|
||||
$dumper = new XmlDumper($container);
|
||||
$this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/xml/services8.xml', $dumper->dump(), '->dump() dumps parameters');
|
||||
}
|
||||
|
||||
public function testAddParameters()
|
||||
{
|
||||
$container = include self::$fixturesPath.'//containers/container8.php';
|
||||
$dumper = new XmlDumper($container);
|
||||
$this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/xml/services8.xml', $dumper->dump(), '->dump() dumps parameters');
|
||||
}
|
||||
|
||||
public function testAddService()
|
||||
{
|
||||
$container = include self::$fixturesPath.'/containers/container9.php';
|
||||
$dumper = new XmlDumper($container);
|
||||
$this->assertEquals(str_replace('%path%', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/xml/services9.xml')), $dumper->dump(), '->dump() dumps services');
|
||||
|
||||
$dumper = new XmlDumper($container = new ContainerBuilder());
|
||||
$container->register('foo', 'FooClass')->addArgument(new \stdClass());
|
||||
try {
|
||||
$dumper->dump();
|
||||
$this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\RuntimeException', $e, '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
$this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
}
|
||||
}
|
||||
|
||||
public function testDumpAnonymousServices()
|
||||
{
|
||||
include self::$fixturesPath.'/containers/container11.php';
|
||||
$dumper = new XmlDumper($container);
|
||||
$this->assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\"?>
|
||||
<container xmlns=\"http://symfony.com/schema/dic/services\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd\">
|
||||
<services>
|
||||
<service id=\"foo\" class=\"FooClass\">
|
||||
<argument type=\"service\">
|
||||
<service class=\"BarClass\">
|
||||
<argument type=\"service\">
|
||||
<service class=\"BazClass\"/>
|
||||
</argument>
|
||||
</service>
|
||||
</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
", $dumper->dump());
|
||||
}
|
||||
|
||||
public function testDumpEntities()
|
||||
{
|
||||
include self::$fixturesPath.'/containers/container12.php';
|
||||
$dumper = new XmlDumper($container);
|
||||
$this->assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\"?>
|
||||
<container xmlns=\"http://symfony.com/schema/dic/services\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd\">
|
||||
<services>
|
||||
<service id=\"foo\" class=\"FooClass\Foo\">
|
||||
<tag name=\"foo"bar\bar\" foo=\"foo"barřž€\"/>
|
||||
<argument>foo<>&bar</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
", $dumper->dump());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?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\Tests\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Dumper\YamlDumper;
|
||||
|
||||
class YamlDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected static $fixturesPath;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\Config\Loader\Loader')) {
|
||||
$this->markTestSkipped('The "Config" component is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$fixturesPath = realpath(__DIR__.'/../Fixtures/');
|
||||
}
|
||||
|
||||
public function testDump()
|
||||
{
|
||||
$dumper = new YamlDumper($container = new ContainerBuilder());
|
||||
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services1.yml', $dumper->dump(), '->dump() dumps an empty container as an empty YAML file');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$dumper = new YamlDumper($container);
|
||||
}
|
||||
|
||||
public function testAddParameters()
|
||||
{
|
||||
$container = include self::$fixturesPath.'/containers/container8.php';
|
||||
$dumper = new YamlDumper($container);
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services8.yml', $dumper->dump(), '->dump() dumps parameters');
|
||||
}
|
||||
|
||||
public function testAddService()
|
||||
{
|
||||
$container = include self::$fixturesPath.'/containers/container9.php';
|
||||
$dumper = new YamlDumper($container);
|
||||
$this->assertEquals(str_replace('%path%', self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/yaml/services9.yml')), $dumper->dump(), '->dump() dumps services');
|
||||
|
||||
$dumper = new YamlDumper($container = new ContainerBuilder());
|
||||
$container->register('foo', 'FooClass')->addArgument(new \stdClass());
|
||||
try {
|
||||
$dumper->dump();
|
||||
$this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\RuntimeException', $e, '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
$this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../includes/classes.php';
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->
|
||||
register('foo', 'FooClass')->
|
||||
addArgument(new Reference('bar'))
|
||||
;
|
||||
|
||||
return $container;
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->
|
||||
register('foo', 'FooClass')->
|
||||
addArgument(new Definition('BarClass', array(new Definition('BazClass'))))
|
||||
;
|
||||
|
||||
return $container;
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->
|
||||
register('foo', 'FooClass\\Foo')->
|
||||
addArgument('foo<>&bar')->
|
||||
addTag('foo"bar\\bar', array('foo' => 'foo"barřž€'))
|
||||
;
|
||||
|
||||
return $container;
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
|
||||
$container = new ContainerBuilder(new ParameterBag(array(
|
||||
'FOO' => '%baz%',
|
||||
'baz' => 'bar',
|
||||
'bar' => 'foo is %%foo bar',
|
||||
'values' => array(true, false, null, 0, 1000.3, 'true', 'false', 'null'),
|
||||
)));
|
||||
|
||||
return $container;
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../includes/classes.php';
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->
|
||||
register('foo', 'FooClass')->
|
||||
addTag('foo', array('foo' => 'foo'))->
|
||||
addTag('foo', array('bar' => 'bar'))->
|
||||
setFactoryClass('FooClass')->
|
||||
setFactoryMethod('getInstance')->
|
||||
setArguments(array('foo', new Reference('foo.baz'), array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, new Reference('service_container')))->
|
||||
setProperties(array('foo' => 'bar', 'moo' => new Reference('foo.baz')))->
|
||||
setScope('prototype')->
|
||||
addMethodCall('setBar', array(new Reference('bar')))->
|
||||
addMethodCall('initialize')->
|
||||
setConfigurator('sc_configure')
|
||||
;
|
||||
$container->
|
||||
register('bar', 'FooClass')->
|
||||
setArguments(array('foo', new Reference('foo.baz'), new Parameter('foo_bar')))->
|
||||
setScope('container')->
|
||||
setConfigurator(array(new Reference('foo.baz'), 'configure'))
|
||||
;
|
||||
$container->
|
||||
register('foo.baz', '%baz_class%')->
|
||||
setFactoryClass('%baz_class%')->
|
||||
setFactoryMethod('getInstance')->
|
||||
setConfigurator(array('%baz_class%', 'configureStatic1'))
|
||||
;
|
||||
$container->register('foo_bar', '%foo_class%');
|
||||
$container->getParameterBag()->clear();
|
||||
$container->getParameterBag()->add(array(
|
||||
'baz_class' => 'BazClass',
|
||||
'foo_class' => 'FooClass',
|
||||
'foo' => 'bar',
|
||||
));
|
||||
$container->setAlias('alias_for_foo', 'foo');
|
||||
$container->
|
||||
register('method_call1', 'FooClass')->
|
||||
setFile(realpath(__DIR__.'/../includes/foo.php'))->
|
||||
addMethodCall('setBar', array(new Reference('foo')))->
|
||||
addMethodCall('setBar', array(new Reference('foo2', ContainerInterface::NULL_ON_INVALID_REFERENCE)))->
|
||||
addMethodCall('setBar', array(new Reference('foo3', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))->
|
||||
addMethodCall('setBar', array(new Reference('foobaz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))
|
||||
;
|
||||
$container->
|
||||
register('factory_service')->
|
||||
setFactoryService('foo.baz')->
|
||||
setFactoryMethod('getInstance')
|
||||
;
|
||||
|
||||
return $container;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user