Merge branch '5.2' into 5.x

* 5.2:
  [HttpFoundation] Drop int return type from parseFilesize()
  Added $translator->addLoader()
  bug symfony/symfony#39878 [doctrine-bridge] Add username to UserNameNotFoundException
  [Uid] Clarify the format returned by getTime()
  fix spelling
  Add check for constant in Curl client
  Revert #38614, add assert to avoid regression
  Fix container injection with TypedReference
  Fix problem when SYMFONY_PHPUNIT_VERSION is empty string value
  Update PHP CS Fixer config to v2.18
This commit is contained in:
Alexander M. Turek 2021-01-19 22:04:23 +01:00
commit d91278a68f
23 changed files with 275 additions and 43 deletions

View File

@ -26,6 +26,8 @@ install:
- echo memory_limit=-1 >> php.ini-min
- echo serialize_precision=-1 >> php.ini-min
- echo max_execution_time=1200 >> php.ini-min
- echo post_max_size=4G >> php.ini-min
- echo upload_max_filesize=4G >> php.ini-min
- echo date.timezone="America/Los_Angeles" >> php.ini-min
- echo extension_dir=ext >> php.ini-min
- echo extension=php_xsl.dll >> php.ini-min

View File

@ -11,8 +11,6 @@ return PhpCsFixer\Config::create()
'@Symfony' => true,
'@Symfony:risky' => true,
'protected_to_private' => false,
'native_constant_invocation' => true,
'list_syntax' => ['syntax' => 'short'],
])
->setRiskyAllowed(true)
->setFinder(

View File

@ -62,7 +62,10 @@ class EntityUserProvider implements UserProviderInterface, PasswordUpgraderInter
}
if (null === $user) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
$e = new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
$e->setUsername($username);
throw $e;
}
return $user;
@ -92,7 +95,10 @@ class EntityUserProvider implements UserProviderInterface, PasswordUpgraderInter
$refreshedUser = $repository->find($id);
if (null === $refreshedUser) {
throw new UsernameNotFoundException('User with id '.json_encode($id).' not found.');
$e = new UsernameNotFoundException('User with id '.json_encode($id).' not found.');
$e->setUsername(json_encode($id));
throw $e;
}
}

View File

@ -95,12 +95,12 @@ $passthruOrFail = function ($command) {
if (\PHP_VERSION_ID >= 80000) {
// PHP 8 requires PHPUnit 9.3+
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '9.4');
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '9.4') ?: '9.4';
} elseif (\PHP_VERSION_ID >= 70200) {
// PHPUnit 8 requires PHP 7.2+
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '8.5');
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '8.5') ?: '8.5';
} else {
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '7.5');
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '7.5') ?: '7.5';
}
$MAX_PHPUNIT_VERSION = $getEnvVar('SYMFONY_MAX_PHPUNIT_VERSION', false);

View File

@ -34,7 +34,10 @@ class ArrayUserProvider implements UserProviderInterface
$user = $this->getUser($username);
if (null === $user) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
$e = new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
$e->setUsername($username);
throw $e;
}
return $user;

View File

@ -904,7 +904,7 @@ EOF;
$factoryCode = $asFile ? 'self::do($container, false)' : sprintf('$this->%s(false)', $methodName);
$factoryCode = $this->getProxyDumper()->getProxyFactoryCode($definition, $id, $factoryCode);
$code .= $asFile ? preg_replace('/function \(([^)]*+)\) {/', 'function (\1) use ($container) {', $factoryCode) : $factoryCode;
$code .= $asFile ? preg_replace('/function \(([^)]*+)\)( {|:)/', 'function (\1) use ($container)\2', $factoryCode) : $factoryCode;
}
$c = $this->addServiceInclude($id, $definition);
@ -934,8 +934,7 @@ EOF;
if ($asFile) {
$code = str_replace('$this', '$container', $code);
$code = str_replace('function () {', 'function () use ($container) {', $code);
$code = str_replace('function ($lazyLoad = true) {', 'function ($lazyLoad = true) use ($container) {', $code);
$code = preg_replace('/function \(([^)]*+)\)( {|:)/', 'function (\1) use ($container)\2', $code);
}
$code .= " }\n";

View File

@ -244,6 +244,26 @@ class PhpDumperTest extends TestCase
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_as_files.txt', $dump);
}
public function testDumpAsFilesWithTypedReference()
{
$container = include self::$fixturesPath.'/containers/container10.php';
$container->getDefinition('foo')->addTag('hot');
$container->register('bar', 'stdClass');
$container->register('closure', 'stdClass')
->setProperty('closures', [
new ServiceClosureArgument(new TypedReference('foo', \stdClass::class, $container::IGNORE_ON_UNINITIALIZED_REFERENCE)),
])
->setPublic(true);
$container->compile();
$dumper = new PhpDumper($container);
$dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true);
if ('\\' === \DIRECTORY_SEPARATOR) {
$dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump);
}
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services10_as_files.txt', $dump);
}
public function testDumpAsFilesWithFactoriesInlined()
{
$container = include self::$fixturesPath.'/containers/container9.php';

View File

@ -0,0 +1,167 @@
Array
(
[Container%s/removed-ids.php] => <?php
namespace Container%s;
return [
'Psr\\Container\\ContainerInterface' => true,
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
'bar' => true,
];
[Container%s/getClosureService.php] => <?php
namespace Container%s;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
* @internal This class has been auto-generated by the Symfony Dependency Injection Component.
*/
class getClosureService extends ProjectServiceContainer
{
/**
* Gets the public 'closure' shared service.
*
* @return \stdClass
*/
public static function do($container, $lazyLoad = true)
{
$container->services['closure'] = $instance = new \stdClass();
$instance->closures = [0 => function () use ($container): ?\stdClass {
return ($container->services['foo'] ?? null);
}];
return $instance;
}
}
[Container%s/ProjectServiceContainer.php] => <?php
namespace Container%s;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
/**
* @internal This class has been auto-generated by the Symfony Dependency Injection Component.
*/
class ProjectServiceContainer extends Container
{
protected $containerDir;
protected $targetDir;
protected $parameters = [];
private $buildParameters;
public function __construct(array $buildParameters = [], $containerDir = __DIR__)
{
$this->buildParameters = $buildParameters;
$this->containerDir = $containerDir;
$this->targetDir = \dirname($containerDir);
$this->services = $this->privates = [];
$this->methodMap = [
'foo' => 'getFooService',
];
$this->fileMap = [
'closure' => 'getClosureService',
];
$this->aliases = [];
}
public function compile(): void
{
throw new LogicException('You cannot compile a dumped container that was already compiled.');
}
public function isCompiled(): bool
{
return true;
}
public function getRemovedIds(): array
{
return require $this->containerDir.\DIRECTORY_SEPARATOR.'removed-ids.php';
}
protected function load($file, $lazyLoad = true)
{
if (class_exists($class = __NAMESPACE__.'\\'.$file, false)) {
return $class::do($this, $lazyLoad);
}
if ('.' === $file[-4]) {
$class = substr($class, 0, -4);
} else {
$file .= '.php';
}
$service = require $this->containerDir.\DIRECTORY_SEPARATOR.$file;
return class_exists($class, false) ? $class::do($this, $lazyLoad) : $service;
}
/**
* Gets the public 'foo' shared service.
*
* @return \FooClass
*/
protected function getFooService()
{
return $this->services['foo'] = new \FooClass(new \stdClass());
}
}
[ProjectServiceContainer.preload.php] => <?php
// This file has been auto-generated by the Symfony Dependency Injection Component
// You can reference it in the "opcache.preload" php.ini setting on PHP >= 7.4 when preloading is desired
use Symfony\Component\DependencyInjection\Dumper\Preloader;
if (in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) {
return;
}
require dirname(__DIR__, %d).'%svendor/autoload.php';
require __DIR__.'/Container%s/ProjectServiceContainer.php';
require __DIR__.'/Container%s/getClosureService.php';
$classes = [];
$classes[] = 'FooClass';
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';
Preloader::preload($classes);
[ProjectServiceContainer.php] => <?php
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
if (\class_exists(\Container%s\ProjectServiceContainer::class, false)) {
// no-op
} elseif (!include __DIR__.'/Container%s/ProjectServiceContainer.php') {
touch(__DIR__.'/Container%s.legacy');
return;
}
if (!\class_exists(ProjectServiceContainer::class, false)) {
\class_alias(\Container%s\ProjectServiceContainer::class, ProjectServiceContainer::class, false);
}
return new \Container%s\ProjectServiceContainer([
'container.build_hash' => '%s',
'container.build_id' => '%s',
'container.build_time' => %d,
], __DIR__.\DIRECTORY_SEPARATOR.'Container%s');
)

View File

@ -176,8 +176,10 @@ class FileType extends AbstractType
* Returns the maximum size of an uploaded file as configured in php.ini.
*
* This method should be kept in sync with Symfony\Component\HttpFoundation\File\UploadedFile::getMaxFilesize().
*
* @return int|float The maximum size of an uploaded file in bytes (returns float if size > PHP_INT_MAX)
*/
private static function getMaxFilesize(): int
private static function getMaxFilesize()
{
$iniMax = strtolower(ini_get('upload_max_filesize'));
@ -212,8 +214,10 @@ class FileType extends AbstractType
* (i.e. try "MB", then "kB", then "bytes").
*
* This method should be kept in sync with Symfony\Component\Validator\Constraints\FileValidator::factorizeSizes().
*
* @param int|float $limit
*/
private function factorizeSizes(int $size, int $limit)
private function factorizeSizes(int $size, $limit)
{
$coef = self::MIB_BYTES;
$coefFactor = self::KIB_BYTES;

View File

@ -173,7 +173,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface,
$curlopts[\CURLOPT_DNS_USE_GLOBAL_CACHE] = false;
}
if (\defined('CURLOPT_HEADEROPT')) {
if (\defined('CURLOPT_HEADEROPT') && \defined('CURLHEADER_SEPARATE')) {
$curlopts[\CURLOPT_HEADEROPT] = \CURLHEADER_SEPARATE;
}

View File

@ -216,7 +216,7 @@ class UploadedFile extends File
/**
* Returns the maximum size of an uploaded file as configured in php.ini.
*
* @return int The maximum size of an uploaded file in bytes
* @return int|float The maximum size of an uploaded file in bytes (returns float if size > PHP_INT_MAX)
*/
public static function getMaxFilesize()
{
@ -228,8 +228,10 @@ class UploadedFile extends File
/**
* Returns the given size from an ini value in bytes.
*
* @return int|float Returns float if size > PHP_INT_MAX
*/
private static function parseFilesize($size): int
private static function parseFilesize($size)
{
if ('' === $size) {
return 0;

View File

@ -1895,16 +1895,10 @@ class Request
}
$basename = basename($baseUrl);
if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri).'/', '/'.$basename.'/')) {
// strip autoindex filename, for virtualhost based on URL path
$baseUrl = \dirname($baseUrl).'/';
$basename = basename($baseUrl);
if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri).'/', '/'.$basename.'/')) {
if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
// no match whatsoever; set it blank
return '';
}
}
// If using mod_rewrite or ISAPI_Rewrite strip the script filename
// out of baseUrl. $pos !== 0 makes sure it is not matching a value

View File

@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException;
use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException;
use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException;
use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
@ -33,7 +34,7 @@ class UploadedFileTest extends TestCase
public function testConstructWhenFileNotExists()
{
$this->expectException(\Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException::class);
$this->expectException(FileNotFoundException::class);
new UploadedFile(
__DIR__.'/Fixtures/not_here',
@ -324,13 +325,16 @@ class UploadedFileTest extends TestCase
{
$size = UploadedFile::getMaxFilesize();
if ($size > \PHP_INT_MAX) {
$this->assertIsFloat($size);
} else {
$this->assertIsInt($size);
}
$this->assertGreaterThan(0, $size);
if (0 === (int) ini_get('post_max_size') && 0 === (int) ini_get('upload_max_filesize')) {
$this->assertSame(\PHP_INT_MAX, $size);
} else {
$this->assertLessThan(\PHP_INT_MAX, $size);
}
}
}

View File

@ -1793,8 +1793,8 @@ class RequestTest extends TestCase
'SCRIPT_NAME' => '/foo/app.php',
'PHP_SELF' => '/foo/app.php',
],
'/sub/foo',
'/bar',
'',
'/sub/foo/bar',
],
[
'/sub/foo/app.php/bar',
@ -1813,8 +1813,18 @@ class RequestTest extends TestCase
'SCRIPT_NAME' => '/foo/app2.phpx',
'PHP_SELF' => '/foo/app2.phpx',
],
'/sub/foo',
'/bar/baz',
'',
'/sub/foo/bar/baz',
],
[
'/foo/api/bar',
[
'SCRIPT_FILENAME' => '/var/www/api/index.php',
'SCRIPT_NAME' => '/api/index.php',
'PHP_SELF' => '/api/index.php',
],
'',
'/foo/api/bar',
],
];
}

View File

@ -73,18 +73,27 @@ class LdapUserProvider implements UserProviderInterface, PasswordUpgraderInterfa
$query = str_replace('{username}', $username, $this->defaultSearch);
$search = $this->ldap->query($this->baseDn, $query);
} catch (ConnectionException $e) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
$e = new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
$e->setUsername($username);
throw $e;
}
$entries = $search->execute();
$count = \count($entries);
if (!$count) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
$e = new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
$e->setUsername($username);
throw $e;
}
if ($count > 1) {
throw new UsernameNotFoundException('More than one user found.');
$e = new UsernameNotFoundException('More than one user found.');
$e->setUsername($username);
throw $e;
}
$entry = $entries[0];

View File

@ -105,7 +105,10 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface
$user = $guardAuthenticator->getUser($token->getCredentials(), $this->userProvider);
if (null === $user) {
throw new UsernameNotFoundException(sprintf('Null returned from "%s::getUser()".', get_debug_type($guardAuthenticator)));
$e = new UsernameNotFoundException(sprintf('Null returned from "%s::getUser()".', get_debug_type($guardAuthenticator)));
$e->setUsername($token->getUsername());
throw $e;
}
if (!$user instanceof UserInterface) {

View File

@ -12,8 +12,10 @@ $ composer require symfony/translation
```php
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
$translator = new Translator('fr_FR');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [
'Hello World!' => 'Bonjour !',
], 'fr_FR');

View File

@ -104,6 +104,9 @@ class Ulid extends AbstractUid
return $this->uid;
}
/**
* @return float Seconds since the Unix epoch 1970-01-01 00:00:00
*/
public function getTime(): float
{
$time = strtr(substr($this->uid, 0, 10), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv');

View File

@ -31,6 +31,9 @@ class UuidV1 extends Uuid
}
}
/**
* @return float Seconds since the Unix epoch 1970-01-01 00:00:00
*/
public function getTime(): float
{
$time = '0'.substr($this->uid, 15, 3).substr($this->uid, 9, 4).substr($this->uid, 0, 8);

View File

@ -50,6 +50,9 @@ class UuidV6 extends Uuid
}
}
/**
* @return float Seconds since the Unix epoch 1970-01-01 00:00:00
*/
public function getTime(): float
{
$time = '0'.substr($this->uid, 0, 8).substr($this->uid, 9, 4).substr($this->uid, 15, 3);

View File

@ -214,8 +214,10 @@ class FileValidator extends ConstraintValidator
/**
* Convert the limit to the smallest possible number
* (i.e. try "MB", then "kB", then "bytes").
*
* @param int|float $limit
*/
private function factorizeSizes(int $size, int $limit, bool $binaryFormat): array
private function factorizeSizes(int $size, $limit, bool $binaryFormat): array
{
if ($binaryFormat) {
$coef = self::MIB_BYTES;

View File

@ -84,7 +84,7 @@
</trans-unit>
<trans-unit id="21">
<source>This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.</source>
<target>הערך קצר מידי. הוא צריך להכיל {{ limit }} תווים לפחות.|הערך קצר מידיץ הוא צריך להכיל {{ limit }} תווים לפחות.</target>
<target>הערך קצר מידי. הוא צריך להכיל {{ limit }} תווים לפחות.|הערך קצר מידי. הערך צריך להכיל {{ limit }} תווים לפחות.</target>
</trans-unit>
<trans-unit id="22">
<source>This value should not be blank.</source>

View File

@ -506,14 +506,12 @@ abstract class FileValidatorTest extends ConstraintValidatorTestCase
[, $limit, $suffix] = $method->invokeArgs(new FileValidator(), [0, UploadedFile::getMaxFilesize(), false]);
// it correctly parses the maxSize option and not only uses simple string comparison
// 1000M should be bigger than the ini value
// 1000G should be bigger than the ini value
$tests[] = [(string) \UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage', [
'{{ limit }}' => $limit,
'{{ suffix }}' => $suffix,
], '1000M'];
], '1000G'];
// it correctly parses the maxSize option and not only uses simple string comparison
// 1000M should be bigger than the ini value
$tests[] = [(string) \UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage', [
'{{ limit }}' => '0.1',
'{{ suffix }}' => 'MB',