Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 02c1cda

Browse filesBrowse files
Merge branch '3.4' into 4.3
* 3.4: CS [Serializer] Skip uninitialized (PHP 7.4) properties in PropertyNormalizer and ObjectNormalizer stop using deprecated Doctrine persistence classes Fix regex lookahead syntax in ApplicationTest [SecurityBundle][FirewallMap] Remove unused property [DI] Improve performance of processDefinition Fix invalid Windows path normalization [Validator][ConstraintValidator] Safe fail on invalid timezones [DoctrineBridge] Fixed submitting invalid ids when using queries with limit fix comparisons with null values at property paths
2 parents af39d09 + a073606 commit 02c1cda
Copy full SHA for 02c1cda
Expand file treeCollapse file tree

27 files changed

+225
-49
lines changed

‎src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ public function getEntities()
5555
*/
5656
public function getEntitiesByIds($identifier, array $values)
5757
{
58+
if (null !== $this->queryBuilder->getMaxResults() || null !== $this->queryBuilder->getFirstResult()) {
59+
// an offset or a limit would apply on results including the where clause with submitted id values
60+
// that could make invalid choices valid
61+
$choices = [];
62+
$metadata = $this->queryBuilder->getEntityManager()->getClassMetadata(current($this->queryBuilder->getRootEntities()));
63+
64+
foreach ($this->getEntities() as $entity) {
65+
if (\in_array(current($metadata->getIdentifierValues($entity)), $values, true)) {
66+
$choices[] = $entity;
67+
}
68+
}
69+
70+
return $choices;
71+
}
72+
5873
$qb = clone $this->queryBuilder;
5974
$alias = current($qb->getRootAliases());
6075
$parameter = 'ORMQueryBuilderLoader_getEntitiesByIds_'.$identifier;

‎src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,31 @@ public function testDisallowChoicesThatAreNotIncludedQueryBuilderSingleIdentifie
955955
$this->assertNull($field->getData());
956956
}
957957

958+
public function testDisallowChoicesThatAreNotIncludedQueryBuilderSingleIdentifierWithLimit()
959+
{
960+
$entity1 = new SingleIntIdEntity(1, 'Foo');
961+
$entity2 = new SingleIntIdEntity(2, 'Bar');
962+
$entity3 = new SingleIntIdEntity(3, 'Baz');
963+
964+
$this->persist([$entity1, $entity2, $entity3]);
965+
966+
$repository = $this->em->getRepository(self::SINGLE_IDENT_CLASS);
967+
968+
$field = $this->factory->createNamed('name', static::TESTED_TYPE, null, [
969+
'em' => 'default',
970+
'class' => self::SINGLE_IDENT_CLASS,
971+
'query_builder' => $repository->createQueryBuilder('e')
972+
->where('e.id IN (1, 2, 3)')
973+
->setMaxResults(1),
974+
'choice_label' => 'name',
975+
]);
976+
977+
$field->submit('3');
978+
979+
$this->assertFalse($field->isSynchronized());
980+
$this->assertNull($field->getData());
981+
}
982+
958983
public function testDisallowChoicesThatAreNotIncludedQueryBuilderSingleAssocIdentifier()
959984
{
960985
$innerEntity1 = new SingleIntIdNoToStringEntity(1, 'InFoo');

‎src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public function parse($name)
4848
}
4949

5050
// normalize name
51-
$name = str_replace(':/', ':', preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name)));
51+
$name = preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name));
5252

5353
if (false !== strpos($name, '..')) {
5454
throw new \RuntimeException(sprintf('Template name "%s" contains invalid characters.', $name));

‎src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php
-2Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,11 @@ class FirewallMap implements FirewallMapInterface
2626
{
2727
private $container;
2828
private $map;
29-
private $contexts;
3029

3130
public function __construct(ContainerInterface $container, iterable $map)
3231
{
3332
$this->container = $container;
3433
$this->map = $map;
35-
$this->contexts = new \SplObjectStorage();
3634
}
3735

3836
public function getListeners(Request $request)

‎src/Symfony/Component/Console/Tests/ApplicationTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Tests/ApplicationTest.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ public function testFindAlternativeCommands()
605605
$this->assertRegExp(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives');
606606
$this->assertRegExp('/afoobar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "afoobar1"');
607607
$this->assertRegExp('/foo:bar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "foo:bar1"');
608-
$this->assertNotRegExp('/foo:bar(?>!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative');
608+
$this->assertNotRegExp('/foo:bar(?!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative');
609609
}
610610
}
611611

‎src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
6363
$instanceofTags = [];
6464
$instanceofCalls = [];
6565
$instanceofBindings = [];
66+
$reflectionClass = null;
6667

6768
foreach ($conditionals as $interface => $instanceofDefs) {
68-
if ($interface !== $class && (!$container->getReflectionClass($class, false))) {
69+
if ($interface !== $class && !(null === $reflectionClass ? $reflectionClass = ($container->getReflectionClass($class, false) ?: false) : $reflectionClass)) {
6970
continue;
7071
}
7172

‎src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php
+14-29Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,13 @@ private function decideAffirmative(TokenInterface $token, array $attributes, $ob
7171
$deny = 0;
7272
foreach ($this->voters as $voter) {
7373
$result = $voter->vote($token, $object, $attributes);
74-
switch ($result) {
75-
case VoterInterface::ACCESS_GRANTED:
76-
return true;
7774

78-
case VoterInterface::ACCESS_DENIED:
79-
++$deny;
80-
81-
break;
75+
if (VoterInterface::ACCESS_GRANTED === $result) {
76+
return true;
77+
}
8278

83-
default:
84-
break;
79+
if (VoterInterface::ACCESS_DENIED === $result) {
80+
++$deny;
8581
}
8682
}
8783

@@ -113,16 +109,10 @@ private function decideConsensus(TokenInterface $token, array $attributes, $obje
113109
foreach ($this->voters as $voter) {
114110
$result = $voter->vote($token, $object, $attributes);
115111

116-
switch ($result) {
117-
case VoterInterface::ACCESS_GRANTED:
118-
++$grant;
119-
120-
break;
121-
122-
case VoterInterface::ACCESS_DENIED:
123-
++$deny;
124-
125-
break;
112+
if (VoterInterface::ACCESS_GRANTED === $result) {
113+
++$grant;
114+
} elseif (VoterInterface::ACCESS_DENIED === $result) {
115+
++$deny;
126116
}
127117
}
128118

@@ -154,17 +144,12 @@ private function decideUnanimous(TokenInterface $token, array $attributes, $obje
154144
foreach ($attributes as $attribute) {
155145
$result = $voter->vote($token, $object, [$attribute]);
156146

157-
switch ($result) {
158-
case VoterInterface::ACCESS_GRANTED:
159-
++$grant;
160-
161-
break;
162-
163-
case VoterInterface::ACCESS_DENIED:
164-
return false;
147+
if (VoterInterface::ACCESS_DENIED === $result) {
148+
return false;
149+
}
165150

166-
default:
167-
break;
151+
if (VoterInterface::ACCESS_GRANTED === $result) {
152+
++$grant;
168153
}
169154
}
170155
}

‎src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,14 @@ protected function extractAttributes($object, $format = null, array $context = [
103103
}
104104
}
105105

106+
$checkPropertyInitialization = \PHP_VERSION_ID >= 70400;
107+
106108
// properties
107109
foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) {
110+
if ($checkPropertyInitialization && !$reflProperty->isInitialized($object)) {
111+
continue;
112+
}
113+
108114
if ($reflProperty->isStatic() || !$this->isAllowedAttribute($object, $reflProperty->name, $format, $context)) {
109115
continue;
110116
}

‎src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,20 @@ protected function extractAttributes($object, $format = null, array $context = [
101101
{
102102
$reflectionObject = new \ReflectionObject($object);
103103
$attributes = [];
104+
$checkPropertyInitialization = \PHP_VERSION_ID >= 70400;
104105

105106
do {
106107
foreach ($reflectionObject->getProperties() as $property) {
108+
if ($checkPropertyInitialization) {
109+
if (!$property->isPublic()) {
110+
$property->setAccessible(true);
111+
}
112+
113+
if (!$property->isInitialized($object)) {
114+
continue;
115+
}
116+
}
117+
107118
if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context)) {
108119
continue;
109120
}
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Serializer\Tests\Fixtures;
13+
14+
/**
15+
* @author Valentin Udaltsov <udaltsov.valentin@gmail.com>
16+
*/
17+
final class Php74Dummy
18+
{
19+
public string $uninitializedProperty;
20+
21+
public string $initializedProperty = 'defaultValue';
22+
}

‎src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
3434
use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy;
3535
use Symfony\Component\Serializer\Tests\Fixtures\OtherSerializedNameDummy;
36+
use Symfony\Component\Serializer\Tests\Fixtures\Php74Dummy;
3637
use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder;
3738
use Symfony\Component\Serializer\Tests\Normalizer\Features\AttributesTestTrait;
3839
use Symfony\Component\Serializer\Tests\Normalizer\Features\CallbacksObject;
@@ -114,6 +115,18 @@ public function testNormalize()
114115
);
115116
}
116117

118+
/**
119+
* @requires PHP 7.4
120+
*/
121+
public function testNormalizeObjectWithUninitializedProperties()
122+
{
123+
$obj = new Php74Dummy();
124+
$this->assertEquals(
125+
['initializedProperty' => 'defaultValue'],
126+
$this->normalizer->normalize($obj, 'any')
127+
);
128+
}
129+
117130
public function testDenormalize()
118131
{
119132
$obj = $this->normalizer->denormalize(

‎src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Symfony\Component\Serializer\SerializerInterface;
3030
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
3131
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyChild;
32+
use Symfony\Component\Serializer\Tests\Fixtures\Php74Dummy;
3233
use Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy;
3334
use Symfony\Component\Serializer\Tests\Fixtures\PropertySiblingHolder;
3435
use Symfony\Component\Serializer\Tests\Normalizer\Features\CallbacksObject;
@@ -86,6 +87,18 @@ public function testNormalize()
8687
);
8788
}
8889

90+
/**
91+
* @requires PHP 7.4
92+
*/
93+
public function testNormalizeObjectWithUninitializedProperties()
94+
{
95+
$obj = new Php74Dummy();
96+
$this->assertEquals(
97+
['initializedProperty' => 'defaultValue'],
98+
$this->normalizer->normalize($obj, 'any')
99+
);
100+
}
101+
89102
public function testDenormalize()
90103
{
91104
$obj = $this->normalizer->denormalize(

‎src/Symfony/Component/Validator/ConstraintValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/ConstraintValidator.php
+5-9Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,12 @@ protected function formatValue($value, $format = 0)
8787
{
8888
if (($format & self::PRETTY_DATE) && $value instanceof \DateTimeInterface) {
8989
if (class_exists('IntlDateFormatter')) {
90-
$locale = \Locale::getDefault();
91-
$formatter = new \IntlDateFormatter($locale, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, $value->getTimezone());
90+
$formatter = new \IntlDateFormatter(\Locale::getDefault(), \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, 'UTC');
9291

93-
// neither the native nor the stub IntlDateFormatter support
94-
// DateTimeImmutable as of yet
95-
if (!$value instanceof \DateTime) {
96-
$value = new \DateTime($value->format('Y-m-d H:i:s.u e'));
97-
}
98-
99-
return $formatter->format($value);
92+
return $formatter->format(new \DateTime(
93+
$value->format('Y-m-d H:i:s.u'),
94+
new \DateTimeZone('UTC')
95+
));
10096
}
10197

10298
return $value->format('Y-m-d H:i:s');

‎src/Symfony/Component/Validator/Constraints/GreaterThanOrEqualValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/GreaterThanOrEqualValidator.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class GreaterThanOrEqualValidator extends AbstractComparisonValidator
2424
*/
2525
protected function compareValues($value1, $value2)
2626
{
27-
return $value1 >= $value2;
27+
return null === $value2 || $value1 >= $value2;
2828
}
2929

3030
/**

‎src/Symfony/Component/Validator/Constraints/GreaterThanValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/GreaterThanValidator.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class GreaterThanValidator extends AbstractComparisonValidator
2424
*/
2525
protected function compareValues($value1, $value2)
2626
{
27-
return $value1 > $value2;
27+
return null === $value2 || $value1 > $value2;
2828
}
2929

3030
/**

‎src/Symfony/Component/Validator/Constraints/LessThanOrEqualValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/LessThanOrEqualValidator.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class LessThanOrEqualValidator extends AbstractComparisonValidator
2424
*/
2525
protected function compareValues($value1, $value2)
2626
{
27-
return $value1 <= $value2;
27+
return null === $value2 || $value1 <= $value2;
2828
}
2929

3030
/**

‎src/Symfony/Component/Validator/Constraints/LessThanValidator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Constraints/LessThanValidator.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class LessThanValidator extends AbstractComparisonValidator
2424
*/
2525
protected function compareValues($value1, $value2)
2626
{
27-
return $value1 < $value2;
27+
return null === $value2 || $value1 < $value2;
2828
}
2929

3030
/**

‎src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php
+10-2Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ public function testFormatValue($expected, $value, $format = 0)
2727

2828
public function formatValueProvider()
2929
{
30+
$defaultTimezone = date_default_timezone_get();
31+
date_default_timezone_set('Europe/Moscow'); // GMT+3
32+
3033
$data = [
3134
['true', true],
3235
['false', false],
@@ -36,10 +39,15 @@ public function formatValueProvider()
3639
['array', []],
3740
['object', $toString = new TestToStringObject()],
3841
['ccc', $toString, ConstraintValidator::OBJECT_TO_STRING],
39-
['object', $dateTime = (new \DateTimeImmutable('@0'))->setTimezone(new \DateTimeZone('UTC'))],
40-
[class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 12:00 AM' : '1970-01-01 00:00:00', $dateTime, ConstraintValidator::PRETTY_DATE],
42+
['object', $dateTime = new \DateTimeImmutable('1971-02-02T08:00:00UTC')],
43+
[class_exists(\IntlDateFormatter::class) ? 'Oct 4, 2019, 11:02 AM' : '2019-10-04 11:02:03', new \DateTimeImmutable('2019-10-04T11:02:03+09:00'), ConstraintValidator::PRETTY_DATE],
44+
[class_exists(\IntlDateFormatter::class) ? 'Feb 2, 1971, 8:00 AM' : '1971-02-02 08:00:00', $dateTime, ConstraintValidator::PRETTY_DATE],
45+
[class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 6:00 AM' : '1970-01-01 06:00:00', new \DateTimeImmutable('1970-01-01T06:00:00Z'), ConstraintValidator::PRETTY_DATE],
46+
[class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 3:00 PM' : '1970-01-01 15:00:00', (new \DateTimeImmutable('1970-01-01T23:00:00'))->setTimezone(new \DateTimeZone('America/New_York')), ConstraintValidator::PRETTY_DATE],
4147
];
4248

49+
date_default_timezone_set($defaultTimezone);
50+
4351
return $data;
4452
}
4553
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.