You are browsing a version that has not yet been released.

Getting Started

Doctrine is a project that aims to handle the persistence of your domain model in a non-interfering way. Non-relational or no-sql databases like MongoDB give you flexibility of building data store around your object model and not vise versa. You can read more on the initial configuration and setup in Introduction to MongoDB Object Document Mapper. This section will give you a basic overview of what could be accomplished using Doctrine MongoDB ODM.

Example Model: Simple Blog

To create the simplest example, let’s assume the following in a simple blog web application:

  • a Blog has a "user".
  • a Blog "user" can make "blog posts"

A first prototype

For the above mentioned example, we start by defining two simple PHP classes: User and BlogPost. The User class will have a collection of BlogPost objects.

1<?php namespace Documents; class User { public function __construct( public string $name = '', public string $email = '', public array $posts = [], ) { } // ... }
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Now define the BlogPost document that contains the title, body and the date of creation:

1<?php namespace Documents; use DateTimeImmutable; class BlogPost { public function __construct( public string $title = '', public string $body = '', public DateTimeImmutable $createdAt = new DateTimeImmutable(), ) { } // ... }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Persistent Models

To make the above classes persistent, we need to provide Doctrine with some mapping information so that it knows how to consume the objects and persist them to the database.

You can provide your mapping information in Annotations or XML:

  • PHP
    1<?php use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; #[ODM\Document] class User { public function __construct( #[ODM\Id] public ?string $id = null, #[ODM\Field] public string $name = '', #[ODM\Field] public string $email = '', #[ODM\ReferenceMany(targetDocument: BlogPost::class, cascade: 'all')] public Collection $posts = new ArrayCollection(), ) { } // ... } #[ODM\Document] class BlogPost { public function __construct( #[ODM\Id] public ?string $id = null, #[ODM\Field] public string $title = '', #[ODM\Field] public string $body = '', #[ODM\Field] public DateTimeImmutable $createdAt = new DateTimeImmutable(), ) { } // ... }
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
  • XML
    1<?xml version="1.0" encoding="UTF-8"?> <doctrine-mongo-mapping xmlns="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd"> <document name="Documents\User"> <id /> <field field-name="name" type="string" /> <field field-name="email" type="string" /> <reference-many field-name="posts" targetDocument="Documents\BlogPost"> <cascade> <all/> </cascade> </reference-many> </document> </doctrine-mongo-mapping> <?xml version="1.0" encoding="UTF-8"?> <doctrine-mongo-mapping xmlns="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping.xsd"> <document name="Documents\BlogPost"> <id /> <field field-name="title" type="string" /> <field field-name="body" type="string" /> <field field-name="createdAt" type="date" /> </document> </doctrine-mongo-mapping>
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

The $id property above is annotated with the #[Id] attribute, which makes it special. It will be use dby Doctrine to store the unique identifier of the document. If you do not provide a value for $id, Doctrine will automatically generate an ObjectId when you persist the document.

That’s it, we have our models, and we can save and retrieve them. Now all we need to do is to properly instantiate the DocumentManager instance. Read more about setting up the Doctrine MongoDB ODM in the Introduction to MongoDB Object Document Mapper:

1<?php use Doctrine\ODM\MongoDB\Configuration; use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Mapping\Driver\AttributeDriver; require_once __DIR__ . '/vendor/autoload.php'; $config = new Configuration(); $config->setProxyDir(__DIR__ . '/generated/proxies'); $config->setProxyNamespace('Proxies'); $config->setHydratorDir(__DIR__ . '/generated/hydrators'); $config->setHydratorNamespace('Hydrators'); $config->setMetadataDriverImpl(AttributeDriver::create(__DIR__ . '/src')); $dm = DocumentManager::create(config: $config); spl_autoload_register($config->getProxyManagerConfiguration()->getProxyAutoloader());
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Usage

Here is how you would use your models now:

1<?php // ... // create user $user = new User( name: 'Bulat S.', email: '[email protected]', ); // tell Doctrine to save $user on the next flush() $dm->persist($user); // create blog post $post = new BlogPost( title: 'My First Blog Post', body: 'MongoDB + Doctrine ODM = awesomeness!', ); // link the blog post to the user $user->posts->add($post); // store everything to MongoDB $dm->flush();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

Note that you do not need to explicitly call persist on the $post because the operation will cascade on to the reference automatically.

After running this code, you should have those two objects stored in the collections User and BlogPost. You can use MongoDB Compass to inspect the contents of your database, where you will see this documents:

// BlogPost collection
{
    _id: ObjectId("4bec5869fdc212081d000000"),
    title: "My First Blog Post",
    body: "MongoDB + Doctrine ODM = awesomeness!",
    createdAt: Date("2010-05-13T18:00:00Z")
}

// User collection
{
    _id: ObjectId("4bec5869fdc212081d010000"),
    name: "Bulat S.",
    email: "[email protected]",
    posts: [
        DBRef("BlogPost", "4bec5869fdc212081d000000")
    ],
}

You can retrieve the user later by its identifier:

1<?php // ... $userId = '....'; $user = $dm->find(User::class, $userId);
2
3
4
5
6

Or you can find the user by name even:

1<?php $user = $dm->getRepository(User::class)->findOneBy(['name' => 'Bulat S.']);
2
3

If you want to iterate over the posts the user references it is as easy as the following:

1<?php foreach ($user->posts as $post) { echo $post->title; }
2
3
4
5

When retrieved from the database, $user->posts is an instance of Doctrine\ODM\MongoDB\PersistentCollection. This class lazy-loads the referenced documents from the database when you access them. It keeps track of changes to the collection and will automatically update the database when you call flush().

You will notice that working with objects is nothing magical and you only have access to the properties and methods that you have defined yourself. You can continue reading Introduction to MongoDB Object Document Mapper.