Merge branch '4.4'

* 4.4:
  Fix travis script
  [Contracts] Fix branch alias
  minor fix for wrong case
  [HttpFoundation] Fix `getMaxFilesize`
  [Cache] fix warning on PHP 7.4
  [Console] fix warning on PHP 7.4
  let BlockingStoreInterface extend PersistingStoreInterface
  Don't add value of (default/static) objects to the signature
  fix(yml): fix comment in milti line value
  Make sure trace_level is always defined
  Ensure $request->hasSession() is always checked before calling getSession()
  Fix bindings and tagged_locator
  Recompile container when translations directory changes
This commit is contained in:
Nicolas Grekas 2019-07-31 14:45:18 +02:00
commit 7b4311791c
33 changed files with 96 additions and 72 deletions

View File

@ -190,7 +190,7 @@ install:
export SYMFONY_DEPRECATIONS_HELPER=weak &&
cp composer.json composer.json.orig &&
echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json &&
php .github/build-packages.php HEAD^ $COMPONENTS &&
php .github/build-packages.php HEAD^ $(find src/Symfony -mindepth 3 -type f -name composer.json -printf '%h\n') &&
mv composer.json composer.json.phpunit &&
mv composer.json.orig composer.json
fi

View File

@ -112,10 +112,9 @@ class AppVariable
if (null === $this->requestStack) {
throw new \RuntimeException('The "app.session" variable is not available.');
}
$request = $this->getRequest();
if ($request = $this->getRequest()) {
return $request->getSession();
}
return $request && $request->hasSession() ? $request->getSession() : null;
}
/**
@ -157,8 +156,7 @@ class AppVariable
public function getFlashes($types = null)
{
try {
$session = $this->getSession();
if (null === $session) {
if (null === $session = $this->getSession()) {
return [];
}
} catch (\RuntimeException $e) {

View File

@ -51,6 +51,7 @@ class AppVariableTest extends TestCase
public function testGetSession()
{
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
$request->method('hasSession')->willReturn(true);
$request->method('getSession')->willReturn($session = new Session());
$this->setRequestStack($request);
@ -267,6 +268,7 @@ class AppVariableTest extends TestCase
$session->method('getFlashBag')->willReturn($flashBag);
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
$request->method('hasSession')->willReturn(true);
$request->method('getSession')->willReturn($session);
$this->setRequestStack($request);

View File

@ -1016,7 +1016,7 @@ class FrameworkExtension extends Extension
}
$defaultDir = $container->getParameterBag()->resolveValue($config['default_path']);
foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) {
if (is_dir($dir = $bundle['path'].'/Resources/translations')) {
if ($container->fileExists($dir = $bundle['path'].'/Resources/translations')) {
$dirs[] = $dir;
} else {
$nonExistingDirs[] = $dir;
@ -1024,7 +1024,7 @@ class FrameworkExtension extends Extension
}
foreach ($config['paths'] as $dir) {
if (is_dir($dir)) {
if ($container->fileExists($dir)) {
$dirs[] = $transPaths[] = $dir;
} else {
throw new \UnexpectedValueException(sprintf('%s defined in translator.paths does not exist or is not a directory', $dir));
@ -1039,7 +1039,7 @@ class FrameworkExtension extends Extension
$container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths);
}
if (is_dir($defaultDir)) {
if ($container->fileExists($defaultDir)) {
$dirs[] = $defaultDir;
} else {
$nonExistingDirs[] = $defaultDir;

View File

@ -26,8 +26,6 @@ use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
use Symfony\Component\Config\Resource\DirectoryResource;
use Symfony\Component\Config\Resource\FileExistenceResource;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
@ -745,17 +743,6 @@ abstract class FrameworkExtensionTest extends TestCase
);
$this->assertNotEmpty($nonExistingDirectories, 'FrameworkBundle should pass non existing directories to Translator');
$resources = $container->getResources();
foreach ($resources as $resource) {
if ($resource instanceof DirectoryResource) {
$this->assertNotContains('translations', $resource->getResource());
}
if ($resource instanceof FileExistenceResource) {
$this->assertNotContains('translations', $resource->getResource());
}
}
}
public function testTranslatorMultipleFallbacks()

View File

@ -117,7 +117,7 @@ class ProfilerController
throw new NotFoundHttpException('The profiler must be enabled.');
}
if ($request->hasSession() && ($session = $request->getSession()) && $session->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
if ($request->hasSession() && ($session = $request->getSession())->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
// keep current flashes for one more request if using AutoExpireFlashBag
$session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
}

View File

@ -88,8 +88,7 @@ class WebDebugToolbarListener implements EventSubscriberInterface
}
if ($response->headers->has('X-Debug-Token') && $response->isRedirect() && $this->interceptRedirects && 'html' === $request->getRequestFormat()) {
$session = $request->getSession();
if (null !== $session && $session->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
if ($request->hasSession() && ($session = $request->getSession())->isStarted() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
// keep current flashes for one more request if using AutoExpireFlashBag
$session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
}

View File

@ -44,7 +44,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace));
}
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) use ($defaultLifetime) {
static function ($key, $value, $isHit) use ($defaultLifetime) {
$item = new CacheItem();
$item->key = $key;
$item->value = $v = $value;
@ -67,7 +67,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
);
$getId = \Closure::fromCallable([$this, 'getId']);
$this->mergeByLifetime = \Closure::bind(
function ($deferred, $namespace, &$expiredIds) use ($getId) {
static function ($deferred, $namespace, &$expiredIds) use ($getId) {
$byLifetime = [];
$now = microtime(true);
$expiredIds = [];

View File

@ -37,7 +37,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
{
$this->storeSerialized = $storeSerialized;
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) use ($defaultLifetime) {
static function ($key, $value, $isHit) use ($defaultLifetime) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;

View File

@ -61,7 +61,7 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
$this->adapterCount = \count($this->adapters);
$this->syncItem = \Closure::bind(
function ($sourceItem, $item) use ($defaultLifetime) {
static function ($sourceItem, $item) use ($defaultLifetime) {
$item->value = $sourceItem->value;
$item->expiry = $sourceItem->expiry;
$item->isHit = $sourceItem->isHit;

View File

@ -48,7 +48,7 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
$this->file = $file;
$this->pool = $fallbackPool;
$this->createCacheItem = \Closure::bind(
function ($key, $value, $isHit) {
static function ($key, $value, $isHit) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;

View File

@ -41,7 +41,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
$this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace);
$this->namespaceLen = \strlen($namespace);
$this->createCacheItem = \Closure::bind(
function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
static function ($key, $innerItem) use ($defaultLifetime, $poolHash) {
$item = new CacheItem();
$item->key = $key;
@ -77,7 +77,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix
*/
function (CacheItemInterface $innerItem, array $item) {
static function (CacheItemInterface $innerItem, array $item) {
// Tags are stored separately, no need to account for them when considering this item's newly set metadata
if (isset(($metadata = $item["\0*\0newMetadata"])[CacheItem::METADATA_TAGS])) {
unset($metadata[CacheItem::METADATA_TAGS]);

View File

@ -45,7 +45,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
$this->tags = $tagsPool ?: $itemsPool;
$this->knownTagVersionsTtl = $knownTagVersionsTtl;
$this->createCacheItem = \Closure::bind(
function ($key, $value, CacheItem $protoItem) {
static function ($key, $value, CacheItem $protoItem) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
@ -59,7 +59,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
CacheItem::class
);
$this->setCacheItemTags = \Closure::bind(
function (CacheItem $item, $key, array &$itemTags) {
static function (CacheItem $item, $key, array &$itemTags) {
$item->isTaggable = true;
if (!$item->isHit) {
return $item;
@ -80,7 +80,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
CacheItem::class
);
$this->getTagsByKey = \Closure::bind(
function ($deferred) {
static function ($deferred) {
$tagsByKey = [];
foreach ($deferred as $key => $item) {
$tagsByKey[$key] = $item->newMetadata[CacheItem::METADATA_TAGS] ?? [];
@ -92,7 +92,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
CacheItem::class
);
$this->invalidateTags = \Closure::bind(
function (AdapterInterface $tagsAdapter, array $tags) {
static function (AdapterInterface $tagsAdapter, array $tags) {
foreach ($tags as $v) {
$v->defaultLifetime = 0;
$v->expiry = null;

View File

@ -42,7 +42,7 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
}
$cacheItemPrototype = &$this->cacheItemPrototype;
$createCacheItem = \Closure::bind(
function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) {
static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) {
$item = clone $cacheItemPrototype;
$item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key);
$item->value = $value;

View File

@ -58,7 +58,7 @@ trait ContractsTrait
static $setMetadata;
$setMetadata = $setMetadata ?? \Closure::bind(
function (CacheItem $item, float $startTime, ?array &$metadata) {
static function (CacheItem $item, float $startTime, ?array &$metadata) {
if ($item->expiry > $endTime = microtime(true)) {
$item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry;
$item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = 1000 * (int) ($endTime - $startTime);

View File

@ -138,7 +138,7 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) {
yield $p->getDocComment().$p;
yield print_r(isset($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);
}
}

View File

@ -185,6 +185,15 @@ EOPHP;
$res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class));
$this->assertTrue($res->isFresh(0));
}
public function testIgnoresObjectsInSignature()
{
$res = new ReflectionClassResource(new \ReflectionClass(TestServiceWithStaticProperty::class));
$this->assertTrue($res->isFresh(0));
TestServiceWithStaticProperty::$initializedObject = new TestServiceWithStaticProperty();
$this->assertTrue($res->isFresh(0));
}
}
interface DummyInterface
@ -224,3 +233,8 @@ class TestServiceSubscriber implements ServiceSubscriberInterface
return self::$subscribedServices;
}
}
class TestServiceWithStaticProperty
{
public static $initializedObject;
}

View File

@ -132,7 +132,7 @@ class ArrayInput extends Input
}
if (0 === strpos($key, '--')) {
$this->addLongOption(substr($key, 2), $value);
} elseif ('-' === $key[0]) {
} elseif (0 === strpos($key, '-')) {
$this->addShortOption(substr($key, 1), $value);
} else {
$this->addArgument($key, $value);

View File

@ -51,15 +51,15 @@ class PassConfig
$this->optimizationPasses = [[
new ValidateEnvPlaceholdersPass(),
new ResolveChildDefinitionsPass(),
new ServiceLocatorTagPass(),
new RegisterServiceSubscribersPass(),
new DecoratorServicePass(),
new ResolveParameterPlaceHoldersPass(false),
new ResolveFactoryClassPass(),
new CheckDefinitionValidityPass(),
new ResolveNamedArgumentsPass(),
new AutowireRequiredMethodsPass(),
new ResolveBindingsPass(),
new ServiceLocatorTagPass(),
new CheckDefinitionValidityPass(),
new AutowirePass(false),
new ResolveTaggedIteratorArgumentPass(),
new ResolveServiceSubscribersPass(),

View File

@ -219,13 +219,26 @@ class UploadedFile extends File
*/
public static function getMaxFilesize()
{
$iniMax = strtolower(ini_get('upload_max_filesize'));
$sizePostMax = self::parseFilesize(ini_get('post_max_size'));
$sizeUploadMax = self::parseFilesize(ini_get('upload_max_filesize'));
if ('' === $iniMax) {
return PHP_INT_MAX;
return min([$sizePostMax, $sizeUploadMax]);
}
/**
* Returns the given size from an ini value in bytes.
*
* @return int The given size in bytes
*/
private static function parseFilesize($size)
{
if ('' === $size) {
return 0;
}
$max = ltrim($iniMax, '+');
$size = strtolower($size);
$max = ltrim($size, '+');
if (0 === strpos($max, '0x')) {
$max = \intval($max, 16);
} elseif (0 === strpos($max, '0')) {
@ -234,7 +247,7 @@ class UploadedFile extends File
$max = (int) $max;
}
switch (substr($iniMax, -1)) {
switch (substr($size, -1)) {
case 't': $max *= 1024;
// no break
case 'g': $max *= 1024;

View File

@ -46,8 +46,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface
}
// bootstrap the session
$session = $this->getSession();
if (!$session) {
if (!$session = $this->getSession()) {
return;
}

View File

@ -121,7 +121,7 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
static $setSession;
if (null === $setSession) {
$setSession = \Closure::bind(function ($subRequest, $request) { $subRequest->session = $request->session; }, null, Request::class);
$setSession = \Closure::bind(static function ($subRequest, $request) { $subRequest->session = $request->session; }, null, Request::class);
}
$setSession($subRequest, $request);

View File

@ -98,8 +98,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface
'trace_header' => 'X-Symfony-Cache',
], $options);
if (!isset($options['trace_level']) && $this->options['debug']) {
$this->options['trace_level'] = 'full';
if (!isset($options['trace_level'])) {
$this->options['trace_level'] = $this->options['debug'] ? 'full' : 'none';
}
}

View File

@ -16,7 +16,7 @@ use Symfony\Component\Lock\Exception\LockConflictedException;
/**
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
*/
interface BlockingStoreInterface
interface BlockingStoreInterface extends PersistingStoreInterface
{
/**
* Waits until a key becomes free, then stores the resource.

View File

@ -26,7 +26,7 @@ use Symfony\Component\Lock\StoreInterface;
*
* @author Jérémy Derussé <jeremy@derusse.com>
*/
class RetryTillSaveStore implements PersistingStoreInterface, BlockingStoreInterface, StoreInterface, LoggerAwareInterface
class RetryTillSaveStore implements BlockingStoreInterface, StoreInterface, LoggerAwareInterface
{
use LoggerAwareTrait;

View File

@ -97,7 +97,7 @@ class LockTest extends TestCase
public function testAcquireBlocking()
{
$key = new Key(uniqid(__METHOD__, true));
$store = $this->getMockBuilder([PersistingStoreInterface::class, BlockingStoreInterface::class])->getMock();
$store = $this->createMock(BlockingStoreInterface::class);
$lock = new Lock($key, $store);
$store
@ -213,7 +213,7 @@ class LockTest extends TestCase
public function testReleaseOnDestruction()
{
$key = new Key(uniqid(__METHOD__, true));
$store = $this->getMockBuilder([PersistingStoreInterface::class, BlockingStoreInterface::class])->getMock();
$store = $this->createMock(BlockingStoreInterface::class);
$lock = new Lock($key, $store, 10);
$store
@ -232,7 +232,7 @@ class LockTest extends TestCase
public function testNoAutoReleaseWhenNotConfigured()
{
$key = new Key(uniqid(__METHOD__, true));
$store = $this->getMockBuilder([PersistingStoreInterface::class, BlockingStoreInterface::class])->getMock();
$store = $this->createMock(BlockingStoreInterface::class);
$lock = new Lock($key, $store, 10, false);
$store

View File

@ -62,8 +62,8 @@ class CombinedStoreTest extends AbstractStoreTest
protected function setUp()
{
$this->strategy = $this->getMockBuilder(StrategyInterface::class)->getMock();
$this->store1 = $this->getMockBuilder([PersistingStoreInterface::class, BlockingStoreInterface::class])->getMock();
$this->store2 = $this->getMockBuilder([PersistingStoreInterface::class, BlockingStoreInterface::class])->getMock();
$this->store1 = $this->createMock(BlockingStoreInterface::class);
$this->store2 = $this->createMock(BlockingStoreInterface::class);
$this->store = new CombinedStore([$this->store1, $this->store2], $this->strategy);
}

View File

@ -40,7 +40,7 @@ class PhpFileLoader extends FileLoader
// the closure forbids access to the private scope in the included file
$loader = $this;
$load = \Closure::bind(function ($file) use ($loader) {
$load = \Closure::bind(static function ($file) use ($loader) {
return include $file;
}, null, ProtectedPhpFileLoader::class);

View File

@ -38,12 +38,11 @@ class AuthenticationUtils
public function getLastAuthenticationError($clearSession = true)
{
$request = $this->getRequest();
$session = $request->getSession();
$authenticationException = null;
if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
$authenticationException = $request->attributes->get(Security::AUTHENTICATION_ERROR);
} elseif (null !== $session && $session->has(Security::AUTHENTICATION_ERROR)) {
} elseif ($request->hasSession() && ($session = $request->getSession())->has(Security::AUTHENTICATION_ERROR)) {
$authenticationException = $session->get(Security::AUTHENTICATION_ERROR);
if ($clearSession) {
@ -65,9 +64,7 @@ class AuthenticationUtils
return $request->attributes->get(Security::LAST_USERNAME, '');
}
$session = $request->getSession();
return null === $session ? '' : $session->get(Security::LAST_USERNAME, '');
return $request->hasSession() ? $request->getSession()->get(Security::LAST_USERNAME, '') : '';
}
/**

View File

@ -75,7 +75,7 @@ class ContextListener
}
$request = $event->getRequest();
$session = $request->hasPreviousSession() ? $request->getSession() : null;
$session = $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null;
if (null === $session || null === $token = $session->get($this->sessionKey)) {
$this->tokenStorage->setToken(null);
@ -122,14 +122,14 @@ class ContextListener
$this->dispatcher->removeListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
$this->registered = false;
$session = $request->getSession();
$token = $this->tokenStorage->getToken();
if ((null === $token = $this->tokenStorage->getToken()) || $this->trustResolver->isAnonymous($token)) {
if ($request->hasPreviousSession()) {
$session->remove($this->sessionKey);
if (null === $token || $this->trustResolver->isAnonymous($token)) {
if ($request->hasPreviousSession() && $request->hasSession()) {
$request->getSession()->remove($this->sessionKey);
}
} else {
$session->set($this->sessionKey, serialize($token));
$request->getSession()->set($this->sessionKey, serialize($token));
if (null !== $this->logger) {
$this->logger->debug('Stored the security token in the session.', ['key' => $this->sessionKey]);

View File

@ -87,7 +87,7 @@ class HttpUtils
static $setSession;
if (null === $setSession) {
$setSession = \Closure::bind(function ($newRequest, $request) { $newRequest->session = $request->session; }, null, Request::class);
$setSession = \Closure::bind(static function ($newRequest, $request) { $newRequest->session = $request->session; }, null, Request::class);
}
$setSession($newRequest, $request);

View File

@ -386,6 +386,9 @@ class Parser
$value = '';
foreach ($this->lines as $line) {
if ('' !== ltrim($line) && '#' === ltrim($line)[0]) {
continue;
}
// If the indentation is not consistent at offset 0, it is to be considered as a ParseError
if (0 === $this->offset && !$deprecatedUsage && isset($line[0]) && ' ' === $line[0]) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);

View File

@ -2152,6 +2152,18 @@ YAML;
return $tests;
}
public function testMultiLineComment()
{
$yaml = <<<YAML
parameters:
abc
# Comment
YAML;
$this->assertSame(['parameters' => 'abc'], $this->parser->parse($yaml));
}
}
class B