Date post: | 08-May-2015 |
Category: |
Documents |
Upload: | jonathan-wage |
View: | 29,771 times |
Download: | 0 times |
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Symfony and DoctrineWhat’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 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: Doctrine\Common\EventManager configuration_class: Doctrine\DBAL\Configuration wrapper_class: ~ options: []
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DBAL Console Commands• Create all configured databases
• Create a specific database
• Drop all configured databases
• Drop a specific database
$ php console doctrine:database:create
$ php console doctrine:database:create --connection=default
$ php console doctrine:database:drop
$ php console doctrine:database:drop --connection=default
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
DBAL Console Commands• Execute SQL queries
• Specify connection
$ php console doctrine:query:sql “SELECT * FROM user”
$ php console doctrine:query:sql “...” --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
•Dependency Injection handles the creation and management of entity manager services
$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);
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
• Console commands implemented for improved developer workflow:
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
ORM
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
• The above compares your current database schema to your new mapping information and executes the necessary queries to bring your database up-to-date.
$ php console doctrine:schema:update
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
•Dependency Injection handles the creation and management of document manager services
$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);
• 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
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:
$user->setName('new name');$dm->flush();
Array( [$set] => Array ( [name] => new name ))
->
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM• Traditional MongoDB find() and findOne()
$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 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
• where(), whereIn(), whereMod(), whereNot(), etc.
class MyController extends DoctrineController{ public function indexAction() { $dm = $this->getDocumentManager(); $query = $dm->createQuery('User') ->where('username', 'jwage');
$user = $query->getSingleResult(); // ... }}
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• Find query
$query = $dm->query('find all User');$users = $query->execute();
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
MongoDB ODM• Selecting fields
$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: Doctrine Sandbox Migrations >> Configuration Source: /Users/jwage/Sites/doctrine2git/tools/sandbox/migrations.xml >> Version Table Name: doctrine_migration_versions >> Migrations Namespace: DoctrineMigrations >> Migrations Directory: /Users/jwage/Sites/doctrine2git/tools/sandbox/DoctrineMigrations >> Current Version: 2010-04-16 13:04:22 (20100416130422) >> Latest Version: 2010-04-16 13:04:22 (20100416130422) >> Executed Migrations: 0 >> Available Migrations: 1 >> New Migrations: 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:
• Omit --dry-run to execute migration.
$ ./doctrine migrations:migrate --dry-runAre you sure you wish to continue?yExecuting 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 0Are you sure you wish to continue?yMigrating 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:
• It would produce a file like:
$ ./doctrine migrations:migrate --write-sqlExecuting 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 Migration File Generated on 2010-04-16 13:04:05# Migrating from 0 to 20100416130422
# Version 20100416130401CREATE 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:
• Run the migrations diff command:$ ./doctrine migrations:diffGenerated new migration class to "/path/to/migrations/DoctrineMigrations/Version20100416130459.php" from schema differences.
/** @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:
• It contains the SQL statements required to update your database with the schema changes.
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'); }}
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Database Migrations• Run migrate command to execute the
generated migration:
• Now your database is up to date and contains the new column named test.
$ ./doctrine migrations:migrate
You can contact Jonathan about Doctrine and Open-Source or for training, consulting, application development, or business related
questions at [email protected]
Doctrine 2 www.doctrine-project.org www.sensiolabs.com
Jonathan H. [email protected]
sensiolabs.com | doctrine-project.org | sympalphp.org | jwage.com
Questions?
You should follow me on http://www.twitter.com/jwage for updates about Symfony, Doctrine and related developments.