Merge branch '3.4' into 4.4
* 3.4: Skip Doctrine DBAL on php 8 until we have a compatible version. [DomCrawler] Catch expected ValueError. [Validator] Catch expected ValueError. [VarDumper] ReflectionFunction::isDisabled() is deprecated. [PropertyAccess] Parse php 8 TypeErrors correctly. [Intl] Fix call to ReflectionProperty::getValue() for static properties. [HttpKernel] Prevent calling method_exists() with non-string values. [Debug] php 8 does not pass $context to error handlers. [Config] Removed implicit cast of ReflectionProperty to string. [Debug] Undefined variables raise a warning in php 8. [Debug] Skip test that would trigger a fatal error on php 8. Address deprecation of ReflectionType::getClass(). Properties $originalName and $mimeType are never null in UploadedFile
This commit is contained in:
commit
8de1091347
@ -60,6 +60,13 @@ class EntityTypeTest extends BaseTypeTest
|
|||||||
|
|
||||||
protected static $supportedFeatureSetVersion = 404;
|
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
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
$this->em = DoctrineTestHelper::createTestEntityManager();
|
$this->em = DoctrineTestHelper::createTestEntityManager();
|
||||||
|
@ -24,6 +24,13 @@ use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
|
|||||||
|
|
||||||
class EntityUserProviderTest extends TestCase
|
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()
|
public function testRefreshUserGetsUserByPrimaryKey()
|
||||||
{
|
{
|
||||||
$em = DoctrineTestHelper::createTestEntityManager();
|
$em = DoctrineTestHelper::createTestEntityManager();
|
||||||
|
@ -59,6 +59,13 @@ class UniqueEntityValidatorTest extends ConstraintValidatorTestCase
|
|||||||
|
|
||||||
protected $repositoryFactory;
|
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
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
$this->repositoryFactory = new TestRepositoryFactory();
|
$this->repositoryFactory = new TestRepositoryFactory();
|
||||||
|
@ -30,9 +30,9 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"cache/integration-tests": "dev-master",
|
"cache/integration-tests": "dev-master",
|
||||||
"doctrine/cache": "~1.6",
|
"doctrine/cache": "^1.6",
|
||||||
"doctrine/dbal": "~2.5",
|
"doctrine/dbal": "^2.5|^3.0",
|
||||||
"predis/predis": "~1.1",
|
"predis/predis": "^1.1",
|
||||||
"psr/simple-cache": "^1.0",
|
"psr/simple-cache": "^1.0",
|
||||||
"symfony/config": "^4.2|^5.0",
|
"symfony/config": "^4.2|^5.0",
|
||||||
"symfony/dependency-injection": "^3.4|^4.1|^5.0",
|
"symfony/dependency-injection": "^3.4|^4.1|^5.0",
|
||||||
|
@ -135,7 +135,11 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
|
|||||||
$defaults = $class->getDefaultProperties();
|
$defaults = $class->getDefaultProperties();
|
||||||
|
|
||||||
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
|
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);
|
yield print_r(isset($defaults[$p->name]) && !\is_object($defaults[$p->name]) ? $defaults[$p->name] : null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,9 +103,14 @@ class ErrorHandlerTest extends TestCase
|
|||||||
$this->fail('ErrorException expected');
|
$this->fail('ErrorException expected');
|
||||||
} catch (\ErrorException $exception) {
|
} catch (\ErrorException $exception) {
|
||||||
// if an exception is thrown, the test passed
|
// 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->assertEquals(__FILE__, $exception->getFile());
|
||||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
|
||||||
|
|
||||||
$trace = $exception->getTrace();
|
$trace = $exception->getTrace();
|
||||||
|
|
||||||
@ -249,11 +254,17 @@ class ErrorHandlerTest extends TestCase
|
|||||||
|
|
||||||
$line = null;
|
$line = null;
|
||||||
$logArgCheck = function ($level, $message, $context) use (&$line) {
|
$logArgCheck = function ($level, $message, $context) use (&$line) {
|
||||||
$this->assertEquals('Notice: Undefined variable: undefVar', $message);
|
|
||||||
$this->assertArrayHasKey('exception', $context);
|
$this->assertArrayHasKey('exception', $context);
|
||||||
$exception = $context['exception'];
|
$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->assertInstanceOf(SilencedErrorContext::class, $exception);
|
||||||
$this->assertSame(E_NOTICE, $exception->getSeverity());
|
|
||||||
$this->assertSame(__FILE__, $exception->getFile());
|
$this->assertSame(__FILE__, $exception->getFile());
|
||||||
$this->assertSame($line, $exception->getLine());
|
$this->assertSame($line, $exception->getLine());
|
||||||
$this->assertNotEmpty($exception->getTrace());
|
$this->assertNotEmpty($exception->getTrace());
|
||||||
@ -267,8 +278,13 @@ class ErrorHandlerTest extends TestCase
|
|||||||
;
|
;
|
||||||
|
|
||||||
$handler = ErrorHandler::register();
|
$handler = ErrorHandler::register();
|
||||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
if (\PHP_VERSION_ID < 80000) {
|
||||||
$handler->screamAt(E_NOTICE);
|
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||||
|
$handler->screamAt(E_NOTICE);
|
||||||
|
} else {
|
||||||
|
$handler->setDefaultLogger($logger, E_WARNING);
|
||||||
|
$handler->screamAt(E_WARNING);
|
||||||
|
}
|
||||||
unset($undefVar);
|
unset($undefVar);
|
||||||
$line = __LINE__ + 1;
|
$line = __LINE__ + 1;
|
||||||
@$undefVar++;
|
@$undefVar++;
|
||||||
|
@ -15,8 +15,8 @@ class ErrorHandlerThatUsesThePreviousOne
|
|||||||
return $handler;
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ use Symfony\Component\Mime\MimeTypes;
|
|||||||
*/
|
*/
|
||||||
class UploadedFile extends File
|
class UploadedFile extends File
|
||||||
{
|
{
|
||||||
private $test = false;
|
private $test;
|
||||||
private $originalName;
|
private $originalName;
|
||||||
private $mimeType;
|
private $mimeType;
|
||||||
private $error;
|
private $error;
|
||||||
@ -83,7 +83,7 @@ class UploadedFile extends File
|
|||||||
* It is extracted from the request from which the file has been uploaded.
|
* It is extracted from the request from which the file has been uploaded.
|
||||||
* Then it should not be considered as a safe value.
|
* Then it should not be considered as a safe value.
|
||||||
*
|
*
|
||||||
* @return string|null The original name
|
* @return string The original name
|
||||||
*/
|
*/
|
||||||
public function getClientOriginalName()
|
public function getClientOriginalName()
|
||||||
{
|
{
|
||||||
@ -112,7 +112,7 @@ class UploadedFile extends File
|
|||||||
* For a trusted mime type, use getMimeType() instead (which guesses the mime
|
* For a trusted mime type, use getMimeType() instead (which guesses the mime
|
||||||
* type based on the file content).
|
* type based on the file content).
|
||||||
*
|
*
|
||||||
* @return string|null The mime type
|
* @return string The mime type
|
||||||
*
|
*
|
||||||
* @see getMimeType()
|
* @see getMimeType()
|
||||||
*/
|
*/
|
||||||
|
@ -602,7 +602,7 @@ abstract class AbstractNumberFormatterTest extends TestCase
|
|||||||
|
|
||||||
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enSymbols');
|
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enSymbols');
|
||||||
$r->setAccessible(true);
|
$r->setAccessible(true);
|
||||||
$expected = $r->getValue('Symfony\Component\Intl\NumberFormatter\NumberFormatter');
|
$expected = $r->getValue();
|
||||||
|
|
||||||
for ($i = 0; $i <= 17; ++$i) {
|
for ($i = 0; $i <= 17; ++$i) {
|
||||||
$this->assertSame($expected[1][$i], $decimalFormatter->getSymbol($i));
|
$this->assertSame($expected[1][$i], $decimalFormatter->getSymbol($i));
|
||||||
@ -619,7 +619,7 @@ abstract class AbstractNumberFormatterTest extends TestCase
|
|||||||
|
|
||||||
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enTextAttributes');
|
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enTextAttributes');
|
||||||
$r->setAccessible(true);
|
$r->setAccessible(true);
|
||||||
$expected = $r->getValue('Symfony\Component\Intl\NumberFormatter\NumberFormatter');
|
$expected = $r->getValue();
|
||||||
|
|
||||||
for ($i = 0; $i <= 5; ++$i) {
|
for ($i = 0; $i <= 5; ++$i) {
|
||||||
$this->assertSame($expected[1][$i], $decimalFormatter->getTextAttribute($i));
|
$this->assertSame($expected[1][$i], $decimalFormatter->getTextAttribute($i));
|
||||||
|
@ -180,7 +180,7 @@ class OptionsResolver implements Options
|
|||||||
$reflClosure = new \ReflectionFunction($value);
|
$reflClosure = new \ReflectionFunction($value);
|
||||||
$params = $reflClosure->getParameters();
|
$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
|
// Initialize the option if no previous value exists
|
||||||
if (!isset($this->defaults[$option])) {
|
if (!isset($this->defaults[$option])) {
|
||||||
$this->defaults[$option] = null;
|
$this->defaults[$option] = null;
|
||||||
@ -1217,4 +1217,13 @@ class OptionsResolver implements Options
|
|||||||
|
|
||||||
return implode('", "', $options);
|
return implode('", "', $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getParameterClassName(\ReflectionParameter $parameter): ?string
|
||||||
|
{
|
||||||
|
if (!($type = $parameter->getType()) || $type->isBuiltin()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type->getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,12 +183,15 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
|
|
||||||
private static function throwInvalidArgumentException(string $message, array $trace, int $i, string $propertyPath, \Throwable $previous = null): void
|
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 (!isset($trace[$i]['file']) || __FILE__ !== $trace[$i]['file']) {
|
||||||
if (0 !== strpos($message, 'Argument ')) {
|
|
||||||
return;
|
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 = 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);
|
$pos += \strlen($delim);
|
||||||
$j = strpos($message, ',', $pos);
|
$j = strpos($message, ',', $pos);
|
||||||
@ -197,6 +200,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);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -384,7 +393,7 @@ class PropertyAccessor implements PropertyAccessorInterface
|
|||||||
$result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}();
|
$result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}();
|
||||||
} catch (\TypeError $e) {
|
} catch (\TypeError $e) {
|
||||||
// handle uninitialized properties in PHP >= 7
|
// handle uninitialized properties in PHP >= 7
|
||||||
if (preg_match((sprintf('/^Return value of %s::%s\(\) must be of the type (\w+), null returned$/', preg_quote(\get_class($object)), $access[self::ACCESS_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)), $access[self::ACCESS_NAME])), $e->getMessage(), $matches)) {
|
||||||
throw new AccessException(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), $access[self::ACCESS_NAME], $matches[1]), 0, $e);
|
throw new AccessException(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), $access[self::ACCESS_NAME], $matches[1]), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +48,14 @@ class LengthValidator extends ConstraintValidator
|
|||||||
$stringValue = ($constraint->normalizer)($stringValue);
|
$stringValue = ($constraint->normalizer)($stringValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$invalidCharset = !@mb_check_encoding($stringValue, $constraint->charset)) {
|
try {
|
||||||
$length = mb_strlen($stringValue, $constraint->charset);
|
$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) {
|
if ($invalidCharset) {
|
||||||
@ -63,6 +69,8 @@ class LengthValidator extends ConstraintValidator
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$length = mb_strlen($stringValue, $constraint->charset);
|
||||||
|
|
||||||
if (null !== $constraint->max && $length > $constraint->max) {
|
if (null !== $constraint->max && $length > $constraint->max) {
|
||||||
$this->context->buildViolation($constraint->min == $constraint->max ? $constraint->exactMessage : $constraint->maxMessage)
|
$this->context->buildViolation($constraint->min == $constraint->max ? $constraint->exactMessage : $constraint->maxMessage)
|
||||||
->setParameter('{{ value }}', $this->formatValue($stringValue))
|
->setParameter('{{ value }}', $this->formatValue($stringValue))
|
||||||
|
@ -376,6 +376,10 @@ class ReflectionCaster
|
|||||||
private static function addMap(array &$a, \Reflector $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL)
|
private static function addMap(array &$a, \Reflector $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL)
|
||||||
{
|
{
|
||||||
foreach ($map as $k => $m) {
|
foreach ($map as $k => $m) {
|
||||||
|
if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) {
|
if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) {
|
||||||
$a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m;
|
$a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user