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

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.      * @return array The entities.
  155.      *
  156.      * @psalm-return list<T>
  157.      */
  158.     public function findAll()
  159.     {
  160.         return $this->findBy([]);
  161.     }
  162.     /**
  163.      * Finds entities by a set of criteria.
  164.      *
  165.      * @param array      $criteria
  166.      * @param array|null $orderBy
  167.      * @param int|null   $limit
  168.      * @param int|null   $offset
  169.      *
  170.      * @return array The objects.
  171.      *
  172.      * @psalm-return list<T>
  173.      */
  174.     public function findBy(array $criteria, ?array $orderBy null$limit null$offset null)
  175.     {
  176.         $persister $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
  177.         return $persister->loadAll($criteria$orderBy$limit$offset);
  178.     }
  179.     /**
  180.      * Finds a single entity by a set of criteria.
  181.      *
  182.      * @param array      $criteria
  183.      * @param array|null $orderBy
  184.      *
  185.      * @return object|null The entity instance or NULL if the entity can not be found.
  186.      *
  187.      * @psalm-return ?T
  188.      */
  189.     public function findOneBy(array $criteria, ?array $orderBy null)
  190.     {
  191.         $persister $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
  192.         return $persister->load($criterianullnull, [], null1$orderBy);
  193.     }
  194.     /**
  195.      * Counts entities by a set of criteria.
  196.      *
  197.      * @param array $criteria
  198.      *
  199.      * @return int The cardinality of the objects that match the given criteria.
  200.      *
  201.      * @todo Add this method to `ObjectRepository` interface in the next major release
  202.      */
  203.     public function count(array $criteria)
  204.     {
  205.         return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->count($criteria);
  206.     }
  207.     /**
  208.      * Adds support for magic method calls.
  209.      *
  210.      * @param string $method
  211.      * @param array  $arguments
  212.      *
  213.      * @return mixed The returned value from the resolved method.
  214.      *
  215.      * @throws ORMException
  216.      * @throws BadMethodCallException If the method called is invalid.
  217.      */
  218.     public function __call($method$arguments)
  219.     {
  220.         if (strpos($method'findBy') === 0) {
  221.             return $this->resolveMagicCall('findBy'substr($method6), $arguments);
  222.         }
  223.         if (strpos($method'findOneBy') === 0) {
  224.             return $this->resolveMagicCall('findOneBy'substr($method9), $arguments);
  225.         }
  226.         if (strpos($method'countBy') === 0) {
  227.             return $this->resolveMagicCall('count'substr($method7), $arguments);
  228.         }
  229.         throw new BadMethodCallException(sprintf(
  230.             'Undefined method "%s". The method name must start with ' .
  231.             'either findBy, findOneBy or countBy!',
  232.             $method
  233.         ));
  234.     }
  235.     /**
  236.      * @return string
  237.      */
  238.     protected function getEntityName()
  239.     {
  240.         return $this->_entityName;
  241.     }
  242.     /**
  243.      * @return string
  244.      */
  245.     public function getClassName()
  246.     {
  247.         return $this->getEntityName();
  248.     }
  249.     /**
  250.      * @return EntityManager
  251.      */
  252.     protected function getEntityManager()
  253.     {
  254.         return $this->_em;
  255.     }
  256.     /**
  257.      * @return Mapping\ClassMetadata
  258.      */
  259.     protected function getClassMetadata()
  260.     {
  261.         return $this->_class;
  262.     }
  263.     /**
  264.      * Select all elements from a selectable that match the expression and
  265.      * return a new collection containing these elements.
  266.      *
  267.      * @return Collection
  268.      *
  269.      * @psalm-return Collection<int, T>
  270.      */
  271.     public function matching(Criteria $criteria)
  272.     {
  273.         $persister $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
  274.         return new LazyCriteriaCollection($persister$criteria);
  275.     }
  276.     /**
  277.      * Resolves a magic method call to the proper existent method at `EntityRepository`.
  278.      *
  279.      * @param string $method    The method to call
  280.      * @param string $by        The property name used as condition
  281.      * @param array  $arguments The arguments to pass at method call
  282.      *
  283.      * @return mixed
  284.      *
  285.      * @throws ORMException If the method called is invalid or the requested field/association does not exist.
  286.      */
  287.     private function resolveMagicCall($method$by, array $arguments)
  288.     {
  289.         if (! $arguments) {
  290.             throw ORMException::findByRequiresParameter($method $by);
  291.         }
  292.         if (self::$inflector === null) {
  293.             self::$inflector InflectorFactory::create()->build();
  294.         }
  295.         $fieldName lcfirst(self::$inflector->classify($by));
  296.         if (! ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName))) {
  297.             throw ORMException::invalidMagicCall($this->_entityName$fieldName$method $by);
  298.         }
  299.         return $this->$method([$fieldName => $arguments[0]], ...array_slice($arguments1));
  300.     }
  301. }