Inheritance and Mapped Super Classes in Doctrine

Single Collection Inheritance in the Doctrine MongoDB ODM allows you to map multiple classes in an inheritance hierarchy to a single collection in MongoDB. An example might be in a CMS where you have several different content types like the base Node, Page and BlogPost which all extends an abstract ContentType class.

First define the ContentType class that is a @MappedSuperclass:

<?php

/**
 * @MappedSuperclass
 * @HasLifecycleCallbacks
 */
abstract class ContentType
{
    /** @Id */
    protected $id;

    /** @Date */
    protected $createdAt;

    /** @Date */
    protected $updatedAt;

    public function getId()
    {
        return $this->id;
    }

    /** @PreUpdate */
    public function preUpdate()
    {
        $this->updatedAt = new DateTime();
    }

    /** @PrePersist */
    public function prePersist()
    {
        $this->createdAt = new DateTime();
        $this->updatedAt = new DateTime();
    }
}

Now we can define our base Node content type:

<?php

/**
 * @Document(collection="pages")
 * @InheritanceType("SINGLE_COLLECTION")
 * @DiscriminatorField(fieldName="type")
 * @DiscriminatorMap({
 *   "node"="Node",
 *   "page"="Page",
 *   "blog_post"="BlogPost"
 * })
 */
class Node extends ContentType
{
    /** @String */
    protected $title;

    public function getTitle()
    {
        return $this->title;
    }

    public function setTitle($title)
    {
        $this->title = $title;
    }
}

This gives us our base content type node functionality that we can extend to create the Page document which adds a body field for the page:

<?php

/** @Document */
class Page extends Node
{
    /** @String */
    protected $body;

    public function getBody()
    {
        return $this->body;
    }

    public function setBody($body)
    {
        $this->body = $body;
    }
}

And the BlogPost document is a custom type of page that adds some additional fields related to blog posts like an excerpt and tags:

<?php

/** @Document */
class BlogPost extends Page
{
    /** @Collection */
    private $tags = array();

    /** @String */
    private $excerpt;

    public function getExcerpt()
    {
        return $this->excerpt;
    }

    public function setExcerpt($excerpt)
    {
        $this->excerpt = $excerpt;
    }

    public function addTag($tag)
    {
        $this->tags[] = $tag;
    }

    public function removeTag($tag)
    {
        $key = array_search($tag, $this->tags);
        if ($key !== false) {
            unset($this->tags[$key]);
        }
    }

    public function getTags()
    {
        return $this->tags;
    }
}

You can easily add new content types by mapping a document class that extends the base Node. All your documents will be stored in a single collection and a discriminator field will be used to discriminate which class created each document.

Now we can use our document classes and create new instances and persist them. Here is an example where we create a new blog post:

<?php

$post = new BlogPost();
$post->setTitle('Test');
$post->setExcerpt('Testing');
$post->setBody('w00t');
$post->addTag('test');
$dm->persist($post);
$dm->flush();

The above would result in a document like the following in MongoDB:

Array
(
    [_id] => 4c4f38978ead0ef23f000000
    [createdAt] => MongoDate Object
        (
            [sec] => 1280260247
            [usec] => 0
        )

    [updatedAt] => MongoDate Object
        (
            [sec] => 1280260247
            [usec] => 0
        )

    [title] => Test
    [body] => w00t
    [tags] => Array
        (
            [0] => test
        )

    [excerpt] => Testing
    [type] => blog_post
)

Posted in: Doctrine, MongoDB, PHP

Tags: , , ,



1 Comment

rssComments RSS transmitTrackBack Identifier URI


[...] This post was mentioned on Twitter by Jonathan H. Wage and Ferenc Kovacs, Bulat Shakirzyanov. Bulat Shakirzyanov said: RT @jwage: New blog post: Inheritance and Mapped Super Classes in Doctrine http://bit.ly/ajjXpQ // Link in last tweet was wrong [...]

Pingback by Tweets that mention Jonathan H. Wage » Archive » Inheritance and Mapped Super Classes in Doctrine -- Topsy.com on July 28, 2010 7:38 pm

addLeave a comment