Merge branch '4.2' into 4.3
* 4.2: [HttpFoundation] Throw exception when the \"session\" extension is not loaded remove invalid test cases [Serializer] Fixed PHP of DenormalizableInterface::denormalize [Cache] work aroung PHP memory leak [Finder] docblock fixes pass error code as a string Catch JsonException and rethrow in JsonEncode
This commit is contained in:
commit
a218efebee
|
@ -225,6 +225,10 @@ class FrameworkExtension extends Extension
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isConfigEnabled($container, $config['session'])) {
|
if ($this->isConfigEnabled($container, $config['session'])) {
|
||||||
|
if (!\extension_loaded('session')) {
|
||||||
|
throw new \LogicException('PHP extension "session" is required.');
|
||||||
|
}
|
||||||
|
|
||||||
$this->sessionConfigEnabled = true;
|
$this->sessionConfigEnabled = true;
|
||||||
$this->registerSessionConfiguration($config['session'], $container, $loader);
|
$this->registerSessionConfiguration($config['session'], $container, $loader);
|
||||||
if (!empty($config['test'])) {
|
if (!empty($config['test'])) {
|
||||||
|
|
|
@ -50,12 +50,15 @@ trait PhpFilesTrait
|
||||||
{
|
{
|
||||||
$time = time();
|
$time = time();
|
||||||
$pruned = true;
|
$pruned = true;
|
||||||
|
$getExpiry = true;
|
||||||
|
|
||||||
set_error_handler($this->includeHandler);
|
set_error_handler($this->includeHandler);
|
||||||
try {
|
try {
|
||||||
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
|
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
|
||||||
try {
|
try {
|
||||||
list($expiresAt) = include $file;
|
if (\is_array($expiresAt = include $file)) {
|
||||||
|
$expiresAt = $expiresAt[0];
|
||||||
|
}
|
||||||
} catch (\ErrorException $e) {
|
} catch (\ErrorException $e) {
|
||||||
$expiresAt = $time;
|
$expiresAt = $time;
|
||||||
}
|
}
|
||||||
|
@ -87,15 +90,21 @@ trait PhpFilesTrait
|
||||||
$values = [];
|
$values = [];
|
||||||
|
|
||||||
begin:
|
begin:
|
||||||
|
$getExpiry = false;
|
||||||
|
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
if (null === $value = $this->values[$id] ?? null) {
|
if (null === $value = $this->values[$id] ?? null) {
|
||||||
$missingIds[] = $id;
|
$missingIds[] = $id;
|
||||||
} elseif ('N;' === $value) {
|
} elseif ('N;' === $value) {
|
||||||
$values[$id] = null;
|
$values[$id] = null;
|
||||||
} elseif ($value instanceof \Closure) {
|
} elseif (!\is_object($value)) {
|
||||||
$values[$id] = $value();
|
|
||||||
} else {
|
|
||||||
$values[$id] = $value;
|
$values[$id] = $value;
|
||||||
|
} elseif (!$value instanceof LazyValue) {
|
||||||
|
// calling a Closure is for @deprecated BC and should be removed in Symfony 5.0
|
||||||
|
$values[$id] = $value();
|
||||||
|
} elseif (false === $values[$id] = include $value->file) {
|
||||||
|
unset($values[$id], $this->values[$id]);
|
||||||
|
$missingIds[] = $id;
|
||||||
}
|
}
|
||||||
if (!$this->appendOnly) {
|
if (!$this->appendOnly) {
|
||||||
unset($this->values[$id]);
|
unset($this->values[$id]);
|
||||||
|
@ -108,10 +117,18 @@ trait PhpFilesTrait
|
||||||
|
|
||||||
set_error_handler($this->includeHandler);
|
set_error_handler($this->includeHandler);
|
||||||
try {
|
try {
|
||||||
|
$getExpiry = true;
|
||||||
|
|
||||||
foreach ($missingIds as $k => $id) {
|
foreach ($missingIds as $k => $id) {
|
||||||
try {
|
try {
|
||||||
$file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
|
$file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
|
||||||
list($expiresAt, $this->values[$id]) = include $file;
|
|
||||||
|
if (\is_array($expiresAt = include $file)) {
|
||||||
|
[$expiresAt, $this->values[$id]] = $expiresAt;
|
||||||
|
} elseif ($now < $expiresAt) {
|
||||||
|
$this->values[$id] = new LazyValue($file);
|
||||||
|
}
|
||||||
|
|
||||||
if ($now >= $expiresAt) {
|
if ($now >= $expiresAt) {
|
||||||
unset($this->values[$id], $missingIds[$k]);
|
unset($this->values[$id], $missingIds[$k]);
|
||||||
}
|
}
|
||||||
|
@ -140,7 +157,13 @@ trait PhpFilesTrait
|
||||||
set_error_handler($this->includeHandler);
|
set_error_handler($this->includeHandler);
|
||||||
try {
|
try {
|
||||||
$file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
|
$file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id);
|
||||||
list($expiresAt, $value) = include $file;
|
$getExpiry = true;
|
||||||
|
|
||||||
|
if (\is_array($expiresAt = include $file)) {
|
||||||
|
[$expiresAt, $value] = $expiresAt;
|
||||||
|
} elseif ($this->appendOnly) {
|
||||||
|
$value = new LazyValue($file);
|
||||||
|
}
|
||||||
} catch (\ErrorException $e) {
|
} catch (\ErrorException $e) {
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -189,13 +212,16 @@ trait PhpFilesTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$isStaticValue) {
|
if (!$isStaticValue) {
|
||||||
$value = str_replace("\n", "\n ", $value);
|
// We cannot use a closure here because of https://bugs.php.net/76982
|
||||||
$value = "static function () {\n\n return {$value};\n\n}";
|
$value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value);
|
||||||
|
$value = "<?php\n\nnamespace Symfony\Component\VarExporter\Internal;\n\nreturn \$getExpiry ? {$expiry} : {$value};\n";
|
||||||
|
} else {
|
||||||
|
$value = "<?php return [{$expiry}, {$value}];\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = $this->files[$key] = $this->getFile($key, true);
|
$file = $this->files[$key] = $this->getFile($key, true);
|
||||||
// Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
|
// Since OPcache only compiles files older than the script execution start, set the file's mtime in the past
|
||||||
$ok = $this->write($file, "<?php return [{$expiry}, {$value}];\n", self::$startTime - 10) && $ok;
|
$ok = $this->write($file, $value, self::$startTime - 10) && $ok;
|
||||||
|
|
||||||
if ($allowCompile) {
|
if ($allowCompile) {
|
||||||
@opcache_invalidate($file, true);
|
@opcache_invalidate($file, true);
|
||||||
|
@ -241,3 +267,16 @@ trait PhpFilesTrait
|
||||||
return @unlink($file);
|
return @unlink($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class LazyValue
|
||||||
|
{
|
||||||
|
public $file;
|
||||||
|
|
||||||
|
public function __construct($file)
|
||||||
|
{
|
||||||
|
$this->file = $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -582,7 +582,7 @@ class Finder implements \IteratorAggregate, \Countable
|
||||||
/**
|
/**
|
||||||
* Searches files and directories which match defined rules.
|
* Searches files and directories which match defined rules.
|
||||||
*
|
*
|
||||||
* @param string|array $dirs A directory path or an array of directories
|
* @param string|string[] $dirs A directory path or an array of directories
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
*
|
||||||
|
|
|
@ -25,7 +25,7 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Iterator $iterator The Iterator to filter
|
* @param \Iterator $iterator The Iterator to filter
|
||||||
* @param array $directories An array of directories to exclude
|
* @param string[] $directories An array of directories to exclude
|
||||||
*/
|
*/
|
||||||
public function __construct(\Iterator $iterator, array $directories)
|
public function __construct(\Iterator $iterator, array $directories)
|
||||||
{
|
{
|
||||||
|
|
|
@ -103,6 +103,10 @@ class NativeSessionStorage implements SessionStorageInterface
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null)
|
public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null)
|
||||||
{
|
{
|
||||||
|
if (!\extension_loaded('session')) {
|
||||||
|
throw new \LogicException('PHP extension "session" is required.');
|
||||||
|
}
|
||||||
|
|
||||||
$options += [
|
$options += [
|
||||||
'cache_limiter' => '',
|
'cache_limiter' => '',
|
||||||
'cache_expire' => 0,
|
'cache_expire' => 0,
|
||||||
|
|
|
@ -24,6 +24,10 @@ class PhpBridgeSessionStorage extends NativeSessionStorage
|
||||||
*/
|
*/
|
||||||
public function __construct($handler = null, MetadataBag $metaBag = null)
|
public function __construct($handler = null, MetadataBag $metaBag = null)
|
||||||
{
|
{
|
||||||
|
if (!\extension_loaded('session')) {
|
||||||
|
throw new \LogicException('PHP extension "session" is required.');
|
||||||
|
}
|
||||||
|
|
||||||
$this->setMetadataBag($metaBag);
|
$this->setMetadataBag($metaBag);
|
||||||
$this->setSaveHandler($handler);
|
$this->setSaveHandler($handler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,14 +47,19 @@ class JsonEncode implements EncoderInterface
|
||||||
*/
|
*/
|
||||||
public function encode($data, $format, array $context = [])
|
public function encode($data, $format, array $context = [])
|
||||||
{
|
{
|
||||||
$jsonEncodeOptions = $context[self::OPTIONS] ?? $this->defaultContext[self::OPTIONS];
|
$options = $context[self::OPTIONS] ?? $this->defaultContext[self::OPTIONS];
|
||||||
$encodedJson = json_encode($data, $jsonEncodeOptions);
|
|
||||||
|
|
||||||
if (\PHP_VERSION_ID >= 70300 && (JSON_THROW_ON_ERROR & $jsonEncodeOptions)) {
|
try {
|
||||||
|
$encodedJson = json_encode($data, $options);
|
||||||
|
} catch (\JsonException $e) {
|
||||||
|
throw new NotEncodableValueException($e->getMessage(), 0, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\PHP_VERSION_ID >= 70300 && (JSON_THROW_ON_ERROR & $options)) {
|
||||||
return $encodedJson;
|
return $encodedJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_ERROR_NONE !== json_last_error() && (false === $encodedJson || !($jsonEncodeOptions & JSON_PARTIAL_OUTPUT_ON_ERROR))) {
|
if (JSON_ERROR_NONE !== json_last_error() && (false === $encodedJson || !($options & JSON_PARTIAL_OUTPUT_ON_ERROR))) {
|
||||||
throw new NotEncodableValueException(json_last_error_msg());
|
throw new NotEncodableValueException(json_last_error_msg());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ interface DenormalizableInterface
|
||||||
* differently based on different input formats
|
* differently based on different input formats
|
||||||
* @param array $context Options for denormalizing
|
* @param array $context Options for denormalizing
|
||||||
*
|
*
|
||||||
* @return object
|
* @return object|object[]
|
||||||
*/
|
*/
|
||||||
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = []);
|
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = []);
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,20 +148,6 @@ abstract class AbstractComparisonValidatorTestCase extends ConstraintValidatorTe
|
||||||
$this->assertNoViolation();
|
$this->assertNoViolation();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideValidComparisonsToPropertyPath
|
|
||||||
*/
|
|
||||||
public function testValidComparisonToPropertyPathOnArray($comparedValue)
|
|
||||||
{
|
|
||||||
$constraint = $this->createConstraint(['propertyPath' => '[root][value]']);
|
|
||||||
|
|
||||||
$this->setObject(['root' => ['value' => 5]]);
|
|
||||||
|
|
||||||
$this->validator->validate($comparedValue, $constraint);
|
|
||||||
|
|
||||||
$this->assertNoViolation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNoViolationOnNullObjectWithPropertyPath()
|
public function testNoViolationOnNullObjectWithPropertyPath()
|
||||||
{
|
{
|
||||||
$constraint = $this->createConstraint(['propertyPath' => 'propertyPath']);
|
$constraint = $this->createConstraint(['propertyPath' => 'propertyPath']);
|
||||||
|
|
|
@ -511,7 +511,7 @@ abstract class AbstractTest extends AbstractValidatorTest
|
||||||
->setParameter('%param%', 'value')
|
->setParameter('%param%', 'value')
|
||||||
->setInvalidValue('Invalid value')
|
->setInvalidValue('Invalid value')
|
||||||
->setPlural(2)
|
->setPlural(2)
|
||||||
->setCode(42)
|
->setCode('42')
|
||||||
->addViolation();
|
->addViolation();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -528,7 +528,7 @@ abstract class AbstractTest extends AbstractValidatorTest
|
||||||
$this->assertSame($entity, $violations[0]->getRoot());
|
$this->assertSame($entity, $violations[0]->getRoot());
|
||||||
$this->assertSame('Invalid value', $violations[0]->getInvalidValue());
|
$this->assertSame('Invalid value', $violations[0]->getInvalidValue());
|
||||||
$this->assertSame(2, $violations[0]->getPlural());
|
$this->assertSame(2, $violations[0]->getPlural());
|
||||||
$this->assertSame(42, $violations[0]->getCode());
|
$this->assertSame('42', $violations[0]->getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNoDuplicateValidationIfClassConstraintInMultipleGroups()
|
public function testNoDuplicateValidationIfClassConstraintInMultipleGroups()
|
||||||
|
|
Reference in New Issue