DoctrineMongoDBBundle
• MongoDB Object Document Mapper
– Transparent persistence to MongoDB
– Same architecture as ORM
– Map a class as an entity and document
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DoctrineMigrationsBundle
• Integration with the database migrations
project.
• Easily manage and deploy different versions
of your database.
• Generate migrations when you change your
schema mapping information
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DBAL
• To use just the DBAL you must configure it:
doctrine.dbal:
dbname: Symfony
user: root
password: ~
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DBAL
• If you need to specify multiple connections
you can use the following syntax:
doctrine.dbal:
default_connection: default
connections:
default:
driver: PDOSqlite
dbname: Symfony
user: root
password: null
host: localhost
port: ~
path: %kernel.data_dir%/symfony.sqlite
event_manager_class: DoctrineCommonEventManager
configuration_class: DoctrineDBALConfiguration
wrapper_class: ~
options: []
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DBAL Console Commands
• Create all configured databases
$ php console doctrine:database:create
• Create a specific database
$ php console doctrine:database:create --connection=default
• Drop all configured databases
$ php console doctrine:database:drop
• Drop a specific database
$ php console doctrine:database:drop --connection=default
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DBAL
• Get the default configured database
connection:
class MyController extends DoctrineController
{
public function indexAction()
{
$conn = $this->getDatabaseConnection();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DBAL
• Get a configured database connection service
by its name:
class MyController extends DoctrineController
{
public function indexAction()
{
$conn = $this->getDatabaseConnection('default');
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• The EntityManager
• Central place for persisting and retrieving entities
• Multiple instances allowed
• One EntityManager per database connection
$config = new DoctrineORMConfiguration();
$config->setMetadataCacheImpl(new DoctrineCommonCacheArrayCache);
$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities"));
$config->setMetadataDriverImpl($driverImpl);
$config->setProxyDir(__DIR__ . '/Proxies');
$config->setProxyNamespace('Proxies');
$connectionOptions = array(
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite'
);
$em = DoctrineORMEntityManager::create($connectionOptions, $config);
• Dependency Injection handles the creation and
management of entity manager services
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• What is an Entity? It is a regular PHP object
that has been mapped to the Doctrine2 ORM:
/** @Entity */
class User
{
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
private $id;
/** @Column(type="string", length=255) */
private $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• No more magic in your domain
• Clean and testable
• Fast!
• Only limited by what you can do with PHP OO
to design your domain
• Inheritance
• Use __construct() without any problems
• Entities are persisted transparently by the
EntityManager
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Configure an entity manager to start using
the ORM:
doctrine.orm:
default_entity_manager: default
cache_driver: apc # array, apc, memcache, xcache
entity_managers:
default:
connection: default
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Console commands implemented for
improved developer workflow:
• Ensure production settings
• Clear metadata, query and result cache
• Load data fixtures
• Create and drop configured databases
• Generate entities from mapping information
• Generate new skeleton entities
• Generate skeleton entity repository classes
• Convert mapping information between formats
• Convert a Doctrine1 schema
• Import mapping information from an existing database
• Execute DQL and SQL queries
• Create, drop and update database schema from mapping information
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Get the default configured entity manager
service:
class MyController extends DoctrineController
{
public function indexAction()
{
$em = $this->getEntityManager();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Get a configured entity manager service by its
name:
class MyController extends DoctrineController
{
public function indexAction()
{
$em = $this->getEntityManager('default');
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Persisting entities is as simple as creating the
object and telling Doctrine to persist it:
class MyController extends DoctrineController
{
public function createAction()
{
$em = $this->getEntityManager();
$user = new User();
$user->setName('Jonathan H. Wage');
$em->persist($user);
$em->flush();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Creating Query instances and issue DQL
queries to retrieve objects:
class MyController extends DoctrineController
{
public function indexAction()
{
$em = $this->getEntityManager();
$query = $em->createQuery('select u from MyBundle:User u');
$users = $query->execute();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Creating QueryBuilder instances to
programatically build DQL queries through a
fluent interface:
class MyController extends DoctrineController
{
public function indexAction()
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder()
->select('u')
->from('MyBundle:User', 'u');
$query = $qb->getQuery();
$users = $query->execute();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Update your database schema during
development as your domain model evolves
• Add a new column to our User entity
/** @Entity */
class User
{
// ...
/** @Column(type="string", length=255) */
private $email;
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
• Run update command to update your
database schema from mapping information
$ php console doctrine:schema:update
• The above compares your current database
schema to your new mapping information and
executes the necessary queries to bring your
database up-to-date.
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Object Document Mapper
• New Doctrine Project for persisting objects to
MongoDB
• Same architecture as ORM
• Transparently persist PHP5 objects to
MongoDB
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• The DocumentManager
• Central place for persisting and retrieving documents
• Multiple instances allowed
$config = new Configuration();
$config->setProxyDir(__DIR__ . '/Proxies');
$config->setProxyNamespace('Proxies');
$config->setDefaultDB('doctrine_odm_sandbox');
$reader = new AnnotationReader();
$reader->setDefaultAnnotationNamespace('DoctrineODMMongoDBMapping');
$config->setMetadataDriverImpl(new AnnotationDriver($reader, __DIR__ . '/Documents'));
$dm = DocumentManager::create(new Mongo(), $config);
• Dependency Injection handles the creation and
management of document manager services
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• To use the MongoDB ODM you must configure
it:
doctrine_odm.mongodb:
default_document_manager: default
cache_driver: array
document_managers:
default:
connection: mongodb
connections:
mongodb:
server: localhost/somedatabase
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• If the defaults are good enough for you then
you can omit all the previous options:
doctrine_odm.mongodb: ~
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• What is a Document? It is a regular PHP object
that has been mapped to the MongoDB ODM:
/** @Document */
class User
{
/**
* @Id
*/
private $id;
/** @String */
private $name;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Get the default configured document
manager:
class MyController extends DoctrineController
{
public function indexAction()
{
$dm = $this->getDocumentManager();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Get a configured document manager by its
name:
class MyController extends DoctrineController
{
public function indexAction()
{
$dm = $this->getDocumentManager('default');
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Just like the ORM persisting documents is
easy:
class MyController extends DoctrineController
{
public function createAction()
{
$dm = $this->getDocumentManager();
$user = new User();
$user->setName('Jonathan H. Wage');
$dm->persist($user);
$dm->flush();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Change tracking
– All objects are tracked in an identity map
– Changesets are calculated on flush
– Changesets are used to perform updates using
the atomic operators
• The following code results in an efficient mongo update
with only the properties that need updated:
Array
(
$user->setName('new name');
->
[$set] => Array
(
$dm->flush(); [name] => new name
)
)
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Query API for building MongoDB queries
through a fluent OO interface:
class MyController extends DoctrineController
{
public function indexAction()
{
$dm = $this->getDocumentManager();
$query = $dm->createQuery('MyBundle:User');
$users = $query->execute();
// ...
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Using Query builder API
class MyController extends DoctrineController
{
public function indexAction()
{
$dm = $this->getDocumentManager();
$query = $dm->createQuery('User')
->where('username', 'jwage');
$user = $query->getSingleResult();
// ...
}
}
• where(), whereIn(), whereMod(), whereNot(),
etc.
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Fluent Query interface generates and
executes find() and findOne() methods
internally
• Query information is collected via fluent oo
interface and executed later
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Document Query Language (DQL)
– SQL like grammar for querying MongoDB
• Query types supported
– Find
– Insert
– Update
– Remove
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
• Document Query Language (DQL)
– atomic operators
– skip and limit main results
– skip and limit embedded documents
– use dot notation for querying embedded
documents
– embed JSON values in your DQL syntax
$query = $dm->query("update User pushAll groups = '[1, 2, 3]'");
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• New DoctrineMigrationsBundle contains
integration with the Doctrine Database
Migrations project
• Migrations have been completely re-written
from Doctrine1 and are an extension of the
database abstraction layer
http://www.doctrine-project.org/projects/migrations
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Migration classes:
class Version20100416130401 extends AbstractMigration
{
public function up(Schema $schema)
{
}
public function down(Schema $schema)
{
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Manually execute SQL for migrations:
class Version20100416130422 extends AbstractMigration
{
public function up(Schema $schema)
{
$this->_addSql('CREATE TABLE addresses (id INT NOT NULL, street
VARCHAR(255) NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB');
}
public function down(Schema $schema)
{
$this->_addSql('DROP TABLE addresses');
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Use API of Schema objects to perform
migration:
class Version20100416130401 extends AbstractMigration
{
public function up(Schema $schema)
{
$table = $schema->createTable('users');
$table->addColumn('username', 'string');
$table->addColumn('password', 'string');
}
public function down(Schema $schema)
{
$schema->dropTable('users');
}
}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Execute migration dry runs:
$ ./doctrine migrations:migrate --dry-run
Are you sure you wish to continue?
y
Executing dry run of migration up to 20100416130452 from 0
>> migrating 20100416130452
-> CREATE TABLE users (username VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL) ENGINE = InnoDB
• Omit --dry-run to execute migration.
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Specify a version number to revert to or 0 to
revert all migrations:
$ ./doctrine migrations:migrate 0
Are you sure you wish to continue?
y
Migrating down to 0 from 20100416130401
-- reverting 20100416130401
-> DROP TABLE users
-- reverted
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Write migration SQL file instead of executing:
$ ./doctrine migrations:migrate --write-sql
Executing dry run of migration up to 20100416130401 from 0
>> migrating 20100416130401
-> CREATE TABLE users (username VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL) ENGINE = InnoDB
Writing migration file to "/path/to/sandbox/doctrine_migration_20100416130405.sql"
• It would produce a file like:
# Doctrine Migration File Generated on 2010-04-16 13:04:05
# Migrating from 0 to 20100416130422
# Version 20100416130401
CREATE TABLE users (username VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL) ENGINE = InnoDB;
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Integration with ORM for generating
migrations when you change your mapping
information. Add a new property to your
Entity: /** @Entity @Table(name="users") */
class User
{
/**
* @var string $test
*/
private $test;
// ...
}
• Run the migrations diff command:
$ ./doctrine migrations:diff
Generated new migration class to "/path/to/migrations/DoctrineMigrations/Version20100416130459.php" from schema differences.
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• The generated migration class looks like:
class Version20100416130459 extends AbstractMigration
{
public function up(Schema $schema)
{
$this->_addSql('ALTER TABLE users ADD test VARCHAR(255) NOT NULL');
}
public function down(Schema $schema)
{
$this->_addSql('ALTER TABLE users DROP test');
}
}
• It contains the SQL statements required to
update your database with the schema
changes.
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations
• Run migrate command to execute the
generated migration:
$ ./doctrine migrations:migrate
• Now your database is up to date and contains
the new column named test.
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Questions?
Jonathan H. Wage
jonathan.wage@sensio.com
sensiolabs.com | doctrine-project.org | sympalphp.org | jwage.com
You should follow me on http://www.twitter.com/jwage for updates about Symfony,
Doctrine and related developments.
You can contact Jonathan about Doctrine and Open-Source or for
training, consulting, application development, or business related
questions at jonathan.wage@sensio.com
Doctrine 2 www.doctrine-project.org www.sensiolabs.com