Skip to content

Commit 80845df

Browse files
committed
Add and improve property hook tests.
1 parent f55bd1d commit 80845df

File tree

6 files changed

+74
-12
lines changed

6 files changed

+74
-12
lines changed

src/Mapping/ClassMetadataFactory.php

+12-9
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
2525
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
2626
use Doctrine\Persistence\Mapping\ReflectionService;
27-
use LogicException;
2827
use ReflectionClass;
2928
use ReflectionException;
3029

@@ -299,14 +298,6 @@ protected function validateRuntimeMetadata(ClassMetadata $class, ClassMetadataIn
299298
// second condition is necessary for mapped superclasses in the middle of an inheritance hierarchy
300299
throw MappingException::noInheritanceOnMappedSuperClass($class->name);
301300
}
302-
303-
foreach ($class->propertyAccessors as $propertyAccessor) {
304-
$property = $propertyAccessor->getUnderlyingReflector();
305-
306-
if (PHP_VERSION_ID >= 80400 && count($property->getHooks()) > 0) {
307-
throw new LogicException('Doctrine ORM does not support property hooks without also enabling Configuration::enableNativeLazyObjects(true). Check https://github.com/doctrine/orm/issues/11624 for details of versions that support property hooks.');
308-
}
309-
}
310301
}
311302

312303
protected function newClassMetadataInstance(string $className): ClassMetadata
@@ -710,6 +701,18 @@ private function inheritIdGeneratorMapping(ClassMetadata $class, ClassMetadata $
710701
protected function wakeupReflection(ClassMetadataInterface $class, ReflectionService $reflService): void
711702
{
712703
$class->wakeupReflection($reflService);
704+
705+
if (PHP_VERSION_ID < 80400) {
706+
return;
707+
}
708+
709+
foreach ($class->propertyAccessors as $propertyAccessor) {
710+
$property = $propertyAccessor->getUnderlyingReflector();
711+
712+
if ($property->isVirtual()) {
713+
throw MappingException::mappingVirtualPropertyNotAllowed($class->name, $property->getName());
714+
}
715+
}
713716
}
714717

715718
protected function initializeReflection(ClassMetadataInterface $class, ReflectionService $reflService): void

src/Mapping/MappingException.php

+9
Original file line numberDiff line numberDiff line change
@@ -688,4 +688,13 @@ public static function invalidAttributeOnEmbeddable(string $entityName, string $
688688
$entityName,
689689
));
690690
}
691+
692+
public static function mappingVirtualPropertyNotAllowed(string $entityName, string $propertyName): self
693+
{
694+
return new self(sprintf(
695+
'Mapping virtual property "%s" on entity "%s" is not allowed.',
696+
$propertyName,
697+
$entityName,
698+
));
699+
}
691700
}

src/Proxy/ProxyFactory.php

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Doctrine\ORM\Utility\IdentifierFlattener;
1414
use Doctrine\Persistence\Mapping\ClassMetadata;
1515
use Doctrine\Persistence\Proxy;
16+
use LogicException;
1617
use ReflectionClass;
1718
use ReflectionProperty;
1819
use Symfony\Component\VarExporter\ProxyHelper;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
// phpcs:ignoreFile
3+
namespace Doctrine\Tests\Models\PropertyHooks;
4+
5+
use Doctrine\DBAL\Types\Types;
6+
use Doctrine\ORM\Mapping\Column;
7+
use Doctrine\ORM\Mapping\Entity;
8+
use Doctrine\ORM\Mapping\GeneratedValue;
9+
use Doctrine\ORM\Mapping\Id;
10+
use Doctrine\ORM\Mapping\Table;
11+
12+
#[Entity]
13+
#[Table(name: 'property_hooks_user')]
14+
class MappingVirtualProperty
15+
{
16+
#[Id, GeneratedValue, Column(type: Types::INTEGER)]
17+
public ?int $id;
18+
19+
#[Column(type: Types::STRING)]
20+
public string $first;
21+
22+
#[Column(type: Types::STRING)]
23+
public string $last;
24+
25+
#[Column(type: Types::STRING)]
26+
public string $fullName {
27+
get => $this->first . " " . $this->last;
28+
set {
29+
[$this->first, $this->last] = explode(' ', $value, 2);
30+
}
31+
}
32+
}

tests/Tests/Models/PropertyHooks/User.php

-3
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ class User
3737
}
3838

3939
public string $fullName {
40-
// Override the "read" action with arbitrary logic.
4140
get => $this->first . " " . $this->last;
42-
43-
// Override the "write" action with arbitrary logic.
4441
set {
4542
[$this->first, $this->last] = explode(' ', $value, 2);
4643
}

tests/Tests/ORM/Functional/PropertyHooksTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Doctrine\Tests\ORM\Functional;
66

7+
use Doctrine\ORM\Mapping\MappingException;
8+
use Doctrine\Tests\Models\PropertyHooks\MappingVirtualProperty;
79
use Doctrine\Tests\Models\PropertyHooks\User;
810
use Doctrine\Tests\OrmFunctionalTestCase;
911
use PHPUnit\Framework\Attributes\RequiresPhp;
@@ -60,9 +62,27 @@ public function testTriggerLazyLoadingWhenAccessingPropertyHooks(): void
6062

6163
$user = $this->_em->getReference(User::class, $user->id);
6264

65+
$this->assertTrue($this->_em->getUnitOfWork()->isUninitializedObject($user));
66+
6367
self::assertEquals('Ludwig', $user->first);
6468
self::assertEquals('von Beethoven', $user->last);
6569
self::assertEquals('Ludwig von Beethoven', $user->fullName);
6670
self::assertEquals('DE', $user->language, 'The property hook uppercases the language.');
71+
72+
$this->assertFalse($this->_em->getUnitOfWork()->isUninitializedObject($user));
73+
74+
$this->_em->clear();
75+
76+
$user = $this->_em->getReference(User::class, $user->id);
77+
78+
self::assertEquals('Ludwig von Beethoven', $user->fullName);
79+
}
80+
81+
public function testMappingVirtualPropertyIsNotSupported(): void
82+
{
83+
$this->expectException(MappingException::class);
84+
$this->expectExceptionMessage('Mapping virtual property "fullName" on entity "Doctrine\Tests\Models\PropertyHooks\MappingVirtualProperty" is not allowed.');
85+
86+
$this->_em->getClassMetadata(MappingVirtualProperty::class);
6787
}
6888
}

0 commit comments

Comments
 (0)