Merge branch '5.1'
* 5.1: (33 commits) [Cache] $lifetime cannot be null [Serializer] minor cleanup fix merge Run PHP 8 as 7.4.99 Remove calls to deprecated ReflectionParameter::getClass(). [VarDumper] fix PHP 8 support Removed "services" prototype node from "custom_authenticator" Add php 8 to travis. [Cache] Accessing undefined constants raises an Error in php8 [Cache] allow DBAL v3 Skip Doctrine DBAL on php 8 until we have a compatible version. [DomCrawler] Catch expected ValueError. Made method signatures compatible with their corresponding traits. [ErrorHandler] Apply php8 fixes from Debug component. [DomCrawler] Catch expected ValueError. [Validator] Catch expected ValueError. [VarDumper] ReflectionFunction::isDisabled() is deprecated. [BrowserKit] Raw body with custom Content-Type header Revert https://github.com/symfony/symfony/pull/34986 Make ExpressionLanguageSyntax validator usable with annotation ...
This commit is contained in:
commit
757b8f7c59
17
.travis.yml
17
.travis.yml
@ -28,7 +28,11 @@ matrix:
|
||||
env: deps=high
|
||||
- php: 7.4
|
||||
env: deps=low
|
||||
- php: nightly
|
||||
services: [memcached]
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@ -135,7 +139,9 @@ before_install:
|
||||
echo session.gc_probability = 0 >> $INI
|
||||
echo opcache.enable_cli = 1 >> $INI
|
||||
echo apc.enable_cli = 1 >> $INI
|
||||
echo extension = memcached.so >> $INI
|
||||
if [[ $PHP != nightly ]]; then
|
||||
echo extension = memcached.so >> $INI
|
||||
fi
|
||||
done
|
||||
|
||||
- |
|
||||
@ -147,6 +153,9 @@ before_install:
|
||||
if ! php --ri sodium > /dev/null; then
|
||||
tfold ext.libsodium tpecl libsodium sodium.so $INI
|
||||
fi
|
||||
if [[ $PHP = nightly ]]; then
|
||||
tfold ext.memcached tpecl memcached-3.1.5 memcached.so $INI
|
||||
fi
|
||||
|
||||
tfold ext.apcu tpecl apcu-5.1.17 apcu.so $INI
|
||||
tfold ext.mongodb tpecl mongodb-1.6.0 mongodb.so $INI
|
||||
@ -222,6 +231,12 @@ install:
|
||||
export COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n' | sort)
|
||||
fi
|
||||
|
||||
- |
|
||||
# Set composer's platform to php 7.4 if we're on php 8.
|
||||
if [[ $PHP = nightly ]]; then
|
||||
composer config platform.php 7.4.99
|
||||
fi
|
||||
|
||||
- |
|
||||
# Install symfony/flex
|
||||
if [[ $deps = low ]]; then
|
||||
|
@ -60,6 +60,13 @@ class EntityTypeTest extends BaseTypeTest
|
||||
|
||||
protected static $supportedFeatureSetVersion = 404;
|
||||
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 80000) {
|
||||
self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->em = DoctrineTestHelper::createTestEntityManager();
|
||||
|
@ -24,6 +24,13 @@ use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
|
||||
|
||||
class EntityUserProviderTest extends TestCase
|
||||
{
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 80000) {
|
||||
self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testRefreshUserGetsUserByPrimaryKey()
|
||||
{
|
||||
$em = DoctrineTestHelper::createTestEntityManager();
|
||||
|
@ -59,6 +59,13 @@ class UniqueEntityValidatorTest extends ConstraintValidatorTestCase
|
||||
|
||||
protected $repositoryFactory;
|
||||
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 80000) {
|
||||
self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->repositoryFactory = new TestRepositoryFactory();
|
||||
|
@ -197,7 +197,7 @@ if (!file_exists("$PHPUNIT_DIR/$PHPUNIT_VERSION_DIR/phpunit") || $configurationH
|
||||
$passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\"");
|
||||
}
|
||||
|
||||
if (preg_match('{\^(\d++\.\d++)[\d\.]*$}', $info['requires']['php'], $phpVersion) && version_compare($phpVersion[1], PHP_VERSION, '<')) {
|
||||
if (preg_match('{\^((\d++\.)\d++)[\d\.]*$}', $info['requires']['php'], $phpVersion) && version_compare($phpVersion[2].'99', PHP_VERSION, '<')) {
|
||||
$passthruOrFail("$COMPOSER config platform.php \"$phpVersion[1].99\"");
|
||||
} else {
|
||||
$passthruOrFail("$COMPOSER config --unset platform.php");
|
||||
|
@ -35,7 +35,7 @@ class CustomAuthenticatorFactory implements AuthenticatorFactoryInterface, Secur
|
||||
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'custom_authenticator';
|
||||
return 'custom_authenticators';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,19 +44,27 @@ class CustomAuthenticatorFactory implements AuthenticatorFactoryInterface, Secur
|
||||
public function addConfiguration(NodeDefinition $builder)
|
||||
{
|
||||
$builder
|
||||
->fixXmlConfig('service')
|
||||
->children()
|
||||
->arrayNode('services')
|
||||
->info('An array of service ids for all of your "authenticators"')
|
||||
->requiresAtLeastOneElement()
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->info('An array of service ids for all of your "authenticators"')
|
||||
->requiresAtLeastOneElement()
|
||||
->prototype('scalar')->end();
|
||||
|
||||
// get the parent array node builder ("firewalls") from inside the children builder
|
||||
$factoryRootNode = $builder->end()->end();
|
||||
$factoryRootNode
|
||||
->fixXmlConfig('custom_authenticator')
|
||||
->validate()
|
||||
->ifTrue(function ($v) { return isset($v['custom_authenticators']) && empty($v['custom_authenticators']); })
|
||||
->then(function ($v) {
|
||||
unset($v['custom_authenticators']);
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): array
|
||||
{
|
||||
return $config['services'];
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
|
@ -24,11 +24,15 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Guard\AuthenticatorInterface as GuardAuthenticatorInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\HttpBasicAuthenticator;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
|
||||
|
||||
class SecurityExtensionTest extends TestCase
|
||||
{
|
||||
@ -520,6 +524,41 @@ class SecurityExtensionTest extends TestCase
|
||||
$container->compile();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideConfigureCustomAuthenticatorData
|
||||
*/
|
||||
public function testConfigureCustomAuthenticator(array $firewall, array $expectedAuthenticators)
|
||||
{
|
||||
$container = $this->getRawContainer();
|
||||
$container->loadFromExtension('security', [
|
||||
'enable_authenticator_manager' => true,
|
||||
'providers' => [
|
||||
'first' => ['id' => 'users'],
|
||||
],
|
||||
|
||||
'firewalls' => [
|
||||
'main' => $firewall,
|
||||
],
|
||||
]);
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->assertEquals($expectedAuthenticators, array_map('strval', $container->getDefinition('security.authenticator.manager.main')->getArgument(0)));
|
||||
}
|
||||
|
||||
public function provideConfigureCustomAuthenticatorData()
|
||||
{
|
||||
yield [
|
||||
['custom_authenticator' => TestAuthenticator::class],
|
||||
[TestAuthenticator::class],
|
||||
];
|
||||
|
||||
yield [
|
||||
['custom_authenticators' => [TestAuthenticator::class, HttpBasicAuthenticator::class]],
|
||||
[TestAuthenticator::class, HttpBasicAuthenticator::class],
|
||||
];
|
||||
}
|
||||
|
||||
protected function getRawContainer()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
@ -547,7 +586,30 @@ class SecurityExtensionTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
class NullAuthenticator implements AuthenticatorInterface
|
||||
class TestAuthenticator implements AuthenticatorInterface
|
||||
{
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): PassportInterface
|
||||
{
|
||||
}
|
||||
|
||||
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
|
||||
{
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
{
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class NullAuthenticator implements GuardAuthenticatorInterface
|
||||
{
|
||||
public function start(Request $request, AuthenticationException $authException = null)
|
||||
{
|
||||
|
@ -39,10 +39,10 @@ class HttpBrowser extends AbstractBrowser
|
||||
parent::__construct([], $history, $cookieJar);
|
||||
}
|
||||
|
||||
protected function doRequest($request): Response
|
||||
protected function doRequest(Request $request): Response
|
||||
{
|
||||
$headers = $this->getHeaders($request);
|
||||
[$body, $extraHeaders] = $this->getBodyAndExtraHeaders($request);
|
||||
[$body, $extraHeaders] = $this->getBodyAndExtraHeaders($request, $headers);
|
||||
|
||||
$response = $this->client->request($request->getMethod(), $request->getUri(), [
|
||||
'headers' => array_merge($headers, $extraHeaders),
|
||||
@ -56,7 +56,7 @@ class HttpBrowser extends AbstractBrowser
|
||||
/**
|
||||
* @return array [$body, $headers]
|
||||
*/
|
||||
private function getBodyAndExtraHeaders(Request $request): array
|
||||
private function getBodyAndExtraHeaders(Request $request, array $headers): array
|
||||
{
|
||||
if (\in_array($request->getMethod(), ['GET', 'HEAD'])) {
|
||||
return ['', []];
|
||||
@ -67,6 +67,10 @@ class HttpBrowser extends AbstractBrowser
|
||||
}
|
||||
|
||||
if (null !== $content = $request->getContent()) {
|
||||
if (isset($headers['content-type'])) {
|
||||
return [$content, []];
|
||||
}
|
||||
|
||||
$part = new TextPart($content, 'utf-8', 'plain', '8bit');
|
||||
|
||||
return [$part->bodyToString(), $part->getPreparedHeaders()->toArray()];
|
||||
|
@ -59,6 +59,10 @@ class HttpBrowserTest extends AbstractBrowserTest
|
||||
['POST', 'http://example.com/', [], [], [], 'content'],
|
||||
['POST', 'http://example.com/', ['headers' => $defaultHeaders + ['Content-Type: text/plain; charset=utf-8', 'Content-Transfer-Encoding: 8bit'], 'body' => 'content', 'max_redirects' => 0]],
|
||||
];
|
||||
yield 'POST JSON' => [
|
||||
['POST', 'http://example.com/', [], [], ['CONTENT_TYPE' => 'application/json'], '["content"]'],
|
||||
['POST', 'http://example.com/', ['headers' => $defaultHeaders + ['content-type' => 'application/json'], 'body' => '["content"]', 'max_redirects' => 0]],
|
||||
];
|
||||
}
|
||||
|
||||
public function testMultiPartRequestWithSingleFile()
|
||||
|
@ -71,8 +71,14 @@ class MemcachedAdapterTest extends AdapterTestCase
|
||||
*/
|
||||
public function testBadOptions($name, $value)
|
||||
{
|
||||
$this->expectException('ErrorException');
|
||||
$this->expectExceptionMessage('constant(): Couldn\'t find constant Memcached::');
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$this->expectException('ErrorException');
|
||||
$this->expectExceptionMessage('constant(): Couldn\'t find constant Memcached::');
|
||||
} else {
|
||||
$this->expectException('Error');
|
||||
$this->expectExceptionMessage('Undefined class constant \'Memcached::');
|
||||
}
|
||||
|
||||
MemcachedAdapter::createConnection([], [$name => $value]);
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,9 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"cache/integration-tests": "dev-master",
|
||||
"doctrine/cache": "~1.6",
|
||||
"doctrine/dbal": "^2.10",
|
||||
"predis/predis": "~1.1",
|
||||
"doctrine/cache": "^1.6",
|
||||
"doctrine/dbal": "^2.10|^3.0",
|
||||
"predis/predis": "^1.1",
|
||||
"psr/simple-cache": "^1.0",
|
||||
"symfony/config": "^4.4|^5.0",
|
||||
"symfony/dependency-injection": "^4.4|^5.0",
|
||||
|
@ -137,7 +137,11 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
|
||||
$defaults = $class->getDefaultProperties();
|
||||
|
||||
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
|
||||
yield $p->getDocComment().$p;
|
||||
yield $p->getDocComment();
|
||||
yield $p->isDefault() ? '<default>' : '';
|
||||
yield $p->isPublic() ? 'public' : 'protected';
|
||||
yield $p->isStatic() ? 'static' : '';
|
||||
yield '$'.$p->name;
|
||||
yield print_r(isset($defaults[$p->name]) && !\is_object($defaults[$p->name]) ? $defaults[$p->name] : null, true);
|
||||
}
|
||||
}
|
||||
|
@ -1143,11 +1143,11 @@ class Crawler implements \Countable, \IteratorAggregate
|
||||
|
||||
try {
|
||||
return mb_convert_encoding($htmlContent, 'HTML-ENTITIES', $charset);
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Exception | \ValueError $e) {
|
||||
try {
|
||||
$htmlContent = iconv($charset, 'UTF-8', $htmlContent);
|
||||
$htmlContent = mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8');
|
||||
} catch (\Exception $e) {
|
||||
} catch (\Exception | \ValueError $e) {
|
||||
}
|
||||
|
||||
return $htmlContent;
|
||||
|
@ -91,9 +91,14 @@ class ErrorHandlerTest extends TestCase
|
||||
$this->fail('ErrorException expected');
|
||||
} catch (\ErrorException $exception) {
|
||||
// if an exception is thrown, the test passed
|
||||
$this->assertEquals(E_NOTICE, $exception->getSeverity());
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$this->assertEquals(E_NOTICE, $exception->getSeverity());
|
||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
} else {
|
||||
$this->assertEquals(E_WARNING, $exception->getSeverity());
|
||||
$this->assertRegExp('/^Warning: Undefined variable \$(foo|bar)/', $exception->getMessage());
|
||||
}
|
||||
$this->assertEquals(__FILE__, $exception->getFile());
|
||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
|
||||
$trace = $exception->getTrace();
|
||||
|
||||
@ -121,7 +126,7 @@ class ErrorHandlerTest extends TestCase
|
||||
public function testFailureCall()
|
||||
{
|
||||
$this->expectException(\ErrorException::class);
|
||||
$this->expectExceptionMessage('fopen(unknown.txt): failed to open stream: No such file or directory');
|
||||
$this->expectExceptionMessageMatches('/^fopen\(unknown\.txt\): [Ff]ailed to open stream: No such file or directory$/');
|
||||
|
||||
ErrorHandler::call('fopen', 'unknown.txt', 'r');
|
||||
}
|
||||
@ -149,9 +154,14 @@ class ErrorHandlerTest extends TestCase
|
||||
$this->fail('An \ErrorException should have been raised');
|
||||
} catch (\ErrorException $e) {
|
||||
$trace = $e->getTrace();
|
||||
$this->assertSame(E_NOTICE, $e->getSeverity());
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$this->assertEquals(E_NOTICE, $e->getSeverity());
|
||||
$this->assertSame('Undefined variable: foo', $e->getMessage());
|
||||
} else {
|
||||
$this->assertEquals(E_WARNING, $e->getSeverity());
|
||||
$this->assertSame('Undefined variable $foo', $e->getMessage());
|
||||
}
|
||||
$this->assertSame(__FILE__, $e->getFile());
|
||||
$this->assertSame('Undefined variable: foo', $e->getMessage());
|
||||
$this->assertSame(0, $e->getCode());
|
||||
$this->assertSame('Symfony\Component\ErrorHandler\{closure}', $trace[0]['function']);
|
||||
$this->assertSame(ErrorHandler::class, $trace[0]['class']);
|
||||
@ -288,11 +298,18 @@ class ErrorHandlerTest extends TestCase
|
||||
|
||||
$line = null;
|
||||
$logArgCheck = function ($level, $message, $context) use (&$line) {
|
||||
$this->assertEquals('Notice: Undefined variable: undefVar', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$exception = $context['exception'];
|
||||
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$this->assertEquals('Notice: Undefined variable: undefVar', $message);
|
||||
$this->assertSame(E_NOTICE, $exception->getSeverity());
|
||||
} else {
|
||||
$this->assertEquals('Warning: Undefined variable $undefVar', $message);
|
||||
$this->assertSame(E_WARNING, $exception->getSeverity());
|
||||
}
|
||||
|
||||
$this->assertInstanceOf(SilencedErrorContext::class, $exception);
|
||||
$this->assertSame(E_NOTICE, $exception->getSeverity());
|
||||
$this->assertSame(__FILE__, $exception->getFile());
|
||||
$this->assertSame($line, $exception->getLine());
|
||||
$this->assertNotEmpty($exception->getTrace());
|
||||
@ -306,8 +323,13 @@ class ErrorHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||
$handler->screamAt(E_NOTICE);
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||
$handler->screamAt(E_NOTICE);
|
||||
} else {
|
||||
$handler->setDefaultLogger($logger, E_WARNING);
|
||||
$handler->screamAt(E_WARNING);
|
||||
}
|
||||
unset($undefVar);
|
||||
$line = __LINE__ + 1;
|
||||
@$undefVar++;
|
||||
|
@ -15,8 +15,8 @@ class ErrorHandlerThatUsesThePreviousOne
|
||||
return $handler;
|
||||
}
|
||||
|
||||
public function handleError($type, $message, $file, $line, $context)
|
||||
public function handleError()
|
||||
{
|
||||
return \call_user_func(self::$previous, $type, $message, $file, $line, $context);
|
||||
return \call_user_func_array(self::$previous, \func_get_args());
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ CHANGELOG
|
||||
* Added a `ChoiceList` facade to leverage explicit choice list caching based on options
|
||||
* Added an `AbstractChoiceLoader` to simplify implementations and handle global optimizations
|
||||
* The `view_timezone` option defaults to the `model_timezone` if no `reference_date` is configured.
|
||||
* Added default `inputmode` attribute to Search, Email and Tel form types.
|
||||
* Implementing the `FormConfigInterface` without implementing the `getIsEmptyCallback()` method
|
||||
is deprecated. The method will be added to the interface in 6.0.
|
||||
* Implementing the `FormConfigBuilderInterface` without implementing the `setIsEmptyCallback()` method
|
||||
|
@ -12,8 +12,6 @@
|
||||
namespace Symfony\Component\Form\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
|
||||
class EmailType extends AbstractType
|
||||
{
|
||||
@ -25,14 +23,6 @@ class EmailType extends AbstractType
|
||||
return TextType::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
$view->vars['attr']['inputmode'] = $options['attr']['inputmode'] ?? 'email';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -12,8 +12,6 @@
|
||||
namespace Symfony\Component\Form\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
|
||||
class SearchType extends AbstractType
|
||||
{
|
||||
@ -25,14 +23,6 @@ class SearchType extends AbstractType
|
||||
return TextType::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
$view->vars['attr']['inputmode'] = $options['attr']['inputmode'] ?? 'search';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -12,8 +12,6 @@
|
||||
namespace Symfony\Component\Form\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
|
||||
class TelType extends AbstractType
|
||||
{
|
||||
@ -25,14 +23,6 @@ class TelType extends AbstractType
|
||||
return TextType::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
$view->vars['attr']['inputmode'] = $options['attr']['inputmode'] ?? 'tel';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -1,36 +0,0 @@
|
||||
<?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\Form\Tests\Extension\Core\Type;
|
||||
|
||||
class EmailTypeTest extends BaseTypeTest
|
||||
{
|
||||
const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\EmailType';
|
||||
|
||||
public function testDefaultInputmode()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE);
|
||||
|
||||
$this->assertSame('email', $form->createView()->vars['attr']['inputmode']);
|
||||
}
|
||||
|
||||
public function testOverwrittenInputmode()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE, null, ['attr' => ['inputmode' => 'text']]);
|
||||
|
||||
$this->assertSame('text', $form->createView()->vars['attr']['inputmode']);
|
||||
}
|
||||
|
||||
public function testSubmitNull($expected = null, $norm = null, $view = null)
|
||||
{
|
||||
parent::testSubmitNull($expected, $norm, '');
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?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\Form\Tests\Extension\Core\Type;
|
||||
|
||||
class SearchTypeTest extends BaseTypeTest
|
||||
{
|
||||
const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\SearchType';
|
||||
|
||||
public function testDefaultInputmode()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE);
|
||||
|
||||
$this->assertSame('search', $form->createView()->vars['attr']['inputmode']);
|
||||
}
|
||||
|
||||
public function testOverwrittenInputmode()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE, null, ['attr' => ['inputmode' => 'text']]);
|
||||
|
||||
$this->assertSame('text', $form->createView()->vars['attr']['inputmode']);
|
||||
}
|
||||
|
||||
public function testSubmitNull($expected = null, $norm = null, $view = null)
|
||||
{
|
||||
parent::testSubmitNull($expected, $norm, '');
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?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\Form\Tests\Extension\Core\Type;
|
||||
|
||||
class TelTypeTest extends BaseTypeTest
|
||||
{
|
||||
const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\TelType';
|
||||
|
||||
public function testDefaultInputmode()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE);
|
||||
|
||||
$this->assertSame('tel', $form->createView()->vars['attr']['inputmode']);
|
||||
}
|
||||
|
||||
public function testOverwrittenInputmode()
|
||||
{
|
||||
$form = $this->factory->create(static::TESTED_TYPE, null, ['attr' => ['inputmode' => 'text']]);
|
||||
|
||||
$this->assertSame('text', $form->createView()->vars['attr']['inputmode']);
|
||||
}
|
||||
|
||||
public function testSubmitNull($expected = null, $norm = null, $view = null)
|
||||
{
|
||||
parent::testSubmitNull($expected, $norm, '');
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\Chunk\FirstChunk;
|
||||
use Symfony\Component\HttpClient\Chunk\InformationalChunk;
|
||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||
use Symfony\Component\HttpClient\Internal\ClientState;
|
||||
use Symfony\Component\HttpClient\Internal\CurlClientState;
|
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
@ -242,8 +243,10 @@ final class CurlResponse implements ResponseInterface
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param CurlClientState $multi
|
||||
*/
|
||||
private static function perform(CurlClientState $multi, array &$responses = null): void
|
||||
private static function perform(ClientState $multi, array &$responses = null): void
|
||||
{
|
||||
if (self::$performing) {
|
||||
if ($responses) {
|
||||
@ -289,8 +292,10 @@ final class CurlResponse implements ResponseInterface
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param CurlClientState $multi
|
||||
*/
|
||||
private static function select(CurlClientState $multi, float $timeout): int
|
||||
private static function select(ClientState $multi, float $timeout): int
|
||||
{
|
||||
if (\PHP_VERSION_ID < 70123 || (70200 <= \PHP_VERSION_ID && \PHP_VERSION_ID < 70211)) {
|
||||
// workaround https://bugs.php.net/76480
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\HttpClient\Response;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\Chunk\FirstChunk;
|
||||
use Symfony\Component\HttpClient\Exception\TransportException;
|
||||
use Symfony\Component\HttpClient\Internal\ClientState;
|
||||
use Symfony\Component\HttpClient\Internal\NativeClientState;
|
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
@ -214,8 +215,10 @@ final class NativeResponse implements ResponseInterface
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param NativeClientState $multi
|
||||
*/
|
||||
private static function perform(NativeClientState $multi, array &$responses = null): void
|
||||
private static function perform(ClientState $multi, array &$responses = null): void
|
||||
{
|
||||
// List of native handles for stream_select()
|
||||
if (null !== $responses) {
|
||||
@ -326,8 +329,10 @@ final class NativeResponse implements ResponseInterface
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param NativeClientState $multi
|
||||
*/
|
||||
private static function select(NativeClientState $multi, float $timeout): int
|
||||
private static function select(ClientState $multi, float $timeout): int
|
||||
{
|
||||
$_ = [];
|
||||
|
||||
|
@ -31,7 +31,7 @@ use Symfony\Component\Mime\MimeTypes;
|
||||
*/
|
||||
class UploadedFile extends File
|
||||
{
|
||||
private $test = false;
|
||||
private $test;
|
||||
private $originalName;
|
||||
private $mimeType;
|
||||
private $error;
|
||||
@ -76,7 +76,7 @@ class UploadedFile extends File
|
||||
* It is extracted from the request from which the file has been uploaded.
|
||||
* Then it should not be considered as a safe value.
|
||||
*
|
||||
* @return string|null The original name
|
||||
* @return string The original name
|
||||
*/
|
||||
public function getClientOriginalName()
|
||||
{
|
||||
@ -105,7 +105,7 @@ class UploadedFile extends File
|
||||
* For a trusted mime type, use getMimeType() instead (which guesses the mime
|
||||
* type based on the file content).
|
||||
*
|
||||
* @return string|null The mime type
|
||||
* @return string The mime type
|
||||
*
|
||||
* @see getMimeType()
|
||||
*/
|
||||
|
@ -600,7 +600,7 @@ abstract class AbstractNumberFormatterTest extends TestCase
|
||||
|
||||
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enSymbols');
|
||||
$r->setAccessible(true);
|
||||
$expected = $r->getValue('Symfony\Component\Intl\NumberFormatter\NumberFormatter');
|
||||
$expected = $r->getValue();
|
||||
|
||||
for ($i = 0; $i <= 17; ++$i) {
|
||||
$this->assertSame($expected[1][$i], $decimalFormatter->getSymbol($i));
|
||||
@ -617,7 +617,7 @@ abstract class AbstractNumberFormatterTest extends TestCase
|
||||
|
||||
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enTextAttributes');
|
||||
$r->setAccessible(true);
|
||||
$expected = $r->getValue('Symfony\Component\Intl\NumberFormatter\NumberFormatter');
|
||||
$expected = $r->getValue();
|
||||
|
||||
for ($i = 0; $i <= 5; ++$i) {
|
||||
$this->assertSame($expected[1][$i], $decimalFormatter->getTextAttribute($i));
|
||||
|
@ -23,6 +23,36 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class ConnectionTest extends TestCase
|
||||
{
|
||||
public function testExtraOptions()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
Connection::fromDsn('sqs://default/queue', [
|
||||
'extra_key',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testExtraParamsInQuery()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
Connection::fromDsn('sqs://default/queue?extra_param=some_value');
|
||||
}
|
||||
|
||||
public function testConfigureWithCredentials()
|
||||
{
|
||||
$awsKey = 'some_aws_access_key_value';
|
||||
$awsSecret = 'some_aws_secret_value';
|
||||
$region = 'eu-west-1';
|
||||
$httpClient = $this->getMockBuilder(HttpClientInterface::class)->getMock();
|
||||
$this->assertEquals(
|
||||
new Connection(['queue_name' => 'queue'], new SqsClient(['region' => $region, 'accessKeyId' => $awsKey, 'accessKeySecret' => $awsSecret], null, $httpClient)),
|
||||
Connection::fromDsn('sqs://default/queue', [
|
||||
'access_key' => $awsKey,
|
||||
'secret_key' => $awsSecret,
|
||||
'region' => $region,
|
||||
], $httpClient)
|
||||
);
|
||||
}
|
||||
|
||||
public function testFromInvalidDsn()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
@ -124,13 +124,13 @@ class Connection
|
||||
$configuration['account'] = 2 === \count($parsedPath) ? $parsedPath[0] : null;
|
||||
|
||||
// check for extra keys in options
|
||||
$optionsExtraKeys = array_diff(array_keys($options), array_keys($configuration));
|
||||
$optionsExtraKeys = array_diff(array_keys($options), array_keys(self::DEFAULT_OPTIONS));
|
||||
if (0 < \count($optionsExtraKeys)) {
|
||||
throw new InvalidArgumentException(sprintf('Unknown option found : [%s]. Allowed options are [%s].', implode(', ', $optionsExtraKeys), implode(', ', array_keys(self::DEFAULT_OPTIONS))));
|
||||
}
|
||||
|
||||
// check for extra keys in options
|
||||
$queryExtraKeys = array_diff(array_keys($query), array_keys($configuration));
|
||||
$queryExtraKeys = array_diff(array_keys($query), array_keys(self::DEFAULT_OPTIONS));
|
||||
if (0 < \count($queryExtraKeys)) {
|
||||
throw new InvalidArgumentException(sprintf('Unknown option found in DSN: [%s]. Allowed options are [%s].', implode(', ', $queryExtraKeys), implode(', ', array_keys(self::DEFAULT_OPTIONS))));
|
||||
}
|
||||
|
@ -17,13 +17,12 @@
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"doctrine/dbal": "^2.10",
|
||||
"doctrine/persistence": "^1.3",
|
||||
"symfony/messenger": "^5.1",
|
||||
"symfony/service-contracts": "^1.1|^2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/dbal": "^2.6",
|
||||
"doctrine/dbal": "^2.10",
|
||||
"doctrine/orm": "^2.6.3",
|
||||
"doctrine/persistence": "^1.3",
|
||||
"symfony/property-access": "^4.4|^5.0",
|
||||
|
@ -39,12 +39,14 @@ class TransportFactory implements TransportFactoryInterface
|
||||
|
||||
// Help the user to select Symfony packages based on protocol.
|
||||
$packageSuggestion = '';
|
||||
if ('amqp://' === substr($dsn, 0, 7)) {
|
||||
if (0 === strpos($dsn, 'amqp://')) {
|
||||
$packageSuggestion = ' Run "composer require symfony/amqp-messenger" to install AMQP transport.';
|
||||
} elseif ('doctrine://' === substr($dsn, 0, 11)) {
|
||||
} elseif (0 === strpos($dsn, 'doctrine://')) {
|
||||
$packageSuggestion = ' Run "composer require symfony/doctrine-messenger" to install Doctrine transport.';
|
||||
} elseif ('redis://' === substr($dsn, 0, 8)) {
|
||||
} elseif (0 === strpos($dsn, 'redis://')) {
|
||||
$packageSuggestion = ' Run "composer require symfony/redis-messenger" to install Redis transport.';
|
||||
} elseif (0 === strpos($dsn, 'sqs://')) {
|
||||
$packageSuggestion = ' Run "composer require symfony/amazon-sqs-messenger" to install Amazon SQS transport.';
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('No transport supports the given Messenger DSN "%s".%s.', $dsn, $packageSuggestion));
|
||||
|
@ -185,7 +185,7 @@ class OptionsResolver implements Options
|
||||
$reflClosure = new \ReflectionFunction($value);
|
||||
$params = $reflClosure->getParameters();
|
||||
|
||||
if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && Options::class === $class->name) {
|
||||
if (isset($params[0]) && Options::class === $this->getParameterClassName($params[0])) {
|
||||
// Initialize the option if no previous value exists
|
||||
if (!isset($this->defaults[$option])) {
|
||||
$this->defaults[$option] = null;
|
||||
@ -206,7 +206,7 @@ class OptionsResolver implements Options
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && self::class === $class->name && (!isset($params[1]) || (null !== ($class = $params[1]->getClass()) && Options::class === $class->name))) {
|
||||
if (isset($params[0]) && null !== ($type = $params[0]->getType()) && self::class === $type->getName() && (!isset($params[1]) || (null !== ($type = $params[1]->getType()) && Options::class === $type->getName()))) {
|
||||
// Store closure for later evaluation
|
||||
$this->nested[$option][] = $value;
|
||||
$this->defaults[$option] = [];
|
||||
@ -1280,4 +1280,13 @@ class OptionsResolver implements Options
|
||||
|
||||
return implode('", "', $options);
|
||||
}
|
||||
|
||||
private function getParameterClassName(\ReflectionParameter $parameter): ?string
|
||||
{
|
||||
if (!($type = $parameter->getType()) || $type->isBuiltin()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $type->getName();
|
||||
}
|
||||
}
|
||||
|
@ -190,12 +190,15 @@ class PropertyAccessor implements PropertyAccessorInterface
|
||||
|
||||
private static function throwInvalidArgumentException(string $message, array $trace, int $i, string $propertyPath, \Throwable $previous = null): void
|
||||
{
|
||||
// the type mismatch is not caused by invalid arguments (but e.g. by an incompatible return type hint of the writer method)
|
||||
if (0 !== strpos($message, 'Argument ')) {
|
||||
if (!isset($trace[$i]['file']) || __FILE__ !== $trace[$i]['file']) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file']) {
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
if (0 !== strpos($message, 'Argument ')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pos = strpos($message, $delim = 'must be of the type ') ?: (strpos($message, $delim = 'must be an instance of ') ?: strpos($message, $delim = 'must implement interface '));
|
||||
$pos += \strlen($delim);
|
||||
$j = strpos($message, ',', $pos);
|
||||
@ -204,6 +207,12 @@ class PropertyAccessor implements PropertyAccessorInterface
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given at property path "%s".', $message, 'NULL' === $type ? 'null' : $type, $propertyPath), 0, $previous);
|
||||
}
|
||||
|
||||
if (preg_match('/^\S+::\S+\(\): Argument #\d+ \(\$\S+\) must be of type (\S+), (\S+) given/', $message, $matches)) {
|
||||
list(, $expectedType, $actualType) = $matches;
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given.', $expectedType, 'NULL' === $actualType ? 'null' : $actualType), 0, $previous);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,7 +404,7 @@ class PropertyAccessor implements PropertyAccessorInterface
|
||||
try {
|
||||
$result[self::VALUE] = $object->$name();
|
||||
} catch (\TypeError $e) {
|
||||
if (preg_match((sprintf('/^Return value of %s::%s\(\) must be of the type (\w+), null returned$/', preg_quote(\get_class($object)), $name)), $e->getMessage(), $matches)) {
|
||||
if (preg_match((sprintf('/^Return value of %s::%s\(\) must be of (?:the )?type (\w+), null returned$/', preg_quote(\get_class($object)), $name)), $e->getMessage(), $matches)) {
|
||||
throw new UninitializedPropertyException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', \get_class($object), $name, $matches[1]), 0, $e);
|
||||
}
|
||||
|
||||
|
@ -270,13 +270,10 @@ abstract class AbstractToken implements TokenInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
$currentUserRoles = array_map('strval', (array) $this->user->getRoles());
|
||||
$userRoles = array_map('strval', (array) $user->getRoles());
|
||||
|
||||
if ($this instanceof SwitchUserToken) {
|
||||
$userRoles[] = 'ROLE_PREVIOUS_ADMIN';
|
||||
}
|
||||
|
||||
if (\count($userRoles) !== \count($this->getRoleNames()) || \count($userRoles) !== \count(array_intersect($userRoles, $this->getRoleNames()))) {
|
||||
if (\count($userRoles) !== \count($currentUserRoles) || \count($userRoles) !== \count(array_intersect($userRoles, $currentUserRoles))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ class AbstractTokenTest extends TestCase
|
||||
*/
|
||||
public function testSetUserDoesNotSetAuthenticatedToFalseWhenUserDoesNotChange($user)
|
||||
{
|
||||
$token = new ConcreteToken();
|
||||
$token = new ConcreteToken(['ROLE_FOO']);
|
||||
$token->setAuthenticated(true);
|
||||
$this->assertTrue($token->isAuthenticated());
|
||||
|
||||
|
@ -411,16 +411,10 @@ abstract class AbstractNormalizer implements NormalizerInterface, DenormalizerIn
|
||||
protected function denormalizeParameter(\ReflectionClass $class, \ReflectionParameter $parameter, string $parameterName, $parameterData, array $context, string $format = null)
|
||||
{
|
||||
try {
|
||||
if (\PHP_VERSION_ID < 70100 && null !== $parameterClass = $parameter->getClass()) {
|
||||
$parameterClass = $parameterClass->name;
|
||||
} elseif (\PHP_VERSION_ID >= 70100 && $parameter->hasType() && ($parameterType = $parameter->getType()) && !$parameterType->isBuiltin()) {
|
||||
if (($parameterType = $parameter->getType()) && !$parameterType->isBuiltin()) {
|
||||
$parameterClass = $parameterType->getName();
|
||||
new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist
|
||||
} else {
|
||||
$parameterClass = null;
|
||||
}
|
||||
|
||||
if (null !== $parameterClass) {
|
||||
if (!$this->serializer instanceof DenormalizerInterface) {
|
||||
throw new LogicException(sprintf('Cannot create an instance of "%s" from serialized data because the serializer inject in "%s" is not a denormalizer.', $parameterClass, static::class));
|
||||
}
|
||||
|
@ -37,6 +37,6 @@ class ExpressionLanguageSyntax extends Constraint
|
||||
*/
|
||||
public function validatedBy()
|
||||
{
|
||||
return $this->service;
|
||||
return $this->service ?? static::class.'Validator';
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class ExpressionLanguageSyntaxValidator extends ConstraintValidator
|
||||
{
|
||||
private $expressionLanguage;
|
||||
|
||||
public function __construct(ExpressionLanguage $expressionLanguage)
|
||||
public function __construct(ExpressionLanguage $expressionLanguage = null)
|
||||
{
|
||||
$this->expressionLanguage = $expressionLanguage;
|
||||
}
|
||||
@ -42,6 +42,10 @@ class ExpressionLanguageSyntaxValidator extends ConstraintValidator
|
||||
throw new UnexpectedTypeException($expression, 'string');
|
||||
}
|
||||
|
||||
if (null === $this->expressionLanguage) {
|
||||
$this->expressionLanguage = new ExpressionLanguage();
|
||||
}
|
||||
|
||||
try {
|
||||
$this->expressionLanguage->lint($expression, ($constraint->validateNames ? ($constraint->names ?? []) : null));
|
||||
} catch (SyntaxError $exception) {
|
||||
|
@ -44,8 +44,14 @@ class LengthValidator extends ConstraintValidator
|
||||
$stringValue = ($constraint->normalizer)($stringValue);
|
||||
}
|
||||
|
||||
if (!$invalidCharset = !@mb_check_encoding($stringValue, $constraint->charset)) {
|
||||
$length = mb_strlen($stringValue, $constraint->charset);
|
||||
try {
|
||||
$invalidCharset = !@mb_check_encoding($stringValue, $constraint->charset);
|
||||
} catch (\ValueError $e) {
|
||||
if (!str_starts_with($e->getMessage(), 'mb_check_encoding(): Argument #2 ($encoding) must be a valid encoding')) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$invalidCharset = true;
|
||||
}
|
||||
|
||||
if ($invalidCharset) {
|
||||
@ -59,6 +65,8 @@ class LengthValidator extends ConstraintValidator
|
||||
return;
|
||||
}
|
||||
|
||||
$length = mb_strlen($stringValue, $constraint->charset);
|
||||
|
||||
if (null !== $constraint->max && $length > $constraint->max) {
|
||||
$this->context->buildViolation($constraint->min == $constraint->max ? $constraint->exactMessage : $constraint->maxMessage)
|
||||
->setParameter('{{ value }}', $this->formatValue($stringValue))
|
||||
|
@ -94,6 +94,9 @@ class Caster
|
||||
if ($hasDebugInfo && \is_array($debugInfo)) {
|
||||
foreach ($debugInfo as $k => $v) {
|
||||
if (!isset($k[0]) || "\0" !== $k[0]) {
|
||||
if (\array_key_exists(self::PREFIX_DYNAMIC.$k, $a)) {
|
||||
continue;
|
||||
}
|
||||
$k = self::PREFIX_VIRTUAL.$k;
|
||||
}
|
||||
|
||||
|
@ -376,6 +376,10 @@ class ReflectionCaster
|
||||
private static function addMap(array &$a, \Reflector $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL)
|
||||
{
|
||||
foreach ($map as $k => $m) {
|
||||
if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) {
|
||||
$a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m;
|
||||
}
|
||||
|
@ -162,15 +162,6 @@ class SplCaster
|
||||
return $a;
|
||||
}
|
||||
|
||||
public static function castFixedArray(\SplFixedArray $c, array $a, Stub $stub, bool $isNested)
|
||||
{
|
||||
$a += [
|
||||
Caster::PREFIX_VIRTUAL.'storage' => $c->toArray(),
|
||||
];
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested)
|
||||
{
|
||||
$storage = [];
|
||||
@ -209,14 +200,16 @@ class SplCaster
|
||||
private static function castSplArray($c, array $a, Stub $stub, bool $isNested): array
|
||||
{
|
||||
$prefix = Caster::PREFIX_VIRTUAL;
|
||||
$class = $stub->class;
|
||||
$flags = $c->getFlags();
|
||||
|
||||
if (!($flags & \ArrayObject::STD_PROP_LIST)) {
|
||||
$c->setFlags(\ArrayObject::STD_PROP_LIST);
|
||||
$a = Caster::castObject($c, $class);
|
||||
$a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class);
|
||||
$c->setFlags($flags);
|
||||
}
|
||||
if (\PHP_VERSION_ID < 70400) {
|
||||
$a[$prefix.'storage'] = $c->getArrayCopy();
|
||||
}
|
||||
$a += [
|
||||
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
|
||||
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
|
||||
@ -224,7 +217,6 @@ class SplCaster
|
||||
if ($c instanceof \ArrayObject) {
|
||||
$a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass());
|
||||
}
|
||||
$a[$prefix.'storage'] = $c->getArrayCopy();
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
@ -115,7 +115,6 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'],
|
||||
'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'],
|
||||
'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'],
|
||||
'SplFixedArray' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFixedArray'],
|
||||
'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],
|
||||
'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'],
|
||||
'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],
|
||||
|
@ -30,6 +30,7 @@ class PdoCasterTest extends TestCase
|
||||
{
|
||||
$pdo = new \PDO('sqlite::memory:');
|
||||
$pdo->setAttribute(\PDO::ATTR_STATEMENT_CLASS, ['PDOStatement', [$pdo]]);
|
||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$cast = PdoCaster::castPdo($pdo, [], new Stub(), false);
|
||||
|
||||
@ -45,7 +46,7 @@ array:2 [
|
||||
"\x00~\x00inTransaction" => false
|
||||
"\x00~\x00attributes" => array:9 [
|
||||
"CASE" => NATURAL
|
||||
"ERRMODE" => SILENT
|
||||
"ERRMODE" => EXCEPTION
|
||||
"PERSISTENT" => false
|
||||
"DRIVER_NAME" => "sqlite"
|
||||
"ORACLE_NULLS" => NATURAL
|
||||
|
@ -49,8 +49,8 @@ ReflectionClass {
|
||||
%A]
|
||||
methods: array:%d [
|
||||
%A
|
||||
"export" => ReflectionMethod {
|
||||
+name: "export"
|
||||
"__construct" => ReflectionMethod {
|
||||
+name: "__construct"
|
||||
+class: "ReflectionClass"
|
||||
%A parameters: {
|
||||
$%s: ReflectionParameter {
|
||||
|
@ -172,14 +172,17 @@ EOTXT;
|
||||
$expected = <<<EOTXT
|
||||
ArrayObject {
|
||||
+"foo": 234
|
||||
-storage: array:1 [
|
||||
0 => 123
|
||||
]
|
||||
flag::STD_PROP_LIST: false
|
||||
flag::ARRAY_AS_PROPS: false
|
||||
iteratorClass: "ArrayIterator"
|
||||
storage: array:1 [
|
||||
0 => 123
|
||||
]
|
||||
}
|
||||
EOTXT;
|
||||
if (\PHP_VERSION_ID < 70400) {
|
||||
$expected = str_replace('-storage:', 'storage:', $expected);
|
||||
}
|
||||
$this->assertDumpEquals($expected, $var);
|
||||
}
|
||||
|
||||
@ -190,13 +193,16 @@ EOTXT;
|
||||
$expected = <<<EOTXT
|
||||
Symfony\Component\VarDumper\Tests\Caster\MyArrayIterator {
|
||||
-foo: 123
|
||||
flag::STD_PROP_LIST: false
|
||||
flag::ARRAY_AS_PROPS: false
|
||||
storage: array:1 [
|
||||
-storage: array:1 [
|
||||
0 => 234
|
||||
]
|
||||
flag::STD_PROP_LIST: false
|
||||
flag::ARRAY_AS_PROPS: false
|
||||
}
|
||||
EOTXT;
|
||||
if (\PHP_VERSION_ID < 70400) {
|
||||
$expected = str_replace('-storage:', 'storage:', $expected);
|
||||
}
|
||||
$this->assertDumpEquals($expected, $var);
|
||||
}
|
||||
|
||||
|
@ -199,6 +199,7 @@ EOTXT;
|
||||
|
||||
/**
|
||||
* @requires extension xml
|
||||
* @requires PHP < 8.0
|
||||
*/
|
||||
public function testXmlResource()
|
||||
{
|
||||
|
Reference in New Issue
Block a user