Skip to content
Snippets Groups Projects
Commit fb0bf2de authored by catch's avatar catch
Browse files

Issue #3031464 by fancyweb, alexpott: Services arguments with escaped "%" are not unescaped

parent 63148faa
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
......@@ -520,6 +520,11 @@ protected function resolveServicesAndParameters($arguments) {
continue;
}
elseif ($type == 'raw') {
$arguments[$key] = $argument->value;
continue;
}
if ($type !== NULL) {
throw new InvalidArgumentException(sprintf('Undefined type "%s" while resolving parameters and services.', $type));
......
......@@ -402,8 +402,22 @@ protected function dumpValue($value) {
elseif ($value instanceof Parameter) {
return $this->getParameterCall((string) $value);
}
elseif (is_string($value) && preg_match('/^\%(.*)\%$/', $value, $matches)) {
return $this->getParameterCall($matches[1]);
elseif (is_string($value) && FALSE !== strpos($value, '%')) {
if (preg_match('/^%([^%]+)%$/', $value, $matches)) {
return $this->getParameterCall($matches[1]);
}
else {
$replaceParameters = function ($matches) {
return $this->getParameterCall($matches[2]);
};
// We cannot directly return the string value because it would
// potentially not always be resolved in the dumpCollection() method.
return (object) [
'type' => 'raw',
'value' => str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, $value)),
];
}
}
elseif ($value instanceof Expression) {
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
......
......@@ -218,6 +218,11 @@ protected function resolveServicesAndParameters($arguments) {
continue;
}
elseif ($type == 'raw') {
$arguments[$key] = $argument->value;
continue;
}
if ($type !== NULL) {
throw new InvalidArgumentException("Undefined type '$type' while resolving parameters and services.");
......
......@@ -751,6 +751,17 @@ public function testGetServiceIds() {
$this->assertEquals($service_definition_keys, $this->container->getServiceIds(), 'Retrieved service IDs match definition after setting new services.');
}
/**
* Tests that raw type services arguments are resolved correctly.
*
* @covers ::get
* @covers ::createService
* @covers ::resolveServicesAndParameters
*/
public function testResolveServicesAndParametersForRawArgument() {
$this->assertEquals(['ccc'], $this->container->get('service_with_raw_argument')->getArguments());
}
/**
* Gets a mock container definition.
*
......@@ -1002,6 +1013,12 @@ protected function getMockContainerDefinition() {
'configurator' => 'configurator_service_test_does_not_exist',
];
// Raw argument
$services['service_with_raw_argument'] = [
'class' => '\Drupal\Tests\Component\DependencyInjection\MockInstantiationService',
'arguments' => $this->getCollection([$this->getRaw('ccc')]),
];
$aliases = [];
$aliases['service.provider_alias'] = 'service.provider';
$aliases['late.service_alias'] = 'late.service';
......@@ -1027,7 +1044,7 @@ protected function getServiceCall($id, $invalid_behavior = ContainerInterface::E
}
/**
* Helper function to return a service definition.
* Helper function to return a parameter definition.
*/
protected function getParameterCall($name) {
return (object) [
......@@ -1063,6 +1080,16 @@ protected function getCollection($collection, $resolve = TRUE) {
];
}
/**
* Helper function to return a raw value definition.
*/
protected function getRaw($value) {
return (object) [
'type' => 'raw',
'value' => $value,
];
}
}
/**
......
......@@ -620,6 +620,47 @@ public function testGetServiceDefinitionForResource() {
$this->dumper->getArray();
}
/**
* Tests that service arguments with escaped percents are correctly dumped.
*
* @dataProvider percentsEscapeProvider
*/
public function testPercentsEscape($expected, $argument) {
$this->containerBuilder->getDefinitions()->willReturn([
'test' => new Definition('\stdClass', [$argument]),
]);
$dump = $this->dumper->getArray();
$this->assertEquals($this->serializeDefinition([
'class' => '\stdClass',
'arguments' => $this->getCollection([
$this->getRaw($expected),
]),
'arguments_count' => 1,
]), $dump['services']['test']);
}
/**
* Data provider for testPercentsEscape().
*
* @return array[]
* Returns data-set elements with:
* - expected final value.
* - escaped value in service definition.
*/
public function percentsEscapeProvider() {
return [
['%foo%', '%%foo%%'],
['foo%bar%', 'foo%%bar%%'],
['%foo%bar', '%%foo%%bar'],
['%', '%'],
['%', '%%'],
['%%', '%%%'],
['%%', '%%%%'],
];
}
/**
* Helper function to return a private service definition.
*/
......@@ -657,6 +698,16 @@ protected function getParameterCall($name) {
];
}
/**
* Helper function to return a raw value definition.
*/
protected function getRaw($value) {
return (object) [
'type' => 'raw',
'value' => $value,
];
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment