Professional Documents
Culture Documents
What's New in The Symfony and Doctrine Integration
What's New in The Symfony and Doctrine Integration
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
Updated DoctrineBundle
Doctrine2 features fully integrated
Database Abstraction Layer Object Relational Mapper
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
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 congure it:
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: connections: default: driver: dbname: user: password: host: port: path: event_manager_class: configuration_class: wrapper_class: options:
Doctrine 2 www.doctrine-project.org
default
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
Specify connection
$ php console doctrine:query:sql ... --connection=default
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
DBAL
Get the default congured database connection:
class MyController extends DoctrineController { public function indexAction() { $conn = $this->getDatabaseConnection(); // ... } }
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
DBAL
Get a congured 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 \Doctrine\ORM\Configuration(); $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache); $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 = \Doctrine\ORM\EntityManager::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
Congure an entity manager to start using the ORM:
doctrine.orm: default_entity_manager: cache_driver: entity_managers: default: connection:
default apc
default
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
ORM
Console commands implemented for improved developer workow:
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
ORM
Console commands implemented for improved developer workow:
Ensure production settings Clear metadata, query and result cache Load data xtures Create and drop congured 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 congured 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 congured 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 uent 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
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('Doctrine\ODM\MongoDB\Mapping\\'); $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 congure it:
doctrine_odm.mongodb: default_document_manager: cache_driver: document_managers: default: connection: connections: mongodb: server: default array
mongodb
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 congured 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 congured 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 ush 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 ( [$set] => Array ( [name] => new name ) )
->
www.sensiolabs.com
Doctrine 2
www.doctrine-project.org
MongoDB ODM
Traditional MongoDB nd() and ndOne()
$users = $dm->find('User', $criteria); $query = $dm->findOne('User', array('username' => 'jwage') ); $user = $query->getSingleResult();
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
MongoDB ODM
Query API for building MongoDB queries through a uent 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(); // ... } }
MongoDB ODM
Fluent Query interface generates and executes nd() and ndOne() methods internally Query information is collected via uent 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
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
MongoDB ODM
Find query
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
MongoDB ODM
Selecting elds
Doctrine 2
www.doctrine-project.org
www.sensiolabs.com
MongoDB ODM
$slice operator for paging embedded collections
$query = $dm->query('find comments skip 20 limit 10 Post');
Array ( [comments] => Array ( [$slice] => Array ( [0] => 20 [1] => 10 ) ) )
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM
Use atomic operators
$query = $dm->query("update User set password = 'changeme' where username = 'jwage'");
MongoDB ODM
Complex update
$query = $dm->query("update User inc count = 1, inc views = 2, set username = 'jwage'");
Array ( [$inc] => Array ( [count] => 1 [views] => 2 ) [$set] => Array ( [username] => jwage ) )
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
Check migrations status:
$ ./doctrine migrations:status == Configuration >> >> >> >> >> >> >> >> >> >> Name: Configuration Source: Version Table Name: Migrations Namespace: Migrations Directory: Current Version: Latest Version: Executed Migrations: Available Migrations: New Migrations: Doctrine Sandbox Migrations /Users/jwage/Sites/doctrine2git/tools/sandbox/migrations.xml doctrine_migration_versions DoctrineMigrations /Users/jwage/Sites/doctrine2git/tools/sandbox/DoctrineMigrations 2010-04-16 13:04:22 (20100416130422) 2010-04-16 13:04:22 (20100416130422) 0 1 1
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
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 le 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"
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; // ... }
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