Add section on EntityRepository into Getting Started Tutorial.
This commit is contained in:
parent
aab2303c37
commit
e1c2084eeb
@ -1151,13 +1151,154 @@ entity is scheduled for an UPDATE against the database. Only the
|
|||||||
changed columns are updated, which offers a pretty good performance
|
changed columns are updated, which offers a pretty good performance
|
||||||
improvement compared to updating all the properties.
|
improvement compared to updating all the properties.
|
||||||
|
|
||||||
|
Entity Repositories
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
For now we have not discussed how to separate the Doctrine query logic from your model.
|
||||||
|
In Doctrine 1 there was the concept of ``Doctrine_Table`` instances for this
|
||||||
|
seperation. The similar concept in Doctrine2 is called Entity Repositories, integrating
|
||||||
|
the `repository pattern <http://martinfowler.com/eaaCatalog/repository.html>`_ at the heart of Doctrine.
|
||||||
|
|
||||||
|
Every Entity uses a default repository by default and offers a bunch of convenience
|
||||||
|
methods that you can use to query for instances of that Entity. Take for example
|
||||||
|
our Product entity. If we wanted to Query by name, we can use:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$product = $entityManager->getRepository('Product')
|
||||||
|
->findOneBy(array('name' => $productName));
|
||||||
|
|
||||||
|
The method ``findOneBy()`` takes an array of fields or association keys and the values to match against.
|
||||||
|
|
||||||
|
If you want to find all entities matching a condition you can use ``findBy()``, for
|
||||||
|
example querying for all closed bugs:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$bugs = $entityManager->getRepository('Bug')
|
||||||
|
->findBy(array('status' => 'CLOSED'));
|
||||||
|
|
||||||
|
foreach ($bugs AS $bug) {
|
||||||
|
// do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
Compared to DQL these query methods are falling short of functionality very fast.
|
||||||
|
Doctrine offers you a convenient way to extend the functionalities of the default ``EntityRepository``
|
||||||
|
and put all the specialized DQL query logic on it. For this you have to create a subclass
|
||||||
|
of ``Doctrine\ORM\EntityRepository``, in our case a ``BugRepository`` and group all
|
||||||
|
the previoiusly discussed query functionality in it:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
|
class BugRepository extends EntityRepository
|
||||||
|
{
|
||||||
|
public function getRecentBugs($number = 30)
|
||||||
|
{
|
||||||
|
$dql = "SELECT b, e, r FROM Bug b JOIN b.engineer e JOIN b.reporter r ORDER BY b.created DESC";
|
||||||
|
|
||||||
|
$query = $entityManager->createQuery($dql);
|
||||||
|
$query->setMaxResults($number);
|
||||||
|
return $query->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRecentBugsArray($number = 30)
|
||||||
|
{
|
||||||
|
$dql = "SELECT b, e, r, p FROM Bug b JOIN b.engineer e ".
|
||||||
|
"JOIN b.reporter r JOIN b.products p ORDER BY b.created DESC";
|
||||||
|
$query = $em->createQuery($dql);
|
||||||
|
$query->setMaxResults($number);
|
||||||
|
return $query->getArrayResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUsersBugs($userId, $number = 15)
|
||||||
|
{
|
||||||
|
$dql = "SELECT b, e, r FROM Bug b JOIN b.engineer e JOIN b.reporter r ".
|
||||||
|
"WHERE b.status = 'OPEN' AND e.id = ?1 OR r.id = ?1 ORDER BY b.created DESC";
|
||||||
|
|
||||||
|
return $entityManager->createQuery($dql)
|
||||||
|
->setParameter(1, $userId)
|
||||||
|
->setMaxResults($number)
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOpenBugsByProduct()
|
||||||
|
{
|
||||||
|
$dql = "SELECT p.id, p.name, count(b.id) AS openBugs FROM Bug b ".
|
||||||
|
"JOIN b.products p WHERE b.status = 'OPEN' GROUP BY p.id";
|
||||||
|
return $em->createQuery($dql)->getScalarResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
To be able to use this query logic through ``$entityManager->getRepository('Bug')``
|
||||||
|
we have to adjust the metadata slightly.
|
||||||
|
|
||||||
|
.. configuration-block::
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @Entity @Table(name="bugs", repositoryClass="BugRepository")
|
||||||
|
*/
|
||||||
|
class Bug
|
||||||
|
{
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
|
||||||
|
.. code-block:: xml
|
||||||
|
|
||||||
|
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
|
||||||
|
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
|
||||||
|
|
||||||
|
<entity name="Bug" table="bugs" entity-repository="BugRepository">
|
||||||
|
|
||||||
|
</entity>
|
||||||
|
</doctrine-mapping>
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
Product:
|
||||||
|
type: entity
|
||||||
|
repositoryClass: BugRepository
|
||||||
|
|
||||||
|
Now we can remove our query logic in all the places and instead use them through the EntityRepository.
|
||||||
|
As an example here is the code of the first use case "List of Bugs":
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$bugs = $entityManager->getRepository('Bug')->getRecentBugs();
|
||||||
|
|
||||||
|
foreach($bugs AS $bug) {
|
||||||
|
echo $bug->description." - ".$bug->created->format('d.m.Y')."\n";
|
||||||
|
echo " Reported by: ".$bug->getReporter()->name."\n";
|
||||||
|
echo " Assigned to: ".$bug->getEngineer()->name."\n";
|
||||||
|
foreach($bug->getProducts() AS $product) {
|
||||||
|
echo " Platform: ".$product->name."\n";
|
||||||
|
}
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
Using EntityRepositories you can avoid coupling your model with specific query logic.
|
||||||
|
You can also re-use query logic easily throughout your application.
|
||||||
|
|
||||||
|
Conclusion
|
||||||
|
----------
|
||||||
|
|
||||||
This tutorial is over here, I hope you had fun. Additional content
|
This tutorial is over here, I hope you had fun. Additional content
|
||||||
will be added to this tutorial incrementally, topics will include:
|
will be added to this tutorial incrementally, topics will include:
|
||||||
|
|
||||||
* Entity Repositories
|
- More on Association Mappings
|
||||||
* More on Association Mappings
|
- Lifecycle Events triggered in the UnitOfWork
|
||||||
* Lifecycle Events triggered in the UnitOfWork
|
- Ordering of Collections
|
||||||
* Ordering of Collections
|
|
||||||
|
|
||||||
Additional details on all the topics discussed here can be found in
|
Additional details on all the topics discussed here can be found in
|
||||||
the respective manual chapters.
|
the respective manual chapters.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user