1
0
mirror of synced 2025-03-06 21:06:16 +03:00

Merge branch 'feature/#6003-count-on-repositories'

Close #6003
This commit is contained in:
Marco Pivetta 2016-09-08 00:56:34 +02:00
commit 8a87fa2d01
6 changed files with 112 additions and 44 deletions

View File

@ -727,6 +727,14 @@ examples are equivalent:
// A single user by its nickname (__call magic)
$user = $em->getRepository('MyProject\Domain\User')->findOneByNickname('romanb');
Additionally, you can just count the result of the provided conditions when you don't really need the data:
.. code-block:: php
<?php
// Check there is no user with nickname
$availableNickname = 0 === $em->getRepository('MyProject\Domain\User')->count(['nickname' => 'nonexistent']);
By Criteria
~~~~~~~~~~~

View File

@ -1535,6 +1535,16 @@ As an example here is the code of the first use case "List of Bugs":
Using EntityRepositories you can avoid coupling your model with specific query logic.
You can also re-use query logic easily throughout your application.
The method ``count()`` takes an array of fields or association keys and the values to match against.
This provides you with a convenient and lightweight way to count a resultset when you don't need to
deal with it:
.. code-block:: php
<?php
$productCount = $entityManager->getRepository(Product::class)
->count(['name' => $productName]);
Conclusion
----------

View File

@ -19,6 +19,7 @@
namespace Doctrine\ORM;
use Doctrine\Common\Util\Inflector;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Common\Persistence\ObjectRepository;
use Doctrine\Common\Collections\Selectable;
@ -196,66 +197,50 @@ class EntityRepository implements ObjectRepository, Selectable
}
/**
* Adds support for magic finders.
* Counts entities by a set of criteria.
*
* @todo Add this method to `ObjectRepository` interface in the next major release
*
* @param array $criteria
*
* @return int The cardinality of the objects that match the given criteria.
*/
public function count(array $criteria)
{
return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->count($criteria);
}
/**
* Adds support for magic method calls.
*
* @param string $method
* @param array $arguments
*
* @return array|object The found entity/entities.
* @return mixed The returned value from the resolved method.
*
* @throws ORMException
* @throws \BadMethodCallException If the method called is an invalid find* method
* or no find* method at all and therefore an invalid
* method call.
* @throws \BadMethodCallException If the method called is invalid
*/
public function __call($method, $arguments)
{
switch (true) {
case (0 === strpos($method, 'findBy')):
$by = substr($method, 6);
$method = 'findBy';
break;
if (0 === strpos($method, 'findBy')) {
return $this->resolveMagicCall('findBy', substr($method, 6), $arguments);
}
case (0 === strpos($method, 'findOneBy')):
$by = substr($method, 9);
$method = 'findOneBy';
break;
if (0 === strpos($method, 'findOneBy')) {
return $this->resolveMagicCall('findOneBy', substr($method, 9), $arguments);
}
if (0 === strpos($method, 'countBy')) {
return $this->resolveMagicCall('count', substr($method, 7), $arguments);
}
default:
throw new \BadMethodCallException(
"Undefined method '$method'. The method name must start with ".
"either findBy or findOneBy!"
);
}
if (empty($arguments)) {
throw ORMException::findByRequiresParameter($method . $by);
}
$fieldName = lcfirst(\Doctrine\Common\Util\Inflector::classify($by));
if ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName)) {
switch (count($arguments)) {
case 1:
return $this->$method(array($fieldName => $arguments[0]));
case 2:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1]);
case 3:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2]);
case 4:
return $this->$method(array($fieldName => $arguments[0]), $arguments[1], $arguments[2], $arguments[3]);
default:
// Do nothing
}
}
throw ORMException::invalidFindByCall($this->_entityName, $fieldName, $method.$by);
}
/**
* @return string
*/
@ -302,4 +287,30 @@ class EntityRepository implements ObjectRepository, Selectable
return new LazyCriteriaCollection($persister, $criteria);
}
/**
* Resolves a magic method call to the proper existent method at `EntityRepository`.
*
* @param string $method The method to call
* @param string $by The property name used as condition
* @param array $arguments The arguments to pass at method call
*
* @throws ORMException If the method called is invalid or the requested field/association does not exist
*
* @return mixed
*/
private function resolveMagicCall($method, $by, array $arguments)
{
if (! $arguments) {
throw ORMException::findByRequiresParameter($method . $by);
}
$fieldName = lcfirst(Inflector::classify($by));
if (! ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName))) {
throw ORMException::invalidMagicCall($this->_entityName, $fieldName, $method . $by);
}
return $this->$method([$fieldName => $arguments[0]], ...array_slice($arguments, 1));
}
}

View File

@ -187,6 +187,21 @@ class ORMException extends Exception
);
}
/**
* @param string $entityName
* @param string $fieldName
* @param string $method
*
* @return ORMException
*/
public static function invalidMagicCall($entityName, $fieldName, $method)
{
return new self(
"Entity '".$entityName."' has no field '".$fieldName."'. ".
"You can therefore not call '".$method."' on the entities' repository"
);
}
/**
* @param string $entityName
* @param string $associationFieldName

View File

@ -822,7 +822,7 @@ class BasicEntityPersister implements EntityPersister
? $this->expandCriteriaParameters($criteria)
: $this->expandParameters($criteria);
return $this->conn->executeQuery($sql, $params, $types)->fetchColumn();
return (int) $this->conn->executeQuery($sql, $params, $types)->fetchColumn();
}
/**

View File

@ -272,6 +272,30 @@ class EntityRepositoryTest extends OrmFunctionalTestCase
$this->assertEquals(4, count($users));
}
public function testCount()
{
$this->loadFixture();
$repos = $this->_em->getRepository(CmsUser::class);
$userCount = $repos->count(array());
$this->assertSame(4, $userCount);
$userCount = $repos->count(array('status' => 'dev'));
$this->assertSame(2, $userCount);
$userCount = $repos->count(array('status' => 'nonexistent'));
$this->assertSame(0, $userCount);
}
public function testCountBy()
{
$this->loadFixture();
$repos = $this->_em->getRepository(CmsUser::class);
$userCount = $repos->countByStatus('dev');
$this->assertSame(2, $userCount);
}
/**
* @expectedException \Doctrine\ORM\ORMException
*/