Skip to content

Commit

Permalink
Merge branch '1.3.x'
Browse files Browse the repository at this point in the history
* 1.3.x:
  Don't apply filters and discriminators when using $indexStats
  Adapt API to BlogPostRepositoryInterface
  Updated RepositoryClass::class syntax and added an Interface
  Some errors or confusing class names changed
  • Loading branch information
alcaeus committed May 3, 2019
2 parents 89c4da8 + 3dc2c8c commit e497155
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 26 deletions.
72 changes: 46 additions & 26 deletions docs/en/cookbook/mapping-classes-to-orm-and-odm.rst
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
Mapping Classes to the ORM and ODM
==================================

Because of the non intrusive design of Doctrine it is possible for you to have plain PHP classes
that are mapped to both a relational database with the Doctrine2 Object Relational Mapper and
MongoDB with the Doctrine MongoDB Object Document Mapper, or any other persistence layer that
Because of the non-intrusive design of Doctrine, it is possible for you to have plain PHP classes
that are mapped to both a relational database (with the Doctrine2 Object Relational Mapper) and
MongoDB (with the Doctrine MongoDB Object Document Mapper), or any other persistence layer that
implements the Doctrine Common `persistence`_ interfaces.

Test Subject
------------

For this cookbook entry we need to define a class that can be persisted to both MySQL and MongoDB.
For this cookbook entry, we need to define a class that can be persisted to both MySQL and MongoDB.
We'll use a ``BlogPost`` as you may want to write some generic blogging functionality that has support
for multiple Doctrine persistence layers:

.. code-block:: php
<?php
namespace Doctrine\Blog;
namespace Documents\Blog;
class BlogPost
{
Expand Down Expand Up @@ -45,9 +45,11 @@ First define the mapping for the ORM:
<?php
namespace Doctrine\Blog;
namespace Documents\Blog;
/** @Entity(repositoryClass="Doctrine\Blog\ORM\BlogPostRepository") */
use Documents\Blog\Repository\ORM\BlogPostRepository;
/** @Entity(repositoryClass=BlogPostRepository::class) */
class BlogPost
{
/** @Id @Column(type="integer") */
Expand All @@ -70,20 +72,20 @@ First define the mapping for the ORM:
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Documents\BlogPost" repository-class="Doctrine\Blog\ORM\BlogPostRepository">
<entity name="Documents\Blog\BlogPost" repository-class="Documents\Blog\Repository\ORM\BlogPostRepository">
<id name="id" type="integer" />
<field name="name" type="string" />
<field name="email" type="text" />
</entity>
</doctrine-mapping>
Now you are able to persist the ``Documents\BlogPost`` with an instance of ``EntityManager``:
Now you are able to persist the ``Documents\Blog\BlogPost`` with an instance of ``EntityManager``:

.. code-block:: php
<?php
$blogPost = new BlogPost()
$blogPost = new BlogPost();
$blogPost->setTitle('test');
$em->persist($blogPost);
Expand All @@ -95,7 +97,7 @@ You can find the blog post:
<?php
$blogPost = $em->getRepository(Documents\BlogPost::class)->findOneBy(['title' => 'test']);
$blogPost = $em->getRepository(BlogPost::class)->findOneBy(array('title' => 'test'));
MongoDB ODM
~~~~~~~~~~~
Expand All @@ -108,9 +110,11 @@ Now map the same class to the Doctrine MongoDB ODM:
<?php
namespace Documents;
namespace Documents\Blog;
use Documents\Blog\Repository\ODM\BlogPostRepository;
/** @Document(repositoryClass="Doctrine\Blog\ODM\MongoDB\BlogPostRepository") */
/** @Document(repositoryClass=BlogPostRepository::class) */
class BlogPost
{
/** @Id */
Expand All @@ -133,8 +137,8 @@ Now map the same class to the Doctrine MongoDB ODM:
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<document name="Documents\BlogPost" repository-class="Doctrine\Blog\ODM\MongoDB\BlogPostRepository">
<field field-name="id" type="id" />
<document name="Documents\Blog\BlogPost" repository-class="Documents\Blog\Repository\ODM\BlogPostRepository">
<id strategy="INCREMENT" type="int" />
<field field-name="name" type="string" />
<field field-name="email" type="text" />
</document>
Expand All @@ -146,7 +150,7 @@ Now the same class is able to be persisted in the same way using an instance of
<?php
$blogPost = new BlogPost()
$blogPost = new BlogPost();
$blogPost->setTitle('test');
$dm->persist($blogPost);
Expand All @@ -158,23 +162,39 @@ You can find the blog post:
<?php
$blogPost = $dm->getRepository(Documents\BlogPost::class)->findOneBy(['title' => 'test']);
$blogPost = $dm->getRepository(BlogPost::class)->findOneBy(array('title' => 'test'));
Repository Classes
------------------

You can implement the same repository interface for the ORM and MongoDB ODM easily:
You can implement the same repository interface for the ORM and MongoDB ODM easily, e.g. by creating ``BlogPostRepositoryInterface``:

.. code-block:: php
<?php
// An Interface to ensure ORM and ODM Repository classes have the same methods implemented
namespace Documents\Blog\Repository;
use Documents\Blog\BlogPost;
interface BlogPostRepositoryInterface
{
public function findPostById(int $id): ?BlogPost;
}
namespace Doctrine\Blog\ORM;
Define repository methods required by the interface for the ORM:

use Doctrine\Blog\BlogPost;
.. code-block:: php
<?php
namespace Documents\Blog\Repository\ORM;
use Documents\Blog\Repository\BlogPostRepositoryInterface;
use Doctrine\ORM\EntityRepository;
class BlogPostRepository extends EntityRepository
class BlogPostRepository extends EntityRepository implements BlogPostRepositoryInterface
{
public function findPostById(int $id): ?BlogPost
{
Expand All @@ -188,14 +208,14 @@ Now define the same repository methods for the MongoDB ODM:
<?php
namespace Doctrine\Blog\ODM\MongoDB;
namespace Documents\Blog\Repository\ODM;
use Documents\BlogPost;
use Doctrine\ODM\MongoDB\DocumentRepository;
use Documents\Blog\Repository\BlogPostRepositoryInterface;
use Doctrine\ODM\MongoDB\Repository\DocumentRepository;
class BlogPostRepository extends DocumentRepository
class BlogPostRepository extends DocumentRepository implements BlogPostRepositoryInterface
{
public function findPostById(string $id): ?BlogPost
public function findPostById(int $id): ?BlogPost
{
return $this->findOneBy(['id' => $id]);
}
Expand Down
6 changes: 6 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Aggregation/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ static function (Stage $stage) {

if ($this->getStage(0) instanceof Stage\GeoNear) {
$pipeline[0]['$geoNear']['query'] = $this->applyFilters($pipeline[0]['$geoNear']['query']);
} elseif ($this->getStage(0) instanceof Stage\IndexStats) {
// Don't apply any filters when using an IndexStats stage: since it
// needs to be the first pipeline stage, prepending a match stage
// with discriminator information will not work

return $pipeline;
} else {
$matchExpression = $this->applyFilters([]);
if ($matchExpression !== []) {
Expand Down
11 changes: 11 additions & 0 deletions tests/Doctrine/ODM/MongoDB/Tests/Aggregation/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
use Documents\BlogTagAggregation;
use Documents\CmsComment;
use Documents\GuestServer;
use Documents\Project;
use Documents\Tag;
use MongoDB\BSON\UTCDateTime;
use function array_keys;

class BuilderTest extends BaseTest
{
Expand Down Expand Up @@ -343,6 +345,15 @@ public function testBuilderWithOutStageReturnsNoData()
$this->assertCount(0, $result);
}

public function testBuilderWithIndexStatsStageDoesNotApplyFilters()
{
$builder = $this->dm
->createAggregationBuilder(Project::class)
->indexStats();

$this->assertSame('$indexStats', array_keys($builder->getPipeline()[0])[0]);
}

private function insertTestData()
{
$baseballTag = new Tag('baseball');
Expand Down

0 comments on commit e497155

Please sign in to comment.