Download as pdf or txt
Download as pdf or txt
You are on page 1of 55

Symfony and Doctrine

Whats 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.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: connections: default: driver: dbname: user: password: host: port: path: event_manager_class: configuration_class: wrapper_class: options:
Doctrine 2 www.doctrine-project.org

default

PDOSqlite Symfony root null localhost ~ %kernel.data_dir%/symfony.sqlite Doctrine\Common\EventManager Doctrine\DBAL\Configuration ~ []


www.sensiolabs.com

DBAL Console Commands


Create all congured databases
$ php console doctrine:database:create

Create a specic database


$ php console doctrine:database:create --connection=default

Drop all congured databases


$ php console doctrine:database:drop

Drop a specic database


$ php console doctrine:database:drop --connection=default

Doctrine 2

www.doctrine-project.org

www.sensiolabs.com

DBAL Console Commands


Execute SQL queries
$ php console doctrine:query:sql SELECT * FROM user

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

# array, apc, memcache, xcache

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

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('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 ) )

$user->setName('new name'); $dm->flush();

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

where(), whereIn(), whereMod(), whereNot(), etc.


Doctrine 2 www.doctrine-project.org www.sensiolabs.com

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

Query types supported


Find Insert Update Remove

Doctrine 2

www.doctrine-project.org

www.sensiolabs.com

MongoDB ODM
Find query

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

Doctrine 2

www.doctrine-project.org

www.sensiolabs.com

MongoDB ODM
Selecting elds

$query = $dm->query('find username, password User');

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

Array ( [$set] => Array ( [password] => changeme ) )


Doctrine 2 www.doctrine-project.org www.sensiolabs.com

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

== Migration Versions >> 2010-04-16 13:04:01 (20100416130401) not migrated

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 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"

It would produce a le 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

You might also like