doctrine mongodb object document mapper

Post on 12-Jan-2015

28.830 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Introduction to the PHP Doctrine MongoDB Object Document Mapper

TRANSCRIPT

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

DoctrineMongoDB Object Document Mapper (ODM)

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

What is Doctrine?

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

• Open source PHP project started in 2006

• Relational database abstraction layer.• mysql, oracle, pgsql, sqlite, etc.

• Object persistence layers for RDBMS, MongoDB, etc.

• Other database related functionalities.

What is Doctrine?

http://www.doctrine-project.org

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

What is MongoDB?

• Key-Value document based storage system.

• Bridge between traditional relational databases and key-value data stores.

http://www.mongodb.org

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Terminology

RDBMS MongoDBDatabase Database

Table Collection

Row Document

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Using MongoDB in PHP

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Connecting

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

Selecting Databases

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Selecting Collections

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Inserting Documents

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

echo $user['_id'];

Insert a new user document and echo the newly generated id

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Updating Documents

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

Update username and password and save the whole document

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Atomic Updates

• Faster than saving the entire document.

• Safer than updating the entire document.

• Updates are done in place and are atomic.

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Atomic Updates

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

Update username and password where username is jwage

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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 values to an array that don’t already exist in the

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

Many other atomic operators exist for manipulating a documents data

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Removing Documents

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Doctrine + MongoDB

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

DocumentManager

• Abstraction on top of the PHP Mongo class

• Manages the persistent state of PHP objects

• Implements UnitOfWork for change tracking

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

• A NEW document instance has no persistent identity, and is not yet associated with a DocumentManager (i.e. those just created with the "new" operator).

• A MANAGED document instance is an instance with a persistent identity that is associated with an DocumentManager and whose persistence is thus managed.

• A DETACHED document instance is an instance with a persistent identity that is not (or no longer) associated with an DocumentManager.

• A REMOVED document instance is an instance with a persistent identity, associated with an DocumentManager, that will be removed from the database upon transaction commit.

Document States

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

$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\ORM\DocumentManager::create($mongo, $config);

DocumentManagerCreate your DocumentManager instance for managing object persistence

Wraps around existing $mongo connection

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Defining Document

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); }}

A document is just a regular ole’ PHP class

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Mapping the Document

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Ready to GoDoctrine now knows about this document and is able

to manage its persistent state

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Inserting, Updating and Deleting Documents

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

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

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Updating Documents$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' ));

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Removing Documents

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

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

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Query APIFluent OO Query API

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Querying MongoDB Directly

// Get user array directly from mongo$user = $mongo->db->users->findOne(array('username' => 'jwage'));

Returns an array of information and not a User object

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

// Get user class instance through Doctrine$user = $dm->findOne('User', array('username' => 'jwage'));

Querying Through Doctrine

Going through Doctrine gives you managed objects back instead of arrays

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

// Get user class instance through Doctrine Query API$user = $dm->createQuery('User') ->field('username')->equals('jwage') ->getSingleResult();

Querying Through Doctrine Query API

Query for same user using the Query API

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

// Find posts within a range of dates$posts = $dm->createQuery('Post') ->field('createdAt')->range($startDate, $endDate) ->execute();

Querying Through Doctrine Query API

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Updating Documents

// Update a document$dm->createQuery('User') ->update() ->field('username')->set('jonwage') ->field('password')->set('newpassword') ->field('username')->equals('jwage') ->execute();

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

// Remove a document$dm->createQuery('User') ->remove() ->field('username')->equals('jwage') ->execute();

// Remove a document$dm->createQuery('User') ->remove() ->field('username')->equals('jwage') ->execute();

Removing Documents

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Embedded Documents

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

/** @String */ public $name;

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

/** @String */ public $city;

/** @String */ public $state;

/** @String */ public $zipcode;}

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

$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();

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Updating Embedded Documents

Uses dot notation and atomic operators for updating

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Add New Address

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

$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' ) ) )));

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

ReferencesMongoDB does not have joins or foreign keys but you

can still store references to other documents and resolve the references in your application code.

Doctrine abstracts the handling of referneces for you so working with them is seamless.

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

/** @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; }}

Organization

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

/** @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); }}

User

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

$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();

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

The Result

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

)

)

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

)

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Working with References

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

$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();

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Change Tracking

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

UnitOfWork• Tracks changes in objects between flushes

• Maintains copy of old values to compare new values to

• Changesets computed and persisted in the most efficient way using atomic operators $inc, $set, $unset, $pullAll, $pushAll, etc.

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Other Features

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Document Query Language

Language for querying documents in a similar way to SQL

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

BNF Grammar

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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]

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Creating Query

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Selecting Fields

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Paging Results

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Selecting Slice of Embedded Documents

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

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Other 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'));

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Lifecycle Events

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/reference/events/en#lifecycle-callbacks

“A lifecycle event is a regular event with the additional feature of providing a mechanism to register direct

callbacks inside the corresponding document classes that are executed when the lifecycle event occurs.”

• preRemove - The preRemove event occurs for a given document before the respective DocumentManager remove operation for that document is executed.

• postRemove - The postRemove event occurs for an document after the document has been removed. It will be invoked after the database delete operations.

• prePersist - The prePersist event occurs for a given document before the respective DocumentManager persist operation for that document is executed.

• postPersist - The postPersist event occurs for an document after the document has been made persistent. It will be invoked after the database insert operations. Generated primary key values are available in the postPersist event.

• preUpdate - The preUpdate event occurs before the database update operations to document data.

• postUpdate - The postUpdate event occurs after the database update operations to document data.

• postLoad - The postLoad event occurs for an document after the document has been loaded into the current DocumentManager from the database or after the refresh operation has been applied to it.

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Event Examples

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

/** * @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(); }}

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

Migrating Data

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

Initial Document

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

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

New Document

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

/** * @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]; } }

Migrate Documents With Old Field Name

Doctrine MongoDB ODM www.doctrine-project.org www.sensiolabs.org

You can contact Jonathan about Doctrine and Open-Source or for training, consulting, application development, or business related

questions at jonathan.wage@sensio.com

Jonathan H. Wage

• http://www.twitter.com/jwage

• http://www.jwage.com

• http://www.facebook.com/jwage

Questions?

top related