Skip to content

Commit e0fc978

Browse files
committed
Merge branch '6.4' into 7.1
* 6.4: (23 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 Bump Symfony version to 6.4.18 Update VERSION for 6.4.17 Update CONTRIBUTORS for 6.4.17 Update CHANGELOG for 6.4.17 Fix exception thrown by YamlEncoder [AssetMapper] Fix JavaScript compiler create self-referencing imports ...
2 parents 975d7f7 + 80e0378 commit e0fc978

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 <[email protected]>
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)