Skip to content

Commit 6a36956

Browse files
committed
Merge branch '7.1' into 7.2
* 7.1: (27 commits) add translations for the Slug constraint [Messenger] Fix `TransportMessageIdStamp` not always added [DoctrineBridge] Fix compatibility to Doctrine persistence 2.5 in Doctrine Bridge 6.4 to avoid Projects stuck on 6.3 [PropertyInfo] Fix add missing composer conflict [ErrorHandler] Don't trigger "internal" deprecations for anonymous LazyClosure instances [VarDumper] Fix displaying closure's "this" from anonymous classes [Doctrine][Messenger] Prevents multiple TransportMessageIdStamp being stored in envelope [HttpKernel] Don't override existing LoggerInterface autowiring alias in LoggerPass reject inline notations followed by invalid content [Security] Fix triggering session tracking from ContextListener [AssetMapper] add leading slash to public prefix fix: modify Exception message parameter order [Yaml] Fix parsing of unquoted strings in Parser::lexUnquotedString() to ignore spaces Update exception.css Remove outdated guard from security xsd schema Bump Symfony version to 7.1.11 Update VERSION for 7.1.10 Update CHANGELOG for 7.1.10 Bump Symfony version to 6.4.18 Update VERSION for 6.4.17 ...
2 parents 3ae42ef + e0fc978 commit 6a36956

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

PropertyAccessor.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,15 +629,22 @@ private function getWriteInfo(string $class, string $property, mixed $value): Pr
629629
*/
630630
private function isPropertyWritable(object $object, string $property): bool
631631
{
632+
if ($object instanceof \stdClass && property_exists($object, $property)) {
633+
return true;
634+
}
635+
632636
$mutatorForArray = $this->getWriteInfo($object::class, $property, []);
637+
if (PropertyWriteInfo::TYPE_PROPERTY === $mutatorForArray->getType()) {
638+
return $mutatorForArray->getVisibility() === 'public';
639+
}
633640

634-
if (PropertyWriteInfo::TYPE_NONE !== $mutatorForArray->getType() || ($object instanceof \stdClass && property_exists($object, $property))) {
641+
if (PropertyWriteInfo::TYPE_NONE !== $mutatorForArray->getType()) {
635642
return true;
636643
}
637644

638645
$mutator = $this->getWriteInfo($object::class, $property, '');
639646

640-
return PropertyWriteInfo::TYPE_NONE !== $mutator->getType() || ($object instanceof \stdClass && property_exists($object, $property));
647+
return PropertyWriteInfo::TYPE_NONE !== $mutator->getType();
641648
}
642649

643650
/**
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\PropertyAccess\Tests\Fixtures;
13+
14+
class AsymmetricVisibility
15+
{
16+
public public(set) mixed $publicPublic = null;
17+
public protected(set) mixed $publicProtected = null;
18+
public private(set) mixed $publicPrivate = null;
19+
private private(set) mixed $privatePrivate = null;
20+
public bool $virtualNoSetHook { get => true; }
21+
}

Tests/PropertyAccessorTest.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\PropertyAccess\PropertyAccess;
2121
use Symfony\Component\PropertyAccess\PropertyAccessor;
2222
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
23+
use Symfony\Component\PropertyAccess\Tests\Fixtures\AsymmetricVisibility;
2324
use Symfony\Component\PropertyAccess\Tests\Fixtures\ExtendedUninitializedProperty;
2425
use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped;
2526
use Symfony\Component\PropertyAccess\Tests\Fixtures\TestAdderRemoverInvalidArgumentLength;
@@ -1046,4 +1047,62 @@ private function createUninitializedObjectPropertyGhost(): UninitializedObjectPr
10461047
return $class::createLazyGhost(initializer: function ($instance) {
10471048
});
10481049
}
1050+
1051+
/**
1052+
* @requires PHP 8.4
1053+
*/
1054+
public function testIsWritableWithAsymmetricVisibility()
1055+
{
1056+
$object = new AsymmetricVisibility();
1057+
1058+
$this->assertTrue($this->propertyAccessor->isWritable($object, 'publicPublic'));
1059+
$this->assertFalse($this->propertyAccessor->isWritable($object, 'publicProtected'));
1060+
$this->assertFalse($this->propertyAccessor->isWritable($object, 'publicPrivate'));
1061+
$this->assertFalse($this->propertyAccessor->isWritable($object, 'privatePrivate'));
1062+
$this->assertFalse($this->propertyAccessor->isWritable($object, 'virtualNoSetHook'));
1063+
}
1064+
1065+
/**
1066+
* @requires PHP 8.4
1067+
*/
1068+
public function testIsReadableWithAsymmetricVisibility()
1069+
{
1070+
$object = new AsymmetricVisibility();
1071+
1072+
$this->assertTrue($this->propertyAccessor->isReadable($object, 'publicPublic'));
1073+
$this->assertTrue($this->propertyAccessor->isReadable($object, 'publicProtected'));
1074+
$this->assertTrue($this->propertyAccessor->isReadable($object, 'publicPrivate'));
1075+
$this->assertFalse($this->propertyAccessor->isReadable($object, 'privatePrivate'));
1076+
$this->assertTrue($this->propertyAccessor->isReadable($object, 'virtualNoSetHook'));
1077+
}
1078+
1079+
/**
1080+
* @requires PHP 8.4
1081+
*
1082+
* @dataProvider setValueWithAsymmetricVisibilityDataProvider
1083+
*/
1084+
public function testSetValueWithAsymmetricVisibility(string $propertyPath, ?string $expectedException)
1085+
{
1086+
$object = new AsymmetricVisibility();
1087+
1088+
if ($expectedException) {
1089+
$this->expectException($expectedException);
1090+
} else {
1091+
$this->expectNotToPerformAssertions();
1092+
}
1093+
1094+
$this->propertyAccessor->setValue($object, $propertyPath, true);
1095+
}
1096+
1097+
/**
1098+
* @return iterable<array{0: string, 1: null|class-string}>
1099+
*/
1100+
public static function setValueWithAsymmetricVisibilityDataProvider(): iterable
1101+
{
1102+
yield ['publicPublic', null];
1103+
yield ['publicProtected', \Error::class];
1104+
yield ['publicPrivate', \Error::class];
1105+
yield ['privatePrivate', NoSuchPropertyException::class];
1106+
yield ['virtualNoSetHook', \Error::class];
1107+
}
10491108
}

0 commit comments

Comments
 (0)