Merge branch '5.3' into 5.4
* 5.3: [HttpClient] Remove deprecated usage of `GuzzleHttp\Promise\queue` [PropertyAccess] Fix handling of uninitialized property of anonymous class [FrameworkBundle] Allow default cache pools to be overwritten by user [DependencyInjection] fix test ResolveBindingsPass remove loading of class iterable [FrameworkBundle] Avoid calling rtrim(null, '/') in AssetsInstallCommand [DependencyInjection] Fix nested env var with resolve processor Allow OutputFormatter::escape() to be used for escaping URLs used in <href> allow a zero time-limit [DependencyInjection] Ignore argument type check in CheckTypeDeclarationsPass if it's a Definition with a factory [Validators] Add translations for Slovak #43735
This commit is contained in:
commit
bbe4105fe9
|
@ -96,8 +96,7 @@ EOT
|
|||
{
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$targetArg = rtrim($input->getArgument('target'), '/');
|
||||
|
||||
$targetArg = rtrim($input->getArgument('target') ?? '', '/');
|
||||
if (!$targetArg) {
|
||||
$targetArg = $this->getPublicDirectory($kernel->getContainer());
|
||||
}
|
||||
|
|
|
@ -341,34 +341,10 @@ class FrameworkExtension extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
// register cache before session so both can share the connection services
|
||||
$this->registerCacheConfiguration($config['cache'], $container);
|
||||
|
||||
if ($this->isConfigEnabled($container, $config['session'])) {
|
||||
if (!\extension_loaded('session')) {
|
||||
throw new LogicException('Session support cannot be enabled as the session extension is not installed. See https://php.net/session.installation for instructions.');
|
||||
}
|
||||
|
||||
$this->sessionConfigEnabled = true;
|
||||
$this->registerSessionConfiguration($config['session'], $container, $loader);
|
||||
if (!empty($config['test'])) {
|
||||
// test listener will replace the existing session listener
|
||||
// as we are aliasing to avoid duplicated registered events
|
||||
$container->setAlias('session_listener', 'test.session.listener');
|
||||
}
|
||||
} elseif (!empty($config['test'])) {
|
||||
$container->removeDefinition('test.session.listener');
|
||||
}
|
||||
|
||||
if ($this->isConfigEnabled($container, $config['request'])) {
|
||||
$this->registerRequestConfiguration($config['request'], $container, $loader);
|
||||
}
|
||||
|
||||
if (null === $config['csrf_protection']['enabled']) {
|
||||
$config['csrf_protection']['enabled'] = $this->sessionConfigEnabled && !class_exists(FullStack::class) && ContainerBuilder::willBeAvailable('symfony/security-csrf', CsrfTokenManagerInterface::class, ['symfony/framework-bundle'], true);
|
||||
}
|
||||
$this->registerSecurityCsrfConfiguration($config['csrf_protection'], $container, $loader);
|
||||
|
||||
if ($this->isConfigEnabled($container, $config['form'])) {
|
||||
if (!class_exists(Form::class)) {
|
||||
throw new LogicException('Form support cannot be enabled as the Form component is not installed. Try running "composer require symfony/form".');
|
||||
|
@ -501,6 +477,31 @@ class FrameworkExtension extends Extension
|
|||
$this->registerUidConfiguration($config['uid'], $container, $loader);
|
||||
}
|
||||
|
||||
// register cache before session so both can share the connection services
|
||||
$this->registerCacheConfiguration($config['cache'], $container);
|
||||
|
||||
if ($this->isConfigEnabled($container, $config['session'])) {
|
||||
if (!\extension_loaded('session')) {
|
||||
throw new LogicException('Session support cannot be enabled as the session extension is not installed. See https://php.net/session.installation for instructions.');
|
||||
}
|
||||
|
||||
$this->sessionConfigEnabled = true;
|
||||
$this->registerSessionConfiguration($config['session'], $container, $loader);
|
||||
if (!empty($config['test'])) {
|
||||
// test listener will replace the existing session listener
|
||||
// as we are aliasing to avoid duplicated registered events
|
||||
$container->setAlias('session_listener', 'test.session.listener');
|
||||
}
|
||||
} elseif (!empty($config['test'])) {
|
||||
$container->removeDefinition('test.session.listener');
|
||||
}
|
||||
|
||||
// csrf depends on session being registered
|
||||
if (null === $config['csrf_protection']['enabled']) {
|
||||
$config['csrf_protection']['enabled'] = $this->sessionConfigEnabled && !class_exists(FullStack::class) && ContainerBuilder::willBeAvailable('symfony/security-csrf', CsrfTokenManagerInterface::class, ['symfony/framework-bundle'], true);
|
||||
}
|
||||
$this->registerSecurityCsrfConfiguration($config['csrf_protection'], $container, $loader);
|
||||
|
||||
$this->addAnnotatedClassesToCompile([
|
||||
'**\\Controller\\',
|
||||
'**\\Entity\\',
|
||||
|
|
|
@ -34,13 +34,13 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Escapes "<" special char in given text.
|
||||
* Escapes "<" and ">" special chars in given text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function escape(string $text)
|
||||
{
|
||||
$text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
|
||||
$text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text);
|
||||
|
||||
return self::escapeTrailingBackslash($text);
|
||||
}
|
||||
|
@ -142,9 +142,10 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
|||
{
|
||||
$offset = 0;
|
||||
$output = '';
|
||||
$tagRegex = '[a-z][^<>]*+';
|
||||
$openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
|
||||
$closeTagRegex = '[a-z][^<>]*+';
|
||||
$currentLineLength = 0;
|
||||
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
|
||||
preg_match_all("#<(($openTagRegex) | /($closeTagRegex)?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE);
|
||||
foreach ($matches[0] as $i => $match) {
|
||||
$pos = $match[1];
|
||||
$text = $match[0];
|
||||
|
@ -178,11 +179,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
|||
|
||||
$output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength);
|
||||
|
||||
if (str_contains($output, "\0")) {
|
||||
return strtr($output, ["\0" => '\\', '\\<' => '<']);
|
||||
}
|
||||
|
||||
return str_replace('\\<', '<', $output);
|
||||
return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,7 +213,8 @@ class OutputFormatter implements WrappableOutputFormatterInterface
|
|||
} elseif ('bg' == $match[0]) {
|
||||
$style->setBackground(strtolower($match[1]));
|
||||
} elseif ('href' === $match[0]) {
|
||||
$style->setHref($match[1]);
|
||||
$url = preg_replace('{\\\\([<>])}', '$1', $match[1]);
|
||||
$style->setHref($url);
|
||||
} elseif ('options' === $match[0]) {
|
||||
preg_match_all('([^,;]+)', strtolower($match[1]), $options);
|
||||
$options = array_shift($options);
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
command 2 description
|
||||
|
||||
<comment>Usage:</comment>
|
||||
descriptor:command2 [options] [--] \<argument_name>
|
||||
descriptor:command2 -o|--option_name \<argument_name>
|
||||
descriptor:command2 \<argument_name>
|
||||
descriptor:command2 [options] [--] \<argument_name\>
|
||||
descriptor:command2 -o|--option_name \<argument_name\>
|
||||
descriptor:command2 \<argument_name\>
|
||||
|
||||
<comment>Arguments:</comment>
|
||||
<info>argument_name</info>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
command åèä description
|
||||
|
||||
<comment>Usage:</comment>
|
||||
descriptor:åèä [options] [--] \<argument_åèä>
|
||||
descriptor:åèä -o|--option_name \<argument_name>
|
||||
descriptor:åèä \<argument_name>
|
||||
descriptor:åèä [options] [--] \<argument_åèä\>
|
||||
descriptor:åèä -o|--option_name \<argument_name\>
|
||||
descriptor:åèä \<argument_name\>
|
||||
|
||||
<comment>Arguments:</comment>
|
||||
<info>argument_åèä</info>
|
||||
|
|
|
@ -1 +1 @@
|
|||
<info>argument_name</info> argument description<comment> [default: "\<comment>style\</>"]</comment>
|
||||
<info>argument_name</info> argument description<comment> [default: "\<comment\>style\</\>"]</comment>
|
||||
|
|
|
@ -1 +1 @@
|
|||
<info>-o, --option_name=OPTION_NAME</info> option description<comment> [default: "\<comment>style\</>"]</comment>
|
||||
<info>-o, --option_name=OPTION_NAME</info> option description<comment> [default: "\<comment\>style\</\>"]</comment>
|
||||
|
|
|
@ -1 +1 @@
|
|||
<info>-o, --option_name=OPTION_NAME</info> option description<comment> [default: ["\<comment>Hello\</comment>","\<info>world\</info>"]]</comment><comment> (multiple values allowed)</comment>
|
||||
<info>-o, --option_name=OPTION_NAME</info> option description<comment> [default: ["\<comment\>Hello\</comment\>","\<info\>world\</info\>"]]</comment><comment> (multiple values allowed)</comment>
|
||||
|
|
|
@ -32,7 +32,10 @@ class OutputFormatterTest extends TestCase
|
|||
$this->assertEquals('foo << bar \\', $formatter->format('foo << bar \\'));
|
||||
$this->assertEquals("foo << \033[32mbar \\ baz\033[39m \\", $formatter->format('foo << <info>bar \\ baz</info> \\'));
|
||||
$this->assertEquals('<info>some info</info>', $formatter->format('\\<info>some info\\</info>'));
|
||||
$this->assertEquals('\\<info>some info\\</info>', OutputFormatter::escape('<info>some info</info>'));
|
||||
$this->assertEquals('\\<info\\>some info\\</info\\>', OutputFormatter::escape('<info>some info</info>'));
|
||||
// every < and > gets escaped if not already escaped, but already escaped ones do not get escaped again
|
||||
// and escaped backslashes remain as such, same with backslashes escaping non-special characters
|
||||
$this->assertEquals('foo \\< bar \\< baz \\\\< foo \\> bar \\> baz \\\\> \\x', OutputFormatter::escape('foo < bar \\< baz \\\\< foo > bar \\> baz \\\\> \\x'));
|
||||
|
||||
$this->assertEquals(
|
||||
"\033[33mSymfony\\Component\\Console does work very well!\033[39m",
|
||||
|
@ -264,6 +267,7 @@ class OutputFormatterTest extends TestCase
|
|||
['<question>some question</question>', 'some question', "\033[30;46msome question\033[39;49m"],
|
||||
['<fg=red>some text with inline style</>', 'some text with inline style', "\033[31msome text with inline style\033[39m"],
|
||||
['<href=idea://open/?file=/path/SomeFile.php&line=12>some URL</>', 'some URL', "\033]8;;idea://open/?file=/path/SomeFile.php&line=12\033\\some URL\033]8;;\033\\"],
|
||||
['<href=https://example.com/\<woohoo\>>some URL with \<woohoo\></>', 'some URL with <woohoo>', "\033]8;;https://example.com/<woohoo>\033\\some URL with <woohoo>\033]8;;\033\\"],
|
||||
['<href=idea://open/?file=/path/SomeFile.php&line=12>some URL</>', 'some URL', 'some URL', 'JetBrains-JediTerm'],
|
||||
];
|
||||
}
|
||||
|
|
|
@ -83,9 +83,9 @@ class FormatterHelperTest extends TestCase
|
|||
$formatter = new FormatterHelper();
|
||||
|
||||
$this->assertEquals(
|
||||
'<error> </error>'."\n".
|
||||
'<error> \<info>some info\</info> </error>'."\n".
|
||||
'<error> </error>',
|
||||
'<error> </error>'."\n".
|
||||
'<error> \<info\>some info\</info\> </error>'."\n".
|
||||
'<error> </error>',
|
||||
$formatter->formatBlock('<info>some info</info>', 'error', true),
|
||||
'::formatBlock() escapes \'<\' chars'
|
||||
);
|
||||
|
|
|
@ -210,6 +210,10 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
|
|||
$class = null;
|
||||
|
||||
if ($value instanceof Definition) {
|
||||
if ($value->getFactory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class = $value->getClass();
|
||||
|
||||
if ($class && isset(self::BUILTIN_TYPES[strtolower($class)])) {
|
||||
|
|
|
@ -126,7 +126,7 @@ class ResolveBindingsPass extends AbstractRecursivePass
|
|||
$this->unusedBindings[$bindingId] = [$key, $this->currentId, $bindingType, $file];
|
||||
}
|
||||
|
||||
if (preg_match('/^(?:(?:array|bool|float|int|string|([^ $]++)) )\$/', $key, $m)) {
|
||||
if (preg_match('/^(?:(?:array|bool|float|int|string|iterable|([^ $]++)) )\$/', $key, $m)) {
|
||||
$bindingNames[substr($key, \strlen($m[0]))] = $binding;
|
||||
}
|
||||
|
||||
|
|
|
@ -272,11 +272,17 @@ class EnvVarProcessor implements EnvVarProcessorInterface
|
|||
}
|
||||
|
||||
if ('resolve' === $prefix) {
|
||||
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($name) {
|
||||
return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($name, $getEnv) {
|
||||
if (!isset($match[1])) {
|
||||
return '%';
|
||||
}
|
||||
$value = $this->container->getParameter($match[1]);
|
||||
|
||||
if (str_starts_with($match[1], 'env(') && str_ends_with($match[1], ')') && 'env()' !== $match[1]) {
|
||||
$value = $getEnv(substr($match[1], 4, -1));
|
||||
} else {
|
||||
$value = $this->container->getParameter($match[1]);
|
||||
}
|
||||
|
||||
if (!is_scalar($value)) {
|
||||
throw new RuntimeException(sprintf('Parameter "%s" found when resolving env var "%s" must be scalar, "%s" given.', $match[1], $name, get_debug_type($value)));
|
||||
}
|
||||
|
|
|
@ -996,6 +996,20 @@ class CheckTypeDeclarationsPassTest extends TestCase
|
|||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
public function testIgnoreDefinitionFactoryArgument()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('bar', Bar::class)
|
||||
->setArguments([
|
||||
(new Definition(Foo::class))
|
||||
->setFactory([Foo::class, 'createStdClass']),
|
||||
]);
|
||||
|
||||
(new CheckTypeDeclarationsPass())->process($container);
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
class CallableClass
|
||||
|
|
|
@ -28,6 +28,7 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
|
|||
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedEnumArgumentDummy;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedIterableArgumentDummy;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\WithTarget;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
@ -212,6 +213,28 @@ class ResolveBindingsPassTest extends TestCase
|
|||
$pass->process($container);
|
||||
}
|
||||
|
||||
public function testIterableBindingTypehint()
|
||||
{
|
||||
$autoloader = static function ($class) {
|
||||
if ('iterable' === $class) {
|
||||
throw new \RuntimeException('We should not search pseudo-type iterable as class');
|
||||
}
|
||||
};
|
||||
spl_autoload_register($autoloader);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$definition = $container->register('bar', NamedIterableArgumentDummy::class);
|
||||
$definition->setBindings([
|
||||
'iterable $items' => new TaggedIteratorArgument('foo'),
|
||||
]);
|
||||
$pass = new ResolveBindingsPass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertInstanceOf(TaggedIteratorArgument::class, $container->getDefinition('bar')->getArgument(0));
|
||||
|
||||
spl_autoload_unregister($autoloader);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 8
|
||||
*/
|
||||
|
|
|
@ -506,6 +506,109 @@ class EnvVarProcessorTest extends TestCase
|
|||
$this->assertEquals('foo', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validResolve
|
||||
*/
|
||||
public function testGetEnvResolve($value, $processed)
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('bar', $value);
|
||||
$container->compile();
|
||||
|
||||
$processor = new EnvVarProcessor($container);
|
||||
|
||||
$result = $processor->getEnv('resolve', 'foo', function () {
|
||||
return '%bar%';
|
||||
});
|
||||
|
||||
$this->assertSame($processed, $result);
|
||||
}
|
||||
|
||||
public function validResolve()
|
||||
{
|
||||
return [
|
||||
['string', 'string'],
|
||||
[1, '1'],
|
||||
[1.1, '1.1'],
|
||||
[true, '1'],
|
||||
[false, ''],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetEnvResolveNoMatch()
|
||||
{
|
||||
$processor = new EnvVarProcessor(new Container());
|
||||
|
||||
$result = $processor->getEnv('resolve', 'foo', function () {
|
||||
return '%%';
|
||||
});
|
||||
|
||||
$this->assertSame('%', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider notScalarResolve
|
||||
*/
|
||||
public function testGetEnvResolveNotScalar($value)
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->expectExceptionMessage('Parameter "bar" found when resolving env var "foo" must be scalar');
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('bar', $value);
|
||||
$container->compile();
|
||||
|
||||
$processor = new EnvVarProcessor($container);
|
||||
|
||||
$processor->getEnv('resolve', 'foo', function () {
|
||||
return '%bar%';
|
||||
});
|
||||
}
|
||||
|
||||
public function notScalarResolve()
|
||||
{
|
||||
return [
|
||||
[null],
|
||||
[[]],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetEnvResolveNestedEnv()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('env(BAR)', 'BAR in container');
|
||||
$container->compile();
|
||||
|
||||
$processor = new EnvVarProcessor($container);
|
||||
$getEnv = \Closure::fromCallable([$processor, 'getEnv']);
|
||||
|
||||
$result = $processor->getEnv('resolve', 'foo', function ($name) use ($getEnv) {
|
||||
return 'foo' === $name ? '%env(BAR)%' : $getEnv('string', $name, function () {});
|
||||
});
|
||||
|
||||
$this->assertSame('BAR in container', $result);
|
||||
}
|
||||
|
||||
public function testGetEnvResolveNestedRealEnv()
|
||||
{
|
||||
$_ENV['BAR'] = 'BAR in environment';
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('env(BAR)', 'BAR in container');
|
||||
$container->compile();
|
||||
|
||||
$processor = new EnvVarProcessor($container);
|
||||
$getEnv = \Closure::fromCallable([$processor, 'getEnv']);
|
||||
|
||||
$result = $processor->getEnv('resolve', 'foo', function ($name) use ($getEnv) {
|
||||
return 'foo' === $name ? '%env(BAR)%' : $getEnv('string', $name, function () {});
|
||||
});
|
||||
|
||||
$this->assertSame('BAR in environment', $result);
|
||||
|
||||
unset($_ENV['BAR']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validCsv
|
||||
*/
|
||||
|
|
|
@ -23,4 +23,9 @@ class Foo
|
|||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function createStdClass(): \stdClass
|
||||
{
|
||||
return new \stdClass();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<?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\Tests\Fixtures;
|
||||
|
||||
class NamedIterableArgumentDummy
|
||||
{
|
||||
public function __construct(iterable $items)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ namespace Symfony\Component\HttpClient;
|
|||
|
||||
use GuzzleHttp\Promise\Promise as GuzzlePromise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Promise\Utils;
|
||||
use Http\Client\Exception\NetworkException;
|
||||
use Http\Client\Exception\RequestException;
|
||||
use Http\Client\HttpAsyncClient;
|
||||
|
@ -75,7 +76,7 @@ final class HttplugClient implements HttplugInterface, HttpAsyncClient, RequestF
|
|||
$this->client = $client ?? HttpClient::create();
|
||||
$this->responseFactory = $responseFactory;
|
||||
$this->streamFactory = $streamFactory ?? ($responseFactory instanceof StreamFactoryInterface ? $responseFactory : null);
|
||||
$this->promisePool = \function_exists('GuzzleHttp\Promise\queue') ? new \SplObjectStorage() : null;
|
||||
$this->promisePool = class_exists(Utils::class) ? new \SplObjectStorage() : null;
|
||||
|
||||
if (null === $this->responseFactory || null === $this->streamFactory) {
|
||||
if (!class_exists(Psr17Factory::class) && !class_exists(Psr17FactoryDiscovery::class)) {
|
||||
|
|
|
@ -52,7 +52,7 @@ final class HttplugWaitLoop
|
|||
return 0;
|
||||
}
|
||||
|
||||
$guzzleQueue = \GuzzleHttp\Promise\queue();
|
||||
$guzzleQueue = \GuzzleHttp\Promise\Utils::queue();
|
||||
|
||||
if (0.0 === $remainingDuration = $maxDuration) {
|
||||
$idleTimeout = 0.0;
|
||||
|
|
|
@ -191,7 +191,7 @@ EOF
|
|||
$this->eventDispatcher->addSubscriber(new StopWorkerOnMemoryLimitListener($this->convertToBytes($memoryLimit), $this->logger));
|
||||
}
|
||||
|
||||
if ($timeLimit = $input->getOption('time-limit')) {
|
||||
if (null !== ($timeLimit = $input->getOption('time-limit'))) {
|
||||
$stopsWhen[] = "been running for {$timeLimit}s";
|
||||
$this->eventDispatcher->addSubscriber(new StopWorkerOnTimeLimitListener($timeLimit, $this->logger));
|
||||
}
|
||||
|
|
|
@ -482,11 +482,11 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||
}
|
||||
} catch (\Error $e) {
|
||||
// handle uninitialized properties in PHP >= 7.4
|
||||
if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ([\w\\\]+)::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) {
|
||||
$r = new \ReflectionProperty($matches[1], $matches[2]);
|
||||
if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ('.preg_quote(get_debug_type($object), '/').')::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) {
|
||||
$r = new \ReflectionProperty($class, $matches[2]);
|
||||
$type = ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type;
|
||||
|
||||
throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $type), 0, $e);
|
||||
throw new UninitializedPropertyException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $matches[1], $r->getName(), $type), 0, $e);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
|
|
|
@ -14,7 +14,6 @@ namespace Symfony\Component\PropertyAccess\Tests;
|
|||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\PropertyAccess\Exception\AccessException;
|
||||
use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
|
||||
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException;
|
||||
|
@ -191,7 +190,7 @@ class PropertyAccessorTest extends TestCase
|
|||
|
||||
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousClass()
|
||||
{
|
||||
$this->expectException(AccessException::class);
|
||||
$this->expectException(UninitializedPropertyException::class);
|
||||
$this->expectExceptionMessage('The method "class@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?');
|
||||
|
||||
$object = eval('return new class() {
|
||||
|
@ -206,9 +205,44 @@ class PropertyAccessorTest extends TestCase
|
|||
$this->propertyAccessor->getValue($object, 'uninitialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7.4
|
||||
*/
|
||||
public function testGetValueThrowsExceptionIfUninitializedNotNullablePropertyWithGetterOfAnonymousClass()
|
||||
{
|
||||
$this->expectException(UninitializedPropertyException::class);
|
||||
$this->expectExceptionMessage('The property "class@anonymous::$uninitialized" is not readable because it is typed "string". You should initialize it or declare a default value instead.');
|
||||
|
||||
$object = eval('return new class() {
|
||||
private string $uninitialized;
|
||||
|
||||
public function getUninitialized(): string
|
||||
{
|
||||
return $this->uninitialized;
|
||||
}
|
||||
};');
|
||||
|
||||
$this->propertyAccessor->getValue($object, 'uninitialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7.4
|
||||
*/
|
||||
public function testGetValueThrowsExceptionIfUninitializedPropertyOfAnonymousClass()
|
||||
{
|
||||
$this->expectException(UninitializedPropertyException::class);
|
||||
$this->expectExceptionMessage('The property "class@anonymous::$uninitialized" is not readable because it is typed "string". You should initialize it or declare a default value instead.');
|
||||
|
||||
$object = eval('return new class() {
|
||||
public string $uninitialized;
|
||||
};');
|
||||
|
||||
$this->propertyAccessor->getValue($object, 'uninitialized');
|
||||
}
|
||||
|
||||
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousStdClass()
|
||||
{
|
||||
$this->expectException(AccessException::class);
|
||||
$this->expectException(UninitializedPropertyException::class);
|
||||
$this->expectExceptionMessage('The method "stdClass@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?');
|
||||
|
||||
$object = eval('return new class() extends \stdClass {
|
||||
|
@ -225,7 +259,7 @@ class PropertyAccessorTest extends TestCase
|
|||
|
||||
public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousChildClass()
|
||||
{
|
||||
$this->expectException(AccessException::class);
|
||||
$this->expectException(UninitializedPropertyException::class);
|
||||
$this->expectExceptionMessage('The method "Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedPrivateProperty@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?');
|
||||
|
||||
$object = eval('return new class() extends \Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedPrivateProperty {};');
|
||||
|
|
|
@ -394,6 +394,14 @@
|
|||
<source>This value is not a valid CSS color.</source>
|
||||
<target>Táto hodnota nie je platná CSS farba.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="102">
|
||||
<source>This value is not a valid CIDR notation.</source>
|
||||
<target>Táto hodnota nie je platnou notáciou CIDR.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="103">
|
||||
<source>The value of the netmask should be between {{ min }} and {{ max }}.</source>
|
||||
<target>Hodnota masky siete by mala byť medzi {{ min }} a {{ max }}.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
Reference in New Issue