ZendCon2010 Doctrine MongoDB ODM

86
Jonathan H. Wage OpenSky Doctrine MongoDB Object Document Mapper +

Transcript of ZendCon2010 Doctrine MongoDB ODM

Page 1: ZendCon2010 Doctrine MongoDB ODM

Jonathan H. Wage OpenSky

Doctrine MongoDBObject Document Mapper

+

Page 2: ZendCon2010 Doctrine MongoDB ODM

Who am I?Jonathan H. Wage

PHP Developer for over 10 yearsSymfony ContributorDoctrine ContributorPublished AuthorBusiness OwnerNashville, TN Resident

http://www.twitter.com/jwagehttp://www.facebook.com/jwage

Page 3: ZendCon2010 Doctrine MongoDB ODM

I work at

What is OpenSky?“a social commerce platform”

Based in New York and is a major opensource software advocate

http://www.shopopensky.com

Page 4: ZendCon2010 Doctrine MongoDB ODM

OpenSky TechnologiesPHP 5.3.2Apache2Symfony2Doctrine2jQuerymule, stomp, hornetqMongoDBnginxvarnish

Page 5: ZendCon2010 Doctrine MongoDB ODM

What is Doctrine?- Open Source PHP Project started in

2006

- Specializes in database functionality

Page 6: ZendCon2010 Doctrine MongoDB ODM

Doctrine Libraries- Database Abstraction Layer

- Database Migrations

- Object Relational Mapper

- MongoDB Object Document Manager

- CouchDB Object Document Manager

Page 7: ZendCon2010 Doctrine MongoDB ODM

Who is on the team?

• Roman S. Borschel

• Guilherme Blanco

• Benjamin Eberlei

• Bulat Shakirzyanov

• Jonathan H. Wage

Page 8: ZendCon2010 Doctrine MongoDB ODM

Project History- First commit April 13th 2006

- First stable version finished and Released September 1st 2008

- One of the first ORM implementations for PHP

- 1.0 is First LTS(long term support) release. Maintained until March 1st 2010

- Integrated with many popular frameworks: Symfony, Zend Framework, Code Igniter

Page 9: ZendCon2010 Doctrine MongoDB ODM

What is MongoDB?

http://en.wikipedia.org/wiki/MongoDB

“MongoDB (from "humongous") is an open source,scalable, high-performance, schema free, document-oriented database written in the C++ programming language.

The goal of MongoDB is to bridge the gap between key-value stores - which are fast and highly scalable - and traditional RDBMS systems - which provide rich queries and deep functionality. It is designed for problems that aren't easily solved by traditional RDBMSs, for example if databases span many servers.”

Page 10: ZendCon2010 Doctrine MongoDB ODM

Database Terminology

RDBMS MongoDBDatabase Database

Table Collection

Row Document

Page 11: ZendCon2010 Doctrine MongoDB ODM

Mapper Terminology

ORM ODMDatabase Database

Repository Repository

Entity Document

Page 12: ZendCon2010 Doctrine MongoDB ODM

Using MongoDB in PHPDownload and run MongoDB Server

http://www.mongodb.org/display/DOCS/Downloads

Install Mongo PECL extensionhttp://www.php.net/manual/en/mongo.installation.php

$ /path/to/mongodb/bin/mongod

$ pecl install mongo

Page 13: ZendCon2010 Doctrine MongoDB ODM

ConnectingCreate new connection instances withthe Mongo class:

$mongo = new Mongo('mongodb://localhost');

Page 14: ZendCon2010 Doctrine MongoDB ODM

Selecting DatabasesMongoDB intances can be selectedusing the selectDB() method:

$mongo = new Mongo('mongodb://localhost');$db = $mongo->selectDB('dbname');

Page 15: ZendCon2010 Doctrine MongoDB ODM

Selecting CollectionsMongoCollection instances can beselected using the selectCollection()method:$mongo = new Mongo('mongodb://localhost');$db = $mongo->selectDB('dbname');$coll = $db->selectCollection('users');

Page 16: ZendCon2010 Doctrine MongoDB ODM

Inserting DocumentsInsert a regular PHP array:

$user = array( 'username' => 'jwage', 'password' => md5('changeme') 'active' => true);$coll->insert($user);

echo $user['_id'];

Page 17: ZendCon2010 Doctrine MongoDB ODM

Finding a DocumentWe can easily find the document we justinserted using the findOne() method:

$user = $coll->findOne(array('username' => 'jwage'));

Page 18: ZendCon2010 Doctrine MongoDB ODM

Updating a DocumentYou can find a document, change it andsave the entire document:

$user = $coll->findOne(array('username' => 'jwage'));$user['username'] = 'jonwage';$user['password'] = md5('newpassword');$coll->save($user);

Page 19: ZendCon2010 Doctrine MongoDB ODM

Atomic UpdatesThe following is faster and safer:

$coll->update(array( 'username' => 'jwage'), array( '$set' => array( 'username' => 'jonwage', 'password' => md5('newpassword') )));

Page 20: ZendCon2010 Doctrine MongoDB ODM

Atomic Updates$inc - increments field by the number value$set - sets field to value$unset - deletes a given field$push - appends value to an array$pushAll - appends multiple values to an array$addToSet - appends multiple new values to an array$pop - removes the last element in an array$pull - removes all occurrences of a value from an array$pullAll - removes all occurrences of multiple values from an array

Page 21: ZendCon2010 Doctrine MongoDB ODM

Atomic ExamplesIncrement num_comments with $inc:

// $inc a blog posts number of comments by 1$db->posts->update($id, array('$inc' => array('num_comments' => 1)))

Page 22: ZendCon2010 Doctrine MongoDB ODM

Atomic ExamplesPush new comment on to end of array:

// $push a new comment on to a blog posts comments$db->posts->update($id, array('$push' => array( 'comments' => array('Hi how are you?'))));

Page 23: ZendCon2010 Doctrine MongoDB ODM

Atomic ExamplesSet an individual field value:

// $set a lock on a blog post$db->posts->update($id, array('$set' => array('locked' => 1)));

Page 24: ZendCon2010 Doctrine MongoDB ODM

Atomic ExamplesUnset a field from a document:

// $unset a lock on a blog post$db->posts->update($id, array('$unset' => array('locked' => 1)));

Page 25: ZendCon2010 Doctrine MongoDB ODM

Removing DocumentsYou can remove documents using theremove() method:

$coll->remove(array('username' => 'jwage'));

Page 26: ZendCon2010 Doctrine MongoDB ODM

+

Doctrine + MongoDB

=

Page 27: ZendCon2010 Doctrine MongoDB ODM

What is it?

- Layer on top of Mongo PECL extension

- Work with objects instead of arrays

- Create rich OO PHP domain and persist transparently using Doctrine

Page 28: ZendCon2010 Doctrine MongoDB ODM

What does it do?- Maps PHP classes to MongoDB

- Manages the state of objects

- Tracks changes and persists them

- Constructs regular PHP objects from MongoDB data

Page 29: ZendCon2010 Doctrine MongoDB ODM

How does it do it?- Implements UnitOfWork

http://martinfowler.com/eaaCatalog/unitOfWork.html

- Tracks changes to managed objects by maintaining a copy of its original data

- Computes changesets and persists them transparently

Page 30: ZendCon2010 Doctrine MongoDB ODM

Easier to build than ORM- Less work to convert objects to arrays

for persistence to MongoDB

- Less work to convert the data in the database to objects since it is already stored in a object-like structure instead of flat like in a RDBMS

Page 31: ZendCon2010 Doctrine MongoDB ODM

ArchitectureDocuments - Lightweight persistent domain object - Regular PHP class - Does not extend any base Doctrine class - Cannot be final or contain final methods - Any two documents in a hierarchy of classes must not

have a mapped property with the same name - Supports inheritance, polymorphic associations and

polymorphic queries. - Both abstract and concrete classes can be documents - Documents may extend non-document classes as well

as document classes, and non-document classes may extend document classes

Page 32: ZendCon2010 Doctrine MongoDB ODM

Architecture- No more base class required

- Values stored in object properties

- Doctrine is transparentnamespace Documents;

class User{ private $id; private $name;}

Page 33: ZendCon2010 Doctrine MongoDB ODM

ArchitectureThe DocumentManager

- Central access point to the ODM functionality provided by Doctrine. API is used to manage the persistence of your objects and to query for persistent objects.

- Employes transactional write behind strategy that delays the execution of queries in order to execute them in the most efficient way

- Internally a DocumentManager uses a UnitOfWork to keep track of your objects

Page 34: ZendCon2010 Doctrine MongoDB ODM

Managing DocumentsTo manage documents with Doctrineyou need a DocumentManager:

$config = new \Doctrine\ODM\MongoDB\Configuration();$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Documents"));$config->setMetadataDriverImpl($driverImpl);

$config->setProxyDir(__DIR__ . '/Proxies');$config->setProxyNamespace('Proxies');

$dm = \Doctrine\ODM\MongoDB\DocumentManager::create($mongo, $config);

Page 35: ZendCon2010 Doctrine MongoDB ODM

DocumentManagerThe DocumentManager is the centralplace for managing the state of PHPobjects. It has methods like:

persist($document)find()findOne()refresh($document)remove($document)detach($document)merge($document)flush()

Page 36: ZendCon2010 Doctrine MongoDB ODM

Document ClassesA Doctrine MongoDB Document is just a regular old PHP object:

class User{ private $id; private $username; private $password;

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

public function getUsername() { return $this->username; }

public function setUsername($username) { $this->username = $username; }

public function getPassword() { return $this->password; }

public function setPassword($password) { $this->password = md5($password); }}

Page 37: ZendCon2010 Doctrine MongoDB ODM

Mapping Information- Annotations

- YAML

- XML

- PHP

/** @Document */class User{ /** @Id */ private $id; /** @String */ private $username; /** @String */ private $password; // ...}

Page 38: ZendCon2010 Doctrine MongoDB ODM

Inserting Documents

$user = new User();$user->setUsername('jwage');$user->setPassword('changeme');

$dm->persist($user);$dm->flush(); // inserts document

$users->batchInsert(array( array( 'username' => 'jwage', 'password' => 'changeme' )));

Page 39: ZendCon2010 Doctrine MongoDB ODM

Finding Documents

$user = $dm->findOne('User', array('username' => 'jwage'));

Page 40: ZendCon2010 Doctrine MongoDB ODM

Updating Documents

Always uses atomic operators

$user = $dm->findOne('User', array('username' => 'jwage'));

$user->setUsername('jonwage');$user->setPassword('newpassword');

$dm->flush(); // updates document

$coll->update( array('_id' => 'theid'), array('$set' => array( 'username' => 'jonwage', 'password' => '5e9d11a14ad1c8dd77e98ef9b53fd1ba' ));

Page 41: ZendCon2010 Doctrine MongoDB ODM

Removing Documents

$user = $dm->findOne('User', array('username' => 'jwage'));

$dm->remove($user);$dm->flush(); // removes document

$coll->remove(array('_id' => 'theid'));

Page 42: ZendCon2010 Doctrine MongoDB ODM

Query BuilderNormally queries are just arrays thatlook like the following:

$user = $dm->findOne('User', array('username' => 'jwage'));

Page 43: ZendCon2010 Doctrine MongoDB ODM

Problems- Not OO

- Not re-usable

- Can become difficult to read as query gets more complex

Page 44: ZendCon2010 Doctrine MongoDB ODM

Query BuilderConstruct a new query instance andstart adding to it:

$q = $dm->createQuery('User') ->field('username')->equals('jwage');

Page 45: ZendCon2010 Doctrine MongoDB ODM

Query BuilderFind posts within a range of dates:

$q = $dm->createQuery('Post') ->field('createdAt')->range($startDate, $endDate);

Page 46: ZendCon2010 Doctrine MongoDB ODM

Query BuilderUpdating documents:

$q = $dm->createQuery('User') ->update() ->field('username')->set('jonwage') ->field('password')->set('newpassword') ->field('username')->equals('jwage');

Page 47: ZendCon2010 Doctrine MongoDB ODM

Query BuilderRemoving documents:

$q = $dm->createQuery('User') ->remove() ->field('username')->equals('jwage');

Page 48: ZendCon2010 Doctrine MongoDB ODM

Query BuilderExecuting queries:

// Execute and get the first result$user = $q->getSingleResult();

// Execute and return an array of results$users = $q->execute();

// Execute update or remove query$q->execute();

// Iterate over cursorforeach ($q->iterate() as $user) { }

Page 49: ZendCon2010 Doctrine MongoDB ODM

Embedded DocumentsInsert document with an embeddeddocument:

$user = array( 'username' => 'jwage', 'password' => 'changeme' 'addresses' => array( array( 'address1' => '6512 Mercomatic Ct.', // ... ) ));$db->users->insert($user);

Page 50: ZendCon2010 Doctrine MongoDB ODM

Embedded DocumentsPush a new address on to the end ofthe addresses array:

$db->users->update($user['_id'], array('$push' => array( 'addresses' => array( 'address1' => 'New address' )

Page 51: ZendCon2010 Doctrine MongoDB ODM

Embedded MappingMap an embedded document using@EmbedOne and @EmbedMany:

class User{ /** @Id */ public $id;

/** @String */ public $name;

/** @EmbedMany(targetDocument="Address") */ public $addresses = array();}

Page 52: ZendCon2010 Doctrine MongoDB ODM

/** @EmbeddedDocument */class Address{ /** @String */ public $address;

/** @String */ public $city;

/** @String */ public $state;

/** @String */ public $zipcode;

Embedded Mapping

Page 53: ZendCon2010 Doctrine MongoDB ODM

$user = new User();$user->name = 'Jonathan H. Wage';

$address = new Address();$address->address = '6512 Mercomatic Ct';$address->city = 'Nashville';$address->state = 'Tennessee';$address->zipcode = '37209';$user->addresses[] = $address;

$dm->persist($user);$dm->flush();

Persisting

Page 54: ZendCon2010 Doctrine MongoDB ODM

$users = array( array( 'name' => 'Jonathan H. Wage', 'addresses' => array( array( 'address' => '6512 Mercomatic Ct', 'city' => 'Nashville', 'state' => 'Tennesseee', 'zipcode' => '37209' ) ) ));$coll->batchInsert($users);

Page 55: ZendCon2010 Doctrine MongoDB ODM

Updating Embedded Documents

$user = $dm->findOne('User', array('name' => 'Jonathan H. Wage'));$user->addresses[0]->zipcode = '37205';

$coll->update( array('_id' => 'theuserid'), array('$set' => array('addresses.0.zipcode' => '37209')));

Page 56: ZendCon2010 Doctrine MongoDB ODM

Adding new Address$user = $dm->findOne('User', array('name' => 'Jonathan H. Wage'));$address = new Address();$address->address = '475 Buckhead Ave.';$address->city = 'Atlanta';$address->state = 'Georgia';$address->zipcode = '30305';$user->addresses[] = $address;$dm->flush();

$coll->update( array('_id' => 'theuserid'), array('$pushAll' => array( 'addresses' => array( array( 'address' => '475 Buckhead Ave.', 'city' => 'Atlanta', 'state' => 'Georgia', 'zipcode' => '30305' ) ) )));

Page 57: ZendCon2010 Doctrine MongoDB ODM

Unsetting Properties

unset($user->addresses[0]->zipcode);$dm->flush();

$coll->update( array('_id' => 'theuserid'), array( '$unset' => array( 'addresses.0.zipcode' => 1 ) ));

Page 58: ZendCon2010 Doctrine MongoDB ODM

ReferencesReference documents from withinanother document by storing anembedded document with the followingproperties:

$ref - referenced collection$id - value of _id for the object referenced$db - referenced database

Page 59: ZendCon2010 Doctrine MongoDB ODM

References- No JOIN syntax like in a relational DB

- References are resolved in app code

- Store one or many references

Page 60: ZendCon2010 Doctrine MongoDB ODM

Reference Mapping

/** @Document */class Organization{ /** @Id */ private $id;

/** @String */ private $name;

/** @ReferenceMany(targetDocument="User") */ private $users = array();

public function setName($name) { $this->name = $name; }

public function addUser(User $user) { $this->users[] = $user; }}

Page 61: ZendCon2010 Doctrine MongoDB ODM

Reference Mapping

/** @Document */class User{ /** @Id */ private $id;

/** @String */ private $name;

/** @ReferenceOne(targetDocument="Organization") */ private $organization;

public function setName($name) { $this->name = $name; }

public function setOrganization(Organization $organization) { $this->organization = $organization; $organization->addUser($this); }}

Page 62: ZendCon2010 Doctrine MongoDB ODM

Persisting

$organization = new Organization();$organization->setName('Sensio Labs');

$user = new User();$user->setName('Jonathan H. Wage');$user->setOrganization($organization);

$dm->persist($organization);$dm->persist($user);$dm->flush();

Page 63: ZendCon2010 Doctrine MongoDB ODM

Inserted OrganizationResulting organization has a reference to the user:

Array( [_id] => 4c86acd78ead0e8759000000 [name] => Sensio Labs [users] => Array ( [0] => Array ( [$ref] => User [$id] => 4c86acd78ead0e8759010000 [$db] => doctrine_odm_sandbox )

)

)

Page 64: ZendCon2010 Doctrine MongoDB ODM

Inserted UserResulting user has a reference to the organization:

Array( [_id] => 4c86acd78ead0e8759010000 [name] => Jonathan H. Wage [organization] => Array ( [$ref] => Organization [$id] => 4c86acd78ead0e8759000000 [$db] => doctrine_odm_sandbox )

)

Page 65: ZendCon2010 Doctrine MongoDB ODM

Working with ReferencesA single reference is represented by aproxy object:

$user = $dm->find('User', array('name' => 'Jonathan H. Wage'));

// instance of uninitialized OrganizationProxy$organization = $user->getOrganization();

// calling getter or setter for uninitialized proxy// queries the database and initialized the proxy document

// query invoked, organization data loaded and doc initializedecho $organization->getName();

Page 66: ZendCon2010 Doctrine MongoDB ODM

Working with ReferencesWhat does a proxy look like?

class OrganizationProxy extends Organization{ private function initialize() { // ... }

public function getName() { $this->initialize(); return parent::getName(); }}

Page 67: ZendCon2010 Doctrine MongoDB ODM

Working with ReferencesA many reference is represented by anuninitialized PersistentCollection:

$organization = $dm->find('Organization', array('name' => 'Sensio Labs'));$users = $organization->getUsers(); // uninitialized collection

// Queries database for users and initializes collectionforeach ($users as $user){ // ...}

Page 68: ZendCon2010 Doctrine MongoDB ODM

Document Query LanguageSQLike grammar for querying DoctrineMongoDB ODM for document objects.

find all FROM BlogPost

Page 69: ZendCon2010 Doctrine MongoDB ODM

QueryLanguage ::= FindQuery | InsertQuery | UpdateQuery | RemoveQuery

FindQuery ::= FindClause [WhereClause] [MapClause] [ReduceClause] [SortClause] [LimitClause] [SkipClause]FindClause ::= "FIND" all | SelectField {"," SelectField}SelectField ::= DocumentFieldNameSortClause ::= SortClauseField {"," SortClauseField}SortClauseField ::= DocumentFieldName "ASC | DESC"LimitClause ::= "LIMIT" LimitIntegerSkipClause ::= "SKIP" SkipIntegerMapClause ::= "MAP" MapFunctionReduceClause ::= "REDUCE" ReduceFunction

DocumentFieldName ::= DocumentFieldName | EmbeddedDocument "." {"." DocumentFieldName}WhereClause ::= "WHERE" WhereClausePart {"AND" WhereClausePart}WhereClausePart ::= ["all", "not"] DocumentFieldName WhereClauseExpression ValueWhereClauseExpression ::= "=" | "!=" | ">=" | "<=" | ">" | "<" | "in" "notIn" | "all" | "size" | "exists" | "type"Value ::= LiteralValue | JsonObject | JsonArray

UpdateQuery ::= UpdateClause [WhereClause]UpdateClause ::= [SetExpression], [UnsetExpression], [IncrementExpression], [PushExpression], [PushAllExpression], [PullExpression], [PullAllExpression], [AddToSetExpression], [AddManyToSetExpression], [PopFirstExpression], [PopLastExpression]SetExpression ::= "SET" DocumentFieldName "=" Value {"," SetExpression}UnsetExpression ::= "UNSET" DocumentFieldName {"," UnsetExpression}IncrementExpression ::= "INC" DocumentFieldName "=" IncrementInteger {"," IncrementExpression}PushExpression ::= "PUSH" DocumentFieldName Value {"," PushExpression}PushAllExpression ::= "PUSHALL" DocumentFieldName Value {"," PushAllExpression}PullExpression ::= "PULL" DocumentFieldName Value {"," PullExpression}PullAllExpression ::= "PULLALL" DocumentFieldName Value {"," PullAllExpression}AddToSetExpression ::= "ADDTOSET" DocumentFieldName Value {"," AddToSetExpression}AddManyToSetExpression ::= "ADDMANYTOSET" DocumentFieldName Value {"," AddManyToSetExpression}PopFirstExpression ::= "POPFIRST" DocumentFieldName {"," PopFirstExpression}PopLastExpression ::= "POPLAST" DocumentFieldName {"," PopLastExpression}

InsertQuery ::= InsertClause InsertSetClause {"," InsertSetClause}InsertSetClause ::= DocumentFieldName "=" Value

RemoveQuery ::= RemoveClause [WhereClause]RemoveClause ::= "REMOVE" DocumentClassName

BNF

Page 70: ZendCon2010 Doctrine MongoDB ODM

Creating QueriesFrom the DocumentManager you canexecute DQL queries using the query()method:

$users = $dm->query('find all FROM User');

$users = $db->user->find();

Page 71: ZendCon2010 Doctrine MongoDB ODM

Selecting Fields

$users = $dm->query('find username FROM User');

$users = $db->user->find(null, array('username'));

Page 72: ZendCon2010 Doctrine MongoDB ODM

Paging Results

$users = $dm->query('find all FROM User limit 30 skip 30');

$users = $db->user->find();$users->limit(30);$users->skip(30);

Page 73: ZendCon2010 Doctrine MongoDB ODM

Selecting Embedded Slice

$post = $dm->query('find title, comments limit 20 skip 10 FROM BlogPost WHERE id = ?', array($id));

$users = $db->user->find( array('_id' => $id), array('title', 'comments' => array( '$slice' => array(20, 10) )));

Page 74: ZendCon2010 Doctrine MongoDB ODM

More Examples

// Find all posts greater than or equal to a date$posts = $dm->query('find all FROM BlogPost WHERE createdAt >= ?', array($date));

// Find all posts sorted by created at desc$posts = $dm->query('find all FROM BlogPost sort createdAt desc');

// Update user$dm->query('update Documents\User set password = ? where username = ?', array('newpassword', 'jwage'));

Page 75: ZendCon2010 Doctrine MongoDB ODM

EventsDoctrine triggers events throughout thelifecycle of objects it manages:

- preRemove- postRemove- prePersist- postPersist- preUpdate- postUpdate- preLoad- postLoad

Page 76: ZendCon2010 Doctrine MongoDB ODM

Maintaining Timestamps/** * @Document * @HasLifecycleCallbacks */class BlogPost{ /** @Id */ public $id; /** @Date */ public $createdAt; /** @Date */ public $updatedAt;

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

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

Page 77: ZendCon2010 Doctrine MongoDB ODM

Migrating ChangesSometimes your documents change and you will need to migrate your data.

Page 78: ZendCon2010 Doctrine MongoDB ODM

Sample ScenarioOur original document looks like this:

/** * @Document */class User{ /** @Id */ public $id; /** @String */ public $name;}

Page 79: ZendCon2010 Doctrine MongoDB ODM

Renaming FieldsLater we want to store first and lastnames in separate fields:

/** * @Document */class User{ /** @Id */ public $id; /** @String */ public $firstName; /** @String */ public $lastName;}

Page 80: ZendCon2010 Doctrine MongoDB ODM

Renaming FieldsHandle documents with only a name:

/** * @Document * @HasLifecycleCallbacks */class User{ /** @Id */ public $id; /** @String */ public $firstName; /** @String */ public $lastName;

/** @PreLoad */ public function preLoad(array &$data) { if (isset($data['name'])) { $e = explode(' ', $data['name']); unset($data['name']); $data['firstName'] = $e[0]; $data['lastName'] = $e[1]; } }}

Page 81: ZendCon2010 Doctrine MongoDB ODM

Why use an object mapper?

Page 82: ZendCon2010 Doctrine MongoDB ODM

Encapsulate your domain in an object oriented interface

Encapsulation

Page 83: ZendCon2010 Doctrine MongoDB ODM

The organization of your domain logic in an OO way improved maintainability

Maintainability

Page 84: ZendCon2010 Doctrine MongoDB ODM

Keeping a clean OO domain model makes your business logic easily testable for improved stability

Testability

Page 85: ZendCon2010 Doctrine MongoDB ODM

Write portable and thin application controller code and fat models.

Portability

Page 86: ZendCon2010 Doctrine MongoDB ODM

Questions?

- http://www.twitter.com/jwage- http://www.facebook.com/jwage- http://www.jwage.com

OpenSky is hiring! Inquire via e-mail at [email protected] or in person after this presentation!