4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\ParameterBag;
14 use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
15 use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
16 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
21 * @author Fabien Potencier <fabien@symfony.com>
23 class ParameterBag implements ParameterBagInterface
25 protected $parameters = array();
26 protected $resolved = false;
29 * @param array $parameters An array of parameters
31 public function __construct(array $parameters = array())
33 $this->add($parameters);
37 * Clears all parameters.
39 public function clear()
41 $this->parameters = array();
45 * Adds parameters to the service container parameters.
47 * @param array $parameters An array of parameters
49 public function add(array $parameters)
51 foreach ($parameters as $key => $value) {
52 $this->parameters[strtolower($key)] = $value;
61 return $this->parameters;
67 public function get($name)
69 $name = strtolower($name);
71 if (!array_key_exists($name, $this->parameters)) {
73 throw new ParameterNotFoundException($name);
76 $alternatives = array();
77 foreach ($this->parameters as $key => $parameterValue) {
78 $lev = levenshtein($name, $key);
79 if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) {
80 $alternatives[] = $key;
84 $nonNestedAlternative = null;
85 if (!count($alternatives) && false !== strpos($name, '.')) {
86 $namePartsLength = array_map('strlen', explode('.', $name));
87 $key = substr($name, 0, -1 * (1 + array_pop($namePartsLength)));
88 while (count($namePartsLength)) {
89 if ($this->has($key)) {
90 if (is_array($this->get($key))) {
91 $nonNestedAlternative = $key;
96 $key = substr($key, 0, -1 * (1 + array_pop($namePartsLength)));
100 throw new ParameterNotFoundException($name, null, null, null, $alternatives, $nonNestedAlternative);
103 return $this->parameters[$name];
107 * Sets a service container parameter.
109 * @param string $name The parameter name
110 * @param mixed $value The parameter value
112 public function set($name, $value)
114 $this->parameters[strtolower($name)] = $value;
120 public function has($name)
122 return array_key_exists(strtolower($name), $this->parameters);
126 * Removes a parameter.
128 * @param string $name The parameter name
130 public function remove($name)
132 unset($this->parameters[strtolower($name)]);
138 public function resolve()
140 if ($this->resolved) {
144 $parameters = array();
145 foreach ($this->parameters as $key => $value) {
147 $value = $this->resolveValue($value);
148 $parameters[$key] = $this->unescapeValue($value);
149 } catch (ParameterNotFoundException $e) {
150 $e->setSourceKey($key);
156 $this->parameters = $parameters;
157 $this->resolved = true;
161 * Replaces parameter placeholders (%name%) by their values.
163 * @param mixed $value A value
164 * @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
166 * @return mixed The resolved value
168 * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
169 * @throws ParameterCircularReferenceException if a circular reference if detected
170 * @throws RuntimeException when a given parameter has a type problem.
172 public function resolveValue($value, array $resolving = array())
174 if (is_array($value)) {
176 foreach ($value as $k => $v) {
177 $args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving);
183 if (!is_string($value)) {
187 return $this->resolveString($value, $resolving);
191 * Resolves parameters inside a string.
193 * @param string $value The string to resolve
194 * @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
196 * @return string The resolved string
198 * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
199 * @throws ParameterCircularReferenceException if a circular reference if detected
200 * @throws RuntimeException when a given parameter has a type problem.
202 public function resolveString($value, array $resolving = array())
204 // we do this to deal with non string values (Boolean, integer, ...)
205 // as the preg_replace_callback throw an exception when trying
206 // a non-string in a parameter value
207 if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
209 $lcKey = strtolower($key);
211 if (isset($resolving[$lcKey])) {
212 throw new ParameterCircularReferenceException(array_keys($resolving));
215 $resolving[$lcKey] = true;
217 return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
220 return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($resolving, $value) {
222 if (!isset($match[1])) {
227 $lcKey = strtolower($key);
228 if (isset($resolving[$lcKey])) {
229 throw new ParameterCircularReferenceException(array_keys($resolving));
232 $resolved = $this->get($key);
234 if (!is_string($resolved) && !is_numeric($resolved)) {
235 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));
238 $resolved = (string) $resolved;
239 $resolving[$lcKey] = true;
241 return $this->isResolved() ? $resolved : $this->resolveString($resolved, $resolving);
245 public function isResolved()
247 return $this->resolved;
253 public function escapeValue($value)
255 if (is_string($value)) {
256 return str_replace('%', '%%', $value);
259 if (is_array($value)) {
261 foreach ($value as $k => $v) {
262 $result[$k] = $this->escapeValue($v);
274 public function unescapeValue($value)
276 if (is_string($value)) {
277 return str_replace('%%', '%', $value);
280 if (is_array($value)) {
282 foreach ($value as $k => $v) {
283 $result[$k] = $this->unescapeValue($v);