Skip to content

Commit

Permalink
add HydrationFactory as extension point for tracking hydrations
Browse files Browse the repository at this point in the history
  • Loading branch information
kbond committed Oct 21, 2024
1 parent 74155c8 commit b329889
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 22 deletions.
6 changes: 4 additions & 2 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,10 @@
<PropertyTypeCoercion>
<code><![CDATA[new $metadataFactoryClassName()]]></code>
</PropertyTypeCoercion>
<RedundantCastGivenDocblockType>
<code><![CDATA[(string) $hydrationMode]]></code>
</file>
<file src="src/Internal/Hydration/DefaultHydratorFactory.php">
<RedundantCastGivenDocblockType occurrences="1">
<code>(string) $hydrationMode</code>
</RedundantCastGivenDocblockType>
</file>
<file src="src/EntityRepository.php">
Expand Down
12 changes: 12 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Doctrine\ORM\Cache\CacheConfiguration;
use Doctrine\ORM\Exception\InvalidEntityRepository;
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
use Doctrine\ORM\Internal\Hydration\DefaultHydratorFactory;
use Doctrine\ORM\Internal\Hydration\HydratorFactory;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
Expand Down Expand Up @@ -44,6 +46,16 @@ class Configuration extends \Doctrine\DBAL\Configuration
/** @psalm-var array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> */
private $identityGenerationPreferences = [];

public function setHydratorFactory(HydratorFactory $factory): void
{
$this->attributes['hydratorFactory'] = $factory;
}

public function getHydratorFactory(): HydratorFactory
{
return $this->attributes['hydratorFactory'] ?? new DefaultHydratorFactory();
}

/** @psalm-param array<class-string<AbstractPlatform>, ClassMetadata::GENERATOR_TYPE_*> $value */
public function setIdentityGenerationPreferences(array $value): void
{
Expand Down
29 changes: 9 additions & 20 deletions src/EntityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Doctrine\ORM\Exception\ORMException;
use Doctrine\ORM\Exception\UnrecognizedIdentifierFields;
use Doctrine\ORM\Internal\Hydration\AbstractHydrator;
use Doctrine\ORM\Internal\Hydration\HydratorFactory;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Proxy\DefaultProxyClassNameResolver;
Expand Down Expand Up @@ -104,6 +105,11 @@ class EntityManager implements EntityManagerInterface
*/
private Cache|null $cache = null;

/**
* The hydrator factory to use.
*/
private HydratorFactory $hydratorFactory;

/**
* Creates a new EntityManager that operates on the given database connection
* and uses the given Configuration and EventManager implementations.
Expand Down Expand Up @@ -146,6 +152,8 @@ public function __construct(
$cacheFactory = $cacheConfig->getCacheFactory();
$this->cache = $cacheFactory->createCache($this);
}

$this->hydratorFactory = $this->config->getHydratorFactory();
}

public function getConnection(): Connection
Expand Down Expand Up @@ -541,15 +549,7 @@ public function getUnitOfWork(): UnitOfWork

public function newHydrator(string|int $hydrationMode): AbstractHydrator
{
return match ($hydrationMode) {
Query::HYDRATE_OBJECT => new Internal\Hydration\ObjectHydrator($this),
Query::HYDRATE_ARRAY => new Internal\Hydration\ArrayHydrator($this),
Query::HYDRATE_SCALAR => new Internal\Hydration\ScalarHydrator($this),
Query::HYDRATE_SINGLE_SCALAR => new Internal\Hydration\SingleScalarHydrator($this),
Query::HYDRATE_SIMPLEOBJECT => new Internal\Hydration\SimpleObjectHydrator($this),
Query::HYDRATE_SCALAR_COLUMN => new Internal\Hydration\ScalarColumnHydrator($this),
default => $this->createCustomHydrator((string) $hydrationMode),
};
return $this->hydratorFactory->create($this, $this->config, $hydrationMode);
}

public function getProxyFactory(): ProxyFactory
Expand Down Expand Up @@ -617,15 +617,4 @@ private function configureMetadataCache(): void

$this->metadataFactory->setCache($metadataCache);
}

private function createCustomHydrator(string $hydrationMode): AbstractHydrator
{
$class = $this->config->getCustomHydrationMode($hydrationMode);

if ($class !== null) {
return new $class($this);
}

throw InvalidHydrationMode::fromMode($hydrationMode);
}
}
37 changes: 37 additions & 0 deletions src/Internal/Hydration/DefaultHydratorFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Internal\Hydration;

use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Exception\InvalidHydrationMode;
use Doctrine\ORM\Query;

final class DefaultHydratorFactory implements HydratorFactory
{
public function create(EntityManagerInterface $em, Configuration $config, string|int $hydrationMode): AbstractHydrator
{
return match ($hydrationMode) {
Query::HYDRATE_OBJECT => new ObjectHydrator($em),
Query::HYDRATE_ARRAY => new ArrayHydrator($em),
Query::HYDRATE_SCALAR => new ScalarHydrator($em),
Query::HYDRATE_SINGLE_SCALAR => new SingleScalarHydrator($em),
Query::HYDRATE_SIMPLEOBJECT => new SimpleObjectHydrator($em),
Query::HYDRATE_SCALAR_COLUMN => new ScalarColumnHydrator($em),
default => $this->createCustomHydrator((string) $hydrationMode, $em, $config),
};
}

private function createCustomHydrator(string $hydrationMode, EntityManagerInterface $em, Configuration $config): AbstractHydrator
{
$class = $config->getCustomHydrationMode($hydrationMode);

if ($class !== null) {
return new $class($em);
}

throw InvalidHydrationMode::fromMode($hydrationMode);
}
}
19 changes: 19 additions & 0 deletions src/Internal/Hydration/HydratorFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\ORM\Internal\Hydration;

use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManagerInterface;

interface HydratorFactory
{
/**
* Create a new instance for the given hydration mode.
*
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
*/
public function create(EntityManagerInterface $em, Configuration $config, string|int $hydrationMode): AbstractHydrator;
}

0 comments on commit b329889

Please sign in to comment.