-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[DependencyInjection] Introduce a new ParameterResolver #17192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Component\DependencyInjection\ParameterBag; | ||
|
||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; | ||
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException; | ||
use Symfony\Component\DependencyInjection\Exception\RuntimeException; | ||
|
||
/** | ||
* Implementation of {@link ParameterResolverInterface}. | ||
* | ||
* @author Fabien Potencier <fabien@symfony.com> | ||
* @author Guilhem N. <egetick@gmail.com> | ||
*/ | ||
trait ParameterResolverTrait | ||
{ | ||
/** | ||
* Replaces parameter placeholders (%name%) by their values. | ||
* | ||
* @param mixed $value A value | ||
* | ||
* @return mixed The resolved value | ||
* | ||
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist | ||
* @throws ParameterCircularReferenceException if a circular reference is detected | ||
* @throws RuntimeException when a given parameter has a type problem. | ||
*/ | ||
public function resolveValue($value, array $resolving = array()) | ||
{ | ||
if (is_array($value)) { | ||
$args = array(); | ||
foreach ($value as $k => $v) { | ||
$args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving); | ||
} | ||
|
||
return $args; | ||
} | ||
|
||
if (!is_string($value)) { | ||
return $value; | ||
} | ||
|
||
// we do this to deal with non string values (Boolean, integer, ...) | ||
// as the preg_replace_callback throw an exception when trying | ||
// a non-string in a parameter value | ||
if (preg_match('/^%([^%\s]+)%$/', $value, $match)) { | ||
$key = $match[1]; | ||
$lcKey = strtolower($key); | ||
|
||
if (isset($resolving[$lcKey])) { | ||
throw new ParameterCircularReferenceException(array_keys($resolving)); | ||
} | ||
|
||
$resolving[$lcKey] = true; | ||
|
||
return $this->getParameter($key, $resolving); | ||
} | ||
|
||
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($resolving, $value) { | ||
// skip %% | ||
if (!isset($match[1])) { | ||
return '%%'; | ||
} | ||
|
||
$key = $match[1]; | ||
$lcKey = strtolower($key); | ||
if (isset($resolving[$lcKey])) { | ||
throw new ParameterCircularReferenceException(array_keys($resolving)); | ||
} | ||
|
||
$resolving[$lcKey] = true; | ||
$resolved = $this->getParameter($key, $resolving); | ||
|
||
if (!is_string($resolved) && !is_numeric($resolved)) { | ||
throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, gettype($resolved), $value)); | ||
} | ||
|
||
return (string) $resolved; | ||
}, $value); | ||
} | ||
|
||
/** | ||
* Gets a parameter. | ||
* | ||
* @param string $name The parameter name | ||
* @param array $resolving used internally to detect circular references | ||
* | ||
* @return mixed The parameter value | ||
* | ||
* @throws ParameterNotFoundException if the parameter is not defined | ||
*/ | ||
abstract protected function getParameter($name, $resolving = array()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if this function should be named There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like having an abstract method in the trait. What about adding a private There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like it to work on top of a any container (and a container may not use |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo the public interface should not leak the
$resolving
argument (it's an implementation detail). We could add a private method that does the actual resolving an letresolveValue()
call it with an empty array as the second argument.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And by the way, the
ParameterResolverInterface
even doesn't require this second argument.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine for me.
Besides that, I'm wondering if we shouldn't make this method private by default: in userland it is unlikely to be used outside the class using the trait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: I agree, but we can't do that for bc reasons, see our previous conversation