Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\DependencyInjection\ParameterBag; Chris@0: Chris@0: use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; Chris@0: use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException; Chris@0: use Symfony\Component\DependencyInjection\Exception\RuntimeException; Chris@0: Chris@0: /** Chris@0: * Holds parameters. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: */ Chris@0: class ParameterBag implements ParameterBagInterface Chris@0: { Chris@0: protected $parameters = array(); Chris@0: protected $resolved = false; Chris@0: Chris@0: /** Chris@0: * @param array $parameters An array of parameters Chris@0: */ Chris@0: public function __construct(array $parameters = array()) Chris@0: { Chris@0: $this->add($parameters); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Clears all parameters. Chris@0: */ Chris@0: public function clear() Chris@0: { Chris@0: $this->parameters = array(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds parameters to the service container parameters. Chris@0: * Chris@0: * @param array $parameters An array of parameters Chris@0: */ Chris@0: public function add(array $parameters) Chris@0: { Chris@0: foreach ($parameters as $key => $value) { Chris@0: $this->parameters[strtolower($key)] = $value; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function all() Chris@0: { Chris@0: return $this->parameters; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function get($name) Chris@0: { Chris@0: $name = strtolower($name); Chris@0: Chris@0: if (!array_key_exists($name, $this->parameters)) { Chris@0: if (!$name) { Chris@0: throw new ParameterNotFoundException($name); Chris@0: } Chris@0: Chris@0: $alternatives = array(); Chris@0: foreach ($this->parameters as $key => $parameterValue) { Chris@0: $lev = levenshtein($name, $key); Chris@0: if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) { Chris@0: $alternatives[] = $key; Chris@0: } Chris@0: } Chris@0: Chris@0: $nonNestedAlternative = null; Chris@0: if (!count($alternatives) && false !== strpos($name, '.')) { Chris@0: $namePartsLength = array_map('strlen', explode('.', $name)); Chris@0: $key = substr($name, 0, -1 * (1 + array_pop($namePartsLength))); Chris@0: while (count($namePartsLength)) { Chris@0: if ($this->has($key)) { Chris@0: if (is_array($this->get($key))) { Chris@0: $nonNestedAlternative = $key; Chris@0: } Chris@0: break; Chris@0: } Chris@0: Chris@0: $key = substr($key, 0, -1 * (1 + array_pop($namePartsLength))); Chris@0: } Chris@0: } Chris@0: Chris@0: throw new ParameterNotFoundException($name, null, null, null, $alternatives, $nonNestedAlternative); Chris@0: } Chris@0: Chris@0: return $this->parameters[$name]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets a service container parameter. Chris@0: * Chris@0: * @param string $name The parameter name Chris@0: * @param mixed $value The parameter value Chris@0: */ Chris@0: public function set($name, $value) Chris@0: { Chris@0: $this->parameters[strtolower($name)] = $value; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function has($name) Chris@0: { Chris@0: return array_key_exists(strtolower($name), $this->parameters); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes a parameter. Chris@0: * Chris@0: * @param string $name The parameter name Chris@0: */ Chris@0: public function remove($name) Chris@0: { Chris@0: unset($this->parameters[strtolower($name)]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function resolve() Chris@0: { Chris@0: if ($this->resolved) { Chris@0: return; Chris@0: } Chris@0: Chris@0: $parameters = array(); Chris@0: foreach ($this->parameters as $key => $value) { Chris@0: try { Chris@0: $value = $this->resolveValue($value); Chris@0: $parameters[$key] = $this->unescapeValue($value); Chris@0: } catch (ParameterNotFoundException $e) { Chris@0: $e->setSourceKey($key); Chris@0: Chris@0: throw $e; Chris@0: } Chris@0: } Chris@0: Chris@0: $this->parameters = $parameters; Chris@0: $this->resolved = true; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Replaces parameter placeholders (%name%) by their values. Chris@0: * Chris@0: * @param mixed $value A value Chris@0: * @param array $resolving An array of keys that are being resolved (used internally to detect circular references) Chris@0: * Chris@0: * @return mixed The resolved value Chris@0: * Chris@0: * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist Chris@0: * @throws ParameterCircularReferenceException if a circular reference if detected Chris@0: * @throws RuntimeException when a given parameter has a type problem. Chris@0: */ Chris@0: public function resolveValue($value, array $resolving = array()) Chris@0: { Chris@0: if (is_array($value)) { Chris@0: $args = array(); Chris@0: foreach ($value as $k => $v) { Chris@0: $args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving); Chris@0: } Chris@0: Chris@0: return $args; Chris@0: } Chris@0: Chris@0: if (!is_string($value)) { Chris@0: return $value; Chris@0: } Chris@0: Chris@0: return $this->resolveString($value, $resolving); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Resolves parameters inside a string. Chris@0: * Chris@0: * @param string $value The string to resolve Chris@0: * @param array $resolving An array of keys that are being resolved (used internally to detect circular references) Chris@0: * Chris@0: * @return string The resolved string Chris@0: * Chris@0: * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist Chris@0: * @throws ParameterCircularReferenceException if a circular reference if detected Chris@0: * @throws RuntimeException when a given parameter has a type problem. Chris@0: */ Chris@0: public function resolveString($value, array $resolving = array()) Chris@0: { Chris@0: // we do this to deal with non string values (Boolean, integer, ...) Chris@0: // as the preg_replace_callback throw an exception when trying Chris@0: // a non-string in a parameter value Chris@0: if (preg_match('/^%([^%\s]+)%$/', $value, $match)) { Chris@0: $key = $match[1]; Chris@0: $lcKey = strtolower($key); Chris@0: Chris@0: if (isset($resolving[$lcKey])) { Chris@0: throw new ParameterCircularReferenceException(array_keys($resolving)); Chris@0: } Chris@0: Chris@0: $resolving[$lcKey] = true; Chris@0: Chris@0: return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving); Chris@0: } Chris@0: Chris@0: return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($resolving, $value) { Chris@0: // skip %% Chris@0: if (!isset($match[1])) { Chris@0: return '%%'; Chris@0: } Chris@0: Chris@0: $key = $match[1]; Chris@0: $lcKey = strtolower($key); Chris@0: if (isset($resolving[$lcKey])) { Chris@0: throw new ParameterCircularReferenceException(array_keys($resolving)); Chris@0: } Chris@0: Chris@0: $resolved = $this->get($key); Chris@0: Chris@0: if (!is_string($resolved) && !is_numeric($resolved)) { Chris@0: throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, gettype($resolved), $value)); Chris@0: } Chris@0: Chris@0: $resolved = (string) $resolved; Chris@0: $resolving[$lcKey] = true; Chris@0: Chris@0: return $this->isResolved() ? $resolved : $this->resolveString($resolved, $resolving); Chris@0: }, $value); Chris@0: } Chris@0: Chris@0: public function isResolved() Chris@0: { Chris@0: return $this->resolved; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function escapeValue($value) Chris@0: { Chris@0: if (is_string($value)) { Chris@0: return str_replace('%', '%%', $value); Chris@0: } Chris@0: Chris@0: if (is_array($value)) { Chris@0: $result = array(); Chris@0: foreach ($value as $k => $v) { Chris@0: $result[$k] = $this->escapeValue($v); Chris@0: } Chris@0: Chris@0: return $result; Chris@0: } Chris@0: Chris@0: return $value; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function unescapeValue($value) Chris@0: { Chris@0: if (is_string($value)) { Chris@0: return str_replace('%%', '%', $value); Chris@0: } Chris@0: Chris@0: if (is_array($value)) { Chris@0: $result = array(); Chris@0: foreach ($value as $k => $v) { Chris@0: $result[$k] = $this->unescapeValue($v); Chris@0: } Chris@0: Chris@0: return $result; Chris@0: } Chris@0: Chris@0: return $value; Chris@0: } Chris@0: }