Merge branch '4.4' into 5.0
* 4.4: [Debug] fix ClassNotFoundFatalErrorHandler [Routing] Fix using a custom matcher & generator dumper class [Serializer] Fix cache in MetadataAwareNameConverter [Dotenv] Fixed infinite loop with missing quote followed by quoted value [HttpClient] Added missing sprintf [TwigBridge] button_widget now has its title attr translated even if its label = null or false [PhpUnitBridge] When using phpenv + phpenv-composer plugin, composer executable is wrapped into a bash script [Messenger] Added check if json_encode succeeded [Messenger] Added check if json_encode succeeded [FrameworkBundle][ContainerLintCommand] Only skip .errored. services [HttpClient] fix exception in case of PSR17 discovery failure [DependencyInjection] Handle ServiceClosureArgument for callable in container linting fix processing chain adapter based cache pool [HttpKernel] release lock explicitly [Security] Prevent canceled remember-me cookie from being accepted [FrameworkBundle][TranslationUpdateCommand] Do not output positive feedback on stderr [Security\Guard] Fix missing typehints do not render preferred choices as selected
This commit is contained in:
commit
d65de0f772
@ -192,15 +192,15 @@ HttpKernel
|
||||
|
||||
* The `Kernel::getRootDir()` and the `kernel.root_dir` parameter have been deprecated
|
||||
* The `KernelInterface::getName()` and the `kernel.name` parameter have been deprecated
|
||||
* Deprecated the first and second constructor argument of `ConfigDataCollector`
|
||||
* Deprecated `ConfigDataCollector::getApplicationName()`
|
||||
* Deprecated the first and second constructor argument of `ConfigDataCollector`
|
||||
* Deprecated `ConfigDataCollector::getApplicationName()`
|
||||
* Deprecated `ConfigDataCollector::getApplicationVersion()`
|
||||
|
||||
Messenger
|
||||
---------
|
||||
|
||||
* The `MiddlewareInterface::handle()` and `SenderInterface::send()` methods must now return an `Envelope` instance.
|
||||
* The return value of handlers isn't forwarded anymore by middleware and buses.
|
||||
* The return value of handlers isn't forwarded anymore by middleware and buses.
|
||||
If you used to return a value, e.g in query bus handlers, you can either:
|
||||
- get the result from the `HandledStamp` in the envelope returned by the bus.
|
||||
- use the `HandleTrait` to leverage a message bus, expecting a single, synchronous message handling and returning its result.
|
||||
@ -214,15 +214,15 @@ Messenger
|
||||
$query->setResult($yourResult);
|
||||
```
|
||||
* The `EnvelopeAwareInterface` was removed and the `MiddlewareInterface::handle()` method now requires an `Envelope` object
|
||||
as first argument. When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
|
||||
If you use your own `MessageBusInterface` implementation, you must wrap the message in an `Envelope` before passing it to middleware.
|
||||
as first argument. When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
|
||||
If you use your own `MessageBusInterface` implementation, you must wrap the message in an `Envelope` before passing it to middleware.
|
||||
If you created your own middleware, you must change the signature to always expect an `Envelope`.
|
||||
* The `MiddlewareInterface::handle()` second argument (`callable $next`) has changed in favor of a `StackInterface` instance.
|
||||
When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
|
||||
If you use your own `MessageBusInterface` implementation, you can use the `StackMiddleware` implementation.
|
||||
When using built-in middleware with the provided `MessageBus`, you will not have to do anything.
|
||||
If you use your own `MessageBusInterface` implementation, you can use the `StackMiddleware` implementation.
|
||||
If you created your own middleware, you must change the signature to always expect an `StackInterface` instance
|
||||
and call `$stack->next()->handle($envelope, $stack)` instead of `$next` to call the next middleware:
|
||||
|
||||
|
||||
Before:
|
||||
```php
|
||||
public function handle($message, callable $next): Envelope
|
||||
@ -230,7 +230,7 @@ Messenger
|
||||
// do something before
|
||||
$message = $next($message);
|
||||
// do something after
|
||||
|
||||
|
||||
return $message;
|
||||
}
|
||||
```
|
||||
@ -242,7 +242,7 @@ Messenger
|
||||
// do something before
|
||||
$envelope = $stack->next()->handle($envelope, $stack);
|
||||
// do something after
|
||||
|
||||
|
||||
return $envelope;
|
||||
}
|
||||
```
|
||||
@ -251,7 +251,7 @@ Messenger
|
||||
respectively `ReceivedStamp`, `ValidationStamp`, `SerializerStamp` and moved to the `Stamp` namespace.
|
||||
* `AllowNoHandlerMiddleware` has been removed in favor of a new constructor argument on `HandleMessageMiddleware`
|
||||
* The `ConsumeMessagesCommand` class now takes an instance of `Psr\Container\ContainerInterface`
|
||||
as first constructor argument, i.e a message bus locator. The CLI command now expects a mandatory
|
||||
as first constructor argument, i.e a message bus locator. The CLI command now expects a mandatory
|
||||
`--bus` option value if there is more than one bus in the locator.
|
||||
* `MessageSubscriberInterface::getHandledMessages()` return value has changed. The value of an array item
|
||||
needs to be an associative array or the method name.
|
||||
|
@ -106,7 +106,7 @@ $COMPOSER = file_exists($COMPOSER = $oldPwd.'/composer.phar')
|
||||
|| ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar 2> /dev/null`))
|
||||
|| ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer`) : `which composer 2> /dev/null`))
|
||||
|| file_exists($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? `git rev-parse --show-toplevel 2> NUL` : `git rev-parse --show-toplevel 2> /dev/null`).DIRECTORY_SEPARATOR.'composer.phar')
|
||||
? $PHP.' '.escapeshellarg($COMPOSER)
|
||||
? (file_get_contents($COMPOSER, null, 0, 18) === '#!/usr/bin/env php' ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang
|
||||
: 'composer';
|
||||
|
||||
$SYMFONY_PHPUNIT_REMOVE = $getEnvVar('SYMFONY_PHPUNIT_REMOVE', 'phpspec/prophecy'.($PHPUNIT_VERSION < 6.0 ? ' symfony/yaml': ''));
|
||||
|
@ -65,12 +65,14 @@
|
||||
{%- endif -%}
|
||||
{%- if preferred_choices|length > 0 -%}
|
||||
{% set options = preferred_choices %}
|
||||
{% set render_preferred_choices = true %}
|
||||
{{- block('choice_widget_options') -}}
|
||||
{%- if choices|length > 0 and separator is not none -%}
|
||||
<option disabled="disabled">{{ separator }}</option>
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- set options = choices -%}
|
||||
{%- set render_preferred_choices = false -%}
|
||||
{{- block('choice_widget_options') -}}
|
||||
</select>
|
||||
{%- endblock choice_widget_collapsed -%}
|
||||
@ -83,7 +85,7 @@
|
||||
{{- block('choice_widget_options') -}}
|
||||
</optgroup>
|
||||
{%- else -%}
|
||||
<option value="{{ choice.value }}"{% if choice.attr %}{% with { attr: choice.attr } %}{{ block('attributes') }}{% endwith %}{% endif %}{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is same as(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}</option>
|
||||
<option value="{{ choice.value }}"{% if choice.attr %}{% with { attr: choice.attr } %}{{ block('attributes') }}{% endwith %}{% endif %}{% if not render_preferred_choices|default(false) and choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is same as(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}</option>
|
||||
{%- endif -%}
|
||||
{% endfor %}
|
||||
{%- endblock choice_widget_options -%}
|
||||
@ -226,13 +228,11 @@
|
||||
'%name%': name,
|
||||
'%id%': id,
|
||||
}) %}
|
||||
{%- elseif label is same as(false) -%}
|
||||
{% set translation_domain = false %}
|
||||
{%- else -%}
|
||||
{%- elseif label is not same as(false) -%}
|
||||
{% set label = name|humanize %}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ translation_domain is same as(false) ? label : label|trans(label_translation_parameters, translation_domain) }}</button>
|
||||
<button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ translation_domain is same as(false) or label is same as(false) ? label : label|trans(label_translation_parameters, translation_domain) }}</button>
|
||||
{%- endblock button_widget -%}
|
||||
|
||||
{%- block submit_widget -%}
|
||||
|
@ -160,12 +160,14 @@
|
||||
{%- endif %}
|
||||
{%- if preferred_choices|length > 0 -%}
|
||||
{% set options = preferred_choices %}
|
||||
{% set render_preferred_choices = true %}
|
||||
{{- block('choice_widget_options') -}}
|
||||
{% if choices|length > 0 and separator is not none -%}
|
||||
<option disabled="disabled">{{ separator }}</option>
|
||||
{%- endif %}
|
||||
{%- endif -%}
|
||||
{% set options = choices -%}
|
||||
{%- set render_preferred_choices = false -%}
|
||||
{{- block('choice_widget_options') -}}
|
||||
</select>
|
||||
{%- endblock choice_widget_collapsed %}
|
||||
|
@ -546,6 +546,31 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
||||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceWithSelectedPreferred()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [
|
||||
'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b'],
|
||||
'preferred_choices' => ['&a'],
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
]);
|
||||
|
||||
$this->assertWidgetMatchesXpath($form->createView(), ['separator' => '-- sep --', 'attr' => ['class' => 'my&class']],
|
||||
'/select
|
||||
[@name="name"]
|
||||
[@class="my&class form-control"]
|
||||
[not(@required)]
|
||||
[
|
||||
./option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
|
||||
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@value="&b"][.="[trans]Choice&B[/trans]"]
|
||||
]
|
||||
[count(./option)=4]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceWithPreferredAndNoSeparator()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [
|
||||
|
@ -102,11 +102,12 @@ final class ContainerLintCommand extends Command
|
||||
$refl->setAccessible(true);
|
||||
$refl->setValue($parameterBag, true);
|
||||
|
||||
$passConfig = $container->getCompilerPassConfig();
|
||||
$passConfig->setRemovingPasses([]);
|
||||
$passConfig->setAfterRemovingPasses([]);
|
||||
|
||||
$skippedIds = $kernelContainer->getRemovedIds();
|
||||
$skippedIds = [];
|
||||
foreach ($container->getServiceIds() as $serviceId) {
|
||||
if (0 === strpos($serviceId, '.errored.')) {
|
||||
$skippedIds[$serviceId] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$container->setParameter('container.build_hash', 'lint_container');
|
||||
|
@ -175,12 +175,12 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
$errorIo->title('Translation Messages Extractor and Dumper');
|
||||
$errorIo->comment(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
|
||||
$io->title('Translation Messages Extractor and Dumper');
|
||||
$io->comment(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
|
||||
|
||||
// load any messages from templates
|
||||
$extractedCatalogue = new MessageCatalogue($input->getArgument('locale'));
|
||||
$errorIo->comment('Parsing templates...');
|
||||
$io->comment('Parsing templates...');
|
||||
$this->extractor->setPrefix($input->getOption('prefix'));
|
||||
foreach ($viewsPaths as $path) {
|
||||
if (is_dir($path) || is_file($path)) {
|
||||
@ -190,7 +190,7 @@ EOF
|
||||
|
||||
// load any existing messages from the translation files
|
||||
$currentCatalogue = new MessageCatalogue($input->getArgument('locale'));
|
||||
$errorIo->comment('Loading translation files...');
|
||||
$io->comment('Loading translation files...');
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $currentCatalogue);
|
||||
@ -258,7 +258,7 @@ EOF
|
||||
}
|
||||
|
||||
if ('xlf' === $input->getOption('output-format')) {
|
||||
$errorIo->comment(sprintf('Xliff output version is <info>%s</info>', $input->getOption('xliff-version')));
|
||||
$io->comment(sprintf('Xliff output version is <info>%s</info>', $input->getOption('xliff-version')));
|
||||
}
|
||||
|
||||
$resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
|
||||
@ -270,7 +270,7 @@ EOF
|
||||
|
||||
// save the files
|
||||
if (true === $input->getOption('force')) {
|
||||
$errorIo->comment('Writing files...');
|
||||
$io->comment('Writing files...');
|
||||
|
||||
$bundleTransPath = false;
|
||||
foreach ($transPaths as $path) {
|
||||
@ -290,7 +290,7 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
$errorIo->success($resultMessage.'.');
|
||||
$io->success($resultMessage.'.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class ClearRememberMeTest extends AbstractWebTestCase
|
||||
$this->assertNotNull($cookieJar->get('REMEMBERME'));
|
||||
|
||||
$client->request('GET', '/foo');
|
||||
$this->assertSame(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertRedirect($client->getResponse(), '/login');
|
||||
$this->assertNull($cookieJar->get('REMEMBERME'));
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
"symfony/security-core": "^4.4|^5.0",
|
||||
"symfony/security-csrf": "^4.4|^5.0",
|
||||
"symfony/security-guard": "^4.4|^5.0",
|
||||
"symfony/security-http": "^4.4.1|^5.0.1"
|
||||
"symfony/security-http": "^4.4.3|^5.0.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-bundle": "^2.0",
|
||||
|
@ -103,7 +103,12 @@ class CachePoolPass implements CompilerPassInterface
|
||||
if (ChainAdapter::class === $class) {
|
||||
$adapters = [];
|
||||
foreach ($adapter->getArgument(0) as $provider => $adapter) {
|
||||
$chainedPool = $adapter = new ChildDefinition($adapter);
|
||||
if ($adapter instanceof ChildDefinition) {
|
||||
$chainedPool = $adapter;
|
||||
} else {
|
||||
$chainedPool = $adapter = new ChildDefinition($adapter);
|
||||
}
|
||||
|
||||
$chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]];
|
||||
$chainedClass = '';
|
||||
|
||||
|
@ -12,7 +12,9 @@
|
||||
namespace Symfony\Component\Cache\Tests\DependencyInjection;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Cache\Adapter\ApcuAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ChainAdapter;
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
@ -174,4 +176,42 @@ class CachePoolPassTest extends TestCase
|
||||
|
||||
$this->cachePoolPass->process($container);
|
||||
}
|
||||
|
||||
public function testChainAdapterPool()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('kernel.container_class', 'app');
|
||||
$container->setParameter('kernel.project_dir', 'foo');
|
||||
|
||||
$container->register('cache.adapter.array', ArrayAdapter::class)
|
||||
->addTag('cache.pool');
|
||||
$container->register('cache.adapter.apcu', ApcuAdapter::class)
|
||||
->setArguments([null, 0, null])
|
||||
->addTag('cache.pool');
|
||||
$container->register('cache.chain', ChainAdapter::class)
|
||||
->addArgument(['cache.adapter.array', 'cache.adapter.apcu'])
|
||||
->addTag('cache.pool');
|
||||
$container->setDefinition('cache.app', new ChildDefinition('cache.chain'))
|
||||
->addTag('cache.pool');
|
||||
$container->setDefinition('doctrine.result_cache_pool', new ChildDefinition('cache.app'))
|
||||
->addTag('cache.pool');
|
||||
|
||||
$this->cachePoolPass->process($container);
|
||||
|
||||
$appCachePool = $container->getDefinition('cache.app');
|
||||
$this->assertInstanceOf(ChildDefinition::class, $appCachePool);
|
||||
$this->assertSame('cache.chain', $appCachePool->getParent());
|
||||
|
||||
$chainCachePool = $container->getDefinition('cache.chain');
|
||||
$this->assertNotInstanceOf(ChildDefinition::class, $chainCachePool);
|
||||
$this->assertCount(2, $chainCachePool->getArgument(0));
|
||||
$this->assertInstanceOf(ChildDefinition::class, $chainCachePool->getArgument(0)[0]);
|
||||
$this->assertSame('cache.adapter.array', $chainCachePool->getArgument(0)[0]->getParent());
|
||||
$this->assertInstanceOf(ChildDefinition::class, $chainCachePool->getArgument(0)[1]);
|
||||
$this->assertSame('cache.adapter.apcu', $chainCachePool->getArgument(0)[1]->getParent());
|
||||
|
||||
$doctrineCachePool = $container->getDefinition('doctrine.result_cache_pool');
|
||||
$this->assertInstanceOf(ChildDefinition::class, $doctrineCachePool);
|
||||
$this->assertSame('cache.app', $doctrineCachePool->getParent());
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
|
||||
@ -219,6 +220,10 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
|
||||
return;
|
||||
}
|
||||
|
||||
if (\in_array($type, ['callable', 'Closure'], true) && $value instanceof ServiceClosureArgument) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('iterable' === $type && (\is_array($value) || $value instanceof \Traversable || $value instanceof IteratorArgument)) {
|
||||
return;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
@ -697,4 +698,28 @@ class CheckTypeDeclarationsPassTest extends TestCase
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
public function testProcessSuccessWhenPassingServiceClosureArgumentToCallable()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('bar', BarMethodCall::class)
|
||||
->addMethodCall('setCallable', [new ServiceClosureArgument(new Reference('foo'))]);
|
||||
|
||||
(new CheckTypeDeclarationsPass(true))->process($container);
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
public function testProcessSuccessWhenPassingServiceClosureArgumentToClosure()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('bar', BarMethodCall::class)
|
||||
->addMethodCall('setClosure', [new ServiceClosureArgument(new Reference('foo'))]);
|
||||
|
||||
(new CheckTypeDeclarationsPass(true))->process($container);
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
}
|
||||
|
@ -40,4 +40,8 @@ class BarMethodCall
|
||||
public function setCallable(callable $callable): void
|
||||
{
|
||||
}
|
||||
|
||||
public function setClosure(\Closure $closure): void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -272,7 +272,10 @@ final class Dotenv
|
||||
$this->cursor += 1 + $len;
|
||||
} elseif ('"' === $this->data[$this->cursor]) {
|
||||
$value = '';
|
||||
++$this->cursor;
|
||||
|
||||
if (++$this->cursor === $this->end) {
|
||||
throw $this->createFormatException('Missing quote to end the value');
|
||||
}
|
||||
|
||||
while ('"' !== $this->data[$this->cursor] || ('\\' === $this->data[$this->cursor - 1] && '\\' !== $this->data[$this->cursor - 2])) {
|
||||
$value .= $this->data[$this->cursor];
|
||||
|
@ -40,6 +40,7 @@ class DotenvTest extends TestCase
|
||||
['FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"],
|
||||
['FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"],
|
||||
['FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"],
|
||||
["FOO=\"foo\nBAR=\"bar\"", "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo\\nBAR=\"bar\"...\n ^ line 1 offset 18"],
|
||||
['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 9"],
|
||||
['export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"],
|
||||
['FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"],
|
||||
|
@ -30,6 +30,10 @@ class ClassNotFoundErrorEnhancerTest extends TestCase
|
||||
// get class loaders wrapped by DebugClassLoader
|
||||
if ($function[0] instanceof DebugClassLoader) {
|
||||
$function = $function[0]->getClassLoader();
|
||||
|
||||
if (!\is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($function[0] instanceof ComposerClassLoader) {
|
||||
|
@ -16,6 +16,7 @@ use Http\Client\Exception\NetworkException;
|
||||
use Http\Client\Exception\RequestException;
|
||||
use Http\Client\HttpAsyncClient;
|
||||
use Http\Client\HttpClient as HttplugInterface;
|
||||
use Http\Discovery\Exception\NotFoundException;
|
||||
use Http\Discovery\Psr17FactoryDiscovery;
|
||||
use Http\Message\RequestFactory;
|
||||
use Http\Message\StreamFactory;
|
||||
@ -75,9 +76,13 @@ final class HttplugClient implements HttplugInterface, HttpAsyncClient, RequestF
|
||||
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".');
|
||||
}
|
||||
|
||||
$psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
|
||||
$this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
|
||||
$this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
|
||||
try {
|
||||
$psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
|
||||
$this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
|
||||
$this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
|
||||
} catch (NotFoundException $e) {
|
||||
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$this->waitLoop = new HttplugWaitLoop($this->client, $this->promisePool, $this->responseFactory, $this->streamFactory);
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\HttpClient;
|
||||
|
||||
use Http\Discovery\Exception\NotFoundException;
|
||||
use Http\Discovery\Psr17FactoryDiscovery;
|
||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||
use Nyholm\Psr7\Request;
|
||||
@ -68,9 +69,13 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str
|
||||
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".');
|
||||
}
|
||||
|
||||
$psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
|
||||
$this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
|
||||
$this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
|
||||
try {
|
||||
$psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null;
|
||||
$this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory();
|
||||
$this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory();
|
||||
} catch (NotFoundException $e) {
|
||||
throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,7 +353,7 @@ trait ResponseTrait
|
||||
}
|
||||
|
||||
if ('' !== $chunk && null !== $response->content && \strlen($chunk) !== fwrite($response->content, $chunk)) {
|
||||
$multi->handlesActivity[$j] = [null, new TransportException('Failed writing %d bytes to the response buffer.', \strlen($chunk))];
|
||||
$multi->handlesActivity[$j] = [null, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($chunk)))];
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -475,7 +475,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
public function release()
|
||||
{
|
||||
flock($this->lock, LOCK_UN);
|
||||
fclose($this->lock);
|
||||
@ -553,7 +553,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
}
|
||||
|
||||
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
|
||||
unset($cache);
|
||||
$cache->release();
|
||||
$this->container = require $cachePath;
|
||||
$this->container->set('kernel', $this);
|
||||
|
||||
|
@ -186,6 +186,18 @@ class ConnectionTest extends TestCase
|
||||
$redis->del('messenger-getnonblocking');
|
||||
}
|
||||
|
||||
public function testJsonError()
|
||||
{
|
||||
$redis = new \Redis();
|
||||
$connection = Connection::fromDsn('redis://localhost/json-error', [], $redis);
|
||||
try {
|
||||
$connection->add("\xB1\x31", []);
|
||||
} catch (TransportException $e) {
|
||||
}
|
||||
|
||||
$this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage());
|
||||
}
|
||||
|
||||
public function testMaxEntries()
|
||||
{
|
||||
$redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock();
|
||||
|
@ -248,6 +248,10 @@ class Connection
|
||||
'uniqid' => uniqid('', true),
|
||||
]);
|
||||
|
||||
if (false === $message) {
|
||||
throw new TransportException(json_last_error_msg());
|
||||
}
|
||||
|
||||
$score = (int) ($this->getCurrentTimeInMilliseconds() + $delayInMs);
|
||||
$added = $this->connection->zadd($this->queue, ['NX'], $score, $message);
|
||||
} else {
|
||||
@ -256,6 +260,10 @@ class Connection
|
||||
'headers' => $headers,
|
||||
]);
|
||||
|
||||
if (false === $message) {
|
||||
throw new TransportException(json_last_error_msg());
|
||||
}
|
||||
|
||||
if ($this->maxEntries) {
|
||||
$added = $this->connection->xadd($this->stream, '*', ['message' => $message], $this->maxEntries, true);
|
||||
} else {
|
||||
|
@ -45,7 +45,7 @@ class GuardAuthenticationListener extends AbstractListener
|
||||
* @param string $providerKey The provider (i.e. firewall) key
|
||||
* @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider
|
||||
*/
|
||||
public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, $guardAuthenticators, LoggerInterface $logger = null)
|
||||
public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, iterable $guardAuthenticators, LoggerInterface $logger = null)
|
||||
{
|
||||
if (empty($providerKey)) {
|
||||
throw new \InvalidArgumentException('$providerKey must not be empty.');
|
||||
|
@ -48,7 +48,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
|
||||
* @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationListener
|
||||
* @param string $providerKey The provider (i.e. firewall) key
|
||||
*/
|
||||
public function __construct($guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker, UserPasswordEncoderInterface $passwordEncoder = null)
|
||||
public function __construct(iterable $guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker, UserPasswordEncoderInterface $passwordEncoder = null)
|
||||
{
|
||||
$this->guardAuthenticators = $guardAuthenticators;
|
||||
$this->userProvider = $userProvider;
|
||||
|
@ -94,6 +94,10 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
|
||||
*/
|
||||
final public function autoLogin(Request $request): ?TokenInterface
|
||||
{
|
||||
if (($cookie = $request->attributes->get(self::COOKIE_ATTR_NAME)) && null === $cookie->getValue()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null === $cookie = $request->cookies->get($this->options['name'])) {
|
||||
return null;
|
||||
}
|
||||
|
@ -39,6 +39,17 @@ class AbstractRememberMeServicesTest extends TestCase
|
||||
$this->assertNull($service->autoLogin(new Request()));
|
||||
}
|
||||
|
||||
public function testAutoLoginReturnsNullAfterLoginFail()
|
||||
{
|
||||
$service = $this->getService(null, ['name' => 'foo', 'path' => null, 'domain' => null]);
|
||||
|
||||
$request = new Request();
|
||||
$request->cookies->set('foo', 'foo');
|
||||
|
||||
$service->loginFail($request);
|
||||
$this->assertNull($service->autoLogin($request));
|
||||
}
|
||||
|
||||
public function testAutoLoginThrowsExceptionWhenImplementationDoesNotReturnUserInterface()
|
||||
{
|
||||
$this->expectException('RuntimeException');
|
||||
|
@ -47,7 +47,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
|
||||
return $this->normalizeFallback($propertyName, $class, $format, $context);
|
||||
}
|
||||
|
||||
if (!isset(self::$normalizeCache[$class][$propertyName])) {
|
||||
if (!\array_key_exists($class, self::$normalizeCache) || !\array_key_exists($propertyName, self::$normalizeCache[$class])) {
|
||||
self::$normalizeCache[$class][$propertyName] = $this->getCacheValueForNormalization($propertyName, $class);
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
|
||||
}
|
||||
|
||||
$cacheKey = $this->getCacheKey($class, $context);
|
||||
if (!isset(self::$denormalizeCache[$cacheKey][$propertyName])) {
|
||||
if (!\array_key_exists($cacheKey, self::$denormalizeCache) || !\array_key_exists($propertyName, self::$denormalizeCache[$cacheKey])) {
|
||||
self::$denormalizeCache[$cacheKey][$propertyName] = $this->getCacheValueForDenormalization($propertyName, $class, $context);
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
|
||||
}
|
||||
|
||||
$attributesMetadata = $this->metadataFactory->getMetadataFor($class)->getAttributesMetadata();
|
||||
if (!isset($attributesMetadata[$propertyName])) {
|
||||
if (!\array_key_exists($propertyName, $attributesMetadata)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface
|
||||
private function getCacheValueForDenormalization(string $propertyName, string $class, array $context): ?string
|
||||
{
|
||||
$cacheKey = $this->getCacheKey($class, $context);
|
||||
if (!isset(self::$attributesMetadataCache[$cacheKey])) {
|
||||
if (!\array_key_exists($cacheKey, self::$attributesMetadataCache)) {
|
||||
self::$attributesMetadataCache[$cacheKey] = $this->getCacheValueForAttributesMetadata($class, $context);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user