diff --git a/docs/en/reference/working-with-objects.rst b/docs/en/reference/working-with-objects.rst index 8368c9f13..bcc9bf185 100644 --- a/docs/en/reference/working-with-objects.rst +++ b/docs/en/reference/working-with-objects.rst @@ -41,7 +41,7 @@ headline "Hello World" with the ID 1234: find('CMS\Article', 1234); $article->setHeadline('Hello World dude!'); - + $article2 = $entityManager->find('CMS\Article', 1234); echo $article2->getHeadline(); @@ -93,25 +93,25 @@ from newly opened EntityManager. { /** @Id @Column(type="integer") @GeneratedValue */ private $id; - + /** @Column(type="string") */ private $headline; - + /** @ManyToOne(targetEntity="User") */ private $author; - + /** @OneToMany(targetEntity="Comment", mappedBy="article") */ private $comments; - + public function __construct() { $this->comments = new ArrayCollection(); } - + public function getAuthor() { return $this->author; } public function getComments() { return $this->comments; } } - + $article = $em->find('Article', 1); This code only retrieves the ``Article`` instance with id 1 executing @@ -132,22 +132,22 @@ your code. See the following code: find('Article', 1); - + // accessing a method of the user instance triggers the lazy-load echo "Author: " . $article->getAuthor()->getName() . "\n"; - + // Lazy Loading Proxies pass instanceof tests: if ($article->getAuthor() instanceof User) { // a User Proxy is a generated "UserProxy" class } - + // accessing the comments as an iterator triggers the lazy-load // retrieving ALL the comments of this article from the database // using a single SELECT statement foreach ($article->getComments() as $comment) { echo $comment->getText() . "\n\n"; } - + // Article::$comments passes instanceof tests for the Collection interface // But it will NOT pass for the ArrayCollection interface if ($article->getComments() instanceof \Doctrine\Common\Collections\Collection) { @@ -167,7 +167,7 @@ methods along the lines of the ``getName()`` method shown below: { // lazy loading code } - + public function getName() { $this->_load(); @@ -262,7 +262,7 @@ which means that its persistent state will be deleted once for and appear in query and collection results. See the section on :ref:`Database and UnitOfWork Out-Of-Sync ` for more information. - + Example: @@ -681,13 +681,13 @@ methods on a repository as follows: getRepository('MyProject\Domain\User')->findBy(array('age' => 20)); - + // All users that are 20 years old and have a surname of 'Miller' $users = $em->getRepository('MyProject\Domain\User')->findBy(array('age' => 20, 'surname' => 'Miller')); - + // A single user by its nickname $user = $em->getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb')); @@ -723,10 +723,18 @@ examples are equivalent: getRepository('MyProject\Domain\User')->findOneBy(array('nickname' => 'romanb')); - + // 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 + + getRepository('MyProject\Domain\User')->count(array('nickname' => 'nonexistent')); + By Criteria ~~~~~~~~~~~ @@ -774,7 +782,7 @@ A DQL query is represented by an instance of the createQuery("select u from MyDomain\Model\User u where u.age >= 20 and u.age <= 30"); $users = $q->getResult(); @@ -817,18 +825,18 @@ in a central location. getRepository('MyDomain\Model\User')->getAllAdminUsers(); diff --git a/docs/en/tutorials/getting-started.rst b/docs/en/tutorials/getting-started.rst index ef4734317..5e0444246 100644 --- a/docs/en/tutorials/getting-started.rst +++ b/docs/en/tutorials/getting-started.rst @@ -103,7 +103,7 @@ Install Doctrine using the Composer Dependency Management tool, by calling: $ composer install This will install the packages Doctrine Common, Doctrine DBAL, Doctrine ORM, -Symfony YAML and Symfony Console into the `vendor` directory. The Symfony +Symfony YAML and Symfony Console into the `vendor` directory. The Symfony dependencies are not required by Doctrine but will be used in this tutorial. Add the following directories: @@ -131,22 +131,22 @@ step: // bootstrap.php use Doctrine\ORM\Tools\Setup; use Doctrine\ORM\EntityManager; - + require_once "vendor/autoload.php"; - + // Create a simple "default" Doctrine ORM configuration for Annotations $isDevMode = true; $config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode); // or if you prefer yaml or XML //$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode); //$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode); - + // database configuration parameters $conn = array( 'driver' => 'pdo_sqlite', 'path' => __DIR__ . '/db.sqlite', ); - + // obtaining the entity manager $entityManager = EntityManager::create($conn, $config); @@ -185,7 +185,7 @@ doctrine command. Its a fairly simple file: getRepository('Product') + ->count(array('name' => $productName)); + Conclusion ---------- diff --git a/lib/Doctrine/ORM/EntityRepository.php b/lib/Doctrine/ORM/EntityRepository.php index 08b2ff193..2b8c1cb51 100644 --- a/lib/Doctrine/ORM/EntityRepository.php +++ b/lib/Doctrine/ORM/EntityRepository.php @@ -196,16 +196,32 @@ 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 quantity of objects that matches the criteria. + */ + public function count(array $criteria) + { + $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName); + + return $persister->count($criteria); + } + + /** + * Adds support for magic finders/counters. * * @param string $method * @param array $arguments * - * @return array|object The found entity/entities. + * @return array|object|int The found entity/entities or its resulting count. * * @throws ORMException - * @throws \BadMethodCallException If the method called is an invalid find* method - * or no find* method at all and therefore an invalid + * @throws \BadMethodCallException If the method called is an invalid find* or countBy method + * or no find* or countBy method at all and therefore an invalid * method call. */ public function __call($method, $arguments) @@ -221,6 +237,11 @@ class EntityRepository implements ObjectRepository, Selectable $method = 'findOneBy'; break; + case (0 === strpos($method, 'countBy')): + $by = substr($method, 7); + $method = 'count'; + break; + default: throw new \BadMethodCallException( "Undefined method '$method'. The method name must start with ". @@ -228,14 +249,16 @@ class EntityRepository implements ObjectRepository, Selectable ); } - if (empty($arguments)) { + $argsCount = count($arguments); + + if (0 === $argsCount) { 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)) { + switch ($argsCount) { case 1: return $this->$method(array($fieldName => $arguments[0])); diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 3b2faf878..c62a10a12 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -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(); } /** diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index ffca89ba0..e0b96387a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -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 */