Skip to content

Commit

Permalink
Merge pull request #10909 from greg0ire/imerge/continue-merge-up
Browse files Browse the repository at this point in the history
Continue merge up
  • Loading branch information
greg0ire authored Oct 6, 2023
2 parents 9a1085d + c69044b commit faec95f
Show file tree
Hide file tree
Showing 40 changed files with 160 additions and 164 deletions.
4 changes: 2 additions & 2 deletions docs/en/reference/unitofwork.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ will still end up with the same reference:
public function testIdentityMapReference(): void
{
$objectA = $this->entityManager->getReference('EntityName', 1);
// check for proxyinterface
$this->assertInstanceOf('Doctrine\Persistence\Proxy', $objectA);
// check entity is not initialized
$this->assertTrue($this->entityManager->isUninitializedObject($objectA));
$objectB = $this->entityManager->find('EntityName', 1);
Expand Down
3 changes: 1 addition & 2 deletions lib/Doctrine/ORM/Cache/DefaultQueryCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Persistence\Proxy;

use function array_map;
use function array_shift;
Expand Down Expand Up @@ -311,7 +310,7 @@ private function storeAssociationCache(QueryCacheKey $key, AssociationMapping $a
$assocIdentifier = $this->uow->getEntityIdentifier($assocValue);
$entityKey = new EntityCacheKey($assocMetadata->rootEntityName, $assocIdentifier);

if (! $assocValue instanceof Proxy && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
if (! $this->uow->isUninitializedObject($assocValue) && ($key->cacheMode & Cache::MODE_REFRESH) || ! $assocRegion->contains($entityKey)) {
// Entity put fail
if (! $assocPersister->storeEntityCache($assocValue, $entityKey)) {
return null;
Expand Down
8 changes: 8 additions & 0 deletions lib/Doctrine/ORM/EntityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,14 @@ public function initializeObject(object $obj): void
$this->unitOfWork->initializeObject($obj);
}

/**
* {@inheritDoc}
*/
public function isUninitializedObject($obj): bool
{
return $this->unitOfWork->isUninitializedObject($obj);
}

public function getFilters(): FilterCollection
{
return $this->filterCollection ??= new FilterCollection($this);
Expand Down
3 changes: 1 addition & 2 deletions lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Persistence\Proxy;

use function array_fill_keys;
use function array_keys;
Expand Down Expand Up @@ -430,7 +429,7 @@ protected function hydrateRowData(array $row, array &$result): void
// PATH B: Single-valued association
$reflFieldValue = $reflField->getValue($parentObject);

if (! $reflFieldValue || isset($this->hints[Query::HINT_REFRESH]) || ($reflFieldValue instanceof Proxy && ! $reflFieldValue->__isInitialized())) {
if (! $reflFieldValue || isset($this->hints[Query::HINT_REFRESH]) || $this->uow->isUninitializedObject($reflFieldValue)) {
// we only need to take action if this value is null,
// we refresh the entity or its an uninitialized proxy.
if (isset($nonemptyComponents[$dqlAlias])) {
Expand Down
19 changes: 19 additions & 0 deletions lib/Doctrine/ORM/Proxy/InternalProxy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Proxy;

use Doctrine\Persistence\Proxy;

/**
* @internal
*
* @template T of object
* @template-extends Proxy<T>
*
* @method void __setInitialized(bool $initialized)
*/
interface InternalProxy extends Proxy
{
}
11 changes: 5 additions & 6 deletions lib/Doctrine/ORM/Proxy/ProxyFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use Doctrine\ORM\UnitOfWork;
use Doctrine\ORM\Utility\IdentifierFlattener;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Proxy;
use ReflectionProperty;
use Symfony\Component\VarExporter\ProxyHelper;
use Symfony\Component\VarExporter\VarExporter;
Expand Down Expand Up @@ -94,13 +93,13 @@ public function __construct(
$proxyGenerator = new ProxyGenerator($proxyDir, $proxyNs);

if ($em->getConfiguration()->isLazyGhostObjectEnabled()) {
$proxyGenerator->setPlaceholder('baseProxyInterface', Proxy::class);
$proxyGenerator->setPlaceholder('baseProxyInterface', InternalProxy::class);
$proxyGenerator->setPlaceholder('useLazyGhostTrait', $this->generateUseLazyGhostTrait(...));
$proxyGenerator->setPlaceholder('skippedProperties', $this->generateSkippedProperties(...));
$proxyGenerator->setPlaceholder('serializeImpl', $this->generateSerializeImpl(...));
$proxyGenerator->setProxyClassTemplate(self::PROXY_CLASS_TEMPLATE);
} else {
$proxyGenerator->setPlaceholder('baseProxyInterface', CommonProxy::class);
$proxyGenerator->setPlaceholder('baseProxyInterface', CommonProxy::class . ', \\' . InternalProxy::class);
}

parent::__construct($proxyGenerator, $em->getMetadataFactory(), $autoGenerate);
Expand All @@ -122,7 +121,7 @@ public function getProxy($className, array $identifier)

$initializer = $this->definitions[$className]->initializer;

$proxy->__construct(static function (Proxy $object) use ($initializer, $proxy): void {
$proxy->__construct(static function (InternalProxy $object) use ($initializer, $proxy): void {
$initializer($object, $proxy);
});

Expand Down Expand Up @@ -226,13 +225,13 @@ private function createInitializer(ClassMetadata $classMetadata, EntityPersister
/**
* Creates a closure capable of initializing a proxy
*
* @return Closure(Proxy, Proxy):void
* @return Closure(InternalProxy, InternalProxy):void
*
* @throws EntityNotFoundException
*/
private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister): Closure
{
return function (Proxy $proxy, Proxy $original) use ($entityPersister, $classMetadata): void {
return function (InternalProxy $proxy, InternalProxy $original) use ($entityPersister, $classMetadata): void {
$identifier = $classMetadata->getIdentifierValues($original);
$entity = $entityPersister->loadById($identifier, $original);

Expand Down
3 changes: 1 addition & 2 deletions lib/Doctrine/ORM/Tools/DebugUnitOfWorkListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Persistence\Proxy;
use ReflectionObject;

use function count;
Expand Down Expand Up @@ -74,7 +73,7 @@ public function dumpIdentityMap(EntityManagerInterface $em): void
if ($value === null) {
fwrite($fh, " NULL\n");
} else {
if ($value instanceof Proxy && ! $value->__isInitialized()) {
if ($uow->isUninitializedObject($value)) {
fwrite($fh, '[PROXY] ');
}

Expand Down
40 changes: 24 additions & 16 deletions lib/Doctrine/ORM/UnitOfWork.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister;
use Doctrine\ORM\Persisters\Entity\SingleTablePersister;
use Doctrine\ORM\Proxy\InternalProxy;
use Doctrine\ORM\Utility\IdentifierFlattener;
use Doctrine\Persistence\PropertyChangedListener;
use Doctrine\Persistence\Proxy;
use Exception;
use InvalidArgumentException;
use RuntimeException;
Expand Down Expand Up @@ -781,7 +781,7 @@ public function computeChangeSets(): void

foreach ($entitiesToProcess as $entity) {
// Ignore uninitialized proxy objects
if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
if ($this->isUninitializedObject($entity)) {
continue;
}

Expand All @@ -805,7 +805,7 @@ public function computeChangeSets(): void
*/
private function computeAssociationChanges(AssociationMapping $assoc, mixed $value): void
{
if ($value instanceof Proxy && ! $value->__isInitialized()) {
if ($this->isUninitializedObject($value)) {
return;
}

Expand Down Expand Up @@ -2015,7 +2015,7 @@ private function cascadeDetach(object $entity, array &$visited): void
*/
private function cascadePersist(object $entity, array &$visited): void
{
if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
if ($this->isUninitializedObject($entity)) {
// nothing to do - proxy is not initialized, therefore we don't do anything with it
return;
}
Expand Down Expand Up @@ -2084,13 +2084,13 @@ private function cascadeRemove(object $entity, array &$visited): void
static fn (AssociationMapping $assoc): bool => $assoc->isCascadeRemove()
);

if ($associationMappings) {
$this->initializeObject($entity);
}

$entitiesToCascade = [];

foreach ($associationMappings as $assoc) {
if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
$entity->__load();
}

$relatedEntities = $class->reflFields[$assoc->fieldName]->getValue($entity);

switch (true) {
Expand Down Expand Up @@ -2144,9 +2144,7 @@ public function lock(object $entity, LockMode|int $lockMode, DateTimeInterface|i
return;
}

if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
$entity->__load();
}
$this->initializeObject($entity);

assert($class->versionField !== null);
$entityVersion = $class->reflFields[$class->versionField]->getValue($entity);
Expand Down Expand Up @@ -2293,7 +2291,6 @@ public function createEntity(string $className, array $data, array &$hints = [])
$unmanagedProxy = $hints[Query::HINT_REFRESH_ENTITY];
if (
$unmanagedProxy !== $entity
&& $unmanagedProxy instanceof Proxy
&& $this->isIdentifierEquals($unmanagedProxy, $entity)
) {
// We will hydrate the given un-managed proxy anyway:
Expand All @@ -2302,7 +2299,7 @@ public function createEntity(string $className, array $data, array &$hints = [])
}
}

if ($entity instanceof Proxy && ! $entity->__isInitialized()) {
if ($this->isUninitializedObject($entity)) {
$entity->__setInitialized(true);
} else {
if (
Expand Down Expand Up @@ -2440,8 +2437,7 @@ public function createEntity(string $className, array $data, array &$hints = [])
$hints['fetchMode'][$class->name][$field] === ClassMetadata::FETCH_EAGER &&
isset($hints[self::HINT_DEFEREAGERLOAD]) &&
! $targetClass->isIdentifierComposite &&
$newValue instanceof Proxy &&
$newValue->__isInitialized() === false
$this->isUninitializedObject($newValue)
) {
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
}
Expand Down Expand Up @@ -2868,7 +2864,7 @@ public function getScheduledCollectionUpdates(): array
*/
public function initializeObject(object $obj): void
{
if ($obj instanceof Proxy) {
if ($obj instanceof InternalProxy) {
$obj->__load();

return;
Expand All @@ -2879,6 +2875,18 @@ public function initializeObject(object $obj): void
}
}

/**
* Tests if a value is an uninitialized entity.
*
* @param mixed $obj
*
* @psalm-assert-if-true InternalProxy $obj
*/
public function isUninitializedObject($obj): bool
{
return $obj instanceof InternalProxy && ! $obj->__isInitialized();
}

/**
* Helper method to show an object as string.
*/
Expand Down
2 changes: 1 addition & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@
<code>$classMetadata</code>
</ArgumentTypeCoercion>
<DirectConstructorCall>
<code><![CDATA[$proxy->__construct(static function (Proxy $object) use ($initializer, $proxy): void {
<code><![CDATA[$proxy->__construct(static function (InternalProxy $object) use ($initializer, $proxy): void {
$initializer($object, $proxy);
})]]></code>
</DirectConstructorCall>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Doctrine\Performance\LazyLoading;

use Doctrine\ORM\Proxy\InternalProxy as Proxy;
use Doctrine\Performance\EntityManagerFactory;
use Doctrine\Performance\Mock\NonProxyLoadingEntityManager;
use Doctrine\Persistence\Proxy;
use Doctrine\Tests\Models\CMS\CmsEmployee;
use Doctrine\Tests\Models\CMS\CmsUser;

Expand Down
17 changes: 7 additions & 10 deletions tests/Doctrine/Tests/ORM/Functional/BasicFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMInvalidArgumentException;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Proxy\InternalProxy;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Persistence\Proxy;
use Doctrine\Tests\IterableTester;
use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\Tests\Models\CMS\CmsArticle;
Expand Down Expand Up @@ -145,7 +145,7 @@ public function testBasicOneToOne(): void

// Address has been eager-loaded because it cant be lazy
self::assertInstanceOf(CmsAddress::class, $user2->address);
self::assertNotInstanceOf(Proxy::class, $user2->address);
self::assertFalse($this->isUninitializedObject($user2->address));
}

#[Group('DDC-1230')]
Expand Down Expand Up @@ -547,8 +547,7 @@ public function testSetToOneAssociationWithGetReference(): void
// Assume we only got the identifier of the user and now want to attach
// the article to the user without actually loading it, using getReference().
$userRef = $this->_em->getReference(CmsUser::class, $user->getId());
self::assertInstanceOf(Proxy::class, $userRef);
self::assertFalse($userRef->__isInitialized());
self::assertTrue($this->isUninitializedObject($userRef));

$article = new CmsArticle();
$article->topic = 'topic';
Expand Down Expand Up @@ -583,8 +582,7 @@ public function testAddToToManyAssociationWithGetReference(): void
// Assume we only got the identifier of the user and now want to attach
// the article to the user without actually loading it, using getReference().
$groupRef = $this->_em->getReference(CmsGroup::class, $group->id);
self::assertInstanceOf(Proxy::class, $groupRef);
self::assertFalse($groupRef->__isInitialized());
self::assertTrue($this->isUninitializedObject($groupRef));

$user = new CmsUser();
$user->name = 'Guilherme';
Expand Down Expand Up @@ -762,9 +760,8 @@ public function testQueryEntityByReference(): void
->setParameter('user', $userRef)
->getSingleResult();

self::assertInstanceOf(Proxy::class, $address2->getUser());
self::assertTrue($userRef === $address2->getUser());
self::assertFalse($userRef->__isInitialized());
self::assertTrue($this->isUninitializedObject($userRef));
self::assertEquals('Germany', $address2->country);
self::assertEquals('Berlin', $address2->city);
self::assertEquals('12345', $address2->zip);
Expand Down Expand Up @@ -966,8 +963,8 @@ public function testManyToOneFetchModeQuery(): void
->setParameter(1, $article->id)
->setFetchMode(CmsArticle::class, 'user', ClassMetadata::FETCH_EAGER)
->getSingleResult();
self::assertInstanceOf(Proxy::class, $article->user, 'It IS a proxy, ...');
self::assertTrue($article->user->__isInitialized(), '...but its initialized!');
self::assertInstanceOf(InternalProxy::class, $article->user, 'It IS a proxy, ...');
self::assertFalse($this->isUninitializedObject($article->user), '...but its initialized!');
$this->assertQueryCount(2);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use DateTime;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\PersistentCollection;
use Doctrine\Persistence\Proxy;
use Doctrine\Tests\IterableTester;
use Doctrine\Tests\Models\Company\CompanyAuction;
use Doctrine\Tests\Models\Company\CompanyEmployee;
Expand Down Expand Up @@ -301,7 +300,7 @@ public function testLazyLoading2(): void
$mainEvent = $result[0]->getMainEvent();
// mainEvent should have been loaded because it can't be lazy
self::assertInstanceOf(CompanyAuction::class, $mainEvent);
self::assertNotInstanceOf(Proxy::class, $mainEvent);
self::assertFalse($this->isUninitializedObject($mainEvent));

$this->_em->clear();

Expand Down Expand Up @@ -432,13 +431,13 @@ public function testGetReferenceEntityWithSubclasses(): void
$this->_em->clear();

$ref = $this->_em->getReference(CompanyPerson::class, $manager->getId());
self::assertNotInstanceOf(Proxy::class, $ref, 'Cannot Request a proxy from a class that has subclasses.');
self::assertFalse($this->isUninitializedObject($ref), 'Cannot Request a proxy from a class that has subclasses.');
self::assertInstanceOf(CompanyPerson::class, $ref);
self::assertInstanceOf(CompanyEmployee::class, $ref, 'Direct fetch of the reference has to load the child class Employee directly.');
$this->_em->clear();

$ref = $this->_em->getReference(CompanyManager::class, $manager->getId());
self::assertInstanceOf(Proxy::class, $ref, 'A proxy can be generated only if no subclasses exists for the requested reference.');
self::assertTrue($this->isUninitializedObject($ref), 'A proxy can be generated only if no subclasses exists for the requested reference.');
}

#[Group('DDC-992')]
Expand Down
Loading

0 comments on commit faec95f

Please sign in to comment.