First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
3
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/.gitignore
vendored
Normal file
3
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
21
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/CHANGELOG.md
vendored
Normal file
21
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* added ArrayNodeDefinition::canBeEnabled() and ArrayNodeDefinition::canBeDisabled()
|
||||
to ease configuration when some sections are respectively disabled / enabled
|
||||
by default.
|
||||
* added a `normalizeKeys()` method for array nodes (to avoid key normalization)
|
||||
* added numerical type handling for config definitions
|
||||
* added convenience methods for optional configuration sections to ArrayNodeDefinition
|
||||
* added a utils class for XML manipulations
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* added a way to add documentation on configuration
|
||||
* implemented `Serializable` on resources
|
||||
* LoaderResolverInterface is now used instead of LoaderResolver for type
|
||||
hinting
|
126
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/ConfigCache.php
vendored
Normal file
126
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/ConfigCache.php
vendored
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?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\Config;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
/**
|
||||
* ConfigCache manages PHP cache files.
|
||||
*
|
||||
* When debug is enabled, it knows when to flush the cache
|
||||
* thanks to an array of ResourceInterface instances.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ConfigCache
|
||||
{
|
||||
private $debug;
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $file The absolute cache path
|
||||
* @param bool $debug Whether debugging is enabled or not
|
||||
*/
|
||||
public function __construct($file, $debug)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->debug = (bool) $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache file path.
|
||||
*
|
||||
* @return string The cache file path
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the cache is still fresh.
|
||||
*
|
||||
* This method always returns true when debug is off and the
|
||||
* cache file exists.
|
||||
*
|
||||
* @return bool true if the cache is fresh, false otherwise
|
||||
*/
|
||||
public function isFresh()
|
||||
{
|
||||
if (!is_file($this->file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->debug) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$metadata = $this->getMetaFile();
|
||||
if (!is_file($metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time = filemtime($this->file);
|
||||
$meta = unserialize(file_get_contents($metadata));
|
||||
foreach ($meta as $resource) {
|
||||
if (!$resource->isFresh($time)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes cache.
|
||||
*
|
||||
* @param string $content The content to write in the cache
|
||||
* @param ResourceInterface[] $metadata An array of ResourceInterface instances
|
||||
*
|
||||
* @throws \RuntimeException When cache file can't be written
|
||||
*/
|
||||
public function write($content, array $metadata = null)
|
||||
{
|
||||
$mode = 0666;
|
||||
$umask = umask();
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->dumpFile($this->file, $content, null);
|
||||
try {
|
||||
$filesystem->chmod($this->file, $mode, $umask);
|
||||
} catch (IOException $e) {
|
||||
// discard chmod failure (some filesystem may not support it)
|
||||
}
|
||||
|
||||
if (null !== $metadata && true === $this->debug) {
|
||||
$filesystem->dumpFile($this->getMetaFile(), serialize($metadata), null);
|
||||
try {
|
||||
$filesystem->chmod($this->getMetaFile(), $mode, $umask);
|
||||
} catch (IOException $e) {
|
||||
// discard chmod failure (some filesystem may not support it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the meta file path.
|
||||
*
|
||||
* @return string The meta file path
|
||||
*/
|
||||
private function getMetaFile()
|
||||
{
|
||||
return $this->file.'.meta';
|
||||
}
|
||||
}
|
393
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/ArrayNode.php
vendored
Normal file
393
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/ArrayNode.php
vendored
Normal file
|
@ -0,0 +1,393 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
|
||||
|
||||
/**
|
||||
* Represents an Array node in the config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ArrayNode extends BaseNode implements PrototypeNodeInterface
|
||||
{
|
||||
protected $xmlRemappings = array();
|
||||
protected $children = array();
|
||||
protected $allowFalse = false;
|
||||
protected $allowNewKeys = true;
|
||||
protected $addIfNotSet = false;
|
||||
protected $performDeepMerging = true;
|
||||
protected $ignoreExtraKeys = false;
|
||||
protected $normalizeKeys = true;
|
||||
|
||||
public function setNormalizeKeys($normalizeKeys)
|
||||
{
|
||||
$this->normalizeKeys = (bool) $normalizeKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes keys between the different configuration formats.
|
||||
*
|
||||
* Namely, you mostly have foo_bar in YAML while you have foo-bar in XML.
|
||||
* After running this method, all keys are normalized to foo_bar.
|
||||
*
|
||||
* If you have a mixed key like foo-bar_moo, it will not be altered.
|
||||
* The key will also not be altered if the target key already exists.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return array The value with normalized keys
|
||||
*/
|
||||
protected function preNormalize($value)
|
||||
{
|
||||
if (!$this->normalizeKeys || !is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) {
|
||||
$value[$normalizedKey] = $v;
|
||||
unset($value[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the children of this node.
|
||||
*
|
||||
* @return array The children
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the xml remappings that should be performed.
|
||||
*
|
||||
* @param array $remappings an array of the form array(array(string, string))
|
||||
*/
|
||||
public function setXmlRemappings(array $remappings)
|
||||
{
|
||||
$this->xmlRemappings = $remappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the xml remappings that should be performed.
|
||||
*
|
||||
* @return array $remappings an array of the form array(array(string, string))
|
||||
*/
|
||||
public function getXmlRemappings()
|
||||
{
|
||||
return $this->xmlRemappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to add default values for this array if it has not been
|
||||
* defined in any of the configuration files.
|
||||
*
|
||||
* @param bool $boolean
|
||||
*/
|
||||
public function setAddIfNotSet($boolean)
|
||||
{
|
||||
$this->addIfNotSet = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether false is allowed as value indicating that the array should be unset.
|
||||
*
|
||||
* @param bool $allow
|
||||
*/
|
||||
public function setAllowFalse($allow)
|
||||
{
|
||||
$this->allowFalse = (bool) $allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether new keys can be defined in subsequent configurations.
|
||||
*
|
||||
* @param bool $allow
|
||||
*/
|
||||
public function setAllowNewKeys($allow)
|
||||
{
|
||||
$this->allowNewKeys = (bool) $allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if deep merging should occur.
|
||||
*
|
||||
* @param bool $boolean
|
||||
*/
|
||||
public function setPerformDeepMerging($boolean)
|
||||
{
|
||||
$this->performDeepMerging = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether extra keys should just be ignore without an exception.
|
||||
*
|
||||
* @param bool $boolean To allow extra keys
|
||||
*/
|
||||
public function setIgnoreExtraKeys($boolean)
|
||||
{
|
||||
$this->ignoreExtraKeys = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the node Name.
|
||||
*
|
||||
* @param string $name The node's name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node has a default value.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDefaultValue()
|
||||
{
|
||||
return $this->addIfNotSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default value.
|
||||
*
|
||||
* @return array The default value
|
||||
*
|
||||
* @throws \RuntimeException if the node has no default value
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
if (!$this->hasDefaultValue()) {
|
||||
throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
|
||||
}
|
||||
|
||||
$defaults = array();
|
||||
foreach ($this->children as $name => $child) {
|
||||
if ($child->hasDefaultValue()) {
|
||||
$defaults[$name] = $child->getDefaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child node.
|
||||
*
|
||||
* @param NodeInterface $node The child node to add
|
||||
*
|
||||
* @throws \InvalidArgumentException when the child node has no name
|
||||
* @throws \InvalidArgumentException when the child node's name is not unique
|
||||
*/
|
||||
public function addChild(NodeInterface $node)
|
||||
{
|
||||
$name = $node->getName();
|
||||
if (!strlen($name)) {
|
||||
throw new \InvalidArgumentException('Child nodes must be named.');
|
||||
}
|
||||
if (isset($this->children[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name));
|
||||
}
|
||||
|
||||
$this->children[$name] = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the value of this node.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed The finalised value
|
||||
*
|
||||
* @throws UnsetKeyException
|
||||
* @throws InvalidConfigurationException if the node doesn't have enough children
|
||||
*/
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
$msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
|
||||
throw new UnsetKeyException($msg);
|
||||
}
|
||||
|
||||
foreach ($this->children as $name => $child) {
|
||||
if (!array_key_exists($name, $value)) {
|
||||
if ($child->isRequired()) {
|
||||
$msg = sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath());
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
if ($child->hasDefaultValue()) {
|
||||
$value[$name] = $child->getDefaultValue();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$value[$name] = $child->finalize($value[$name]);
|
||||
} catch (UnsetKeyException $e) {
|
||||
unset($value[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the type of the value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @throws InvalidTypeException
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
if (!is_array($value) && (!$this->allowFalse || false !== $value)) {
|
||||
$ex = new InvalidTypeException(sprintf(
|
||||
'Invalid type for path "%s". Expected array, but got %s',
|
||||
$this->getPath(),
|
||||
gettype($value)
|
||||
));
|
||||
if ($hint = $this->getInfo()) {
|
||||
$ex->addHint($hint);
|
||||
}
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the value.
|
||||
*
|
||||
* @param mixed $value The value to normalize
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*
|
||||
* @throws InvalidConfigurationException
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = $this->remapXml($value);
|
||||
|
||||
$normalized = array();
|
||||
foreach ($value as $name => $val) {
|
||||
if (isset($this->children[$name])) {
|
||||
$normalized[$name] = $this->children[$name]->normalize($val);
|
||||
unset($value[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
// if extra fields are present, throw exception
|
||||
if (count($value) && !$this->ignoreExtraKeys) {
|
||||
$msg = sprintf('Unrecognized option%s "%s" under "%s"', 1 === count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath());
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remaps multiple singular values to a single plural value.
|
||||
*
|
||||
* @param array $value The source values
|
||||
*
|
||||
* @return array The remapped values
|
||||
*/
|
||||
protected function remapXml($value)
|
||||
{
|
||||
foreach ($this->xmlRemappings as $transformation) {
|
||||
list($singular, $plural) = $transformation;
|
||||
|
||||
if (!isset($value[$singular])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value[$plural] = Processor::normalizeConfig($value, $singular, $plural);
|
||||
unset($value[$singular]);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges values together.
|
||||
*
|
||||
* @param mixed $leftSide The left side to merge.
|
||||
* @param mixed $rightSide The right side to merge.
|
||||
*
|
||||
* @return mixed The merged values
|
||||
*
|
||||
* @throws InvalidConfigurationException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function mergeValues($leftSide, $rightSide)
|
||||
{
|
||||
if (false === $rightSide) {
|
||||
// if this is still false after the last config has been merged the
|
||||
// finalization pass will take care of removing this key entirely
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false === $leftSide || !$this->performDeepMerging) {
|
||||
return $rightSide;
|
||||
}
|
||||
|
||||
foreach ($rightSide as $k => $v) {
|
||||
// no conflict
|
||||
if (!array_key_exists($k, $leftSide)) {
|
||||
if (!$this->allowNewKeys) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'You are not allowed to define new elements for path "%s". '
|
||||
.'Please define all elements for this path in one config file. '
|
||||
.'If you are trying to overwrite an element, make sure you redefine it '
|
||||
.'with the same name.',
|
||||
$this->getPath()
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$leftSide[$k] = $v;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($this->children[$k])) {
|
||||
throw new \RuntimeException('merge() expects a normalized config array.');
|
||||
}
|
||||
|
||||
$leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v);
|
||||
}
|
||||
|
||||
return $leftSide;
|
||||
}
|
||||
}
|
356
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/BaseNode.php
vendored
Normal file
356
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/BaseNode.php
vendored
Normal file
|
@ -0,0 +1,356 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\Exception;
|
||||
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
|
||||
/**
|
||||
* The base node class.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class BaseNode implements NodeInterface
|
||||
{
|
||||
protected $name;
|
||||
protected $parent;
|
||||
protected $normalizationClosures = array();
|
||||
protected $finalValidationClosures = array();
|
||||
protected $allowOverwrite = true;
|
||||
protected $required = false;
|
||||
protected $equivalentValues = array();
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
* @param NodeInterface $parent The parent of this node
|
||||
*
|
||||
* @throws \InvalidArgumentException if the name contains a period.
|
||||
*/
|
||||
public function __construct($name, NodeInterface $parent = null)
|
||||
{
|
||||
if (false !== strpos($name, '.')) {
|
||||
throw new \InvalidArgumentException('The name must not contain ".".');
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
public function setAttribute($key, $value)
|
||||
{
|
||||
$this->attributes[$key] = $value;
|
||||
}
|
||||
|
||||
public function getAttribute($key, $default = null)
|
||||
{
|
||||
return isset($this->attributes[$key]) ? $this->attributes[$key] : $default;
|
||||
}
|
||||
|
||||
public function hasAttribute($key)
|
||||
{
|
||||
return isset($this->attributes[$key]);
|
||||
}
|
||||
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function setAttributes(array $attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
public function removeAttribute($key)
|
||||
{
|
||||
unset($this->attributes[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an info message.
|
||||
*
|
||||
* @param string $info
|
||||
*/
|
||||
public function setInfo($info)
|
||||
{
|
||||
$this->setAttribute('info', $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns info message.
|
||||
*
|
||||
* @return string The info text
|
||||
*/
|
||||
public function getInfo()
|
||||
{
|
||||
return $this->getAttribute('info');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the example configuration for this node.
|
||||
*
|
||||
* @param string|array $example
|
||||
*/
|
||||
public function setExample($example)
|
||||
{
|
||||
$this->setAttribute('example', $example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the example configuration for this node.
|
||||
*
|
||||
* @return string|array The example
|
||||
*/
|
||||
public function getExample()
|
||||
{
|
||||
return $this->getAttribute('example');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an equivalent value.
|
||||
*
|
||||
* @param mixed $originalValue
|
||||
* @param mixed $equivalentValue
|
||||
*/
|
||||
public function addEquivalentValue($originalValue, $equivalentValue)
|
||||
{
|
||||
$this->equivalentValues[] = array($originalValue, $equivalentValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this node as required.
|
||||
*
|
||||
* @param bool $boolean Required node
|
||||
*/
|
||||
public function setRequired($boolean)
|
||||
{
|
||||
$this->required = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this node can be overridden.
|
||||
*
|
||||
* @param bool $allow
|
||||
*/
|
||||
public function setAllowOverwrite($allow)
|
||||
{
|
||||
$this->allowOverwrite = (bool) $allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the closures used for normalization.
|
||||
*
|
||||
* @param \Closure[] $closures An array of Closures used for normalization
|
||||
*/
|
||||
public function setNormalizationClosures(array $closures)
|
||||
{
|
||||
$this->normalizationClosures = $closures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the closures used for final validation.
|
||||
*
|
||||
* @param \Closure[] $closures An array of Closures used for final validation
|
||||
*/
|
||||
public function setFinalValidationClosures(array $closures)
|
||||
{
|
||||
$this->finalValidationClosures = $closures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this node is required.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
return $this->required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this node.
|
||||
*
|
||||
* @return string The Node's name.
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the path of this node.
|
||||
*
|
||||
* @return string The Node's path
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
$path = $this->name;
|
||||
|
||||
if (null !== $this->parent) {
|
||||
$path = $this->parent->getPath().'.'.$path;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two values together.
|
||||
*
|
||||
* @param mixed $leftSide
|
||||
* @param mixed $rightSide
|
||||
*
|
||||
* @return mixed The merged value
|
||||
*
|
||||
* @throws ForbiddenOverwriteException
|
||||
*/
|
||||
final public function merge($leftSide, $rightSide)
|
||||
{
|
||||
if (!$this->allowOverwrite) {
|
||||
throw new ForbiddenOverwriteException(sprintf(
|
||||
'Configuration path "%s" cannot be overwritten. You have to '
|
||||
.'define all options for this path, and any of its sub-paths in '
|
||||
.'one configuration section.',
|
||||
$this->getPath()
|
||||
));
|
||||
}
|
||||
|
||||
$this->validateType($leftSide);
|
||||
$this->validateType($rightSide);
|
||||
|
||||
return $this->mergeValues($leftSide, $rightSide);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a value, applying all normalization closures.
|
||||
*
|
||||
* @param mixed $value Value to normalize.
|
||||
*
|
||||
* @return mixed The normalized value.
|
||||
*/
|
||||
final public function normalize($value)
|
||||
{
|
||||
$value = $this->preNormalize($value);
|
||||
|
||||
// run custom normalization closures
|
||||
foreach ($this->normalizationClosures as $closure) {
|
||||
$value = $closure($value);
|
||||
}
|
||||
|
||||
// replace value with their equivalent
|
||||
foreach ($this->equivalentValues as $data) {
|
||||
if ($data[0] === $value) {
|
||||
$value = $data[1];
|
||||
}
|
||||
}
|
||||
|
||||
// validate type
|
||||
$this->validateType($value);
|
||||
|
||||
// normalize value
|
||||
return $this->normalizeValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the value before any other normalization is applied.
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return $value The normalized array value
|
||||
*/
|
||||
protected function preNormalize($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parent node for this node.
|
||||
*
|
||||
* @return NodeInterface|null
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes a value, applying all finalization closures.
|
||||
*
|
||||
* @param mixed $value The value to finalize
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws InvalidConfigurationException
|
||||
*/
|
||||
final public function finalize($value)
|
||||
{
|
||||
$this->validateType($value);
|
||||
|
||||
$value = $this->finalizeValue($value);
|
||||
|
||||
// Perform validation on the final value if a closure has been set.
|
||||
// The closure is also allowed to return another value.
|
||||
foreach ($this->finalValidationClosures as $closure) {
|
||||
try {
|
||||
$value = $closure($value);
|
||||
} catch (Exception $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": %s', $this->getPath(), $e->getMessage()), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the type of a Node.
|
||||
*
|
||||
* @param mixed $value The value to validate
|
||||
*
|
||||
* @throws InvalidTypeException when the value is invalid
|
||||
*/
|
||||
abstract protected function validateType($value);
|
||||
|
||||
/**
|
||||
* Normalizes the value.
|
||||
*
|
||||
* @param mixed $value The value to normalize.
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*/
|
||||
abstract protected function normalizeValue($value);
|
||||
|
||||
/**
|
||||
* Merges two values together.
|
||||
*
|
||||
* @param mixed $leftSide
|
||||
* @param mixed $rightSide
|
||||
*
|
||||
* @return mixed The merged value
|
||||
*/
|
||||
abstract protected function mergeValues($leftSide, $rightSide);
|
||||
|
||||
/**
|
||||
* Finalizes a value.
|
||||
*
|
||||
* @param mixed $value The value to finalize
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*/
|
||||
abstract protected function finalizeValue($value);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
|
||||
/**
|
||||
* This node represents a Boolean value in the config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class BooleanNode extends ScalarNode
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
if (!is_bool($value)) {
|
||||
$ex = new InvalidTypeException(sprintf(
|
||||
'Invalid type for path "%s". Expected boolean, but got %s.',
|
||||
$this->getPath(),
|
||||
gettype($value)
|
||||
));
|
||||
if ($hint = $this->getInfo()) {
|
||||
$ex->addHint($hint);
|
||||
}
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,489 @@
|
|||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\ArrayNode;
|
||||
use Symfony\Component\Config\Definition\PrototypedArrayNode;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining an array node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
|
||||
{
|
||||
protected $performDeepMerging = true;
|
||||
protected $ignoreExtraKeys = false;
|
||||
protected $children = array();
|
||||
protected $prototype;
|
||||
protected $atLeastOne = false;
|
||||
protected $allowNewKeys = true;
|
||||
protected $key;
|
||||
protected $removeKeyItem;
|
||||
protected $addDefaults = false;
|
||||
protected $addDefaultChildren = false;
|
||||
protected $nodeBuilder;
|
||||
protected $normalizeKeys = true;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($name, NodeParentInterface $parent = null)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
|
||||
$this->nullEquivalent = array();
|
||||
$this->trueEquivalent = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom children builder.
|
||||
*
|
||||
* @param NodeBuilder $builder A custom NodeBuilder
|
||||
*/
|
||||
public function setBuilder(NodeBuilder $builder)
|
||||
{
|
||||
$this->nodeBuilder = $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a builder to add children nodes.
|
||||
*
|
||||
* @return NodeBuilder
|
||||
*/
|
||||
public function children()
|
||||
{
|
||||
return $this->getNodeBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a prototype for child nodes.
|
||||
*
|
||||
* @param string $type the type of node
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function prototype($type)
|
||||
{
|
||||
return $this->prototype = $this->getNodeBuilder()->node(null, $type)->setParent($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the default value if the node is not set in the configuration.
|
||||
*
|
||||
* This method is applicable to concrete nodes only (not to prototype nodes).
|
||||
* If this function has been called and the node is not set during the finalization
|
||||
* phase, it's default value will be derived from its children default values.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function addDefaultsIfNotSet()
|
||||
{
|
||||
$this->addDefaults = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds children with a default value when none are defined.
|
||||
*
|
||||
* @param int|string|array|null $children The number of children|The child name|The children names to be added
|
||||
*
|
||||
* This method is applicable to prototype nodes only.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function addDefaultChildrenIfNoneSet($children = null)
|
||||
{
|
||||
$this->addDefaultChildren = $children;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the node to have at least one element.
|
||||
*
|
||||
* This method is applicable to prototype nodes only.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function requiresAtLeastOneElement()
|
||||
{
|
||||
$this->atLeastOne = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disallows adding news keys in a subsequent configuration.
|
||||
*
|
||||
* If used all keys have to be defined in the same configuration file.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function disallowNewKeysInSubsequentConfigs()
|
||||
{
|
||||
$this->allowNewKeys = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a normalization rule for XML configurations.
|
||||
*
|
||||
* @param string $singular The key to remap
|
||||
* @param string $plural The plural of the key for irregular plurals
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function fixXmlConfig($singular, $plural = null)
|
||||
{
|
||||
$this->normalization()->remap($singular, $plural);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attribute which value is to be used as key.
|
||||
*
|
||||
* This is useful when you have an indexed array that should be an
|
||||
* associative array. You can select an item from within the array
|
||||
* to be the key of the particular item. For example, if "id" is the
|
||||
* "key", then:
|
||||
*
|
||||
* array(
|
||||
* array('id' => 'my_name', 'foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* becomes
|
||||
*
|
||||
* array(
|
||||
* 'my_name' => array('foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* If you'd like "'id' => 'my_name'" to still be present in the resulting
|
||||
* array, then you can set the second argument of this method to false.
|
||||
*
|
||||
* This method is applicable to prototype nodes only.
|
||||
*
|
||||
* @param string $name The name of the key
|
||||
* @param bool $removeKeyItem Whether or not the key item should be removed.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function useAttributeAsKey($name, $removeKeyItem = true)
|
||||
{
|
||||
$this->key = $name;
|
||||
$this->removeKeyItem = $removeKeyItem;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be unset.
|
||||
*
|
||||
* @param bool $allow
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function canBeUnset($allow = true)
|
||||
{
|
||||
$this->merge()->allowUnset($allow);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an "enabled" boolean to enable the current section.
|
||||
*
|
||||
* By default, the section is disabled. If any configuration is specified then
|
||||
* the node will be automatically enabled:
|
||||
*
|
||||
* enableableArrayNode: {enabled: true, ...} # The config is enabled & default values get overridden
|
||||
* enableableArrayNode: ~ # The config is enabled & use the default values
|
||||
* enableableArrayNode: true # The config is enabled & use the default values
|
||||
* enableableArrayNode: {other: value, ...} # The config is enabled & default values get overridden
|
||||
* enableableArrayNode: {enabled: false, ...} # The config is disabled
|
||||
* enableableArrayNode: false # The config is disabled
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function canBeEnabled()
|
||||
{
|
||||
$this
|
||||
->addDefaultsIfNotSet()
|
||||
->treatFalseLike(array('enabled' => false))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->beforeNormalization()
|
||||
->ifArray()
|
||||
->then(function ($v) {
|
||||
$v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->children()
|
||||
->booleanNode('enabled')
|
||||
->defaultFalse()
|
||||
;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an "enabled" boolean to enable the current section.
|
||||
*
|
||||
* By default, the section is enabled.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function canBeDisabled()
|
||||
{
|
||||
$this
|
||||
->addDefaultsIfNotSet()
|
||||
->treatFalseLike(array('enabled' => false))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->children()
|
||||
->booleanNode('enabled')
|
||||
->defaultTrue()
|
||||
;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the deep merging of the node.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function performNoDeepMerging()
|
||||
{
|
||||
$this->performDeepMerging = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows extra config keys to be specified under an array without
|
||||
* throwing an exception.
|
||||
*
|
||||
* Those config values are simply ignored and removed from the
|
||||
* resulting array. This should be used only in special cases where
|
||||
* you want to send an entire configuration array through a special
|
||||
* tree that processes only part of the array.
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function ignoreExtraKeys()
|
||||
{
|
||||
$this->ignoreExtraKeys = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets key normalization.
|
||||
*
|
||||
* @param bool $bool Whether to enable key normalization
|
||||
*
|
||||
* @return ArrayNodeDefinition
|
||||
*/
|
||||
public function normalizeKeys($bool)
|
||||
{
|
||||
$this->normalizeKeys = (bool) $bool;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a node definition.
|
||||
*
|
||||
* $node = new ArrayNodeDefinition()
|
||||
* ->children()
|
||||
* ->scalarNode('foo')->end()
|
||||
* ->scalarNode('baz')->end()
|
||||
* ->end()
|
||||
* ->append($this->getBarNodeDefinition())
|
||||
* ;
|
||||
*
|
||||
* @param NodeDefinition $node A NodeDefinition instance
|
||||
*
|
||||
* @return ArrayNodeDefinition This node
|
||||
*/
|
||||
public function append(NodeDefinition $node)
|
||||
{
|
||||
$this->children[$node->name] = $node->setParent($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a node builder to be used to add children and prototype.
|
||||
*
|
||||
* @return NodeBuilder The node builder
|
||||
*/
|
||||
protected function getNodeBuilder()
|
||||
{
|
||||
if (null === $this->nodeBuilder) {
|
||||
$this->nodeBuilder = new NodeBuilder();
|
||||
}
|
||||
|
||||
return $this->nodeBuilder->setParent($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createNode()
|
||||
{
|
||||
if (null === $this->prototype) {
|
||||
$node = new ArrayNode($this->name, $this->parent);
|
||||
|
||||
$this->validateConcreteNode($node);
|
||||
|
||||
$node->setAddIfNotSet($this->addDefaults);
|
||||
|
||||
foreach ($this->children as $child) {
|
||||
$child->parent = $node;
|
||||
$node->addChild($child->getNode());
|
||||
}
|
||||
} else {
|
||||
$node = new PrototypedArrayNode($this->name, $this->parent);
|
||||
|
||||
$this->validatePrototypeNode($node);
|
||||
|
||||
if (null !== $this->key) {
|
||||
$node->setKeyAttribute($this->key, $this->removeKeyItem);
|
||||
}
|
||||
|
||||
if (true === $this->atLeastOne) {
|
||||
$node->setMinNumberOfElements(1);
|
||||
}
|
||||
|
||||
if ($this->default) {
|
||||
$node->setDefaultValue($this->defaultValue);
|
||||
}
|
||||
|
||||
if (false !== $this->addDefaultChildren) {
|
||||
$node->setAddChildrenIfNoneSet($this->addDefaultChildren);
|
||||
if ($this->prototype instanceof static && null === $this->prototype->prototype) {
|
||||
$this->prototype->addDefaultsIfNotSet();
|
||||
}
|
||||
}
|
||||
|
||||
$this->prototype->parent = $node;
|
||||
$node->setPrototype($this->prototype->getNode());
|
||||
}
|
||||
|
||||
$node->setAllowNewKeys($this->allowNewKeys);
|
||||
$node->addEquivalentValue(null, $this->nullEquivalent);
|
||||
$node->addEquivalentValue(true, $this->trueEquivalent);
|
||||
$node->addEquivalentValue(false, $this->falseEquivalent);
|
||||
$node->setPerformDeepMerging($this->performDeepMerging);
|
||||
$node->setRequired($this->required);
|
||||
$node->setIgnoreExtraKeys($this->ignoreExtraKeys);
|
||||
$node->setNormalizeKeys($this->normalizeKeys);
|
||||
|
||||
if (null !== $this->normalization) {
|
||||
$node->setNormalizationClosures($this->normalization->before);
|
||||
$node->setXmlRemappings($this->normalization->remappings);
|
||||
}
|
||||
|
||||
if (null !== $this->merge) {
|
||||
$node->setAllowOverwrite($this->merge->allowOverwrite);
|
||||
$node->setAllowFalse($this->merge->allowFalse);
|
||||
}
|
||||
|
||||
if (null !== $this->validation) {
|
||||
$node->setFinalValidationClosures($this->validation->rules);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration of a concrete node.
|
||||
*
|
||||
* @param ArrayNode $node The related node
|
||||
*
|
||||
* @throws InvalidDefinitionException
|
||||
*/
|
||||
protected function validateConcreteNode(ArrayNode $node)
|
||||
{
|
||||
$path = $node->getPath();
|
||||
|
||||
if (null !== $this->key) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (true === $this->atLeastOne) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->default) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->defaultValue() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (false !== $this->addDefaultChildren) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration of a prototype node.
|
||||
*
|
||||
* @param PrototypedArrayNode $node The related node
|
||||
*
|
||||
* @throws InvalidDefinitionException
|
||||
*/
|
||||
protected function validatePrototypeNode(PrototypedArrayNode $node)
|
||||
{
|
||||
$path = $node->getPath();
|
||||
|
||||
if ($this->addDefaults) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (false !== $this->addDefaultChildren) {
|
||||
if ($this->default) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('A default value and default children might not be used together at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (null !== $this->key && (null === $this->addDefaultChildren || is_int($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
|
||||
if (null === $this->key && (is_string($this->addDefaultChildren) || is_array($this->addDefaultChildren))) {
|
||||
throw new InvalidDefinitionException(
|
||||
sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s"', $path)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\BooleanNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class BooleanNodeDefinition extends ScalarNodeDefinition
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($name, NodeParentInterface $parent = null)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
|
||||
$this->nullEquivalent = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a Node.
|
||||
*
|
||||
* @return BooleanNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new BooleanNode($this->name, $this->parent);
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\EnumNode;
|
||||
|
||||
/**
|
||||
* Enum Node Definition.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class EnumNodeDefinition extends ScalarNodeDefinition
|
||||
{
|
||||
private $values;
|
||||
|
||||
/**
|
||||
* @param array $values
|
||||
*
|
||||
* @return EnumNodeDefinition|$this
|
||||
*/
|
||||
public function values(array $values)
|
||||
{
|
||||
$values = array_unique($values);
|
||||
|
||||
if (count($values) <= 1) {
|
||||
throw new \InvalidArgumentException('->values() must be called with at least two distinct values.');
|
||||
}
|
||||
|
||||
$this->values = $values;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a Node.
|
||||
*
|
||||
* @return EnumNode The node
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
if (null === $this->values) {
|
||||
throw new \RuntimeException('You must call ->values() on enum nodes.');
|
||||
}
|
||||
|
||||
return new EnumNode($this->name, $this->parent, $this->values);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
|
||||
|
||||
/**
|
||||
* This class builds an if expression.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class ExprBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $ifPart;
|
||||
public $thenPart;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the expression as being always used.
|
||||
*
|
||||
* @param \Closure $then
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function always(\Closure $then = null)
|
||||
{
|
||||
$this->ifPart = function ($v) { return true; };
|
||||
|
||||
if (null !== $then) {
|
||||
$this->thenPart = $then;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure to use as tests.
|
||||
*
|
||||
* The default one tests if the value is true.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifTrue(\Closure $closure = null)
|
||||
{
|
||||
if (null === $closure) {
|
||||
$closure = function ($v) { return true === $v; };
|
||||
}
|
||||
|
||||
$this->ifPart = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is a string.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifString()
|
||||
{
|
||||
$this->ifPart = function ($v) { return is_string($v); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is null.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifNull()
|
||||
{
|
||||
$this->ifPart = function ($v) { return null === $v; };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is an array.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifArray()
|
||||
{
|
||||
$this->ifPart = function ($v) { return is_array($v); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is in an array.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifInArray(array $array)
|
||||
{
|
||||
$this->ifPart = function ($v) use ($array) { return in_array($v, $array, true); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value is not in an array.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function ifNotInArray(array $array)
|
||||
{
|
||||
$this->ifPart = function ($v) use ($array) { return !in_array($v, $array, true); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the closure to run if the test pass.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function then(\Closure $closure)
|
||||
{
|
||||
$this->thenPart = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure returning an empty array.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function thenEmptyArray()
|
||||
{
|
||||
$this->thenPart = function ($v) { return array(); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure marking the value as invalid at validation time.
|
||||
*
|
||||
* if you want to add the value of the node in your message just use a %s placeholder.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function thenInvalid($message)
|
||||
{
|
||||
$this->thenPart = function ($v) use ($message) {throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a closure unsetting this key of the array at validation time.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*
|
||||
* @throws UnsetKeyException
|
||||
*/
|
||||
public function thenUnset()
|
||||
{
|
||||
$this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); };
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the related node.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
if (null === $this->ifPart) {
|
||||
throw new \RuntimeException('You must specify an if part.');
|
||||
}
|
||||
if (null === $this->thenPart) {
|
||||
throw new \RuntimeException('You must specify a then part.');
|
||||
}
|
||||
|
||||
return $this->node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the expressions.
|
||||
*
|
||||
* @param ExprBuilder[] $expressions An array of ExprBuilder instances to build
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function buildExpressions(array $expressions)
|
||||
{
|
||||
foreach ($expressions as $k => $expr) {
|
||||
if ($expr instanceof self) {
|
||||
$if = $expr->ifPart;
|
||||
$then = $expr->thenPart;
|
||||
$expressions[$k] = function ($v) use ($if, $then) {
|
||||
return $if($v) ? $then($v) : $v;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return $expressions;
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\FloatNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a float node.
|
||||
*
|
||||
* @author Jeanmonod David <david.jeanmonod@gmail.com>
|
||||
*/
|
||||
class FloatNodeDefinition extends NumericNodeDefinition
|
||||
{
|
||||
/**
|
||||
* Instantiates a Node.
|
||||
*
|
||||
* @return FloatNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new FloatNode($this->name, $this->parent, $this->min, $this->max);
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\IntegerNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining an integer node.
|
||||
*
|
||||
* @author Jeanmonod David <david.jeanmonod@gmail.com>
|
||||
*/
|
||||
class IntegerNodeDefinition extends NumericNodeDefinition
|
||||
{
|
||||
/**
|
||||
* Instantiates a Node.
|
||||
*
|
||||
* @return IntegerNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new IntegerNode($this->name, $this->parent, $this->min, $this->max);
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class builds merge conditions.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class MergeBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $allowFalse = false;
|
||||
public $allowOverwrite = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be unset.
|
||||
*
|
||||
* @param bool $allow
|
||||
*
|
||||
* @return MergeBuilder
|
||||
*/
|
||||
public function allowUnset($allow = true)
|
||||
{
|
||||
$this->allowFalse = $allow;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be overwritten.
|
||||
*
|
||||
* @param bool $deny Whether the overwriting is forbidden or not
|
||||
*
|
||||
* @return MergeBuilder
|
||||
*/
|
||||
public function denyOverwrite($deny = true)
|
||||
{
|
||||
$this->allowOverwrite = !$deny;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the related node.
|
||||
*
|
||||
* @return NodeDefinition
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->node;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for building a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class NodeBuilder implements NodeParentInterface
|
||||
{
|
||||
protected $parent;
|
||||
protected $nodeMapping;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->nodeMapping = array(
|
||||
'variable' => __NAMESPACE__.'\\VariableNodeDefinition',
|
||||
'scalar' => __NAMESPACE__.'\\ScalarNodeDefinition',
|
||||
'boolean' => __NAMESPACE__.'\\BooleanNodeDefinition',
|
||||
'integer' => __NAMESPACE__.'\\IntegerNodeDefinition',
|
||||
'float' => __NAMESPACE__.'\\FloatNodeDefinition',
|
||||
'array' => __NAMESPACE__.'\\ArrayNodeDefinition',
|
||||
'enum' => __NAMESPACE__.'\\EnumNodeDefinition',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent node.
|
||||
*
|
||||
* @param ParentNodeDefinitionInterface $parent The parent node
|
||||
*
|
||||
* @return NodeBuilder This node builder
|
||||
*/
|
||||
public function setParent(ParentNodeDefinitionInterface $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child array node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*
|
||||
* @return ArrayNodeDefinition The child node
|
||||
*/
|
||||
public function arrayNode($name)
|
||||
{
|
||||
return $this->node($name, 'array');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child scalar node.
|
||||
*
|
||||
* @param string $name the name of the node
|
||||
*
|
||||
* @return ScalarNodeDefinition The child node
|
||||
*/
|
||||
public function scalarNode($name)
|
||||
{
|
||||
return $this->node($name, 'scalar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child Boolean node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*
|
||||
* @return BooleanNodeDefinition The child node
|
||||
*/
|
||||
public function booleanNode($name)
|
||||
{
|
||||
return $this->node($name, 'boolean');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child integer node.
|
||||
*
|
||||
* @param string $name the name of the node
|
||||
*
|
||||
* @return IntegerNodeDefinition The child node
|
||||
*/
|
||||
public function integerNode($name)
|
||||
{
|
||||
return $this->node($name, 'integer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child float node.
|
||||
*
|
||||
* @param string $name the name of the node
|
||||
*
|
||||
* @return FloatNodeDefinition The child node
|
||||
*/
|
||||
public function floatNode($name)
|
||||
{
|
||||
return $this->node($name, 'float');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child EnumNode.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return EnumNodeDefinition
|
||||
*/
|
||||
public function enumNode($name)
|
||||
{
|
||||
return $this->node($name, 'enum');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child variable node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*
|
||||
* @return VariableNodeDefinition The builder of the child node
|
||||
*/
|
||||
public function variableNode($name)
|
||||
{
|
||||
return $this->node($name, 'variable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent node.
|
||||
*
|
||||
* @return ParentNodeDefinitionInterface The parent node
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
* @param string $type The type of the node
|
||||
*
|
||||
* @return NodeDefinition The child node
|
||||
*
|
||||
* @throws \RuntimeException When the node type is not registered
|
||||
* @throws \RuntimeException When the node class is not found
|
||||
*/
|
||||
public function node($name, $type)
|
||||
{
|
||||
$class = $this->getNodeClass($type);
|
||||
|
||||
$node = new $class($name);
|
||||
|
||||
$this->append($node);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a node definition.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* $node = new ArrayNodeDefinition('name')
|
||||
* ->children()
|
||||
* ->scalarNode('foo')->end()
|
||||
* ->scalarNode('baz')->end()
|
||||
* ->append($this->getBarNodeDefinition())
|
||||
* ->end()
|
||||
* ;
|
||||
*
|
||||
* @param NodeDefinition $node
|
||||
*
|
||||
* @return NodeBuilder This node builder
|
||||
*/
|
||||
public function append(NodeDefinition $node)
|
||||
{
|
||||
if ($node instanceof ParentNodeDefinitionInterface) {
|
||||
$builder = clone $this;
|
||||
$builder->setParent(null);
|
||||
$node->setBuilder($builder);
|
||||
}
|
||||
|
||||
if (null !== $this->parent) {
|
||||
$this->parent->append($node);
|
||||
// Make this builder the node parent to allow for a fluid interface
|
||||
$node->setParent($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or overrides a node Type.
|
||||
*
|
||||
* @param string $type The name of the type
|
||||
* @param string $class The fully qualified name the node definition class
|
||||
*
|
||||
* @return NodeBuilder This node builder
|
||||
*/
|
||||
public function setNodeClass($type, $class)
|
||||
{
|
||||
$this->nodeMapping[strtolower($type)] = $class;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class name of the node definition.
|
||||
*
|
||||
* @param string $type The node type
|
||||
*
|
||||
* @return string The node definition class name
|
||||
*
|
||||
* @throws \RuntimeException When the node type is not registered
|
||||
* @throws \RuntimeException When the node class is not found
|
||||
*/
|
||||
protected function getNodeClass($type)
|
||||
{
|
||||
$type = strtolower($type);
|
||||
|
||||
if (!isset($this->nodeMapping[$type])) {
|
||||
throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
|
||||
}
|
||||
|
||||
$class = $this->nodeMapping[$type];
|
||||
|
||||
if (!class_exists($class)) {
|
||||
throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,343 @@
|
|||
<?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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\NodeInterface;
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class NodeDefinition implements NodeParentInterface
|
||||
{
|
||||
protected $name;
|
||||
protected $normalization;
|
||||
protected $validation;
|
||||
protected $defaultValue;
|
||||
protected $default = false;
|
||||
protected $required = false;
|
||||
protected $merge;
|
||||
protected $allowEmptyValue = true;
|
||||
protected $nullEquivalent;
|
||||
protected $trueEquivalent = true;
|
||||
protected $falseEquivalent = false;
|
||||
|
||||
/**
|
||||
* @var NodeParentInterface|null
|
||||
*/
|
||||
protected $parent;
|
||||
protected $attributes = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
* @param NodeParentInterface|null $parent The parent
|
||||
*/
|
||||
public function __construct($name, NodeParentInterface $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent node.
|
||||
*
|
||||
* @param NodeParentInterface $parent The parent
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function setParent(NodeParentInterface $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets info message.
|
||||
*
|
||||
* @param string $info The info text
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function info($info)
|
||||
{
|
||||
return $this->attribute('info', $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets example configuration.
|
||||
*
|
||||
* @param string|array $example
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function example($example)
|
||||
{
|
||||
return $this->attribute('example', $example);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute on the node.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function attribute($key, $value)
|
||||
{
|
||||
$this->attributes[$key] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent node.
|
||||
*
|
||||
* @return NodeParentInterface|null The builder of the parent node
|
||||
*/
|
||||
public function end()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the node.
|
||||
*
|
||||
* @param bool $forceRootNode Whether to force this node as the root node
|
||||
*
|
||||
* @return NodeInterface
|
||||
*/
|
||||
public function getNode($forceRootNode = false)
|
||||
{
|
||||
if ($forceRootNode) {
|
||||
$this->parent = null;
|
||||
}
|
||||
|
||||
if (null !== $this->normalization) {
|
||||
$this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
|
||||
}
|
||||
|
||||
if (null !== $this->validation) {
|
||||
$this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules);
|
||||
}
|
||||
|
||||
$node = $this->createNode();
|
||||
$node->setAttributes($this->attributes);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value.
|
||||
*
|
||||
* @param mixed $value The default value
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function defaultValue($value)
|
||||
{
|
||||
$this->default = true;
|
||||
$this->defaultValue = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the node as required.
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function isRequired()
|
||||
{
|
||||
$this->required = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the equivalent value used when the node contains null.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function treatNullLike($value)
|
||||
{
|
||||
$this->nullEquivalent = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the equivalent value used when the node contains true.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function treatTrueLike($value)
|
||||
{
|
||||
$this->trueEquivalent = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the equivalent value used when the node contains false.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function treatFalseLike($value)
|
||||
{
|
||||
$this->falseEquivalent = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets null as the default value.
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function defaultNull()
|
||||
{
|
||||
return $this->defaultValue(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets true as the default value.
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function defaultTrue()
|
||||
{
|
||||
return $this->defaultValue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets false as the default value.
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function defaultFalse()
|
||||
{
|
||||
return $this->defaultValue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an expression to run before the normalization.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function beforeNormalization()
|
||||
{
|
||||
return $this->normalization()->before();
|
||||
}
|
||||
|
||||
/**
|
||||
* Denies the node value being empty.
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function cannotBeEmpty()
|
||||
{
|
||||
$this->allowEmptyValue = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an expression to run for the validation.
|
||||
*
|
||||
* The expression receives the value of the node and must return it. It can
|
||||
* modify it.
|
||||
* An exception should be thrown when the node is not valid.
|
||||
*
|
||||
* @return ExprBuilder
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
return $this->validation()->rule();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the node can be overwritten.
|
||||
*
|
||||
* @param bool $deny Whether the overwriting is forbidden or not
|
||||
*
|
||||
* @return NodeDefinition|$this
|
||||
*/
|
||||
public function cannotBeOverwritten($deny = true)
|
||||
{
|
||||
$this->merge()->denyOverwrite($deny);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the builder for validation rules.
|
||||
*
|
||||
* @return ValidationBuilder
|
||||
*/
|
||||
protected function validation()
|
||||
{
|
||||
if (null === $this->validation) {
|
||||
$this->validation = new ValidationBuilder($this);
|
||||
}
|
||||
|
||||
return $this->validation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the builder for merging rules.
|
||||
*
|
||||
* @return MergeBuilder
|
||||
*/
|
||||
protected function merge()
|
||||
{
|
||||
if (null === $this->merge) {
|
||||
$this->merge = new MergeBuilder($this);
|
||||
}
|
||||
|
||||
return $this->merge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the builder for normalization rules.
|
||||
*
|
||||
* @return NormalizationBuilder
|
||||
*/
|
||||
protected function normalization()
|
||||
{
|
||||
if (null === $this->normalization) {
|
||||
$this->normalization = new NormalizationBuilder($this);
|
||||
}
|
||||
|
||||
return $this->normalization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate and configure the node according to this definition.
|
||||
*
|
||||
* @return NodeInterface $node The node instance
|
||||
*
|
||||
* @throws InvalidDefinitionException When the definition is invalid
|
||||
*/
|
||||
abstract protected function createNode();
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* An interface that must be implemented by all node parents.
|
||||
*
|
||||
* @author Victor Berchet <victor@suumit.com>
|
||||
*/
|
||||
interface NodeParentInterface
|
||||
{
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class builds normalization conditions.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class NormalizationBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $before = array();
|
||||
public $remappings = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a key to remap to its plural form.
|
||||
*
|
||||
* @param string $key The key to remap
|
||||
* @param string $plural The plural of the key in case of irregular plural
|
||||
*
|
||||
* @return NormalizationBuilder
|
||||
*/
|
||||
public function remap($key, $plural = null)
|
||||
{
|
||||
$this->remappings[] = array($key, null === $plural ? $key.'s' : $plural);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a closure to run before the normalization or an expression builder to build it if null is provided.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder|NormalizationBuilder
|
||||
*/
|
||||
public function before(\Closure $closure = null)
|
||||
{
|
||||
if (null !== $closure) {
|
||||
$this->before[] = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->before[] = new ExprBuilder($this->node);
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* Abstract class that contains common code of integer and float node definitions.
|
||||
*
|
||||
* @author David Jeanmonod <david.jeanmonod@gmail.com>
|
||||
*/
|
||||
abstract class NumericNodeDefinition extends ScalarNodeDefinition
|
||||
{
|
||||
protected $min;
|
||||
protected $max;
|
||||
|
||||
/**
|
||||
* Ensures that the value is smaller than the given reference.
|
||||
*
|
||||
* @param mixed $max
|
||||
*
|
||||
* @return NumericNodeDefinition
|
||||
*
|
||||
* @throws \InvalidArgumentException when the constraint is inconsistent
|
||||
*/
|
||||
public function max($max)
|
||||
{
|
||||
if (isset($this->min) && $this->min > $max) {
|
||||
throw new \InvalidArgumentException(sprintf('You cannot define a max(%s) as you already have a min(%s)', $max, $this->min));
|
||||
}
|
||||
$this->max = $max;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the value is bigger than the given reference.
|
||||
*
|
||||
* @param mixed $min
|
||||
*
|
||||
* @return NumericNodeDefinition
|
||||
*
|
||||
* @throws \InvalidArgumentException when the constraint is inconsistent
|
||||
*/
|
||||
public function min($min)
|
||||
{
|
||||
if (isset($this->max) && $this->max < $min) {
|
||||
throw new \InvalidArgumentException(sprintf('You cannot define a min(%s) as you already have a max(%s)', $min, $this->max));
|
||||
}
|
||||
$this->min = $min;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* An interface that must be implemented by nodes which can have children.
|
||||
*
|
||||
* @author Victor Berchet <victor@suumit.com>
|
||||
*/
|
||||
interface ParentNodeDefinitionInterface
|
||||
{
|
||||
public function children();
|
||||
|
||||
public function append(NodeDefinition $node);
|
||||
|
||||
public function setBuilder(NodeBuilder $builder);
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\ScalarNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ScalarNodeDefinition extends VariableNodeDefinition
|
||||
{
|
||||
/**
|
||||
* Instantiate a Node.
|
||||
*
|
||||
* @return ScalarNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new ScalarNode($this->name, $this->parent);
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\NodeInterface;
|
||||
|
||||
/**
|
||||
* This is the entry class for building a config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class TreeBuilder implements NodeParentInterface
|
||||
{
|
||||
protected $tree;
|
||||
protected $root;
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* Creates the root node.
|
||||
*
|
||||
* @param string $name The name of the root node
|
||||
* @param string $type The type of the root node
|
||||
* @param NodeBuilder $builder A custom node builder instance
|
||||
*
|
||||
* @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array')
|
||||
*
|
||||
* @throws \RuntimeException When the node type is not supported
|
||||
*/
|
||||
public function root($name, $type = 'array', NodeBuilder $builder = null)
|
||||
{
|
||||
$builder = $builder ?: new NodeBuilder();
|
||||
|
||||
return $this->root = $builder->node($name, $type)->setParent($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the tree.
|
||||
*
|
||||
* @return NodeInterface
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function buildTree()
|
||||
{
|
||||
if (null === $this->root) {
|
||||
throw new \RuntimeException('The configuration tree has no root node.');
|
||||
}
|
||||
if (null !== $this->tree) {
|
||||
return $this->tree;
|
||||
}
|
||||
|
||||
return $this->tree = $this->root->getNode(true);
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
/**
|
||||
* This class builds validation conditions.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class ValidationBuilder
|
||||
{
|
||||
protected $node;
|
||||
public $rules = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param NodeDefinition $node The related node
|
||||
*/
|
||||
public function __construct(NodeDefinition $node)
|
||||
{
|
||||
$this->node = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a closure to run as normalization or an expression builder to build it if null is provided.
|
||||
*
|
||||
* @param \Closure $closure
|
||||
*
|
||||
* @return ExprBuilder|ValidationBuilder
|
||||
*/
|
||||
public function rule(\Closure $closure = null)
|
||||
{
|
||||
if (null !== $closure) {
|
||||
$this->rules[] = $closure;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->rules[] = new ExprBuilder($this->node);
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Builder;
|
||||
|
||||
use Symfony\Component\Config\Definition\VariableNode;
|
||||
|
||||
/**
|
||||
* This class provides a fluent interface for defining a node.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class VariableNodeDefinition extends NodeDefinition
|
||||
{
|
||||
/**
|
||||
* Instantiate a Node.
|
||||
*
|
||||
* @return VariableNode The node
|
||||
*/
|
||||
protected function instantiateNode()
|
||||
{
|
||||
return new VariableNode($this->name, $this->parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createNode()
|
||||
{
|
||||
$node = $this->instantiateNode();
|
||||
|
||||
if (null !== $this->normalization) {
|
||||
$node->setNormalizationClosures($this->normalization->before);
|
||||
}
|
||||
|
||||
if (null !== $this->merge) {
|
||||
$node->setAllowOverwrite($this->merge->allowOverwrite);
|
||||
}
|
||||
|
||||
if (true === $this->default) {
|
||||
$node->setDefaultValue($this->defaultValue);
|
||||
}
|
||||
|
||||
$node->setAllowEmptyValue($this->allowEmptyValue);
|
||||
$node->addEquivalentValue(null, $this->nullEquivalent);
|
||||
$node->addEquivalentValue(true, $this->trueEquivalent);
|
||||
$node->addEquivalentValue(false, $this->falseEquivalent);
|
||||
$node->setRequired($this->required);
|
||||
|
||||
if (null !== $this->validation) {
|
||||
$node->setFinalValidationClosures($this->validation->rules);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
/**
|
||||
* Configuration interface.
|
||||
*
|
||||
* @author Victor Berchet <victor@suumit.com>
|
||||
*/
|
||||
interface ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* Generates the configuration tree builder.
|
||||
*
|
||||
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
|
||||
*/
|
||||
public function getConfigTreeBuilder();
|
||||
}
|
|
@ -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\Config\Definition\Dumper;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\NodeInterface;
|
||||
use Symfony\Component\Config\Definition\ArrayNode;
|
||||
use Symfony\Component\Config\Definition\EnumNode;
|
||||
use Symfony\Component\Config\Definition\PrototypedArrayNode;
|
||||
|
||||
/**
|
||||
* Dumps a XML reference configuration for the given configuration/node instance.
|
||||
*
|
||||
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||
*/
|
||||
class XmlReferenceDumper
|
||||
{
|
||||
private $reference;
|
||||
|
||||
public function dump(ConfigurationInterface $configuration, $namespace = null)
|
||||
{
|
||||
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
|
||||
}
|
||||
|
||||
public function dumpNode(NodeInterface $node, $namespace = null)
|
||||
{
|
||||
$this->reference = '';
|
||||
$this->writeNode($node, 0, true, $namespace);
|
||||
$ref = $this->reference;
|
||||
$this->reference = null;
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NodeInterface $node
|
||||
* @param int $depth
|
||||
* @param bool $root If the node is the root node
|
||||
* @param string $namespace The namespace of the node
|
||||
*/
|
||||
private function writeNode(NodeInterface $node, $depth = 0, $root = false, $namespace = null)
|
||||
{
|
||||
$rootName = ($root ? 'config' : $node->getName());
|
||||
$rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
|
||||
|
||||
// xml remapping
|
||||
if ($node->getParent()) {
|
||||
$remapping = array_filter($node->getParent()->getXmlRemappings(), function ($mapping) use ($rootName) {
|
||||
return $rootName === $mapping[1];
|
||||
});
|
||||
|
||||
if (count($remapping)) {
|
||||
list($singular) = current($remapping);
|
||||
$rootName = $singular;
|
||||
}
|
||||
}
|
||||
$rootName = str_replace('_', '-', $rootName);
|
||||
|
||||
$rootAttributes = array();
|
||||
$rootAttributeComments = array();
|
||||
$rootChildren = array();
|
||||
$rootComments = array();
|
||||
|
||||
if ($node instanceof ArrayNode) {
|
||||
$children = $node->getChildren();
|
||||
|
||||
// comments about the root node
|
||||
if ($rootInfo = $node->getInfo()) {
|
||||
$rootComments[] = $rootInfo;
|
||||
}
|
||||
|
||||
if ($rootNamespace) {
|
||||
$rootComments[] = 'Namespace: '.$rootNamespace;
|
||||
}
|
||||
|
||||
// render prototyped nodes
|
||||
if ($node instanceof PrototypedArrayNode) {
|
||||
array_unshift($rootComments, 'prototype');
|
||||
|
||||
if ($key = $node->getKeyAttribute()) {
|
||||
$rootAttributes[$key] = str_replace('-', ' ', $rootName).' '.$key;
|
||||
}
|
||||
|
||||
$prototype = $node->getPrototype();
|
||||
|
||||
if ($prototype instanceof ArrayNode) {
|
||||
$children = $prototype->getChildren();
|
||||
} else {
|
||||
if ($prototype->hasDefaultValue()) {
|
||||
$prototypeValue = $prototype->getDefaultValue();
|
||||
} else {
|
||||
switch (get_class($prototype)) {
|
||||
case 'Symfony\Component\Config\Definition\ScalarNode':
|
||||
$prototypeValue = 'scalar value';
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Config\Definition\FloatNode':
|
||||
case 'Symfony\Component\Config\Definition\IntegerNode':
|
||||
$prototypeValue = 'numeric value';
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Config\Definition\BooleanNode':
|
||||
$prototypeValue = 'true|false';
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Config\Definition\EnumNode':
|
||||
$prototypeValue = implode('|', array_map('json_encode', $prototype->getValues()));
|
||||
break;
|
||||
|
||||
default:
|
||||
$prototypeValue = 'value';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get attributes and elements
|
||||
foreach ($children as $child) {
|
||||
if (!$child instanceof ArrayNode) {
|
||||
// get attributes
|
||||
|
||||
// metadata
|
||||
$name = str_replace('_', '-', $child->getName());
|
||||
$value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world
|
||||
|
||||
// comments
|
||||
$comments = array();
|
||||
if ($info = $child->getInfo()) {
|
||||
$comments[] = $info;
|
||||
}
|
||||
|
||||
if ($example = $child->getExample()) {
|
||||
$comments[] = 'Example: '.$example;
|
||||
}
|
||||
|
||||
if ($child->isRequired()) {
|
||||
$comments[] = 'Required';
|
||||
}
|
||||
|
||||
if ($child instanceof EnumNode) {
|
||||
$comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues()));
|
||||
}
|
||||
|
||||
if (count($comments)) {
|
||||
$rootAttributeComments[$name] = implode(";\n", $comments);
|
||||
}
|
||||
|
||||
// default values
|
||||
if ($child->hasDefaultValue()) {
|
||||
$value = $child->getDefaultValue();
|
||||
}
|
||||
|
||||
// append attribute
|
||||
$rootAttributes[$name] = $value;
|
||||
} else {
|
||||
// get elements
|
||||
$rootChildren[] = $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render comments
|
||||
|
||||
// root node comment
|
||||
if (count($rootComments)) {
|
||||
foreach ($rootComments as $comment) {
|
||||
$this->writeLine('<!-- '.$comment.' -->', $depth);
|
||||
}
|
||||
}
|
||||
|
||||
// attribute comments
|
||||
if (count($rootAttributeComments)) {
|
||||
foreach ($rootAttributeComments as $attrName => $comment) {
|
||||
$commentDepth = $depth + 4 + strlen($attrName) + 2;
|
||||
$commentLines = explode("\n", $comment);
|
||||
$multiline = (count($commentLines) > 1);
|
||||
$comment = implode(PHP_EOL.str_repeat(' ', $commentDepth), $commentLines);
|
||||
|
||||
if ($multiline) {
|
||||
$this->writeLine('<!--', $depth);
|
||||
$this->writeLine($attrName.': '.$comment, $depth + 4);
|
||||
$this->writeLine('-->', $depth);
|
||||
} else {
|
||||
$this->writeLine('<!-- '.$attrName.': '.$comment.' -->', $depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render start tag + attributes
|
||||
$rootIsVariablePrototype = isset($prototypeValue);
|
||||
$rootIsEmptyTag = (0 === count($rootChildren) && !$rootIsVariablePrototype);
|
||||
$rootOpenTag = '<'.$rootName;
|
||||
if (1 >= ($attributesCount = count($rootAttributes))) {
|
||||
if (1 === $attributesCount) {
|
||||
$rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
|
||||
}
|
||||
|
||||
$rootOpenTag .= $rootIsEmptyTag ? ' />' : '>';
|
||||
|
||||
if ($rootIsVariablePrototype) {
|
||||
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
|
||||
}
|
||||
|
||||
$this->writeLine($rootOpenTag, $depth);
|
||||
} else {
|
||||
$this->writeLine($rootOpenTag, $depth);
|
||||
|
||||
$i = 1;
|
||||
|
||||
foreach ($rootAttributes as $attrName => $attrValue) {
|
||||
$attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
|
||||
|
||||
$this->writeLine($attr, $depth + 4);
|
||||
|
||||
if ($attributesCount === $i++) {
|
||||
$this->writeLine($rootIsEmptyTag ? '/>' : '>', $depth);
|
||||
|
||||
if ($rootIsVariablePrototype) {
|
||||
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render children tags
|
||||
foreach ($rootChildren as $child) {
|
||||
$this->writeLine('');
|
||||
$this->writeNode($child, $depth + 4);
|
||||
}
|
||||
|
||||
// render end tag
|
||||
if (!$rootIsEmptyTag && !$rootIsVariablePrototype) {
|
||||
$this->writeLine('');
|
||||
|
||||
$rootEndTag = '</'.$rootName.'>';
|
||||
$this->writeLine($rootEndTag, $depth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a single config reference line
|
||||
*
|
||||
* @param string $text
|
||||
* @param int $indent
|
||||
*/
|
||||
private function writeLine($text, $indent = 0)
|
||||
{
|
||||
$indent = strlen($text) + $indent;
|
||||
$format = '%'.$indent.'s';
|
||||
|
||||
$this->reference .= sprintf($format, $text)."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the string conversion of the value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function writeValue($value)
|
||||
{
|
||||
if ('%%%%not_defined%%%%' === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (is_string($value) || is_numeric($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (false === $value) {
|
||||
return 'false';
|
||||
}
|
||||
|
||||
if (true === $value) {
|
||||
return 'true';
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return implode(',', $value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
<?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\Config\Definition\Dumper;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\NodeInterface;
|
||||
use Symfony\Component\Config\Definition\ArrayNode;
|
||||
use Symfony\Component\Config\Definition\EnumNode;
|
||||
use Symfony\Component\Config\Definition\PrototypedArrayNode;
|
||||
use Symfony\Component\Yaml\Inline;
|
||||
|
||||
/**
|
||||
* Dumps a Yaml reference configuration for the given configuration/node instance.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
*/
|
||||
class YamlReferenceDumper
|
||||
{
|
||||
private $reference;
|
||||
|
||||
public function dump(ConfigurationInterface $configuration)
|
||||
{
|
||||
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree());
|
||||
}
|
||||
|
||||
public function dumpNode(NodeInterface $node)
|
||||
{
|
||||
$this->reference = '';
|
||||
$this->writeNode($node);
|
||||
$ref = $this->reference;
|
||||
$this->reference = null;
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NodeInterface $node
|
||||
* @param int $depth
|
||||
*/
|
||||
private function writeNode(NodeInterface $node, $depth = 0)
|
||||
{
|
||||
$comments = array();
|
||||
$default = '';
|
||||
$defaultArray = null;
|
||||
$children = null;
|
||||
$example = $node->getExample();
|
||||
|
||||
// defaults
|
||||
if ($node instanceof ArrayNode) {
|
||||
$children = $node->getChildren();
|
||||
|
||||
if ($node instanceof PrototypedArrayNode) {
|
||||
$prototype = $node->getPrototype();
|
||||
|
||||
if ($prototype instanceof ArrayNode) {
|
||||
$children = $prototype->getChildren();
|
||||
}
|
||||
|
||||
// check for attribute as key
|
||||
if ($key = $node->getKeyAttribute()) {
|
||||
$keyNodeClass = 'Symfony\Component\Config\Definition\\'.($prototype instanceof ArrayNode ? 'ArrayNode' : 'ScalarNode');
|
||||
$keyNode = new $keyNodeClass($key, $node);
|
||||
$keyNode->setInfo('Prototype');
|
||||
|
||||
// add children
|
||||
foreach ($children as $childNode) {
|
||||
$keyNode->addChild($childNode);
|
||||
}
|
||||
$children = array($key => $keyNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$children) {
|
||||
if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
|
||||
$default = '';
|
||||
} elseif (!is_array($example)) {
|
||||
$default = '[]';
|
||||
}
|
||||
}
|
||||
} elseif ($node instanceof EnumNode) {
|
||||
$comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues()));
|
||||
$default = '~';
|
||||
} else {
|
||||
$default = '~';
|
||||
|
||||
if ($node->hasDefaultValue()) {
|
||||
$default = $node->getDefaultValue();
|
||||
|
||||
if (is_array($default)) {
|
||||
if (count($defaultArray = $node->getDefaultValue())) {
|
||||
$default = '';
|
||||
} elseif (!is_array($example)) {
|
||||
$default = '[]';
|
||||
}
|
||||
} else {
|
||||
$default = Inline::dump($default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// required?
|
||||
if ($node->isRequired()) {
|
||||
$comments[] = 'Required';
|
||||
}
|
||||
|
||||
// example
|
||||
if ($example && !is_array($example)) {
|
||||
$comments[] = 'Example: '.$example;
|
||||
}
|
||||
|
||||
$default = (string) $default != '' ? ' '.$default : '';
|
||||
$comments = count($comments) ? '# '.implode(', ', $comments) : '';
|
||||
|
||||
$text = rtrim(sprintf('%-20s %s %s', $node->getName().':', $default, $comments), ' ');
|
||||
|
||||
if ($info = $node->getInfo()) {
|
||||
$this->writeLine('');
|
||||
// indenting multi-line info
|
||||
$info = str_replace("\n", sprintf("\n%".($depth * 4)."s# ", ' '), $info);
|
||||
$this->writeLine('# '.$info, $depth * 4);
|
||||
}
|
||||
|
||||
$this->writeLine($text, $depth * 4);
|
||||
|
||||
// output defaults
|
||||
if ($defaultArray) {
|
||||
$this->writeLine('');
|
||||
|
||||
$message = count($defaultArray) > 1 ? 'Defaults' : 'Default';
|
||||
|
||||
$this->writeLine('# '.$message.':', $depth * 4 + 4);
|
||||
|
||||
$this->writeArray($defaultArray, $depth + 1);
|
||||
}
|
||||
|
||||
if (is_array($example)) {
|
||||
$this->writeLine('');
|
||||
|
||||
$message = count($example) > 1 ? 'Examples' : 'Example';
|
||||
|
||||
$this->writeLine('# '.$message.':', $depth * 4 + 4);
|
||||
|
||||
$this->writeArray($example, $depth + 1);
|
||||
}
|
||||
|
||||
if ($children) {
|
||||
foreach ($children as $childNode) {
|
||||
$this->writeNode($childNode, $depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a single config reference line
|
||||
*
|
||||
* @param string $text
|
||||
* @param int $indent
|
||||
*/
|
||||
private function writeLine($text, $indent = 0)
|
||||
{
|
||||
$indent = strlen($text) + $indent;
|
||||
$format = '%'.$indent.'s';
|
||||
|
||||
$this->reference .= sprintf($format, $text)."\n";
|
||||
}
|
||||
|
||||
private function writeArray(array $array, $depth)
|
||||
{
|
||||
$isIndexed = array_values($array) === $array;
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$val = '';
|
||||
} else {
|
||||
$val = $value;
|
||||
}
|
||||
|
||||
if ($isIndexed) {
|
||||
$this->writeLine('- '.$val, $depth * 4);
|
||||
} else {
|
||||
$this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$this->writeArray($value, $depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/EnumNode.php
vendored
Normal file
58
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/EnumNode.php
vendored
Normal file
|
@ -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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
|
||||
/**
|
||||
* Node which only allows a finite set of values.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class EnumNode extends ScalarNode
|
||||
{
|
||||
private $values;
|
||||
|
||||
public function __construct($name, NodeInterface $parent = null, array $values = array())
|
||||
{
|
||||
$values = array_unique($values);
|
||||
if (count($values) <= 1) {
|
||||
throw new \InvalidArgumentException('$values must contain at least two distinct elements.');
|
||||
}
|
||||
|
||||
parent::__construct($name, $parent);
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
$value = parent::finalizeValue($value);
|
||||
|
||||
if (!in_array($value, $this->values, true)) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'The value %s is not allowed for path "%s". Permissible values: %s',
|
||||
json_encode($value),
|
||||
$this->getPath(),
|
||||
implode(', ', array_map('json_encode', $this->values))));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown whenever the key of an array is not unique. This can
|
||||
* only be the case if the configuration is coming from an XML file.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class DuplicateKeyException extends InvalidConfigurationException
|
||||
{
|
||||
}
|
|
@ -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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* Base exception for all configuration exceptions.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class Exception extends \RuntimeException
|
||||
{
|
||||
}
|
|
@ -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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a configuration path is overwritten from a
|
||||
* subsequent configuration file, but the entry node specifically forbids this.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ForbiddenOverwriteException extends InvalidConfigurationException
|
||||
{
|
||||
}
|
|
@ -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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* A very general exception which can be thrown whenever non of the more specific
|
||||
* exceptions is suitable.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class InvalidConfigurationException extends Exception
|
||||
{
|
||||
private $path;
|
||||
private $containsHints = false;
|
||||
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds extra information that is suffixed to the original exception message.
|
||||
*
|
||||
* @param string $hint
|
||||
*/
|
||||
public function addHint($hint)
|
||||
{
|
||||
if (!$this->containsHints) {
|
||||
$this->message .= "\nHint: ".$hint;
|
||||
$this->containsHints = true;
|
||||
} else {
|
||||
$this->message .= ', '.$hint;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* Thrown when an error is detected in a node Definition.
|
||||
*
|
||||
* @author Victor Berchet <victor.berchet@suumit.com>
|
||||
*/
|
||||
class InvalidDefinitionException extends Exception
|
||||
{
|
||||
}
|
|
@ -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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is thrown if an invalid type is encountered.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class InvalidTypeException extends InvalidConfigurationException
|
||||
{
|
||||
}
|
|
@ -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\Config\Definition\Exception;
|
||||
|
||||
/**
|
||||
* This exception is usually not encountered by the end-user, but only used
|
||||
* internally to signal the parent scope to unset a key.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class UnsetKeyException extends Exception
|
||||
{
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
|
||||
/**
|
||||
* This node represents a float value in the config tree.
|
||||
*
|
||||
* @author Jeanmonod David <david.jeanmonod@gmail.com>
|
||||
*/
|
||||
class FloatNode extends NumericNode
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
// Integers are also accepted, we just cast them
|
||||
if (is_int($value)) {
|
||||
$value = (float) $value;
|
||||
}
|
||||
|
||||
if (!is_float($value)) {
|
||||
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected float, but got %s.', $this->getPath(), gettype($value)));
|
||||
if ($hint = $this->getInfo()) {
|
||||
$ex->addHint($hint);
|
||||
}
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
|
||||
/**
|
||||
* This node represents an integer value in the config tree.
|
||||
*
|
||||
* @author Jeanmonod David <david.jeanmonod@gmail.com>
|
||||
*/
|
||||
class IntegerNode extends NumericNode
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
if (!is_int($value)) {
|
||||
$ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected int, but got %s.', $this->getPath(), gettype($value)));
|
||||
if ($hint = $this->getInfo()) {
|
||||
$ex->addHint($hint);
|
||||
}
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
/**
|
||||
* Common Interface among all nodes.
|
||||
*
|
||||
* In most cases, it is better to inherit from BaseNode instead of implementing
|
||||
* this interface yourself.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface NodeInterface
|
||||
{
|
||||
/**
|
||||
* Returns the name of the node.
|
||||
*
|
||||
* @return string The name of the node
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Returns the path of the node.
|
||||
*
|
||||
* @return string The node path
|
||||
*/
|
||||
public function getPath();
|
||||
|
||||
/**
|
||||
* Returns true when the node is required.
|
||||
*
|
||||
* @return bool If the node is required
|
||||
*/
|
||||
public function isRequired();
|
||||
|
||||
/**
|
||||
* Returns true when the node has a default value.
|
||||
*
|
||||
* @return bool If the node has a default value
|
||||
*/
|
||||
public function hasDefaultValue();
|
||||
|
||||
/**
|
||||
* Returns the default value of the node.
|
||||
*
|
||||
* @return mixed The default value
|
||||
*
|
||||
* @throws \RuntimeException if the node has no default value
|
||||
*/
|
||||
public function getDefaultValue();
|
||||
|
||||
/**
|
||||
* Normalizes the supplied value.
|
||||
*
|
||||
* @param mixed $value The value to normalize
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*/
|
||||
public function normalize($value);
|
||||
|
||||
/**
|
||||
* Merges two values together.
|
||||
*
|
||||
* @param mixed $leftSide
|
||||
* @param mixed $rightSide
|
||||
*
|
||||
* @return mixed The merged values
|
||||
*/
|
||||
public function merge($leftSide, $rightSide);
|
||||
|
||||
/**
|
||||
* Finalizes a value.
|
||||
*
|
||||
* @param mixed $value The value to finalize
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*/
|
||||
public function finalize($value);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
|
||||
/**
|
||||
* This node represents a numeric value in the config tree.
|
||||
*
|
||||
* @author David Jeanmonod <david.jeanmonod@gmail.com>
|
||||
*/
|
||||
class NumericNode extends ScalarNode
|
||||
{
|
||||
protected $min;
|
||||
protected $max;
|
||||
|
||||
public function __construct($name, NodeInterface $parent = null, $min = null, $max = null)
|
||||
{
|
||||
parent::__construct($name, $parent);
|
||||
$this->min = $min;
|
||||
$this->max = $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
$value = parent::finalizeValue($value);
|
||||
|
||||
$errorMsg = null;
|
||||
if (isset($this->min) && $value < $this->min) {
|
||||
$errorMsg = sprintf('The value %s is too small for path "%s". Should be greater than or equal to %s', $value, $this->getPath(), $this->min);
|
||||
}
|
||||
if (isset($this->max) && $value > $this->max) {
|
||||
$errorMsg = sprintf('The value %s is too big for path "%s". Should be less than or equal to %s', $value, $this->getPath(), $this->max);
|
||||
}
|
||||
if (isset($errorMsg)) {
|
||||
$ex = new InvalidConfigurationException($errorMsg);
|
||||
$ex->setPath($this->getPath());
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition;
|
||||
|
||||
/**
|
||||
* This class is the entry point for config normalization/merging/finalization.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class Processor
|
||||
{
|
||||
/**
|
||||
* Processes an array of configurations.
|
||||
*
|
||||
* @param NodeInterface $configTree The node tree describing the configuration
|
||||
* @param array $configs An array of configuration items to process
|
||||
*
|
||||
* @return array The processed configuration
|
||||
*/
|
||||
public function process(NodeInterface $configTree, array $configs)
|
||||
{
|
||||
$currentConfig = array();
|
||||
foreach ($configs as $config) {
|
||||
$config = $configTree->normalize($config);
|
||||
$currentConfig = $configTree->merge($currentConfig, $config);
|
||||
}
|
||||
|
||||
return $configTree->finalize($currentConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an array of configurations.
|
||||
*
|
||||
* @param ConfigurationInterface $configuration The configuration class
|
||||
* @param array $configs An array of configuration items to process
|
||||
*
|
||||
* @return array The processed configuration
|
||||
*/
|
||||
public function processConfiguration(ConfigurationInterface $configuration, array $configs)
|
||||
{
|
||||
return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a configuration entry.
|
||||
*
|
||||
* This method returns a normalize configuration array for a given key
|
||||
* to remove the differences due to the original format (YAML and XML mainly).
|
||||
*
|
||||
* Here is an example.
|
||||
*
|
||||
* The configuration in XML:
|
||||
*
|
||||
* <twig:extension>twig.extension.foo</twig:extension>
|
||||
* <twig:extension>twig.extension.bar</twig:extension>
|
||||
*
|
||||
* And the same configuration in YAML:
|
||||
*
|
||||
* extensions: ['twig.extension.foo', 'twig.extension.bar']
|
||||
*
|
||||
* @param array $config A config array
|
||||
* @param string $key The key to normalize
|
||||
* @param string $plural The plural form of the key if it is irregular
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeConfig($config, $key, $plural = null)
|
||||
{
|
||||
if (null === $plural) {
|
||||
$plural = $key.'s';
|
||||
}
|
||||
|
||||
if (isset($config[$plural])) {
|
||||
return $config[$plural];
|
||||
}
|
||||
|
||||
if (isset($config[$key])) {
|
||||
if (is_string($config[$key]) || !is_int(key($config[$key]))) {
|
||||
// only one
|
||||
return array($config[$key]);
|
||||
}
|
||||
|
||||
return $config[$key];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
/**
|
||||
* This interface must be implemented by nodes which can be used as prototypes.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface PrototypeNodeInterface extends NodeInterface
|
||||
{
|
||||
/**
|
||||
* Sets the name of the node.
|
||||
*
|
||||
* @param string $name The name of the node
|
||||
*/
|
||||
public function setName($name);
|
||||
}
|
|
@ -0,0 +1,331 @@
|
|||
<?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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
|
||||
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
|
||||
use Symfony\Component\Config\Definition\Exception\Exception;
|
||||
|
||||
/**
|
||||
* Represents a prototyped Array node in the config tree.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class PrototypedArrayNode extends ArrayNode
|
||||
{
|
||||
protected $prototype;
|
||||
protected $keyAttribute;
|
||||
protected $removeKeyAttribute = false;
|
||||
protected $minNumberOfElements = 0;
|
||||
protected $defaultValue = array();
|
||||
protected $defaultChildren;
|
||||
|
||||
/**
|
||||
* Sets the minimum number of elements that a prototype based node must
|
||||
* contain. By default this is zero, meaning no elements.
|
||||
*
|
||||
* @param int $number
|
||||
*/
|
||||
public function setMinNumberOfElements($number)
|
||||
{
|
||||
$this->minNumberOfElements = $number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attribute which value is to be used as key.
|
||||
*
|
||||
* This is useful when you have an indexed array that should be an
|
||||
* associative array. You can select an item from within the array
|
||||
* to be the key of the particular item. For example, if "id" is the
|
||||
* "key", then:
|
||||
*
|
||||
* array(
|
||||
* array('id' => 'my_name', 'foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* becomes
|
||||
*
|
||||
* array(
|
||||
* 'my_name' => array('foo' => 'bar'),
|
||||
* );
|
||||
*
|
||||
* If you'd like "'id' => 'my_name'" to still be present in the resulting
|
||||
* array, then you can set the second argument of this method to false.
|
||||
*
|
||||
* @param string $attribute The name of the attribute which value is to be used as a key
|
||||
* @param bool $remove Whether or not to remove the key
|
||||
*/
|
||||
public function setKeyAttribute($attribute, $remove = true)
|
||||
{
|
||||
$this->keyAttribute = $attribute;
|
||||
$this->removeKeyAttribute = $remove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the name of the attribute which value should be used as key.
|
||||
*
|
||||
* @return string The name of the attribute
|
||||
*/
|
||||
public function getKeyAttribute()
|
||||
{
|
||||
return $this->keyAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value of this node.
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the default value is not an array
|
||||
*/
|
||||
public function setDefaultValue($value)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
|
||||
}
|
||||
|
||||
$this->defaultValue = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the node has a default value.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDefaultValue()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default children when none are set.
|
||||
*
|
||||
* @param int|string|array|null $children The number of children|The child name|The children names to be added
|
||||
*/
|
||||
public function setAddChildrenIfNoneSet($children = array('defaults'))
|
||||
{
|
||||
if (null === $children) {
|
||||
$this->defaultChildren = array('defaults');
|
||||
} else {
|
||||
$this->defaultChildren = is_int($children) && $children > 0 ? range(1, $children) : (array) $children;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default value.
|
||||
*
|
||||
* The default value could be either explicited or derived from the prototype
|
||||
* default value.
|
||||
*
|
||||
* @return array The default value
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
if (null !== $this->defaultChildren) {
|
||||
$default = $this->prototype->hasDefaultValue() ? $this->prototype->getDefaultValue() : array();
|
||||
$defaults = array();
|
||||
foreach (array_values($this->defaultChildren) as $i => $name) {
|
||||
$defaults[null === $this->keyAttribute ? $i : $name] = $default;
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the node prototype.
|
||||
*
|
||||
* @param PrototypeNodeInterface $node
|
||||
*/
|
||||
public function setPrototype(PrototypeNodeInterface $node)
|
||||
{
|
||||
$this->prototype = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the prototype.
|
||||
*
|
||||
* @return PrototypeNodeInterface The prototype
|
||||
*/
|
||||
public function getPrototype()
|
||||
{
|
||||
return $this->prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable adding concrete children for prototyped nodes.
|
||||
*
|
||||
* @param NodeInterface $node The child node to add
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function addChild(NodeInterface $node)
|
||||
{
|
||||
throw new Exception('A prototyped array node can not have concrete children.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the value of this node.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed The finalized value
|
||||
*
|
||||
* @throws UnsetKeyException
|
||||
* @throws InvalidConfigurationException if the node doesn't have enough children
|
||||
*/
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
$msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
|
||||
throw new UnsetKeyException($msg);
|
||||
}
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
$this->prototype->setName($k);
|
||||
try {
|
||||
$value[$k] = $this->prototype->finalize($v);
|
||||
} catch (UnsetKeyException $e) {
|
||||
unset($value[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($value) < $this->minNumberOfElements) {
|
||||
$msg = sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements);
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the value.
|
||||
*
|
||||
* @param mixed $value The value to normalize
|
||||
*
|
||||
* @return mixed The normalized value
|
||||
*
|
||||
* @throws InvalidConfigurationException
|
||||
* @throws DuplicateKeyException
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
{
|
||||
if (false === $value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = $this->remapXml($value);
|
||||
|
||||
$isAssoc = array_keys($value) !== range(0, count($value) - 1);
|
||||
$normalized = array();
|
||||
foreach ($value as $k => $v) {
|
||||
if (null !== $this->keyAttribute && is_array($v)) {
|
||||
if (!isset($v[$this->keyAttribute]) && is_int($k) && !$isAssoc) {
|
||||
$msg = sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath());
|
||||
$ex = new InvalidConfigurationException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
} elseif (isset($v[$this->keyAttribute])) {
|
||||
$k = $v[$this->keyAttribute];
|
||||
|
||||
// remove the key attribute when required
|
||||
if ($this->removeKeyAttribute) {
|
||||
unset($v[$this->keyAttribute]);
|
||||
}
|
||||
|
||||
// if only "value" is left
|
||||
if (1 == count($v) && isset($v['value'])) {
|
||||
$v = $v['value'];
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($k, $normalized)) {
|
||||
$msg = sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath());
|
||||
$ex = new DuplicateKeyException($msg);
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
$this->prototype->setName($k);
|
||||
if (null !== $this->keyAttribute || $isAssoc) {
|
||||
$normalized[$k] = $this->prototype->normalize($v);
|
||||
} else {
|
||||
$normalized[] = $this->prototype->normalize($v);
|
||||
}
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges values together.
|
||||
*
|
||||
* @param mixed $leftSide The left side to merge.
|
||||
* @param mixed $rightSide The right side to merge.
|
||||
*
|
||||
* @return mixed The merged values
|
||||
*
|
||||
* @throws InvalidConfigurationException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function mergeValues($leftSide, $rightSide)
|
||||
{
|
||||
if (false === $rightSide) {
|
||||
// if this is still false after the last config has been merged the
|
||||
// finalization pass will take care of removing this key entirely
|
||||
return false;
|
||||
}
|
||||
|
||||
if (false === $leftSide || !$this->performDeepMerging) {
|
||||
return $rightSide;
|
||||
}
|
||||
|
||||
foreach ($rightSide as $k => $v) {
|
||||
// prototype, and key is irrelevant, so simply append the element
|
||||
if (null === $this->keyAttribute) {
|
||||
$leftSide[] = $v;
|
||||
continue;
|
||||
}
|
||||
|
||||
// no conflict
|
||||
if (!array_key_exists($k, $leftSide)) {
|
||||
if (!$this->allowNewKeys) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'You are not allowed to define new elements for path "%s". '.
|
||||
'Please define all elements for this path in one config file.',
|
||||
$this->getPath()
|
||||
));
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$leftSide[$k] = $v;
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->prototype->setName($k);
|
||||
$leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
|
||||
}
|
||||
|
||||
return $leftSide;
|
||||
}
|
||||
}
|
|
@ -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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated since version 2.4, to be removed in 3.0. Use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper instead.
|
||||
*/
|
||||
class ReferenceDumper extends YamlReferenceDumper
|
||||
{
|
||||
}
|
|
@ -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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
|
||||
|
||||
/**
|
||||
* This node represents a scalar value in the config tree.
|
||||
*
|
||||
* The following values are considered scalars:
|
||||
* * booleans
|
||||
* * strings
|
||||
* * null
|
||||
* * integers
|
||||
* * floats
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ScalarNode extends VariableNode
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
if (!is_scalar($value) && null !== $value) {
|
||||
$ex = new InvalidTypeException(sprintf(
|
||||
'Invalid type for path "%s". Expected scalar, but got %s.',
|
||||
$this->getPath(),
|
||||
gettype($value)
|
||||
));
|
||||
if ($hint = $this->getInfo()) {
|
||||
$ex->addHint($hint);
|
||||
}
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
119
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/VariableNode.php
vendored
Normal file
119
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Definition/VariableNode.php
vendored
Normal file
|
@ -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\Config\Definition;
|
||||
|
||||
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
|
||||
|
||||
/**
|
||||
* This node represents a value of variable type in the config tree.
|
||||
*
|
||||
* This node is intended for values of arbitrary type.
|
||||
* Any PHP type is accepted as a value.
|
||||
*
|
||||
* @author Jeremy Mikola <jmikola@gmail.com>
|
||||
*/
|
||||
class VariableNode extends BaseNode implements PrototypeNodeInterface
|
||||
{
|
||||
protected $defaultValueSet = false;
|
||||
protected $defaultValue;
|
||||
protected $allowEmptyValue = true;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDefaultValue($value)
|
||||
{
|
||||
$this->defaultValueSet = true;
|
||||
$this->defaultValue = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasDefaultValue()
|
||||
{
|
||||
return $this->defaultValueSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
$v = $this->defaultValue;
|
||||
|
||||
return $v instanceof \Closure ? $v() : $v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this node is allowed to have an empty value.
|
||||
*
|
||||
* @param bool $boolean True if this entity will accept empty values.
|
||||
*/
|
||||
public function setAllowEmptyValue($boolean)
|
||||
{
|
||||
$this->allowEmptyValue = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateType($value)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function finalizeValue($value)
|
||||
{
|
||||
if (!$this->allowEmptyValue && empty($value)) {
|
||||
$ex = new InvalidConfigurationException(sprintf(
|
||||
'The path "%s" cannot contain an empty value, but got %s.',
|
||||
$this->getPath(),
|
||||
json_encode($value)
|
||||
));
|
||||
if ($hint = $this->getInfo()) {
|
||||
$ex->addHint($hint);
|
||||
}
|
||||
$ex->setPath($this->getPath());
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mergeValues($leftSide, $rightSide)
|
||||
{
|
||||
return $rightSide;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?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\Config\Exception;
|
||||
|
||||
/**
|
||||
* Exception class for when a circular reference is detected when importing resources.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FileLoaderImportCircularReferenceException extends FileLoaderLoadException
|
||||
{
|
||||
public function __construct(array $resources, $code = null, $previous = null)
|
||||
{
|
||||
$message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
|
||||
|
||||
\Exception::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?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\Config\Exception;
|
||||
|
||||
/**
|
||||
* Exception class for when a resource cannot be loaded or imported.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@thatsquality.com>
|
||||
*/
|
||||
class FileLoaderLoadException extends \Exception
|
||||
{
|
||||
/**
|
||||
* @param string $resource The resource that could not be imported
|
||||
* @param string $sourceResource The original resource importing the new resource
|
||||
* @param int $code The error code
|
||||
* @param \Exception $previous A previous exception
|
||||
*/
|
||||
public function __construct($resource, $sourceResource = null, $code = null, $previous = null)
|
||||
{
|
||||
$message = '';
|
||||
if ($previous) {
|
||||
// Include the previous exception, to help the user see what might be the underlying cause
|
||||
|
||||
// Trim the trailing period of the previous message. We only want 1 period remove so no rtrim...
|
||||
if ('.' === substr($previous->getMessage(), -1)) {
|
||||
$trimmedMessage = substr($previous->getMessage(), 0, -1);
|
||||
$message .= sprintf('%s', $trimmedMessage).' in ';
|
||||
} else {
|
||||
$message .= sprintf('%s', $previous->getMessage()).' in ';
|
||||
}
|
||||
$message .= $resource.' ';
|
||||
|
||||
// show tweaked trace to complete the human readable sentence
|
||||
if (null === $sourceResource) {
|
||||
$message .= sprintf('(which is loaded in resource "%s")', $this->varToString($resource));
|
||||
} else {
|
||||
$message .= sprintf('(which is being imported from "%s")', $this->varToString($sourceResource));
|
||||
}
|
||||
$message .= '.';
|
||||
|
||||
// if there's no previous message, present it the default way
|
||||
} elseif (null === $sourceResource) {
|
||||
$message .= sprintf('Cannot load resource "%s".', $this->varToString($resource));
|
||||
} else {
|
||||
$message .= sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource));
|
||||
}
|
||||
|
||||
// Is the resource located inside a bundle?
|
||||
if ('@' === $resource[0]) {
|
||||
$parts = explode(DIRECTORY_SEPARATOR, $resource);
|
||||
$bundle = substr($parts[0], 1);
|
||||
$message .= sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
|
||||
$message .= sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource);
|
||||
}
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
protected function varToString($var)
|
||||
{
|
||||
if (is_object($var)) {
|
||||
return sprintf('Object(%s)', get_class($var));
|
||||
}
|
||||
|
||||
if (is_array($var)) {
|
||||
$a = array();
|
||||
foreach ($var as $k => $v) {
|
||||
$a[] = sprintf('%s => %s', $k, $this->varToString($v));
|
||||
}
|
||||
|
||||
return sprintf('Array(%s)', implode(', ', $a));
|
||||
}
|
||||
|
||||
if (is_resource($var)) {
|
||||
return sprintf('Resource(%s)', get_resource_type($var));
|
||||
}
|
||||
|
||||
if (null === $var) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (false === $var) {
|
||||
return 'false';
|
||||
}
|
||||
|
||||
if (true === $var) {
|
||||
return 'true';
|
||||
}
|
||||
|
||||
return (string) $var;
|
||||
}
|
||||
}
|
96
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/FileLocator.php
vendored
Normal file
96
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/FileLocator.php
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?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\Config;
|
||||
|
||||
/**
|
||||
* FileLocator uses an array of pre-defined paths to find files.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FileLocator implements FileLocatorInterface
|
||||
{
|
||||
protected $paths;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|array $paths A path or an array of paths where to look for resources
|
||||
*/
|
||||
public function __construct($paths = array())
|
||||
{
|
||||
$this->paths = (array) $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function locate($name, $currentPath = null, $first = true)
|
||||
{
|
||||
if ('' == $name) {
|
||||
throw new \InvalidArgumentException('An empty file name is not valid to be located.');
|
||||
}
|
||||
|
||||
if ($this->isAbsolutePath($name)) {
|
||||
if (!file_exists($name)) {
|
||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
$paths = $this->paths;
|
||||
|
||||
if (null !== $currentPath) {
|
||||
array_unshift($paths, $currentPath);
|
||||
}
|
||||
|
||||
$paths = array_unique($paths);
|
||||
$filepaths = array();
|
||||
|
||||
foreach ($paths as $path) {
|
||||
if (file_exists($file = $path.DIRECTORY_SEPARATOR.$name)) {
|
||||
if (true === $first) {
|
||||
return $file;
|
||||
}
|
||||
$filepaths[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$filepaths) {
|
||||
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist (in: %s).', $name, implode(', ', $paths)));
|
||||
}
|
||||
|
||||
return $filepaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the file path is an absolute path.
|
||||
*
|
||||
* @param string $file A file path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isAbsolutePath($file)
|
||||
{
|
||||
if ($file[0] === '/' || $file[0] === '\\'
|
||||
|| (strlen($file) > 3 && ctype_alpha($file[0])
|
||||
&& $file[1] === ':'
|
||||
&& ($file[2] === '\\' || $file[2] === '/')
|
||||
)
|
||||
|| null !== parse_url($file, PHP_URL_SCHEME)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -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\Config;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface FileLocatorInterface
|
||||
{
|
||||
/**
|
||||
* Returns a full path for a given file name.
|
||||
*
|
||||
* @param string $name The file name to locate
|
||||
* @param string|null $currentPath The current path
|
||||
* @param bool $first Whether to return the first occurrence or an array of filenames
|
||||
*
|
||||
* @return string|array The full path to the file or an array of file paths
|
||||
*
|
||||
* @throws \InvalidArgumentException When file is not found
|
||||
*/
|
||||
public function locate($name, $currentPath = null, $first = true);
|
||||
}
|
19
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/LICENSE
vendored
Normal file
19
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/LICENSE
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2004-2015 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,55 @@
|
|||
<?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\Config\Loader;
|
||||
|
||||
use Symfony\Component\Config\Exception\FileLoaderLoadException;
|
||||
|
||||
/**
|
||||
* DelegatingLoader delegates loading to other loaders using a loader resolver.
|
||||
*
|
||||
* This loader acts as an array of LoaderInterface objects - each having
|
||||
* a chance to load a given resource (handled by the resolver)
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DelegatingLoader extends Loader
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
|
||||
*/
|
||||
public function __construct(LoaderResolverInterface $resolver)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, $type = null)
|
||||
{
|
||||
if (false === $loader = $this->resolver->resolve($resource, $type)) {
|
||||
throw new FileLoaderLoadException($resource);
|
||||
}
|
||||
|
||||
return $loader->load($resource, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
return false !== $this->resolver->resolve($resource, $type);
|
||||
}
|
||||
}
|
129
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Loader/FileLoader.php
vendored
Normal file
129
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Loader/FileLoader.php
vendored
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?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\Config\Loader;
|
||||
|
||||
use Symfony\Component\Config\FileLocatorInterface;
|
||||
use Symfony\Component\Config\Exception\FileLoaderLoadException;
|
||||
use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;
|
||||
|
||||
/**
|
||||
* 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 Loader
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $loading = array();
|
||||
|
||||
/**
|
||||
* @var FileLocatorInterface
|
||||
*/
|
||||
protected $locator;
|
||||
|
||||
private $currentDir;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param FileLocatorInterface $locator A FileLocatorInterface instance
|
||||
*/
|
||||
public function __construct(FileLocatorInterface $locator)
|
||||
{
|
||||
$this->locator = $locator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current directory.
|
||||
*
|
||||
* @param string $dir
|
||||
*/
|
||||
public function setCurrentDir($dir)
|
||||
{
|
||||
$this->currentDir = $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file locator used by this loader.
|
||||
*
|
||||
* @return FileLocatorInterface
|
||||
*/
|
||||
public function getLocator()
|
||||
{
|
||||
return $this->locator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a resource.
|
||||
*
|
||||
* @param mixed $resource A Resource
|
||||
* @param string|null $type The resource type or null if unknown
|
||||
* @param bool $ignoreErrors Whether to ignore import errors or not
|
||||
* @param string|null $sourceResource The original resource importing the new resource
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws FileLoaderLoadException
|
||||
* @throws FileLoaderImportCircularReferenceException
|
||||
*/
|
||||
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
|
||||
{
|
||||
try {
|
||||
$loader = $this->resolve($resource, $type);
|
||||
|
||||
if ($loader instanceof self && null !== $this->currentDir) {
|
||||
// we fallback to the current locator to keep BC
|
||||
// as some some loaders do not call the parent __construct()
|
||||
// @deprecated should be removed in 3.0
|
||||
$locator = $loader->getLocator() ?: $this->locator;
|
||||
$resource = $locator->locate($resource, $this->currentDir, false);
|
||||
}
|
||||
|
||||
$resources = is_array($resource) ? $resource : array($resource);
|
||||
for ($i = 0; $i < $resourcesCount = count($resources); ++$i) {
|
||||
if (isset(self::$loading[$resources[$i]])) {
|
||||
if ($i == $resourcesCount - 1) {
|
||||
throw new FileLoaderImportCircularReferenceException(array_keys(self::$loading));
|
||||
}
|
||||
} else {
|
||||
$resource = $resources[$i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
self::$loading[$resource] = true;
|
||||
|
||||
try {
|
||||
$ret = $loader->load($resource, $type);
|
||||
} catch (\Exception $e) {
|
||||
unset(self::$loading[$resource]);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
unset(self::$loading[$resource]);
|
||||
|
||||
return $ret;
|
||||
} catch (FileLoaderImportCircularReferenceException $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
if (!$ignoreErrors) {
|
||||
// prevent embedded imports from nesting multiple exceptions
|
||||
if ($e instanceof FileLoaderLoadException) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
throw new FileLoaderLoadException($resource, $sourceResource, null, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Loader/Loader.php
vendored
Normal file
78
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Loader/Loader.php
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?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\Config\Loader;
|
||||
|
||||
use Symfony\Component\Config\Exception\FileLoaderLoadException;
|
||||
|
||||
/**
|
||||
* Loader is the abstract class used by all built-in loaders.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class Loader implements LoaderInterface
|
||||
{
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResolver()
|
||||
{
|
||||
return $this->resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setResolver(LoaderResolverInterface $resolver)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string|null $type The resource type or null if unknown
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function import($resource, $type = null)
|
||||
{
|
||||
return $this->resolve($resource, $type)->load($resource, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a loader able to load an imported resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string|null $type The resource type or null if unknown
|
||||
*
|
||||
* @return LoaderInterface A LoaderInterface instance
|
||||
*
|
||||
* @throws FileLoaderLoadException If no loader is found
|
||||
*/
|
||||
public function resolve($resource, $type = null)
|
||||
{
|
||||
if ($this->supports($resource, $type)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$loader = null === $this->resolver ? false : $this->resolver->resolve($resource, $type);
|
||||
|
||||
if (false === $loader) {
|
||||
throw new FileLoaderLoadException($resource);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?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\Config\Loader;
|
||||
|
||||
/**
|
||||
* LoaderInterface is the interface implemented by all loader classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface LoaderInterface
|
||||
{
|
||||
/**
|
||||
* Loads a resource.
|
||||
*
|
||||
* @param mixed $resource The resource
|
||||
* @param string|null $type The resource type or null if unknown
|
||||
*
|
||||
* @throws \Exception If something went wrong
|
||||
*/
|
||||
public function load($resource, $type = null);
|
||||
|
||||
/**
|
||||
* Returns whether this class supports the given resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string|null $type The resource type or null if unknown
|
||||
*
|
||||
* @return bool True if this class supports the given resource, false otherwise
|
||||
*/
|
||||
public function supports($resource, $type = null);
|
||||
|
||||
/**
|
||||
* Gets the loader resolver.
|
||||
*
|
||||
* @return LoaderResolverInterface A LoaderResolverInterface instance
|
||||
*/
|
||||
public function getResolver();
|
||||
|
||||
/**
|
||||
* Sets the loader resolver.
|
||||
*
|
||||
* @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
|
||||
*/
|
||||
public function setResolver(LoaderResolverInterface $resolver);
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?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\Config\Loader;
|
||||
|
||||
/**
|
||||
* LoaderResolver selects a loader for a given resource.
|
||||
*
|
||||
* A resource can be anything (e.g. a full path to a config file or a Closure).
|
||||
* Each loader determines whether it can load a resource and how.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class LoaderResolver implements LoaderResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var LoaderInterface[] An array of LoaderInterface objects
|
||||
*/
|
||||
private $loaders = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param LoaderInterface[] $loaders An array of loaders
|
||||
*/
|
||||
public function __construct(array $loaders = array())
|
||||
{
|
||||
foreach ($loaders as $loader) {
|
||||
$this->addLoader($loader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolve($resource, $type = null)
|
||||
{
|
||||
foreach ($this->loaders as $loader) {
|
||||
if ($loader->supports($resource, $type)) {
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a loader.
|
||||
*
|
||||
* @param LoaderInterface $loader A LoaderInterface instance
|
||||
*/
|
||||
public function addLoader(LoaderInterface $loader)
|
||||
{
|
||||
$this->loaders[] = $loader;
|
||||
$loader->setResolver($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered loaders.
|
||||
*
|
||||
* @return LoaderInterface[] An array of LoaderInterface instances
|
||||
*/
|
||||
public function getLoaders()
|
||||
{
|
||||
return $this->loaders;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Config\Loader;
|
||||
|
||||
/**
|
||||
* LoaderResolverInterface selects a loader for a given resource.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface LoaderResolverInterface
|
||||
{
|
||||
/**
|
||||
* Returns a loader able to load the resource.
|
||||
*
|
||||
* @param mixed $resource A resource
|
||||
* @param string|null $type The resource type or null if unknown
|
||||
*
|
||||
* @return LoaderInterface|false The loader or false if none is able to load the resource
|
||||
*/
|
||||
public function resolve($resource, $type = null);
|
||||
}
|
17
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/README.md
vendored
Normal file
17
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/README.md
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
Config Component
|
||||
================
|
||||
|
||||
Config provides the infrastructure for loading configurations from different
|
||||
data sources and optionally monitoring these data sources for changes. There
|
||||
are additional tools for validating, normalizing and handling of defaults that
|
||||
can optionally be used to convert from different formats to arrays.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/Config/
|
||||
$ composer install
|
||||
$ phpunit
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<?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\Config\Resource;
|
||||
|
||||
/**
|
||||
* DirectoryResource represents a resources stored in a subdirectory tree.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DirectoryResource implements ResourceInterface, \Serializable
|
||||
{
|
||||
private $resource;
|
||||
private $pattern;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $resource The file path to the resource
|
||||
* @param string|null $pattern A pattern to restrict monitored files
|
||||
*/
|
||||
public function __construct($resource, $pattern = null)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
$this->pattern = $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pattern to restrict monitored files.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPattern()
|
||||
{
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
if (!is_dir($this->resource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$newestMTime = filemtime($this->resource);
|
||||
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
|
||||
// if regex filtering is enabled only check matching files
|
||||
if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// always monitor directories for changes, except the .. entries
|
||||
// (otherwise deleted files wouldn't get detected)
|
||||
if ($file->isDir() && '/..' === substr($file, -3)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newestMTime = max($file->getMTime(), $newestMTime);
|
||||
}
|
||||
|
||||
return $newestMTime < $timestamp;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array($this->resource, $this->pattern));
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list($this->resource, $this->pattern) = unserialize($serialized);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?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\Config\Resource;
|
||||
|
||||
/**
|
||||
* FileResource represents a resource stored on the filesystem.
|
||||
*
|
||||
* The resource can be a file or a directory.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FileResource implements ResourceInterface, \Serializable
|
||||
{
|
||||
/**
|
||||
* @var string|false
|
||||
*/
|
||||
private $resource;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $resource The file path to the resource
|
||||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = realpath($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
if (false === $this->resource || !file_exists($this->resource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return filemtime($this->resource) <= $timestamp;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->resource);
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$this->resource = unserialize($serialized);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?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\Config\Resource;
|
||||
|
||||
/**
|
||||
* ResourceInterface is the interface that must be implemented by all Resource classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface ResourceInterface
|
||||
{
|
||||
/**
|
||||
* Returns a string representation of the Resource.
|
||||
*
|
||||
* @return string A string representation of the Resource
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Returns true if the resource has not been updated since the given timestamp.
|
||||
*
|
||||
* @param int $timestamp The last time the resource was loaded
|
||||
*
|
||||
* @return bool True if the resource has not been updated, false otherwise
|
||||
*/
|
||||
public function isFresh($timestamp);
|
||||
|
||||
/**
|
||||
* Returns the tied resource.
|
||||
*
|
||||
* @return mixed The resource
|
||||
*/
|
||||
public function getResource();
|
||||
}
|
238
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Util/XmlUtils.php
vendored
Normal file
238
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/Util/XmlUtils.php
vendored
Normal file
|
@ -0,0 +1,238 @@
|
|||
<?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\Config\Util;
|
||||
|
||||
/**
|
||||
* XMLUtils is a bunch of utility methods to XML operations.
|
||||
*
|
||||
* This class contains static methods only and is not meant to be instantiated.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Martin Hasoň <martin.hason@gmail.com>
|
||||
*/
|
||||
class XmlUtils
|
||||
{
|
||||
/**
|
||||
* This class should not be instantiated.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an XML file.
|
||||
*
|
||||
* @param string $file An XML file path
|
||||
* @param string|callable|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation
|
||||
*
|
||||
* @return \DOMDocument
|
||||
*
|
||||
* @throws \InvalidArgumentException When loading of XML file returns error
|
||||
*/
|
||||
public static function loadFile($file, $schemaOrCallable = null)
|
||||
{
|
||||
$content = @file_get_contents($file);
|
||||
if ('' === trim($content)) {
|
||||
throw new \InvalidArgumentException(sprintf('File %s does not contain valid XML, it is empty.', $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($content, LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
|
||||
libxml_disable_entity_loader($disableEntities);
|
||||
|
||||
throw new \InvalidArgumentException(implode("\n", static::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.');
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $schemaOrCallable) {
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
libxml_clear_errors();
|
||||
|
||||
$e = null;
|
||||
if (is_callable($schemaOrCallable)) {
|
||||
try {
|
||||
$valid = call_user_func($schemaOrCallable, $dom, $internalErrors);
|
||||
} catch (\Exception $e) {
|
||||
$valid = false;
|
||||
}
|
||||
} elseif (!is_array($schemaOrCallable) && is_file((string) $schemaOrCallable)) {
|
||||
$schemaSource = file_get_contents((string) $schemaOrCallable);
|
||||
$valid = @$dom->schemaValidateSource($schemaSource);
|
||||
} else {
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
|
||||
throw new \InvalidArgumentException('The schemaOrCallable argument has to be a valid path to XSD file or callable.');
|
||||
}
|
||||
|
||||
if (!$valid) {
|
||||
$messages = static::getXmlErrors($internalErrors);
|
||||
if (empty($messages)) {
|
||||
$messages = array(sprintf('The XML file "%s" is not valid.', $file));
|
||||
}
|
||||
throw new \InvalidArgumentException(implode("\n", $messages), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param bool $checkPrefix Check prefix in an element or an attribute name
|
||||
*
|
||||
* @return array A PHP array
|
||||
*/
|
||||
public static function convertDomElementToArray(\DomElement $element, $checkPrefix = true)
|
||||
{
|
||||
$prefix = (string) $element->prefix;
|
||||
$empty = true;
|
||||
$config = array();
|
||||
foreach ($element->attributes as $name => $node) {
|
||||
if ($checkPrefix && !in_array((string) $node->prefix, array('', $prefix), true)) {
|
||||
continue;
|
||||
}
|
||||
$config[$name] = static::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 ($checkPrefix && $prefix != (string) $node->prefix) {
|
||||
continue;
|
||||
} elseif (!$node instanceof \DOMComment) {
|
||||
$value = static::convertDomElementToArray($node, $checkPrefix);
|
||||
|
||||
$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 = static::phpize($nodeValue);
|
||||
if (count($config)) {
|
||||
$config['value'] = $value;
|
||||
} else {
|
||||
$config = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return !$empty ? $config : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
case ctype_digit($value):
|
||||
$raw = $value;
|
||||
$cast = (int) $value;
|
||||
|
||||
return '0' == $value[0] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
|
||||
case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)):
|
||||
$raw = $value;
|
||||
$cast = (int) $value;
|
||||
|
||||
return '0' == $value[1] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
|
||||
case 'true' === $lowercaseValue:
|
||||
return true;
|
||||
case 'false' === $lowercaseValue:
|
||||
return false;
|
||||
case isset($value[1]) && '0b' == $value[0].$value[1]:
|
||||
return bindec($value);
|
||||
case is_numeric($value):
|
||||
return '0x' === $value[0].$value[1] ? hexdec($value) : (float) $value;
|
||||
case preg_match('/^0x[0-9a-f]++$/i', $value):
|
||||
return hexdec($value);
|
||||
case preg_match('/^(-|\+)?[0-9]+(\.[0-9]+)?$/', $value):
|
||||
return (float) $value;
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
protected static 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 ?: 'n/a',
|
||||
$error->line,
|
||||
$error->column
|
||||
);
|
||||
}
|
||||
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
35
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/composer.json
vendored
Normal file
35
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/composer.json
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "symfony/config",
|
||||
"type": "library",
|
||||
"description": "Symfony Config Component",
|
||||
"keywords": [],
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/filesystem": "~2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Symfony\\Component\\Config\\": "" }
|
||||
},
|
||||
"target-dir": "Symfony/Component/Config",
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.6-dev"
|
||||
}
|
||||
}
|
||||
}
|
28
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/phpunit.xml.dist
vendored
Normal file
28
sites/all/modules/civicrm/vendor/symfony/config/Symfony/Component/Config/phpunit.xml.dist
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Symfony Config Component Test Suite">
|
||||
<directory>./Tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./</directory>
|
||||
<exclude>
|
||||
<directory>./Resources</directory>
|
||||
<directory>./Tests</directory>
|
||||
<directory>./vendor</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
|
@ -0,0 +1,3 @@
|
|||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
|
@ -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 bool $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 bool
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isPublic()
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this Alias is public.
|
||||
*
|
||||
* @param bool $boolean If this Alias should be public
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setPublic($boolean)
|
||||
{
|
||||
$this->public = (bool) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id of this alias.
|
||||
*
|
||||
* @return string The alias id
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.6.0
|
||||
-----
|
||||
|
||||
* added new factory syntax and deprecated the old one
|
||||
|
||||
2.5.0
|
||||
-----
|
||||
|
||||
* added DecoratorServicePass and a way to override a service definition (Definition::setDecoratedService())
|
||||
* deprecated SimpleXMLElement class.
|
||||
|
||||
2.4.0
|
||||
-----
|
||||
|
||||
* added support for expressions in service definitions
|
||||
* added ContainerAwareTrait to add default container aware behavior to a class
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* added Extension::isConfigEnabled() to ease working with enableable configurations
|
||||
* added an Extension base class with sensible defaults to be used in conjunction
|
||||
with the Config component.
|
||||
* added PrependExtensionInterface (to be able to allow extensions to prepend
|
||||
application configuration settings for any Bundle)
|
||||
|
||||
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,154 @@
|
|||
<?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 bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
|
||||
*/
|
||||
public function __construct($onlyConstructorArguments = false)
|
||||
{
|
||||
$this->onlyConstructorArguments = (bool) $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 ($definition->getFactoryService()) {
|
||||
$this->processArguments(array(new Reference($definition->getFactoryService())));
|
||||
}
|
||||
if (is_array($definition->getFactory())) {
|
||||
$this->processArguments($definition->getFactory());
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
if (is_array($argument->getFactory())) {
|
||||
$this->processArguments($argument->getFactory());
|
||||
}
|
||||
if ($argument->getFactoryService()) {
|
||||
$this->processArguments(array(new Reference($argument->getFactoryService())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?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 $currentPath;
|
||||
private $checkedNodes;
|
||||
|
||||
/**
|
||||
* Checks the ContainerBuilder object for circular references.
|
||||
*
|
||||
* @param ContainerBuilder $container The ContainerBuilder instances
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$graph = $container->getCompiler()->getServiceReferenceGraph();
|
||||
|
||||
$this->checkedNodes = array();
|
||||
foreach ($graph->getNodes() as $id => $node) {
|
||||
$this->currentPath = array($id);
|
||||
|
||||
$this->checkOutEdges($node->getOutEdges());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for circular references.
|
||||
*
|
||||
* @param ServiceReferenceGraphEdge[] $edges An array of Edges
|
||||
*
|
||||
* @throws ServiceCircularReferenceException When a circular reference is found.
|
||||
*/
|
||||
private function checkOutEdges(array $edges)
|
||||
{
|
||||
foreach ($edges as $edge) {
|
||||
$node = $edge->getDestNode();
|
||||
$id = $node->getId();
|
||||
|
||||
if (empty($this->checkedNodes[$id])) {
|
||||
$searchKey = array_search($id, $this->currentPath);
|
||||
$this->currentPath[] = $id;
|
||||
|
||||
if (false !== $searchKey) {
|
||||
throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
|
||||
}
|
||||
|
||||
$this->checkOutEdges($node->getOutEdges());
|
||||
|
||||
$this->checkedNodes[$id] = true;
|
||||
array_pop($this->currentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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\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));
|
||||
}
|
||||
|
||||
if ($definition->getFactory() && ($definition->getFactoryClass() || $definition->getFactoryService() || $definition->getFactoryMethod())) {
|
||||
throw new RuntimeException(sprintf('A service ("%s") can use either the old or the new factory syntax, not both.', $id));
|
||||
}
|
||||
|
||||
// non-synthetic, non-abstract service has class
|
||||
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
|
||||
if ($definition->getFactory() || $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
|
||||
));
|
||||
}
|
||||
|
||||
// tag attribute values must be scalars
|
||||
foreach ($definition->getTags() as $name => $tags) {
|
||||
foreach ($tags as $attributes) {
|
||||
foreach ($attributes as $attribute => $value) {
|
||||
if (!is_scalar($value) && null !== $value) {
|
||||
throw new RuntimeException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s".', $id, $name, $attribute));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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\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,166 @@
|
|||
<?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 $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 = isset($children[$scope]) ? $children[$scope] : array();
|
||||
$this->currentScopeAncestors = isset($ancestors[$scope]) ? $ancestors[$scope] : array();
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
return $this->container->getDefinition($id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<?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;
|
||||
|
||||
/**
|
||||
* 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 = array();
|
||||
private $loggingFormatter;
|
||||
private $serviceReferenceGraph;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->passConfig = new PassConfig();
|
||||
$this->serviceReferenceGraph = new ServiceReferenceGraph();
|
||||
$this->loggingFormatter = new LoggingFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,54 @@
|
|||
<?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\Alias;
|
||||
|
||||
/**
|
||||
* Overwrites a service but keeps the overridden one.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DecoratorServicePass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if (!$decorated = $definition->getDecoratedService()) {
|
||||
continue;
|
||||
}
|
||||
$definition->setDecoratedService(null);
|
||||
|
||||
list($inner, $renamedId) = $decorated;
|
||||
if (!$renamedId) {
|
||||
$renamedId = $id.'.inner';
|
||||
}
|
||||
|
||||
// we create a new alias/service for the service we are replacing
|
||||
// to be able to reference it in the new one
|
||||
if ($container->hasAlias($inner)) {
|
||||
$alias = $container->getAlias($inner);
|
||||
$public = $alias->isPublic();
|
||||
$container->setAlias($renamedId, new Alias((string) $alias, false));
|
||||
} else {
|
||||
$definition = $container->getDefinition($inner);
|
||||
$public = $definition->isPublic();
|
||||
$definition->setPublic(false);
|
||||
$container->setDefinition($renamedId, $definition);
|
||||
}
|
||||
|
||||
$container->setAlias($inner, new Alias($id, $public));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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\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 bool If the definition is inlineable
|
||||
*/
|
||||
private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
|
||||
{
|
||||
if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($definition->isPublic() || $definition->isLazy()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->graph->hasNode($id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->currentId == $id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
|
||||
$ids[] = $edge->getSourceNode()->getId();
|
||||
}
|
||||
|
||||
if (count(array_unique($ids)) > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($ids) > 1 && is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($ids) > 1 && $definition->getFactoryService()) {
|
||||
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,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\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
$exprLangProviders = $container->getExpressionLanguageProviders();
|
||||
|
||||
foreach ($container->getExtensions() as $extension) {
|
||||
if ($extension instanceof PrependExtensionInterface) {
|
||||
$extension->prepend($container);
|
||||
}
|
||||
}
|
||||
|
||||
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->setResourceTracking($container->isTrackingResources());
|
||||
$tmpContainer->addObjectResource($extension);
|
||||
|
||||
foreach ($exprLangProviders as $provider) {
|
||||
$tmpContainer->addExpressionLanguageProvider($provider);
|
||||
}
|
||||
|
||||
$extension->load($config, $tmpContainer);
|
||||
|
||||
$container->merge($tmpContainer);
|
||||
$container->getParameterBag()->add($parameters);
|
||||
}
|
||||
|
||||
$container->addDefinitions($definitions);
|
||||
$container->addAliases($aliases);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
<?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 = array();
|
||||
private $beforeOptimizationPasses = array();
|
||||
private $beforeRemovingPasses = array();
|
||||
private $optimizationPasses;
|
||||
private $removingPasses;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->mergePass = new MergeExtensionConfigurationPass();
|
||||
|
||||
$this->optimizationPasses = array(
|
||||
new ResolveDefinitionTemplatesPass(),
|
||||
new DecoratorServicePass(),
|
||||
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,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\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,88 @@
|
|||
<?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
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $repeat = false;
|
||||
|
||||
/**
|
||||
* @var RepeatablePassInterface[]
|
||||
*/
|
||||
private $passes;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RepeatablePassInterface[] $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 RepeatablePassInterface[] An array of RepeatablePassInterface objects
|
||||
*/
|
||||
public function getPasses()
|
||||
{
|
||||
return $this->passes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?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;
|
||||
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
|
||||
*
|
||||
* @throws InvalidArgumentException if the service definition does not exist
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->compiler = $container->getCompiler();
|
||||
$this->formatter = $this->compiler->getLoggingFormatter();
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
$aliasId = (string) $alias;
|
||||
|
||||
try {
|
||||
$definition = $container->getDefinition($aliasId);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with "%s".', $alias, $id), null, $e);
|
||||
}
|
||||
|
||||
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,166 @@
|
|||
<?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 ($container->getDefinitions() as $id => $definition) {
|
||||
// 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->setFactory($parentDef->getFactory());
|
||||
$def->setConfigurator($parentDef->getConfigurator());
|
||||
$def->setFile($parentDef->getFile());
|
||||
$def->setPublic($parentDef->isPublic());
|
||||
$def->setLazy($parentDef->isLazy());
|
||||
|
||||
// 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['factory'])) {
|
||||
$def->setFactory($definition->getFactory());
|
||||
}
|
||||
if (isset($changes['configurator'])) {
|
||||
$def->setConfigurator($definition->getConfigurator());
|
||||
}
|
||||
if (isset($changes['file'])) {
|
||||
$def->setFile($definition->getFile());
|
||||
}
|
||||
if (isset($changes['public'])) {
|
||||
$def->setPublic($definition->isPublic());
|
||||
}
|
||||
if (isset($changes['lazy'])) {
|
||||
$def->setLazy($definition->isLazy());
|
||||
}
|
||||
if (isset($changes['decorated_service'])) {
|
||||
$decoratedService = $definition->getDecoratedService();
|
||||
if (null === $decoratedService) {
|
||||
$def->setDecoratedService($decoratedService);
|
||||
} else {
|
||||
$def->setDecoratedService($decoratedService[0], $decoratedService[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = (int) 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,105 @@
|
|||
<?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 $e) {
|
||||
// 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 $e) {
|
||||
// ignore property
|
||||
}
|
||||
}
|
||||
$definition->setProperties($properties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes arguments to determine invalid references.
|
||||
*
|
||||
* @param array $arguments An array of Reference objects
|
||||
* @param bool $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::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,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\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
|
||||
*/
|
||||
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()));
|
||||
$definition->setFactoryClass($parameterBag->resolveValue($definition->getFactoryClass()));
|
||||
|
||||
$factory = $definition->getFactory();
|
||||
|
||||
if (is_array($factory) && isset($factory[0])) {
|
||||
$factory[0] = $parameterBag->resolveValue($factory[0]);
|
||||
$definition->setFactory($factory);
|
||||
}
|
||||
|
||||
$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,99 @@
|
|||
<?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\Exception\ServiceCircularReferenceException;
|
||||
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)
|
||||
{
|
||||
$seen = array();
|
||||
while ($this->container->hasAlias($id)) {
|
||||
if (isset($seen[$id])) {
|
||||
throw new ServiceCircularReferenceException($id, array_keys($seen));
|
||||
}
|
||||
$seen[$id] = true;
|
||||
$id = (string) $this->container->getAlias($id);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
<?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
|
||||
{
|
||||
/**
|
||||
* @var ServiceReferenceGraphNode[]
|
||||
*/
|
||||
private $nodes = array();
|
||||
|
||||
/**
|
||||
* Checks if the graph has a specific node.
|
||||
*
|
||||
* @param string $id Id to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
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 ServiceReferenceGraphNode[] 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,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\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 = array();
|
||||
private $outEdges = array();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 bool 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 bool 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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,574 @@
|
|||
<?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\InactiveScopeException;
|
||||
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
|
||||
{
|
||||
/**
|
||||
* @var ParameterBagInterface
|
||||
*/
|
||||
protected $parameterBag;
|
||||
|
||||
protected $services = array();
|
||||
protected $methodMap = array();
|
||||
protected $aliases = array();
|
||||
protected $scopes = array();
|
||||
protected $scopeChildren = array();
|
||||
protected $scopedServices = array();
|
||||
protected $scopeStacks = array();
|
||||
protected $loading = array();
|
||||
|
||||
private $underscoreMap = array('_' => '', '.' => '_', '\\' => '_');
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ParameterBagInterface $parameterBag A ParameterBagInterface instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(ParameterBagInterface $parameterBag = null)
|
||||
{
|
||||
$this->parameterBag = $parameterBag ?: new ParameterBag();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 bool 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 bool 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.
|
||||
*
|
||||
* Setting a service to null resets the service: has() returns false and get()
|
||||
* behaves in the same way as if the service was never created.
|
||||
*
|
||||
* @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(sprintf('You cannot set service "%s" of scope "prototype".', $id));
|
||||
}
|
||||
|
||||
$id = strtolower($id);
|
||||
|
||||
if ('service_container' === $id) {
|
||||
// BC: 'service_container' is no longer a self-reference but always
|
||||
// $this, so ignore this call.
|
||||
// @todo Throw InvalidArgumentException in next major release.
|
||||
return;
|
||||
}
|
||||
if (self::SCOPE_CONTAINER !== $scope) {
|
||||
if (!isset($this->scopedServices[$scope])) {
|
||||
throw new RuntimeException(sprintf('You cannot set service "%s" of inactive scope.', $id));
|
||||
}
|
||||
|
||||
$this->scopedServices[$scope][$id] = $service;
|
||||
}
|
||||
|
||||
$this->services[$id] = $service;
|
||||
|
||||
if (method_exists($this, $method = 'synchronize'.strtr($id, $this->underscoreMap).'Service')) {
|
||||
$this->$method();
|
||||
}
|
||||
|
||||
if (null === $service) {
|
||||
if (self::SCOPE_CONTAINER !== $scope) {
|
||||
unset($this->scopedServices[$scope][$id]);
|
||||
}
|
||||
|
||||
unset($this->services[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given service is defined.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return bool true if the service is defined, false otherwise
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function has($id)
|
||||
{
|
||||
for ($i = 2;;) {
|
||||
if ('service_container' === $id
|
||||
|| isset($this->aliases[$id])
|
||||
|| isset($this->services[$id])
|
||||
|| array_key_exists($id, $this->services)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (--$i && $id !== $lcId = strtolower($id)) {
|
||||
$id = $lcId;
|
||||
} else {
|
||||
return method_exists($this, 'get'.strtr($id, $this->underscoreMap).'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 int $invalidBehavior The behavior when the service does not exist
|
||||
*
|
||||
* @return object The associated service
|
||||
*
|
||||
* @throws ServiceCircularReferenceException When a circular reference is detected
|
||||
* @throws ServiceNotFoundException When the service is not defined
|
||||
* @throws \Exception if an exception has been thrown when the service has been resolved
|
||||
*
|
||||
* @see Reference
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
|
||||
{
|
||||
// Attempt to retrieve the service by checking first aliases then
|
||||
// available services. Service IDs are case insensitive, however since
|
||||
// this method can be called thousands of times during a request, avoid
|
||||
// calling strtolower() unless necessary.
|
||||
for ($i = 2;;) {
|
||||
if ('service_container' === $id) {
|
||||
return $this;
|
||||
}
|
||||
if (isset($this->aliases[$id])) {
|
||||
$id = $this->aliases[$id];
|
||||
}
|
||||
// Re-use shared service instance if it exists.
|
||||
if (isset($this->services[$id]) || array_key_exists($id, $this->services)) {
|
||||
return $this->services[$id];
|
||||
}
|
||||
|
||||
if (isset($this->loading[$id])) {
|
||||
throw new ServiceCircularReferenceException($id, array_keys($this->loading));
|
||||
}
|
||||
|
||||
if (isset($this->methodMap[$id])) {
|
||||
$method = $this->methodMap[$id];
|
||||
} elseif (--$i && $id !== $lcId = strtolower($id)) {
|
||||
$id = $lcId;
|
||||
continue;
|
||||
} elseif (method_exists($this, $method = 'get'.strtr($id, $this->underscoreMap).'Service')) {
|
||||
// $method is set to the right value, proceed
|
||||
} else {
|
||||
if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
if (!$id) {
|
||||
throw new ServiceNotFoundException($id);
|
||||
}
|
||||
|
||||
$alternatives = array();
|
||||
foreach ($this->services as $key => $associatedService) {
|
||||
$lev = levenshtein($id, $key);
|
||||
if ($lev <= strlen($id) / 3 || false !== strpos($key, $id)) {
|
||||
$alternatives[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ServiceNotFoundException($id, null, null, $alternatives);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loading[$id] = true;
|
||||
|
||||
try {
|
||||
$service = $this->$method();
|
||||
} catch (\Exception $e) {
|
||||
unset($this->loading[$id]);
|
||||
|
||||
if (array_key_exists($id, $this->services)) {
|
||||
unset($this->services[$id]);
|
||||
}
|
||||
|
||||
if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
unset($this->loading[$id]);
|
||||
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given service has actually been initialized.
|
||||
*
|
||||
* @param string $id The service identifier
|
||||
*
|
||||
* @return bool true if service has already been initialized, false otherwise
|
||||
*/
|
||||
public function initialized($id)
|
||||
{
|
||||
$id = strtolower($id);
|
||||
|
||||
if ('service_container' === $id) {
|
||||
// BC: 'service_container' was a synthetic service previously.
|
||||
// @todo Change to false in next major release.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($this->aliases[$id])) {
|
||||
$id = $this->aliases[$id];
|
||||
}
|
||||
|
||||
return isset($this->services[$id]) || array_key_exists($id, $this->services);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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]);
|
||||
}
|
||||
}
|
||||
$ids[] = 'service_container';
|
||||
|
||||
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) {
|
||||
if (isset($this->scopedServices[$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])) {
|
||||
$services[] = $this->scopedServices[$child];
|
||||
unset($this->scopedServices[$child]);
|
||||
}
|
||||
}
|
||||
|
||||
// update global map
|
||||
$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;
|
||||
|
||||
if ($this->scopeStacks[$name]->isEmpty()) {
|
||||
unset($this->scopeStacks[$name]);
|
||||
}
|
||||
|
||||
foreach ($services as $array) {
|
||||
foreach ($array as $id => $service) {
|
||||
$this->set($id, $service, $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a scope to the container.
|
||||
*
|
||||
* @param ScopeInterface $scope
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @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 bool
|
||||
*
|
||||
* @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 bool
|
||||
*
|
||||
* @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 strtr(ucwords(strtr($id, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|null $container A ContainerInterface instance or null
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container = null);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?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;
|
||||
|
||||
/**
|
||||
* ContainerAware trait.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
trait ContainerAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Sets the Container associated with this Controller.
|
||||
*
|
||||
* @param ContainerInterface $container A ContainerInterface instance
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,157 @@
|
|||
<?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 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 bool 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 bool 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 bool
|
||||
*
|
||||
* @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 bool
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isScopeActive($name);
|
||||
}
|
|
@ -0,0 +1,777 @@
|
|||
<?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 $factory;
|
||||
private $factoryClass;
|
||||
private $factoryMethod;
|
||||
private $factoryService;
|
||||
private $scope = ContainerInterface::SCOPE_CONTAINER;
|
||||
private $properties = array();
|
||||
private $calls = array();
|
||||
private $configurator;
|
||||
private $tags = array();
|
||||
private $public = true;
|
||||
private $synthetic = false;
|
||||
private $abstract = false;
|
||||
private $synchronized = false;
|
||||
private $lazy = false;
|
||||
private $decoratedService;
|
||||
|
||||
protected $arguments;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|null $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a factory.
|
||||
*
|
||||
* @param string|array $factory A PHP function or an array containing a class/Reference and a method to call
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function setFactory($factory)
|
||||
{
|
||||
if (is_string($factory) && strpos($factory, '::') !== false) {
|
||||
$factory = explode('::', $factory, 2);
|
||||
}
|
||||
|
||||
$this->factory = $factory;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory.
|
||||
*
|
||||
* @return string|array The PHP function or an array containing a class/Reference and a method to call
|
||||
*/
|
||||
public function getFactory()
|
||||
{
|
||||
return $this->factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @deprecated Deprecated since version 2.6, to be removed in 3.0.
|
||||
*/
|
||||
public function setFactoryClass($factoryClass)
|
||||
{
|
||||
$this->factoryClass = $factoryClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory class.
|
||||
*
|
||||
* @return string|null The factory class name
|
||||
*
|
||||
* @api
|
||||
* @deprecated Deprecated since version 2.6, to be removed in 3.0.
|
||||
*/
|
||||
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
|
||||
* @deprecated Deprecated since version 2.6, to be removed in 3.0.
|
||||
*/
|
||||
public function setFactoryMethod($factoryMethod)
|
||||
{
|
||||
$this->factoryMethod = $factoryMethod;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the service that this service is decorating.
|
||||
*
|
||||
* @param null|string $id The decorated service id, use null to remove decoration
|
||||
* @param null|string $renamedId The new decorated service id
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @throws InvalidArgumentException In case the decorated service id and the new decorated service id are equals.
|
||||
*/
|
||||
public function setDecoratedService($id, $renamedId = null)
|
||||
{
|
||||
if ($renamedId && $id == $renamedId) {
|
||||
throw new \InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
|
||||
}
|
||||
|
||||
if (null === $id) {
|
||||
$this->decoratedService = null;
|
||||
} else {
|
||||
$this->decoratedService = array($id, $renamedId);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service that decorates this service.
|
||||
*
|
||||
* @return null|array An array composed of the decorated service id and the new id for it, null if no service is decorated
|
||||
*/
|
||||
public function getDecoratedService()
|
||||
{
|
||||
return $this->decoratedService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory method.
|
||||
*
|
||||
* @return string|null The factory method name
|
||||
*
|
||||
* @api
|
||||
* @deprecated Deprecated since version 2.6, to be removed in 3.0.
|
||||
*/
|
||||
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
|
||||
* @deprecated Deprecated since version 2.6, to be removed in 3.0.
|
||||
*/
|
||||
public function setFactoryService($factoryService)
|
||||
{
|
||||
$this->factoryService = $factoryService;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the factory service id.
|
||||
*
|
||||
* @return string|null The factory service id
|
||||
*
|
||||
* @api
|
||||
* @deprecated Deprecated since version 2.6, to be removed in 3.0.
|
||||
*/
|
||||
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|null 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 int $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 int $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 bool
|
||||
*
|
||||
* @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 bool
|
||||
*
|
||||
* @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|null 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 bool $boolean
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setPublic($boolean)
|
||||
{
|
||||
$this->public = (bool) $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is public facing.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isPublic()
|
||||
{
|
||||
return $this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the synchronized flag of this service.
|
||||
*
|
||||
* @param bool $boolean
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setSynchronized($boolean)
|
||||
{
|
||||
$this->synchronized = (bool) $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is synchronized.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isSynchronized()
|
||||
{
|
||||
return $this->synchronized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lazy flag of this service.
|
||||
*
|
||||
* @param bool $lazy
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function setLazy($lazy)
|
||||
{
|
||||
$this->lazy = (bool) $lazy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this service is lazy.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isLazy()
|
||||
{
|
||||
return $this->lazy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this definition is synthetic, that is not constructed by the
|
||||
* container, but dynamically injected.
|
||||
*
|
||||
* @param bool $boolean
|
||||
*
|
||||
* @return Definition the current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setSynthetic($boolean)
|
||||
{
|
||||
$this->synthetic = (bool) $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is synthetic, that is not constructed by the
|
||||
* container, but dynamically injected.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function isSynthetic()
|
||||
{
|
||||
return $this->synthetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is abstract, that means it merely serves as a
|
||||
* template for other definitions.
|
||||
*
|
||||
* @param bool $boolean
|
||||
*
|
||||
* @return Definition the current instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setAbstract($boolean)
|
||||
{
|
||||
$this->abstract = (bool) $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this definition is abstract, that means it merely serves as a
|
||||
* template for other definitions.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @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|null The PHP callable to call
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getConfigurator()
|
||||
{
|
||||
return $this->configurator;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
<?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 = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $parent The id of Definition instance to decorate.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($parent)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->parent = $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
public function setFactory($callable)
|
||||
{
|
||||
$this->changes['factory'] = true;
|
||||
|
||||
return parent::setFactory($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function setLazy($boolean)
|
||||
{
|
||||
$this->changes['lazy'] = true;
|
||||
|
||||
return parent::setLazy($boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDecoratedService($id, $renamedId = null)
|
||||
{
|
||||
$this->changes['decorated_service'] = true;
|
||||
|
||||
return parent::setDecoratedService($id, $renamedId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 int $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 int $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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue