Merge branch '5.3' into 5.4

* 5.3:
  [5.3] cs fixes
  [Cache] Fix saving items with no expiration through ProxyAdapter
  CS fixes
  [HttpClient] Fix tracing requests made after calling withOptions()
  [Cache] disable lock on CLI
  [VarDumper] add more "transient-on-macos" groups
This commit is contained in:
Nicolas Grekas 2021-12-16 22:52:00 +01:00
commit 61be138778
36 changed files with 150 additions and 67 deletions

View File

@ -11,6 +11,7 @@ return (new PhpCsFixer\Config())
'@Symfony' => true,
'@Symfony:risky' => true,
'protected_to_private' => false,
'native_constant_invocation' => ['strict' => false],
'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false],
])
->setRiskyAllowed(true)

View File

@ -49,7 +49,7 @@ final class DoctrineLoader implements LoaderInterface
$className = $metadata->getClassName();
try {
$doctrineMetadata = $this->entityManager->getClassMetadata($className);
} catch (MappingException | OrmMappingException $exception) {
} catch (MappingException|OrmMappingException $exception) {
return false;
}

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Symfony\Component\Mailer\DataCollector\MessageDataCollector;
use Symfony\Component\Mailer\EventListener\MessageLoggerListener;
return static function (ContainerConfigurator $container) {
$container->services()

View File

@ -74,7 +74,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
} elseif (0 === $item->expiry) {
} elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);

View File

@ -79,7 +79,7 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
$key = (string) $key;
if (null === $item->expiry) {
$ttl = 0 < $defaultLifetime ? $defaultLifetime : 0;
} elseif (0 === $item->expiry) {
} elseif (!$item->expiry) {
$ttl = 0;
} elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) {
$expiredIds[] = $getId($key);

View File

@ -190,14 +190,14 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
$now = microtime(true);
if (0 === $expiry) {
$expiry = \PHP_INT_MAX;
}
if (null !== $expiry) {
if (!$expiry) {
$expiry = \PHP_INT_MAX;
} elseif ($expiry <= $now) {
$this->deleteItem($key);
if (null !== $expiry && $expiry <= $now) {
$this->deleteItem($key);
return true;
return true;
}
}
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;

View File

@ -92,7 +92,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
$item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
}
$innerItem->set($item["\0*\0value"]);
$innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', 0 === $item["\0*\0expiry"] ? \PHP_INT_MAX : $item["\0*\0expiry"])) : null);
$innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null);
},
null,
CacheItem::class

View File

@ -0,0 +1,72 @@
<?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\Cache\Tests\Adapter;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\CacheItem;
/**
* @group integration
*/
class ProxyAdapterAndRedisAdapterTest extends AbstractRedisAdapterTest
{
protected $skippedTests = [
'testPrune' => 'RedisAdapter does not implement PruneableInterface.',
];
public static function setUpBeforeClass(): void
{
parent::setUpBeforeClass();
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
}
public function createCachePool($defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface
{
return new ProxyAdapter(new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), 100), 'ProxyNS', $defaultLifetime);
}
public function testSaveItemPermanently()
{
$setCacheItemExpiry = \Closure::bind(
static function (CacheItem $item, $expiry) {
$item->expiry = $expiry;
return $item;
},
null,
CacheItem::class
);
$cache = $this->createCachePool(1);
$value = rand();
$item = $cache->getItem('foo');
$setCacheItemExpiry($item, 0);
$cache->save($item->set($value));
$item = $cache->getItem('bar');
$setCacheItemExpiry($item, 0.0);
$cache->save($item->set($value));
$item = $cache->getItem('baz');
$cache->save($item->set($value));
$this->assertSame($value, $this->cache->getItem('foo')->get());
$this->assertSame($value, $this->cache->getItem('bar')->get());
$this->assertSame($value, $this->cache->getItem('baz')->get());
sleep(1);
$this->assertSame($value, $this->cache->getItem('foo')->get());
$this->assertSame($value, $this->cache->getItem('bar')->get());
$this->assertFalse($this->cache->getItem('baz')->isHit());
}
}

View File

@ -14,12 +14,10 @@ namespace Symfony\Component\Cache\Tests\Adapter;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Adapter\AdapterInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
use Symfony\Component\Cache\LockRegistry;
use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter;
use Symfony\Component\Filesystem\Filesystem;
@ -181,24 +179,6 @@ class TagAwareAdapterTest extends AdapterTestCase
$this->assertFalse($item->isHit());
}
public function testLog()
{
$lockFiles = LockRegistry::setFiles([__FILE__]);
$logger = $this->createMock(LoggerInterface::class);
$logger
->expects($this->atLeastOnce())
->method($this->anything());
$cache = new TagAwareAdapter(new ArrayAdapter());
$cache->setLogger($logger);
// Computing will produce at least one log
$cache->get('foo', static function (): string { return 'ccc'; });
LockRegistry::setFiles($lockFiles);
}
/**
* @return MockObject&PruneableCacheInterface
*/

View File

@ -31,7 +31,7 @@ trait ContractsTrait
doGet as private contractsGet;
}
private $callbackWrapper = [LockRegistry::class, 'compute'];
private $callbackWrapper;
private $computing = [];
/**
@ -41,8 +41,16 @@ trait ContractsTrait
*/
public function setCallbackWrapper(?callable $callbackWrapper): callable
{
if (!isset($this->callbackWrapper)) {
$this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']);
if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
$this->setCallbackWrapper(null);
}
}
$previousWrapper = $this->callbackWrapper;
$this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
$this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) {
return $callback($item, $save);
};
@ -82,6 +90,10 @@ trait ContractsTrait
$this->computing[$key] = $key;
$startTime = microtime(true);
if (!isset($this->callbackWrapper)) {
$this->setCallbackWrapper($this->setCallbackWrapper(null));
}
try {
$value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
$setMetadata($item, $startTime, $metadata);

View File

@ -137,7 +137,7 @@ class PhpFileLoader extends FileLoader
default:
try {
$configBuilder = $this->configBuilder($type);
} catch (InvalidArgumentException | \LogicException $e) {
} catch (InvalidArgumentException|\LogicException $e) {
throw new \InvalidArgumentException(sprintf('Could not resolve argument "%s" for "%s".', $type.' $'.$parameter->getName(), $path), 0, $e);
}
$configBuilders[] = $configBuilder;

View File

@ -1194,11 +1194,11 @@ class Crawler implements \Countable, \IteratorAggregate
try {
return mb_convert_encoding($htmlContent, 'HTML-ENTITIES', $charset);
} catch (\Exception | \ValueError $e) {
} catch (\Exception|\ValueError $e) {
try {
$htmlContent = iconv($charset, 'UTF-8', $htmlContent);
$htmlContent = mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8');
} catch (\Exception | \ValueError $e) {
} catch (\Exception|\ValueError $e) {
}
return $htmlContent;

View File

@ -81,8 +81,8 @@ final class Dotenv
/**
* Loads one or several .env files.
*
* @param string $path A file to load
* @param ...string $extraPaths A list of additional files to load
* @param string $path A file to load
* @param string[] ...$extraPaths A list of additional files to load
*
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable
@ -167,8 +167,8 @@ final class Dotenv
/**
* Loads one or several .env files and enables override existing vars.
*
* @param string $path A file to load
* @param ...string $extraPaths A list of additional files to load
* @param string $path A file to load
* @param string[] ...$extraPaths A list of additional files to load
*
* @throws FormatException when a file has a syntax error
* @throws PathException when a file does not exist or is not readable

View File

@ -44,7 +44,7 @@ final class HttpClient
$curlVersion = $curlVersion ?? curl_version();
// HTTP/2 push crashes before curl 7.61
if (0x073d00 > $curlVersion['version_number'] || !(\CURL_VERSION_HTTP2 & $curlVersion['features'])) {
if (0x073D00 > $curlVersion['version_number'] || !(\CURL_VERSION_HTTP2 & $curlVersion['features'])) {
return new AmpHttpClient($defaultOptions, null, $maxHostConnections, $maxPendingPushes);
}
}

View File

@ -327,7 +327,7 @@ final class AmpResponse implements ResponseInterface, StreamableInterface
// Discard body of redirects
while (null !== yield $response->getBody()->read()) {
}
} catch (HttpException | StreamException $e) {
} catch (HttpException|StreamException $e) {
// Ignore streaming errors on previous responses
}

View File

@ -27,7 +27,7 @@ class CurlHttpClientTest extends HttpClientTestCase
$this->markTestSkipped('PHP 7.3.0 to 7.3.3 don\'t support HTTP/2 PUSH');
}
if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073d00 > ($v = curl_version())['version_number'] || !(\CURL_VERSION_HTTP2 & $v['features'])) {
if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073D00 > ($v = curl_version())['version_number'] || !(\CURL_VERSION_HTTP2 & $v['features'])) {
$this->markTestSkipped('curl <7.61 is used or it is not compiled with support for HTTP/2 PUSH');
}
}

View File

@ -218,4 +218,18 @@ class TraceableHttpClientTest extends TestCase
$this->assertCount(1, $events['GET http://localhost:8057']->getPeriods());
$this->assertGreaterThan(0.0, $events['GET http://localhost:8057']->getDuration());
}
public function testWithOptions()
{
$sut = new TraceableHttpClient(new NativeHttpClient());
$sut2 = $sut->withOptions(['base_uri' => 'http://localhost:8057']);
$response = $sut2->request('GET', '/');
$this->assertSame(200, $response->getStatusCode());
$this->assertSame('http://localhost:8057/', $response->getInfo('url'));
$this->assertCount(1, $sut->getTracedRequests());
}
}

View File

@ -27,13 +27,14 @@ use Symfony\Contracts\Service\ResetInterface;
final class TraceableHttpClient implements HttpClientInterface, ResetInterface, LoggerAwareInterface
{
private $client;
private $tracedRequests = [];
private $stopwatch;
private $tracedRequests;
public function __construct(HttpClientInterface $client, Stopwatch $stopwatch = null)
{
$this->client = $client;
$this->stopwatch = $stopwatch;
$this->tracedRequests = new \ArrayObject();
}
/**
@ -84,7 +85,7 @@ final class TraceableHttpClient implements HttpClientInterface, ResetInterface,
public function getTracedRequests(): array
{
return $this->tracedRequests;
return $this->tracedRequests->getArrayCopy();
}
public function reset()
@ -93,7 +94,7 @@ final class TraceableHttpClient implements HttpClientInterface, ResetInterface,
$this->client->reset();
}
$this->tracedRequests = [];
$this->tracedRequests->exchangeArray([]);
}
/**

View File

@ -663,7 +663,7 @@ class PdoSessionHandler extends AbstractSessionHandler
$selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR);
$insertStmt = null;
do {
while (true) {
$selectStmt->execute();
$sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM);
@ -712,7 +712,7 @@ class PdoSessionHandler extends AbstractSessionHandler
}
return '';
} while (true);
}
}
/**

View File

@ -47,7 +47,7 @@ class ControllerResolver implements ControllerResolverInterface
if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) {
try {
$controller[0] = $this->instantiateController($controller[0]);
} catch (\Error | \LogicException $e) {
} catch (\Error|\LogicException $e) {
try {
// We cannot just check is_callable but have to use reflection because a non-static method
// can still be called statically in PHP but we don't want that. This is deprecated in PHP 7, so we
@ -118,7 +118,7 @@ class ControllerResolver implements ControllerResolverInterface
try {
$controller = [$this->instantiateController($class), $method];
} catch (\Error | \LogicException $e) {
} catch (\Error|\LogicException $e) {
try {
if ((new \ReflectionMethod($class, $method))->isStatic()) {
return $class.'::'.$method;

View File

@ -164,4 +164,3 @@ class InMemoryTransport implements TransportInterface, ResetInterface
);
}
}

View File

@ -91,7 +91,7 @@ final class MercureTransport extends AbstractTransport
$sentMessage->setMessageId($messageId);
return $sentMessage;
} catch (MercureRuntimeException | InvalidArgumentException $e) {
} catch (MercureRuntimeException|InvalidArgumentException $e) {
throw new RuntimeException('Unable to post the Mercure message: '.$e->getMessage(), $e->getCode(), $e);
}
}

View File

@ -87,7 +87,7 @@ final class SpotHitTransport extends AbstractTransport
$data = $response->toArray();
} catch (TransportExceptionInterface $e) {
throw new TransportException('Could not reach the remote SpotHit server.', $response, 0, $e);
} catch (HttpExceptionInterface | DecodingExceptionInterface $e) {
} catch (HttpExceptionInterface|DecodingExceptionInterface $e) {
throw new TransportException('Unexpected reply from the remote SpotHit server.', $response, 0, $e);
}

View File

@ -133,7 +133,7 @@ abstract class AbstractPipes implements PipesInterface
}
if ($input) {
for (;;) {
while (true) {
$data = fread($input, self::CHUNK_SIZE);
if (!isset($data[0])) {
break;

View File

@ -772,7 +772,8 @@ class ProcessTest extends TestCase
$start = microtime(true);
try {
$process->start();
foreach ($process as $buffer);
foreach ($process as $buffer) {
}
$this->fail('A RuntimeException should have been raised');
} catch (RuntimeException $e) {
}

View File

@ -85,7 +85,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
$this->userChecker->checkPreAuth($user);
$this->checkAuthentication($user, $token);
$this->userChecker->checkPostAuth($user);
} catch (AccountStatusException | BadCredentialsException $e) {
} catch (AccountStatusException|BadCredentialsException $e) {
if ($this->hideUserNotFoundExceptions && !$e instanceof CustomUserMessageAccountStatusException) {
throw new BadCredentialsException('Bad credentials.', 0, $e);
}

View File

@ -15,8 +15,6 @@ use Psr\Cache\CacheItemPoolInterface;
/**
* @author Ryan Weaver <ryan@symfonycasts.com>
*
* @final
*/
final class ExpiredSignatureStorage
{

View File

@ -163,7 +163,7 @@ class UsernamePasswordFormAuthenticationListenerTest extends TestCase
/**
* @dataProvider postOnlyDataProvider
*/
public function testHandleNonStringUsernameWith__toString(bool $postOnly)
public function testHandleNonStringUsernameWithToString(bool $postOnly)
{
$usernameClass = $this->createMock(DummyUserClass::class);
$usernameClass

View File

@ -37,9 +37,9 @@ abstract class AbstractUnicodeTestCase extends AbstractAsciiTestCase
['*', [42]],
['AZ', [65, 90]],
['€', [8364]],
['€', [0x20ac]],
['€', [0x20AC]],
['Ʃ', [425]],
['Ʃ', [0x1a9]],
['Ʃ', [0x1A9]],
['☢☎❄', [0x2622, 0x260E, 0x2744]],
];
}

View File

@ -57,7 +57,7 @@ class XliffFileLoader implements LoaderInterface
} else {
$dom = XmlUtils::loadFile($resource);
}
} catch (\InvalidArgumentException | XmlParsingException | InvalidXmlException $e) {
} catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) {
throw new InvalidResourceException(sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e);
}

View File

@ -39,7 +39,7 @@ class BinaryUtil
// https://tools.ietf.org/html/rfc4122#section-4.1.4
// 0x01b21dd213814000 is the number of 100-ns intervals between the
// UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
private const TIME_OFFSET_INT = 0x01b21dd213814000;
private const TIME_OFFSET_INT = 0x01B21DD213814000;
private const TIME_OFFSET_BIN = "\x01\xb2\x1d\xd2\x13\x81\x40\x00";
private const TIME_OFFSET_COM1 = "\xfe\x4d\xe2\x2d\xec\x7e\xbf\xff";
private const TIME_OFFSET_COM2 = "\xfe\x4d\xe2\x2d\xec\x7e\xc0\x00";

View File

@ -54,7 +54,7 @@ class UuidV1 extends Uuid
$seq = substr($uuid, 19, 4);
while (null === self::$clockSeq || $seq === self::$clockSeq) {
self::$clockSeq = sprintf('%04x', random_int(0, 0x3fff) | 0x8000);
self::$clockSeq = sprintf('%04x', random_int(0, 0x3FFF) | 0x8000);
}
$seq = self::$clockSeq;

View File

@ -56,7 +56,7 @@ class UuidV6 extends Uuid
// UUIDv6 prefers a truly random number here, let's XOR both to preserve the entropy
if (null === self::$node) {
$seed = [random_int(0, 0xffffff), random_int(0, 0xffffff)];
$seed = [random_int(0, 0xFFFFFF), random_int(0, 0xFFFFFF)];
$node = unpack('N2', hex2bin('00'.substr($uuidV1, 24, 6)).hex2bin('00'.substr($uuidV1, 30)));
self::$node = sprintf('%06x%06x', ($seed[0] ^ $node[1]) | 0x010000, $seed[1] ^ $node[2]);
}

View File

@ -46,7 +46,7 @@ class HostnameDummy
#[Hostname]
private $a;
#[Hostname(message: "myMessage", requireTld: false)]
#[Hostname(message: 'myMessage', requireTld: false)]
private $b;
#[Hostname(groups: ['my_group'], payload: 'some attached data')]

View File

@ -37,6 +37,9 @@ class ServerDumperTest extends TestCase
$dumper->dump($data);
}
/**
* @group transient-on-macos
*/
public function testDump()
{
$wrappedDumper = $this->createMock(DataDumperInterface::class);

View File

@ -22,6 +22,9 @@ class ConnectionTest extends TestCase
{
private const VAR_DUMPER_SERVER = 'tcp://127.0.0.1:9913';
/**
* @group transient-on-macos
*/
public function testDump()
{
$cloner = new VarCloner();