Skip to content

Commit

Permalink
Merge pull request #1599 from nicolas-grekas/lazy-service-repo
Browse files Browse the repository at this point in the history
  • Loading branch information
ostrolucky committed Jan 6, 2023
2 parents 6370f16 + 863b9b3 commit fe9b2cc
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 31 deletions.
62 changes: 62 additions & 0 deletions Repository/LazyServiceEntityRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Doctrine\Bundle\DoctrineBundle\Repository;

use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use LogicException;
use Symfony\Component\VarExporter\LazyGhostTrait;

use function sprintf;

/**
* Optional EntityRepository base class with a simplified constructor (for autowiring).
*
* To use in your class, inject the "registry" service and call
* the parent constructor. For example:
*
* class YourEntityRepository extends ServiceEntityRepository
* {
* public function __construct(ManagerRegistry $registry)
* {
* parent::__construct($registry, YourEntity::class);
* }
* }
*
* @internal to be renamed ServiceEntityRepository when PHP 8.1 / Symfony 6.2 becomes required
*
* @template T of object
* @template-extends EntityRepository<T>
*/
class LazyServiceEntityRepository extends EntityRepository implements ServiceEntityRepositoryInterface
{
use LazyGhostTrait;

/**
* @param string $entityClass The class name of the entity this repository manages
* @psalm-param class-string<T> $entityClass
*/
public function __construct(ManagerRegistry $registry, string $entityClass)
{
$initializer = function ($instance, $property) use ($registry, $entityClass) {
$manager = $registry->getManagerForClass($entityClass);

if ($manager === null) {
throw new LogicException(sprintf(
'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.',
$entityClass
));
}

parent::__construct($manager, $manager->getClassMetadata($entityClass));

return $this->$property;
};

self::createLazyGhost([
"\0*\0_em" => $initializer,
"\0*\0_class" => $initializer,
"\0*\0_entityName" => $initializer,
], null, $this);
}
}
68 changes: 38 additions & 30 deletions Repository/ServiceEntityRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,51 @@
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use LogicException;
use Symfony\Component\VarExporter\LazyGhostTrait;

use function sprintf;
use function trait_exists;

/**
* Optional EntityRepository base class with a simplified constructor (for autowiring).
*
* To use in your class, inject the "registry" service and call
* the parent constructor. For example:
*
* class YourEntityRepository extends ServiceEntityRepository
* {
* public function __construct(ManagerRegistry $registry)
* {
* parent::__construct($registry, YourEntity::class);
* }
* }
*
* @template T of object
* @template-extends EntityRepository<T>
*/
class ServiceEntityRepository extends EntityRepository implements ServiceEntityRepositoryInterface
{
if (trait_exists(LazyGhostTrait::class)) {
class ServiceEntityRepository extends LazyServiceEntityRepository
{
}
} else {
/**
* @param string $entityClass The class name of the entity this repository manages
* @psalm-param class-string<T> $entityClass
* Optional EntityRepository base class with a simplified constructor (for autowiring).
*
* To use in your class, inject the "registry" service and call
* the parent constructor. For example:
*
* class YourEntityRepository extends ServiceEntityRepository
* {
* public function __construct(ManagerRegistry $registry)
* {
* parent::__construct($registry, YourEntity::class);
* }
* }
*
* @template T of object
* @template-extends EntityRepository<T>
*/
public function __construct(ManagerRegistry $registry, string $entityClass)
class ServiceEntityRepository extends EntityRepository implements ServiceEntityRepositoryInterface
{
$manager = $registry->getManagerForClass($entityClass);
/**
* @param string $entityClass The class name of the entity this repository manages
* @psalm-param class-string<T> $entityClass
*/
public function __construct(ManagerRegistry $registry, string $entityClass)
{
$manager = $registry->getManagerForClass($entityClass);

if ($manager === null) {
throw new LogicException(sprintf(
'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.',
$entityClass
));
}
if ($manager === null) {
throw new LogicException(sprintf(
'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.',
$entityClass
));
}

parent::__construct($manager, $manager->getClassMetadata($entityClass));
parent::__construct($manager, $manager->getClassMetadata($entityClass));
}
}
}
3 changes: 2 additions & 1 deletion Tests/Repository/ServiceEntityRepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public function testConstructorThrowsExceptionWhenNoManagerFound(): void
EXCEPTION
);
/** @psalm-suppress UndefinedClass */
new ServiceEntityRepository($registry, TestEntity::class);
$repo = new ServiceEntityRepository($registry, TestEntity::class);
$repo->getClassName();
}
}
1 change: 1 addition & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

<rule ref="PSR1.Classes.ClassDeclaration.MultipleClasses">
<exclude-pattern>Tests/*</exclude-pattern>
<exclude-pattern>Repository/ServiceEntityRepository.php</exclude-pattern>
</rule>
<rule ref="Squiz.Classes.ClassFileName.NoMatch">
<exclude-pattern>Tests/*</exclude-pattern>
Expand Down
13 changes: 13 additions & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<!-- We use the "Foo" namespace in unit tests. We are aware that those classes don't exist. -->
<referencedClass name="Foo\*"/>
<referencedClass name="Symfony\Bridge\Doctrine\Attribute\MapEntity"/>
<referencedClass name="Symfony\Component\VarExporter\LazyGhostTrait"/>
<referencedClass name="Symfony\Component\VarExporter\LazyObjectInterface"/>
</errorLevel>
</UndefinedClass>
Expand All @@ -62,5 +63,17 @@
<directory name="Tests/DependencyInjection"/>
</errorLevel>
</UndefinedDocblockClass>
<UndefinedTrait>
<errorLevel type="suppress">
<!-- Consumer is meant to check if trait exists before using this class -->
<file name="Repository/LazyServiceEntityRepository.php"/>
</errorLevel>
</UndefinedTrait>
<DuplicateClass>
<errorLevel type="suppress">
<!-- Conditional class definition-->
<file name="Repository/ServiceEntityRepository.php"/>
</errorLevel>
</DuplicateClass>
</issueHandlers>
</psalm>

0 comments on commit fe9b2cc

Please sign in to comment.