Skip to content

Commit b2c94d8

Browse files
committed
Merge branch '7.4' into 8.0
* 7.4: use PHPUnit attributes instead of annotations [WebProfilerBundle] Add link to `xdebug_info()` to config panel issue fix #59412 catalan translation [DependencyInjection][Routing] Define array-shapes to help writing PHP configs using yaml-like arrays [HttpFoundation] Make `Request::createFromGlobals()` use `request_parse_body` when possible
2 parents 9bdb146 + ac4e4da commit b2c94d8

19 files changed

+544
-175
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ CHANGELOG
2525
* Allow multiple `#[AsDecorator]` attributes
2626
* Handle returning arrays and config-builders from config files
2727
* Handle declaring services using PHP arrays that follow the same shape as corresponding yaml files
28+
* Add `ServicesConfig` to help writing PHP configs using yaml-like array-shapes
2829
* Deprecate using `$this` or its internal scope from PHP config files; use the `$loader` variable instead
2930
* Deprecate XML configuration format, use YAML or PHP instead
3031
* Deprecate `ExtensionInterface::getXsdValidationBasePath()` and `getNamespace()`

Loader/Config/ServicesConfig.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Config;
13+
14+
use Symfony\Component\DependencyInjection\ContainerInterface;
15+
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
16+
use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator;
17+
use Symfony\Component\DependencyInjection\Reference;
18+
use Symfony\Component\ExpressionLanguage\Expression;
19+
20+
require_once __DIR__.\DIRECTORY_SEPARATOR.'functions.php';
21+
22+
/**
23+
* @psalm-type Arguments = list<mixed>|array<string, mixed>
24+
* @psalm-type Callback = string|array{0:string|Reference|ReferenceConfigurator,1:string}|\Closure|Reference|ReferenceConfigurator|Expression
25+
* @psalm-type Tags = list<string|array<string, array<string, mixed>>>
26+
* @psalm-type Deprecation = array{package: string, version: string, message?: string}
27+
* @psalm-type Call = array<string, Arguments>|array{0:string, 1?:Arguments, 2?:bool}|array{method:string, arguments?:Arguments, returns_clone?:bool}
28+
* @psalm-type Imports = list<string|array{
29+
* resource: string,
30+
* type?: string|null,
31+
* ignore_errors?: bool,
32+
* }>
33+
* @psalm-type Parameters = array<string, scalar|\UnitEnum|array<scalar|\UnitEnum|array|null>|null>
34+
* @psalm-type Defaults = array{
35+
* public?: bool,
36+
* tags?: Tags,
37+
* resource_tags?: Tags,
38+
* autowire?: bool,
39+
* autoconfigure?: bool,
40+
* bind?: array<string, mixed>,
41+
* }
42+
* @psalm-type Instanceof = array{
43+
* shared?: bool,
44+
* lazy?: bool|string,
45+
* public?: bool,
46+
* properties?: array<string, mixed>,
47+
* configurator?: Callback,
48+
* calls?: list<Call>,
49+
* tags?: Tags,
50+
* resource_tags?: Tags,
51+
* autowire?: bool,
52+
* bind?: array<string, mixed>,
53+
* constructor?: string,
54+
* }
55+
* @psalm-type Definition = array{
56+
* class?: string,
57+
* file?: string,
58+
* parent?: string,
59+
* shared?: bool,
60+
* synthetic?: bool,
61+
* lazy?: bool|string,
62+
* public?: bool,
63+
* abstract?: bool,
64+
* deprecated?: Deprecation,
65+
* factory?: Callback,
66+
* configurator?: Callback,
67+
* arguments?: Arguments,
68+
* properties?: array<string, mixed>,
69+
* calls?: list<Call>,
70+
* tags?: Tags,
71+
* resource_tags?: Tags,
72+
* decorates?: string,
73+
* decoration_inner_name?: string,
74+
* decoration_priority?: int,
75+
* decoration_on_invalid?: 'exception'|'ignore'|null|ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE|ContainerInterface::IGNORE_ON_INVALID_REFERENCE|ContainerInterface::NULL_ON_INVALID_REFERENCE,
76+
* autowire?: bool,
77+
* autoconfigure?: bool,
78+
* bind?: array<string, mixed>,
79+
* constructor?: string,
80+
* from_callable?: mixed,
81+
* }
82+
* @psalm-type Alias = string|array{
83+
* alias: string,
84+
* public?: bool,
85+
* deprecated?: Deprecation,
86+
* }
87+
* @psalm-type Prototype = array{
88+
* resource: string,
89+
* namespace?: string,
90+
* exclude?: string|list<string>,
91+
* parent?: string,
92+
* shared?: bool,
93+
* lazy?: bool|string,
94+
* public?: bool,
95+
* abstract?: bool,
96+
* deprecated?: Deprecation,
97+
* factory?: Callback,
98+
* arguments?: Arguments,
99+
* properties?: array<string, mixed>,
100+
* configurator?: Callback,
101+
* calls?: list<Call>,
102+
* tags?: Tags,
103+
* resource_tags?: Tags,
104+
* autowire?: bool,
105+
* autoconfigure?: bool,
106+
* bind?: array<string, mixed>,
107+
* constructor?: string,
108+
* }
109+
* @psalm-type Stack = array{
110+
* stack: list<Definition|Alias|Prototype|array<class-string, Arguments|null>>,
111+
* public?: bool,
112+
* deprecated?: Deprecation,
113+
* }
114+
* @psalm-type Services = array<string, Definition|Alias|Prototype|Stack>|array<class-string, Arguments|null>
115+
*/
116+
class ServicesConfig
117+
{
118+
public readonly array $services;
119+
120+
/**
121+
* @param Services $services
122+
* @param Imports $imports
123+
* @param Parameters $parameters
124+
* @param Defaults $defaults
125+
* @param Instanceof $instanceof
126+
*/
127+
public function __construct(
128+
array $services = [],
129+
public readonly array $imports = [],
130+
public readonly array $parameters = [],
131+
array $defaults = [],
132+
array $instanceof = [],
133+
) {
134+
if (isset($services['_defaults']) || isset($services['_instanceof'])) {
135+
throw new InvalidArgumentException('The $services argument should not contain "_defaults" or "_instanceof" keys, use the $defaults and $instanceof parameters instead.');
136+
}
137+
138+
$services['_defaults'] = $defaults;
139+
$services['_instanceof'] = $instanceof;
140+
$this->services = $services;
141+
}
142+
}

Loader/Config/functions.php

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Config;
13+
14+
use Symfony\Component\Config\Loader\ParamConfigurator;
15+
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
16+
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
17+
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
18+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
19+
use Symfony\Component\DependencyInjection\Definition;
20+
use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator;
21+
use Symfony\Component\DependencyInjection\Loader\Configurator\ClosureReferenceConfigurator;
22+
use Symfony\Component\DependencyInjection\Loader\Configurator\EnvConfigurator;
23+
use Symfony\Component\DependencyInjection\Loader\Configurator\InlineServiceConfigurator;
24+
use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator;
25+
use Symfony\Component\ExpressionLanguage\Expression;
26+
27+
/**
28+
* Creates a parameter.
29+
*/
30+
function param(string $name): ParamConfigurator
31+
{
32+
return new ParamConfigurator($name);
33+
}
34+
35+
/**
36+
* Creates a reference to a service.
37+
*/
38+
function service(string $serviceId): ReferenceConfigurator
39+
{
40+
return new ReferenceConfigurator($serviceId);
41+
}
42+
43+
/**
44+
* Creates an inline service.
45+
*/
46+
function inline_service(?string $class = null): InlineServiceConfigurator
47+
{
48+
return new InlineServiceConfigurator(new Definition($class));
49+
}
50+
51+
/**
52+
* Creates a service locator.
53+
*
54+
* @param array<ReferenceConfigurator|InlineServiceConfigurator> $values
55+
*/
56+
function service_locator(array $values): ServiceLocatorArgument
57+
{
58+
$values = AbstractConfigurator::processValue($values, true);
59+
60+
return new ServiceLocatorArgument($values);
61+
}
62+
63+
/**
64+
* Creates a lazy iterator.
65+
*
66+
* @param ReferenceConfigurator[] $values
67+
*/
68+
function iterator(array $values): IteratorArgument
69+
{
70+
return new IteratorArgument(AbstractConfigurator::processValue($values, true));
71+
}
72+
73+
/**
74+
* Creates a lazy iterator by tag name.
75+
*/
76+
function tagged_iterator(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, ?string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): TaggedIteratorArgument
77+
{
78+
return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod, (array) $exclude, $excludeSelf);
79+
}
80+
81+
/**
82+
* Creates a service locator by tag name.
83+
*/
84+
function tagged_locator(string $tag, ?string $indexAttribute = null, ?string $defaultIndexMethod = null, ?string $defaultPriorityMethod = null, string|array $exclude = [], bool $excludeSelf = true): ServiceLocatorArgument
85+
{
86+
return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, true, $defaultPriorityMethod, (array) $exclude, $excludeSelf));
87+
}
88+
89+
/**
90+
* Creates an expression.
91+
*/
92+
function expr(string $expression): Expression
93+
{
94+
return new Expression($expression);
95+
}
96+
97+
/**
98+
* Creates an abstract argument.
99+
*/
100+
function abstract_arg(string $description): AbstractArgument
101+
{
102+
return new AbstractArgument($description);
103+
}
104+
105+
/**
106+
* Creates an environment variable reference.
107+
*/
108+
function env(string $name): EnvConfigurator
109+
{
110+
return new EnvConfigurator($name);
111+
}
112+
113+
/**
114+
* Creates a closure service reference.
115+
*/
116+
function service_closure(string $serviceId): ClosureReferenceConfigurator
117+
{
118+
return new ClosureReferenceConfigurator($serviceId);
119+
}
120+
121+
/**
122+
* Creates a closure.
123+
*/
124+
function closure(string|array|\Closure|ReferenceConfigurator|Expression $callable): InlineServiceConfigurator
125+
{
126+
return (new InlineServiceConfigurator(new Definition('Closure')))
127+
->factory(['Closure', 'fromCallable'])
128+
->args([$callable]);
129+
}

Loader/Configurator/AbstractConfigurator.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ public static function processValue(mixed $value, bool $allowServices = false):
101101
case $value instanceof \UnitEnum:
102102
return $value;
103103

104+
case $value instanceof \Closure:
105+
return self::processClosure($value);
106+
104107
case $value instanceof ArgumentInterface:
105108
case $value instanceof Definition:
106109
case $value instanceof Expression:
@@ -120,7 +123,7 @@ public static function processValue(mixed $value, bool $allowServices = false):
120123
*
121124
* @throws InvalidArgumentException if the closure is anonymous or references a non-static method
122125
*/
123-
final public static function processClosure(\Closure $closure): callable
126+
private static function processClosure(\Closure $closure): callable
124127
{
125128
$function = new \ReflectionFunction($closure);
126129
if ($function->isAnonymous()) {

0 commit comments

Comments
 (0)