vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php line 166

Open in your IDE?
  1. <?php
  2. /*
  3.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14.  *
  15.  * This software consists of voluntary contributions made by many individuals
  16.  * and is licensed under the MIT license. For more information, see
  17.  * <http://www.doctrine-project.org>.
  18.  */
  19. namespace Doctrine\ORM;
  20. use BadMethodCallException;
  21. use Doctrine\Common\Collections\Collection;
  22. use Doctrine\Common\Collections\Criteria;
  23. use Doctrine\Common\Collections\Selectable;
  24. use Doctrine\Inflector\Inflector;
  25. use Doctrine\Inflector\InflectorFactory;
  26. use Doctrine\ORM\Mapping\ClassMetadata;
  27. use Doctrine\ORM\Query\ResultSetMappingBuilder;
  28. use Doctrine\Persistence\ObjectRepository;
  29. use function array_slice;
  30. use function lcfirst;
  31. use function sprintf;
  32. use function strpos;
  33. use function substr;
  34. use function trigger_error;
  35. use const E_USER_DEPRECATED;
  36. /**
  37.  * An EntityRepository serves as a repository for entities with generic as well as
  38.  * business specific methods for retrieving entities.
  39.  *
  40.  * This class is designed for inheritance and users can subclass this class to
  41.  * write their own repositories with business-specific methods to locate entities.
  42.  *
  43.  * @template T
  44.  * @template-implements Selectable<int,T>
  45.  * @template-implements ObjectRepository<T>
  46.  */
  47. class EntityRepository implements ObjectRepositorySelectable
  48. {
  49.     /** @var string */
  50.     protected $_entityName;
  51.     /** @var EntityManager */
  52.     protected $_em;
  53.     /** @var ClassMetadata */
  54.     protected $_class;
  55.     /** @var Inflector */
  56.     private static $inflector;
  57.     /**
  58.      * Initializes a new <tt>EntityRepository</tt>.
  59.      *
  60.      * @psalm-param Mapping\ClassMetadata $class
  61.      */
  62.     public function __construct(EntityManagerInterface $emMapping\ClassMetadata $class)
  63.     {
  64.         $this->_entityName $class->name;
  65.         $this->_em         $em;
  66.         $this->_class      $class;
  67.     }
  68.     /**
  69.      * Creates a new QueryBuilder instance that is prepopulated for this entity name.
  70.      *
  71.      * @param string $alias
  72.      * @param string $indexBy The index for the from.
  73.      *
  74.      * @return QueryBuilder
  75.      */
  76.     public function createQueryBuilder($alias$indexBy null)
  77.     {
  78.         return $this->_em->createQueryBuilder()
  79.             ->select($alias)
  80.             ->from($this->_entityName$alias$indexBy);
  81.     }
  82.     /**
  83.      * Creates a new result set mapping builder for this entity.
  84.      *
  85.      * The column naming strategy is "INCREMENT".
  86.      *
  87.      * @param string $alias
  88.      *
  89.      * @return ResultSetMappingBuilder
  90.      */
  91.     public function createResultSetMappingBuilder($alias)
  92.     {
  93.         $rsm = new ResultSetMappingBuilder($this->_emResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT);
  94.         $rsm->addRootEntityFromClassMetadata($this->_entityName$alias);
  95.         return $rsm;
  96.     }
  97.     /**
  98.      * Creates a new Query instance based on a predefined metadata named query.
  99.      *
  100.      * @param string $queryName
  101.      *
  102.      * @return Query
  103.      */
  104.     public function createNamedQuery($queryName)
  105.     {
  106.         return $this->_em->createQuery($this->_class->getNamedQuery($queryName));
  107.     }
  108.     /**
  109.      * Creates a native SQL query.
  110.      *
  111.      * @param string $queryName
  112.      *
  113.      * @return NativeQuery
  114.      */
  115.     public function createNativeNamedQuery($queryName)
  116.     {
  117.         $queryMapping $this->_class->getNamedNativeQuery($queryName);
  118.         $rsm          = new Query\ResultSetMappingBuilder($this->_em);
  119.         $rsm->addNamedNativeQueryMapping($this->_class$queryMapping);
  120.         return $this->_em->createNativeQuery($queryMapping['query'], $rsm);
  121.     }
  122.     /**
  123.      * Clears the repository, causing all managed entities to become detached.
  124.      *
  125.      * @deprecated 2.8 This method is being removed from the ORM and won't have any replacement
  126.      *
  127.      * @return void
  128.      */
  129.     public function clear()
  130.     {
  131.         @trigger_error('Method ' __METHOD__ '() is deprecated and will be removed in Doctrine ORM 3.0.'E_USER_DEPRECATED);
  132.         $this->_em->clear($this->_class->rootEntityName);
  133.     }
  134.     /**
  135.      * Finds an entity by its primary key / identifier.
  136.      *
  137.      * @param mixed    $id          The identifier.
  138.      * @param int|null $lockMode    One of the \Doctrine\DBAL\LockMode::* constants
  139.      *                              or NULL if no specific lock mode should be used
  140.      *                              during the search.
  141.      * @param int|null $lockVersion The lock version.
  142.      *
  143.      * @return object|null The entity instance or NULL if the entity can not be found.
  144.      *
  145.      * @psalm-return ?T
  146.      */
  147.     public function find($id$lockMode null$lockVersion null)
  148.     {
  149.         return $this->_em->find($this->_entityName$id$lockMode$lockVersion);
  150.     }
  151.     /**
  152.      * Finds all entities in the repository.
  153.      *
  154.      * @psalm-return list<T> The entities.
  155.      */
  156.     public function findAll()
  157.     {
  158.         return $this->findBy([]);
  159.     }
  160.     /**
  161.      * Finds entities by a set of criteria.
  162.      *
  163.      * @param int|null $limit
  164.      * @param int|null $offset
  165.      *
  166.      * @psalm-param array<string, mixed> $criteria
  167.      * @psalm-param array<string, string>|null $orderBy
  168.      * @psalm-return list<T> The objects.
  169.      */
  170.     public function findBy(array $criteria, ?array $orderBy null$limit null$offset null)
  171.     {
  172.         $persister $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
  173.         return $persister->loadAll($criteria$orderBy$limit$offset);
  174.     }
  175.     /**
  176.      * Finds a single entity by a set of criteria.
  177.      *
  178.      * @return object|null The entity instance or NULL if the entity can not be found.
  179.      *
  180.      * @psalm-param array<string, mixed> $criteria
  181.      * @psalm-param array<string, string>|null $orderBy
  182.      * @psalm-return ?T
  183.      */
  184.     public function findOneBy(array $criteria, ?array $orderBy null)
  185.     {
  186.         $persister $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
  187.         return $persister->load($criterianullnull, [], null1$orderBy);
  188.     }
  189.     /**
  190.      * Counts entities by a set of criteria.
  191.      *
  192.      * @return int The cardinality of the objects that match the given criteria.
  193.      *
  194.      * @psalm-param array<string, mixed> $criteria
  195.      * @todo Add this method to `ObjectRepository` interface in the next major release
  196.      */
  197.     public function count(array $criteria)
  198.     {
  199.         return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->count($criteria);
  200.     }
  201.     /**
  202.      * Adds support for magic method calls.
  203.      *
  204.      * @param string $method
  205.      *
  206.      * @return mixed The returned value from the resolved method.
  207.      *
  208.      * @throws ORMException
  209.      * @throws BadMethodCallException If the method called is invalid.
  210.      *
  211.      * @psalm-param list<mixed> $arguments
  212.      */
  213.     public function __call($method$arguments)
  214.     {
  215.         if (strpos($method'findBy') === 0) {
  216.             return $this->resolveMagicCall('findBy'substr($method6), $arguments);
  217.         }
  218.         if (strpos($method'findOneBy') === 0) {
  219.             return $this->resolveMagicCall('findOneBy'substr($method9), $arguments);
  220.         }
  221.         if (strpos($method'countBy') === 0) {
  222.             return $this->resolveMagicCall('count'substr($method7), $arguments);
  223.         }
  224.         throw new BadMethodCallException(sprintf(
  225.             'Undefined method "%s". The method name must start with ' .
  226.             'either findBy, findOneBy or countBy!',
  227.             $method
  228.         ));
  229.     }
  230.     /**
  231.      * @return string
  232.      */
  233.     protected function getEntityName()
  234.     {
  235.         return $this->_entityName;
  236.     }
  237.     /**
  238.      * @return string
  239.      */
  240.     public function getClassName()
  241.     {
  242.         return $this->getEntityName();
  243.     }
  244.     /**
  245.      * @return EntityManager
  246.      */
  247.     protected function getEntityManager()
  248.     {
  249.         return $this->_em;
  250.     }
  251.     /**
  252.      * @return Mapping\ClassMetadata
  253.      */
  254.     protected function getClassMetadata()
  255.     {
  256.         return $this->_class;
  257.     }
  258.     /**
  259.      * Select all elements from a selectable that match the expression and
  260.      * return a new collection containing these elements.
  261.      *
  262.      * @psalm-return Collection<int, T>
  263.      */
  264.     public function matching(Criteria $criteria)
  265.     {
  266.         $persister $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
  267.         return new LazyCriteriaCollection($persister$criteria);
  268.     }
  269.     /**
  270.      * Resolves a magic method call to the proper existent method at `EntityRepository`.
  271.      *
  272.      * @param string $method The method to call
  273.      * @param string $by     The property name used as condition
  274.      *
  275.      * @return mixed
  276.      *
  277.      * @throws ORMException If the method called is invalid or the requested field/association does not exist.
  278.      *
  279.      * @psalm-param list<mixed> $arguments The arguments to pass at method call
  280.      */
  281.     private function resolveMagicCall(string $methodstring $by, array $arguments)
  282.     {
  283.         if (! $arguments) {
  284.             throw ORMException::findByRequiresParameter($method $by);
  285.         }
  286.         if (self::$inflector === null) {
  287.             self::$inflector InflectorFactory::create()->build();
  288.         }
  289.         $fieldName lcfirst(self::$inflector->classify($by));
  290.         if (! ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName))) {
  291.             throw ORMException::invalidMagicCall($this->_entityName$fieldName$method $by);
  292.         }
  293.         return $this->$method([$fieldName => $arguments[0]], ...array_slice($arguments1));
  294.     }
  295. }