Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement proxy name resolver #11009

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/AbstractQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Result;
use Doctrine\Deprecations\Deprecation;
Expand All @@ -20,6 +19,7 @@
use Doctrine\ORM\Cache\TimestampCacheKey;
use Doctrine\ORM\Internal\Hydration\IterableResult;
use Doctrine\ORM\Mapping\MappingException as ORMMappingException;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\ResultSetMapping;
Expand Down Expand Up @@ -430,7 +430,7 @@ public function processParameterValue($value)
}

try {
$class = ClassUtils::getClass($value);
$class = DefaultProxyClassNameResolver::getClass($value);
$value = $this->_em->getUnitOfWork()->getSingleIdentifierValue($value);

if ($value === null) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Cache/DefaultCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace Doctrine\ORM\Cache;

use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\Persister\CachedPersister;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\ORMInvalidArgumentException;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\UnitOfWork;

use function is_array;
Expand Down Expand Up @@ -293,7 +293,7 @@
private function toIdentifierArray(ClassMetadata $metadata, $identifier): array
{
if (is_object($identifier)) {
$class = ClassUtils::getClass($identifier);
$class = DefaultProxyClassNameResolver::getClass($identifier);

Check warning on line 296 in lib/Doctrine/ORM/Cache/DefaultCache.php

View check run for this annotation

Codecov / codecov/patch

lib/Doctrine/ORM/Cache/DefaultCache.php#L296

Added line #L296 was not covered by tests
if ($this->em->getMetadataFactory()->hasMetadataFor($class)) {
$identifier = $this->uow->getSingleIdentifierValue($identifier);

Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Doctrine\ORM\Cache;

use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Query;
use Doctrine\ORM\UnitOfWork;
use Doctrine\ORM\Utility\IdentifierFlattener;
Expand Down Expand Up @@ -112,7 +112,7 @@ public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, $e
}

if (! isset($assoc['id'])) {
$targetClass = ClassUtils::getClass($data[$name]);
$targetClass = DefaultProxyClassNameResolver::getClass($data[$name]);
$targetId = $this->uow->getEntityIdentifier($data[$name]);
$data[$name] = new AssociationCacheEntry($targetClass, $targetId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\Cache\CollectionCacheKey;
use Doctrine\ORM\Cache\CollectionHydrator;
Expand All @@ -19,6 +18,7 @@
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\UnitOfWork;

use function array_values;
Expand Down Expand Up @@ -148,7 +148,7 @@ public function storeCollectionCache(CollectionCacheKey $key, $elements)
}

$class = $this->targetEntity;
$className = ClassUtils::getClass($elements[$index]);
$className = DefaultProxyClassNameResolver::getClass($elements[$index]);

if ($className !== $this->targetEntity->name) {
$class = $this->metadataFactory->getMetadataFor($className);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Doctrine\ORM\Cache\Persister\Collection;

use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyCollection;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;

class ReadOnlyCachedCollectionPersister extends NonStrictReadWriteCachedCollectionPersister
{
Expand All @@ -17,7 +17,7 @@ public function update(PersistentCollection $collection)
{
if ($collection->isDirty() && $collection->getSnapshot()) {
throw CannotUpdateReadOnlyCollection::fromEntityAndField(
ClassUtils::getClass($collection->getOwner()),
DefaultProxyClassNameResolver::getClass($collection->getOwner()),
$this->association['fieldName']
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Doctrine\ORM\Cache\Persister\Entity;

use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Cache;
use Doctrine\ORM\Cache\CollectionCacheKey;
use Doctrine\ORM\Cache\EntityCacheKey;
Expand All @@ -21,6 +20,7 @@
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Persisters\Entity\EntityPersister;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\UnitOfWork;

use function array_merge;
Expand Down Expand Up @@ -190,7 +190,7 @@ public function getEntityHydrator()
public function storeEntityCache($entity, EntityCacheKey $key)
{
$class = $this->class;
$className = ClassUtils::getClass($entity);
$className = DefaultProxyClassNameResolver::getClass($entity);

if ($className !== $this->class->name) {
$class = $this->metadataFactory->getMetadataFor($className);
Expand Down Expand Up @@ -438,7 +438,7 @@ public function loadById(array $identifier, $entity = null)
}

$class = $this->class;
$className = ClassUtils::getClass($entity);
$className = DefaultProxyClassNameResolver::getClass($entity);

if ($className !== $this->class->name) {
$class = $this->metadataFactory->getMetadataFor($className);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

namespace Doctrine\ORM\Cache\Persister\Entity;

use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Cache\Exception\CannotUpdateReadOnlyEntity;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;

/**
* Specific read-only region entity persister
Expand All @@ -17,6 +17,6 @@ class ReadOnlyCachedEntityPersister extends NonStrictReadWriteCachedEntityPersis
*/
public function update($entity)
{
throw CannotUpdateReadOnlyEntity::fromEntity(ClassUtils::getClass($entity));
throw CannotUpdateReadOnlyEntity::fromEntity(DefaultProxyClassNameResolver::getClass($entity));
}
}
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/EntityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use Doctrine\Common\Cache\Psr6\CacheAdapter;
use Doctrine\Common\EventManager;
use Doctrine\Common\Persistence\PersistentObject;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\LockMode;
Expand All @@ -24,6 +23,7 @@
use Doctrine\ORM\Exception\UnrecognizedIdentifierFields;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Proxy\ProxyFactory;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\FilterCollection;
Expand Down Expand Up @@ -444,7 +444,7 @@ public function find($className, $id, $lockMode = null, $lockVersion = null)

foreach ($id as $i => $value) {
if (is_object($value)) {
$className = ClassUtils::getClass($value);
$className = DefaultProxyClassNameResolver::getClass($value);
if ($this->metadataFactory->hasMetadataFor($className)) {
$id[$i] = $this->unitOfWork->getSingleIdentifierValue($value);

Expand Down
3 changes: 3 additions & 0 deletions lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Doctrine\ORM\Mapping\Exception\CannotGenerateIds;
use Doctrine\ORM\Mapping\Exception\InvalidCustomGenerator;
use Doctrine\ORM\Mapping\Exception\UnknownGeneratorType;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory;
use Doctrine\Persistence\Mapping\ClassMetadata as ClassMetadataInterface;
use Doctrine\Persistence\Mapping\Driver\MappingDriver;
Expand Down Expand Up @@ -98,6 +99,8 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
/** @return void */
public function setEntityManager(EntityManagerInterface $em)
{
parent::setProxyClassNameResolver(new DefaultProxyClassNameResolver());

$this->em = $em;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use BackedEnum;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Expr\Comparison;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Platforms\AbstractPlatform;
Expand All @@ -26,6 +25,7 @@
use Doctrine\ORM\Persisters\Exception\UnrecognizedField;
use Doctrine\ORM\Persisters\SqlExpressionVisitor;
use Doctrine\ORM\Persisters\SqlValueVisitor;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Repository\Exception\InvalidFindByCall;
Expand Down Expand Up @@ -2028,7 +2028,7 @@ private function getIndividualValue($value): array
return [$value->value];
}

$valueClass = ClassUtils::getClass($value);
$valueClass = DefaultProxyClassNameResolver::getClass($value);

if ($this->em->getMetadataFactory()->isTransient($valueClass)) {
return [$value];
Expand Down
40 changes: 40 additions & 0 deletions lib/Doctrine/ORM/Proxy/DefaultProxyClassNameResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Proxy;

use Doctrine\Persistence\Mapping\ProxyClassNameResolver;
use Doctrine\Persistence\Proxy;

use function get_class;
use function strrpos;
use function substr;

/**
* Class-related functionality for objects that might or not be proxy objects
* at the moment.
*/
final class DefaultProxyClassNameResolver implements ProxyClassNameResolver
{
public function resolveClassName(string $className): string
{
$pos = strrpos($className, '\\' . Proxy::MARKER . '\\');

if ($pos === false) {
return $className;
}

return substr($className, $pos + Proxy::MARKER_LENGTH + 2);
}

/**
* @param object $object
*
* @return class-string
*/
public static function getClass($object): string
{
return (new self())->resolveClassName(get_class($object));
}
}
5 changes: 5 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@
<exclude-pattern>tests/Doctrine/Tests/ORM/Functional/Ticket/DDC832Test.php</exclude-pattern>
</rule>

<rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
<!-- we need to test what happens with an stdClass proxy -->
<exclude-pattern>tests/Doctrine/Tests/Proxy/DefaultProxyClassNameResolverTest.php</exclude-pattern>
</rule>

<rule ref="Squiz.Commenting.FunctionComment.WrongStyle">
<!-- https://github.com/squizlabs/PHP_CodeSniffer/issues/1961 -->
<exclude-pattern>tests/Doctrine/Tests/Mocks/DatabasePlatformMock.php</exclude-pattern>
Expand Down
9 changes: 9 additions & 0 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,15 @@
<code>$columnList</code>
</PossiblyUndefinedVariable>
</file>
<file src="lib/Doctrine/ORM/Proxy/DefaultProxyClassNameResolver.php">
<LessSpecificReturnStatement>
<code>$className</code>
<code>substr($className, $pos + Proxy::MARKER_LENGTH + 2)</code>
</LessSpecificReturnStatement>
<MoreSpecificReturnType>
<code>string</code>
</MoreSpecificReturnType>
</file>
<file src="lib/Doctrine/ORM/Proxy/ProxyFactory.php">
<ArgumentTypeCoercion>
<code>$classMetadata</code>
Expand Down
4 changes: 2 additions & 2 deletions tests/Doctrine/Tests/ORM/Functional/PostLoadEventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Doctrine\Tests\ORM\Functional;

use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Event\PostLoadEventArgs;
use Doctrine\ORM\Events;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\Tests\Models\CMS\CmsAddress;
use Doctrine\Tests\Models\CMS\CmsEmail;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
Expand Down Expand Up @@ -302,7 +302,7 @@ class PostLoadListenerLoadEntityInEventHandler
public function postLoad(PostLoadEventArgs $event): void
{
$object = $event->getObject();
$class = ClassUtils::getClass($object);
$class = DefaultProxyClassNameResolver::getClass($object);
if (! isset($this->firedByClasses[$class])) {
$this->firedByClasses[$class] = 1;
} else {
Expand Down
4 changes: 2 additions & 2 deletions tests/Doctrine/Tests/ORM/Functional/ReferenceProxyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Doctrine\Tests\ORM\Functional;

use Doctrine\Common\Proxy\Proxy as CommonProxy;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
use Doctrine\ORM\Proxy\InternalProxy;
use Doctrine\Tests\Models\Company\CompanyAuction;
use Doctrine\Tests\Models\ECommerce\ECommerceProduct;
Expand Down Expand Up @@ -227,7 +227,7 @@ public function testCommonPersistenceProxy(): void

$entity = $this->_em->getReference(ECommerceProduct::class, $id);
assert($entity instanceof ECommerceProduct);
$className = ClassUtils::getClass($entity);
$className = DefaultProxyClassNameResolver::getClass($entity);

self::assertInstanceOf(InternalProxy::class, $entity);
self::assertTrue($this->isUninitializedObject($entity));
Expand Down