Post on 06-May-2015
description
Pablo Godel @pgodel - MidwestPHP 2013March 2nd 2013 - St. Paul, MN
https://joind.in/8211
Sunday, March 3, 13
Who Am I?
⁃ Born in Argentina, living in the US since 1999⁃ PHP & Symfony developer
⁃ Founder of the original PHP mailing list in spanish ⁃ Master of the parrilla
Sunday, March 3, 13
Sunday, March 3, 13
Sunday, March 3, 13
⁃ Founded ServerGrove Networks in 2005
⁃ Provider of web hosting specialized in PHP, Symfony, ZendFramework, and others
⁃ Mongohosting.com!
⁃ Servers in Miami, FL and Dublin, Ireland
ServerGrove!
Sunday, March 3, 13
⁃ Very active open source supporter through codecontributions and usergroups/conference sponsoring
Community is our teacher
Sunday, March 3, 13
Agenda
- Introduction to MongoDB- PHP and MongoDB- PHP Libraries- Introduction to Symfony2- Symfony2 and MongoDB
Sunday, March 3, 13
What is MongoDB?
Who is 10Gen?
Sunday, March 3, 13
MongoMongo as in "humongous". Used to describe something extremely large or important.
Sunday, March 3, 13
MongoDB is a scalable, high-performance, open source NoSQL database.
- Document Oriented DB- Written in C++
- Available for *nux (Linux, Solaris, etc), Windows and OS X
- Lots of Drivers (PHP, Java, Python, Ruby...)
Sunday, March 3, 13
- Flexible JSON-style documents- Full Indexing- Complex Queries / Map Reduce- Aggregation Framework- GridFS (store files natively)- Multiple Replication Options- Sharding- Simple Installation / Zero Config
Features
Sunday, March 3, 13
Document Oriented
Database => DatabaseTable => CollectionRow => Document
Coming from SQL?
Sunday, March 3, 13
JSON-style documents
{ name: { first: 'John', last: 'Doe' }, title: 'Engineer', age: 40}
Sunday, March 3, 13
No Schema or fixed tables
{ name: { first: 'Foo', last: 'Bar' }, title: 'Student', school: 'Harvard'}
Sunday, March 3, 13
Embedded documents{ "_id" : ObjectId("4ccba15ef597e9352e060000") "srcFilename" : "/etc/apache2/sites-enabled/example1.com", "vhostDirective" : { "directives" : [ { "name" : "CustomLog", "value" : "logs/example1.com-access_log combined" }, { "name" : "DocumentRoot", "value" : "/var/www/vhosts/example1.com/httpdocs" }, { "name" : "ServerName", "value" : "example1.com" } ] } }
Sunday, March 3, 13
Document Referencing{ "_id" : ObjectId("4cc4a5c3f597e9db6e010109"), "billingId" : NumberLong(650), "created" : ISODate("2010-10-24T21:31:47Z"), "servers" : [ { "$ref" : "server", "$id" : ObjectId("4cc4a5c4f597e9db6e050201") }], "users" : [ { "$ref" : "user", "$id" : ObjectId("4cc4a5c4f597e9db6e980201") }, { "$ref" : "user", "$id" : ObjectId("4cc4a5c4f597e9db6e9c0201") }] }
Sunday, March 3, 13
Full Indexing
db.coll.ensureIndex({name.last: 1})
db.coll.ensureIndex({name.first: 1, name.last: 1})
db.coll.ensureIndex({age: 0})
Sunday, March 3, 13
Querying
db.coll.find({name: 'John'})
db.coll.find({keywords: 'storage'})
db.coll.find({keywords: {$in: ['storage', 'DBMS']}}
Sunday, March 3, 13
GridFS
- Files are divided in chunks and stored over multiple documents
- Transparent API
$grid->storeFile("/path/to/somefile.txt", array("metadata" => array("date" => new MongoDate())));
Sunday, March 3, 13
Replication
Source: http://www.mongodb.org/display/DOCS/Replication
Sunday, March 3, 13
Shards
Source: http://www.mongodb.org/display/DOCS/Introduction
Sunday, March 3, 13
Simple Installation/Zero Config
wget http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.2.3.tgz
tar zxvf mongodb-osx-x86_64-2.2.3.tgz
cd mongodb-osx-x86_64-2.2.3
./mongod
OS X
Sunday, March 3, 13
/etc/yum.repos.d/10gen.repo
CentOS Linux
[10gen]name=10gen Repositorybaseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64gpgcheck=0
$ yum install -y mongo-10gen-server$ service mongod start
Simple Installation/Zero Config
Sunday, March 3, 13
Why is MongoDB good for Rapid Development of Web Apps?
Sunday, March 3, 13
Schema-less / Document Oriented
FLEXIBILITY
Rapid Development
by exfordy
Sunday, March 3, 13
EASIER MIGRATIONS
by exfordy
Rapid Development
Schema-less / Document Oriented
Sunday, March 3, 13
NO JOINS!
Rapid Development
Sunday, March 3, 13
SPEED
by xavi talleda
Performance
Sunday, March 3, 13
SCALABILITY
by Jimee, Jackie, Tom & Asha
Performance
Sunday, March 3, 13
No TransactionsNo Rollbacks
Unsafe defaultsMap Reduce locks
A Word of Caution
by Ernst Vikne
Sunday, March 3, 13
Great Use Cases
- Content Management
- Product Catalogs
- Realtime Analytics
- Logs Storage
Sunday, March 3, 13
and
Sunday, March 3, 13
PECL driver
pecl install mongoecho “extension=mongo.so >> /path/php.ini”
Linux
OS X
Windowshttps://github.com/mongodb/mongo-php-driver/downloads
http://php-osx.liip.ch/
Sunday, March 3, 13
Attention
$m = new Mongo();
Mongo 1.2.x
$m = new MongoClient();
Mongo 1.3.x
Sunday, March 3, 13
<?php
// connect$m = new MongoClient();
// select a database$db = $m->comedy;
// select a collection (analogous to a relational database's table)$collection = $db->cartoons;
// add a record$obj = array( "title" => "Calvin and Hobbes", "author" => "Bill Watterson" );$collection->insert($obj);
// add another record, with a different "shape"$obj = array( "title" => "XKCD", "online" => true );$collection->insert($obj);
// find everything in the collection$cursor = $collection->find();
// iterate through the resultsforeach ($cursor as $obj) { echo $obj["title"] . "\n";}
?>
Usage
Sunday, March 3, 13
<?php
// save a file$id = $grid->storeFile("game.tgz");$game = $grid->findOne();
// add a downloads counter$game->file['downloads'] = 0;$grid->save($game->file);
// increment the counter$grid->update(array("_id" => $id), array('$inc' => array("downloads" => 1)));
?>
Storing Files
Sunday, March 3, 13
SQL to Mongo Mapping Chart
This is a PHP-specific version of the » SQL to Mongo mapping chart in the main docs.
SQL StatementMongo Query Language Statement
CREATE TABLE USERS (a Number, b Number)Implicit or use MongoDB::createCollection().INSERT INTO USERS VALUES(1,1)$db->users->insert(array("a" => 1, "b" => 1));SELECT a,b FROM users$db->users->find(array(), array("a" => 1, "b" => 1));SELECT * FROM users WHERE age=33$db->users->find(array("age" => 33));SELECT a,b FROM users WHERE age=33$db->users->find(array("age" => 33), array("a" => 1, "b" => 1));SELECT a,b FROM users WHERE age=33 ORDER BY name$db->users->find(array("age" => 33), array("a" => 1, "b" => 1))->sort(array("name" => 1));SELECT * FROM users WHERE age>33$db->users->find(array("age" => array('$gt' => 33)));SELECT * FROM users WHERE age<33$db->users->find(array("age" => array('$lt' => 33)));SELECT * FROM users WHERE name LIKE "%Joe%"$db->users->find(array("name" => new MongoRegex("/Joe/")));SELECT * FROM users WHERE name LIKE "Joe%"$db->users->find(array("name" => new MongoRegex("/^Joe/")));SELECT * FROM users WHERE age>33 AND age<=40$db->users->find(array("age" => array('$gt' => 33, '$lte' => 40)));SELECT * FROM users ORDER BY name DESC
http://php.net/manual/en/mongo.sqltomongo.php
SQL to Mongo Queries
Sunday, March 3, 13
Admin Interfaces
- Genghis
- RockMongo
- php-mongodb-admin
http://genghisapp.com/
http://code.google.com/p/rock-php/wiki/rock_mongo
https://github.com/jwage/php-mongodb-admin
Sunday, March 3, 13
- Doctrine ODM
- Mandango
- many more...
PHP Libraries
Doctrine MongoDB Object Document Mapper is built for PHP 5.3.2+ and provides transparent persistence for PHP objects.
Mandango is a simple, poweful and ultrafast Object Document Mapper (ODM) for PHP and MongoDB.
Sunday, March 3, 13
Doctrine MongoDB ODM
http://doctrine-project.org
Doctrine MongoDB Object Document Mapper is built for PHP 5.3.2+ and provides transparent
persistence for PHP objects.
Sunday, March 3, 13
/** @Document */class User{ /** @Id */ private $id;
/** @String */ private $name;
/** @String */ private $email;
/** @ReferenceMany(targetDocument="BlogPost", cascade="all") */ private $posts;
// ...}
Doctrine MongoDB ODM
Sunday, March 3, 13
/** @Document */class BlogPost{ /** @Id */ private $id;
/** @String */ private $title;
/** @String */ private $body;
/** @Date */ private $createdAt;
// ...}
Doctrine MongoDB ODM
Sunday, March 3, 13
<?php
// create user$user = new User();$user->setName('Bulat S.');$user->setEmail('email@example.com');
// tell Doctrine 2 to save $user on the next flush()$dm->persist($user);
// create blog post$post = new BlogPost();$post->setTitle('My First Blog Post');$post->setBody('MongoDB + Doctrine 2 ODM = awesomeness!');$post->setCreatedAt(new DateTime());
$user->addPost($post);
// store everything to MongoDB$dm->flush();
Doctrine MongoDB ODM
Sunday, March 3, 13
Array( [_id] => 4bec5869fdc212081d000000 [title] => My First Blog Post [body] => MongoDB + Doctrine 2 ODM = awesomeness! [createdAt] => MongoDate Object ( [sec] => 1273723200 [usec] => 0 ))
Doctrine MongoDB ODM
Sunday, March 3, 13
Array( [_id] => 4bec5869fdc212081d010000 [name] => Bulat S. [email] => email@example.com [posts] => Array ( [0] => Array ( [$ref] => blog_posts [$id] => 4bec5869fdc212081d000000 [$db] => test_database ) ))
Doctrine MongoDB ODM
Sunday, March 3, 13
$user = $dm->find('User', $userId);
$user = $dm->getRepository('User')->findOneByName('Bulat S.');
$posts = $user->getPosts();foreach ($posts as $post) { echo $post;}
Doctrine MongoDB ODMRetrieving Persisted Objects
Sunday, March 3, 13
// src/YourNamespace/YourBundle/ServerRepository.phpnamespace YourNamespace\YourBundle;
use Doctrine\ODM\MongoDB\DocumentRepository;
class ServerRepository extends DocumentRepository{ public function getActiveServers() { return $this->createQueryBuilder() ->field('isActive')->equals(true) ->sort('name', 'asc')->getQuery()->execute(); }
Document Repositories
$rep = $dm->getRepository(‘@YourBundle/Server’);$servers = $rep->getActiveServers();
Usage
Doctrine MongoDB ODM
Sunday, March 3, 13
/** @Document */class Image{ /** @Id */ private $id;
/** @Field */ private $name;
/** @File */ private $file;
Doctrine MongoDB ODM
Sunday, March 3, 13
// store file$image = new Image();$image->setName('Test image');$image->setFile('/path/to/image.png');
$dm->persist($image);$dm->flush();
// retrieve and return file to client$image = $dm->createQueryBuilder('Documents\Image') ->field('name')->equals('Test image') ->getQuery() ->getSingleResult();
header('Content-type: image/png;');echo $image->getFile()->getBytes();
Doctrine MongoDB ODM
Sunday, March 3, 13
// Eager ID creation
public function __construct(){ $this->id = (string) new \MongoId();}
Tips: Doctrine MongoDB ODM
Sunday, March 3, 13
// Creation date
public function __construct(){ $this->id = (string) new \MongoId(); $this->createdDt = new \DateTime();}
Tips: Doctrine MongoDB ODM
Sunday, March 3, 13
// ArrayCollections
public function __construct(){ $this->id = (string) new \MongoId(); $this->createdDt = new \DateTime(); $this->entries = new ArrayCollection();}
Tips: Doctrine MongoDB ODM
Sunday, March 3, 13
// Space Saving
/** @String(name=”n”) */ private $name;
/** @String(name=”e”) */ private $email;
Tips: Doctrine MongoDB ODM
Sunday, March 3, 13
Symfony is a PHP Web Development Framework.
Sunday, March 3, 13
“First, Symfony2 is a reusable set of standalone, decoupled, and cohesive PHP components that solve common web
development problems.Then, based on these components, Symfony2 is also a
full-stack web framework.”
http://fabien.potencier.org/article/49/what-is-symfony2
Sunday, March 3, 13
25 High Quality Components
Sunday, March 3, 13
• DependencyInjection• EventDispatcher• HttpFoundation• DomCrawler• ClassLoader• CssSelector• HttpKernel• BrowserKit• Templating• Translation• Serializer
All of them at GitHub: http://github.com/symfony
• Serializer• Validator • Security • Routing • Console • Process • Config • Finder • Locale • Yaml• Form• More...
Symfony 2 Components
Sunday, March 3, 13
http://symfony.com/doc/current/components/index.html
http://fabien.potencier.org/
Components Documentation
Blog post series about creating a framework based on the Symfony2 Components
Symfony 2 Components
Sunday, March 3, 13
• Rewritten from scratch for PHP 5.3• Based on the HTTP specification• Very stable and solid API • Extensible through the creation of Bundles (replacement for
sf1 plugins)• Flexible configuration using YAML, XML, annotations or
PHP • All configuration is compiled to PHP code and cached• Lots of unit tests• Source code audited by independent security firm thanks to
donations of the Symfony Community
Symfony 2 Highlights
Sunday, March 3, 13
• Extensible Configuration with Service Container/Dependency Injection
• Complete redesign of Forms support• Validations• Extensible Security with Authentication/Authorization • Advanced and powerful templating through Twig• Routes configured with YAML, XML or Annotations• ESI Caching support out of the box• Assets management with Assetic• Translations• Environments
HighlightsSymfony 2
Sunday, March 3, 13
• 698 developers contributed to Symfony2• 7000+ pull requests• 969 1901 bundles at knpbundles.com• Very active IRC and mailing lists support channels
• Community Gamification through SensioLabs Connect
• Symfony2 Ecosystem
Highlights: CommunitySymfony 2
Sunday, March 3, 13
Highlights: BundlesSymfony 2
Sunday, March 3, 13
http://symfony.com/download
Getting StartedSymfony 2
Sunday, March 3, 13
or
tar zxf Symfony_Standard_Vendors_2.2.0.tgz
unzip Symfony_Standard_Vendors_2.2.0.zip
Getting StartedSymfony 2
Sunday, March 3, 13
$ curl -s https://getcomposer.org/installer | php
$ php composer.phar create-project \symfony/framework-standard-edition path/ 2.2.0
http://getcomposer.org/
Getting Started with ComposerSymfony 2
Sunday, March 3, 13
Distributions
http://symfony.com/distributions
A Symfony distribution is made up of Symfony2 components, a selection of bundles,
a directory structure, a default configuration.
Getting StartedSymfony 2
Sunday, March 3, 13
http://symfony.com/distributions
Symfony Standard Distribution
• Directory structure• Default configuration• Bundles⁃ DoctrineBundle⁃ JMSSecurityExtraBundle⁃ SensioDistributionBundle⁃ SensioFrameworkExtraBundle⁃ SensioGeneratorBundle⁃ AsseticBundle
Getting StartedSymfony 2
Sunday, March 3, 13
Getting StartedSymfony 2
Sunday, March 3, 13
Getting StartedSymfony 2
Sunday, March 3, 13
Symfony 2 Directory Structure
Sunday, March 3, 13
Symfony 2 Directory Structure
Sunday, March 3, 13
Symfony 2 Directory Structure
Sunday, March 3, 13
Symfony 2 Directory Structure
Sunday, March 3, 13
Configuration: app/config.ymlSymfony 2
Sunday, March 3, 13
Configuration: app/parameters.iniSymfony 2
Sunday, March 3, 13
Configuration: app/config_dev.ymlSymfony 2
Sunday, March 3, 13
Browser
Bootstrap (app.php)
Controller
Template Response
Request
Want to know more? Go to Raul Fraile’s Symfony2 Internals Talk
Sunday, March 3, 13
Bootstrap (app.php)
Sunday, March 3, 13
Bootstrap File - web/app.phpSymfony 2
Sunday, March 3, 13
Controllers
Sunday, March 3, 13
ControllersSymfony 2
Sunday, March 3, 13
Controllers
Sunday, March 3, 13
Sunday, March 3, 13
Templates
Sunday, March 3, 13
Templating / Twig
{# comments are not rendered #}
{# multi-line comments! {{ var }}#}
Comments:
Output variables: {{ var }}{{ var | upper }}{{ var | raw }}{{ object.property }}{{ true ? ‘yes’ : ‘no’ }}
http://twig.sensiolabs.org/
Symfony 2
Sunday, March 3, 13
{% set var = ‘hello’ %}{% set foo = var ~ ’ and goodbye’ %}
{% if foo is ‘bar’ %}...
{% else %}...
{% endif %}
Blocks:
Symfony 2 Templating / Twig
http://twig.sensiolabs.org/Sunday, March 3, 13
{% for key, val in list %}
{{ loop.index }}. {{ val }}
{% else %}
No keys.
{% endfor %}
Blocks:
Symfony 2 Templating / Twig
http://twig.sensiolabs.org/Sunday, March 3, 13
{% include “Bundle:Demo:template.html.twig” %}Include:
Render:{% render “Bundle:Demo:action” %}
Extends:{% extends "Bundle::layout.html.twig" %}
Symfony 2 Templating / Twig
http://twig.sensiolabs.org/Sunday, March 3, 13
Awesome Twig Presentations
http://slideshare.net/weaverryan/being-dangerous-with-twig-symfony-live-paris
http://www.slideshare.net/fabpot/twig-the-flexible-fast-and-securetemplate-language-for-php
http://www.slideshare.net/javier.eguiluz/twig-avanzado-sf2vigo (Spanish)
Twig avanzado - Javier Eguiluz
Being Dangerous with Twig - Ryan Weaver
Twig, The Flexible, Fast and Secure Template Language for PHP - Fabien Potencier
Sunday, March 3, 13
layout.html.twigSymfony 2
Sunday, March 3, 13
index.html.twigSymfony 2
Sunday, March 3, 13
Symfony 2 index.html.twig
Sunday, March 3, 13
Bundles
Sunday, March 3, 13
Bundles
Everything in Symfony2 is contained in Bundles
Symfony 2
Sunday, March 3, 13
Even Symfony2 is a collection of Bundles
BundlesSymfony 2
Sunday, March 3, 13
Directory StructureSymfony 2
Sunday, March 3, 13
Bundles Registration app/AppKernel.php
Symfony 2
Sunday, March 3, 13
- DoctrineMongoDBBundle
- MandangoBundle
Bundles for MongoDBSymfony 2
Sunday, March 3, 13
Installation with Composer
{ require": { "doctrine/mongodb-odm-bundle": "3.0.*" }, "minimum-stability": "dev"}
$ php composer.phar update
composer.json
Installing DoctrineMongoDBBundleSymfony 2
$ php composer.phar install doctrine/mongodb-odm-bundle
Sunday, March 3, 13
Installation with Composer
$ php composer.phar require \ doctrine/mongodb-odm-bundle:3.0.*
Installing DoctrineMongoDBBundleSymfony 2
Sunday, March 3, 13
// app/autoload.phpuse Doctrine\ODM\MongoDB\Mapping\Driver\AnnotationDriver;AnnotationDriver::registerAnnotationClasses();
app/autoload.php
Symfony 2Configuring DoctrineMongoDBBundle
Sunday, March 3, 13
doctrine_mongodb: connections: default: server: mongodb://localhost:27017 options: connect: true default_database: test_database document_managers: default: auto_mapping: true
app/config/config.yml
Configuring DoctrineMongoDBBundleSymfony 2
Sunday, March 3, 13
doctrine_mongodb: connections: default: server: mongodb://localhost:27017 options: connect: true
usage: server: mongodb://user:pass@db1.mongohosting.com:27017 options: replicaSet: true connect: true default_database: test_database document_managers: default: mappings: SGCBundle: ~ SGCRepositoryAppBundle: yml MyBundle: { type: xml, dir: Resources/config/doctrine/mapping }
Multiple Connections & Bundle MappingsSymfony 2
Sunday, March 3, 13
Defining DocumentsSymfony 2
Sunday, March 3, 13
// src/Acme/StoreBundle/Document/Product.phpnamespace Acme\StoreBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/** * @MongoDB\Document(collection="product") */class Product{ /** * @MongoDB\Id */ protected $id;
/** * @MongoDB\String @MongoDB\Index(unique=true, order="asc") */ protected $name;
Defining DocumentsSymfony 2
Sunday, March 3, 13
// src/Acme/StoreBundle/Controller/DefaultController.phpuse Acme\StoreBundle\Document\Product;use Symfony\Component\HttpFoundation\Response;// ...
public function createAction(){ $product = new Product(); $product->setName('A Foo Bar'); $product->setPrice('19.99');
$dm = $this->get('doctrine_mongodb')->getManager(); $dm->persist($product); $dm->flush();
return new Response('Created product id '.$product->getId());}
Using DocumentsSymfony 2
Sunday, March 3, 13
public function createAction(){ $dm = $this->get('doctrine_mongodb')->getManager();
$form = $this->createForm(new RegistrationType(), new Registration());
$form->bindRequest($this->getRequest());
if ($form->isValid()) { $registration = $form->getData();
$dm->persist($registration->getUser()); $dm->flush();
return $this->redirect(...); }
http://symfony.com/doc/master/bundles/DoctrineMongoDBBundle/form.html
FormsSymfony 2Since Documents are Plain PHP Objects integrating it with Symfony Forms is straightforward.
Sunday, March 3, 13
Symfony2 Commandsdoctrine doctrine:mongodb:cache:clear-metadata Clear all metadata cache for a document manager. doctrine:mongodb:fixtures:load Load data fixtures to your database. doctrine:mongodb:generate:documents Generate document classes and method stubs from your mapping information. doctrine:mongodb:generate:hydrators Generates hydrator classes for document classes. doctrine:mongodb:generate:proxies Generates proxy classes for document classes. doctrine:mongodb:generate:repositories Generate repository classes from your mapping information. doctrine:mongodb:mapping:info Show basic information about all mapped documents. doctrine:mongodb:query Query mongodb and inspect the outputted results from your document classes. doctrine:mongodb:schema:create Allows you to create databases, collections and indexes for your documents doctrine:mongodb:schema:drop Allows you to drop databases, collections and indexes for your documents
ODM CommandsSymfony 2
Sunday, March 3, 13
app/config/config.yml
TIP: Storing Symfony Sessions in MongoDB
Sunday, March 3, 13
TIP: Mixing Doctrine ODM & ORM
http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/cookbook/blending-orm-and-
mongodb-odm.html
OrderEntity (ORM)
ProductDocument (ODM)
Sunday, March 3, 13
TIP: Persisting objects with ODM or ORM<?php
namespace Doctrine\Blog;
/** @Entity(repositoryClass="Doctrine\Blog\ORM\BlogPostRepository") */class BlogPost{ /** @Id @Column(type="integer") */ private $id;
/** @Column(type="string") */ private $title;
/** @Column(type="text") */ private $body;
// ...}
Sunday, March 3, 13
TIP: Persisting objects with ODM or ORM<?php
namespace Documents;
/** @Document(repositoryClass="Doctrine\Blog\ODM\MongoDB\BlogPostRepository") */class BlogPost{ /** @Id */ private $id;
/** @Field(type="string") */ private $title;
/** @Field(type="string") */ private $body;
// ...}
Sunday, March 3, 13
- SonataDoctrineMongoDBAdminBundle
- IsmaAmbrosiGeneratorBundle
- TranslationEditorBundle
- ServerGroveLiveChat
Bundles using MongoDBSymfony 2
Sunday, March 3, 13
- http://php.net/mongo
- http://docs.mongodb.org/manual/
- http://symfony.com/doc/current/index.html
- http://www.doctrine-project.org/docs/mongodb-odm
Additional Resources
Sunday, March 3, 13
Questions?
Sunday, March 3, 13
Thank you!
Rate Me Please! https://joind.in/8211 Slides: http://slideshare.net/pgodel
Twitter: @pgodelE-mail: pablo@servergrove.com
Sunday, March 3, 13