SlideShare una empresa de Scribd logo
1 de 99
Descargar para leer sin conexión
Doctrine 2
       Enterprise Persistence
           Layer for PHP



Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
What is different in Doctrine 2?




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
100% re-written code




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Requires PHP 5.3




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




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




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Fully Namespaced
• Doctrine makes use of PHP 5.3 namespaces.
  Currently we have the following
  namespaces:

      – DoctrineCommon
      – DoctrineDBAL
      – DoctrineORM




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Common
• Standalone package containing all common
  code shared between DBAL and ORM

      – Cache drivers
      – Annotations Parser
      – Command Line Interface
      – Class Loaders
      – Lexer Parser
      – ...and other various utilities


Doctrine 2   www.doctrine-project.org      www.sensiolabs.com
DBAL
• Database Abstraction Layer built on top of
  PDO.

      – Multiple DBMS supported
             •   MySQL
             •   Sqlite
             •   Pgsql
             •   etc.
      – Database Introspection
      – DDL Statment API


Doctrine 2          www.doctrine-project.org     www.sensiolabs.com
ORM
• Object Relational Mapper built on top of
  Common and DBAL

      – Inheritance
      – Doctrine Query Language
      – XML, YAML or Annotations Metadata
      – Query Cache
      – Result Cache
      – ...much more


Doctrine 2   www.doctrine-project.org    www.sensiolabs.com
Complete separation of your
    domain model and persistence
                layer



Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
We learned lots building Doctrine
 1 and we used that to help us
        build Doctrine 2



Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Some performance comparisons
   between Doctrine 1 and 2




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Performance of Doctrine 1



                     To hydrate 5000 records
                       in Doctrine 1 it takes
                      roughly 4.3 seconds.




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



                Under Doctrine 2, hydrating
              those same 5000 records only
                    takes 1.4 seconds.




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


              ...and with 10000 records it still
               only takes about 3.5 seconds.

               Twice the data and still faster
                      than Doctrine 1



Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
Why is it faster?
• PHP 5.3 gives us a huge performance
  improvement when using a heavily OO
  framework like Doctrine

• Better optimized hydration algorithm

• Killed the magical aspect of Doctrine 1

• All around more explicit and less magical
  code results in better and faster code.
Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Why kill the magic?
• Eliminate the WTF factor of Doctrine 1




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
The Doctrine 1 magical
               features are both a
              blessing and a curse

Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
Blessing and a Curse
• Magic is great when it works
• The magic you love is also the cause of all
  the pain you’ve felt with Doctrine 1
• When it doesn’t work it is hard to debug
• Edge cases are hard to fix
• Edge cases are hard to work around
• Edge cases, edge cases, edge cases
• Everything is okay until you try and go
  outside the box the magic provides
• ...magic is slow
Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
How will we replace the magic?
      This new thing called OOP :)

•    Object Composition
•    Inheritance
•    Aggregation
•    Containment
•    Encapsulation
•    ...etc


Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Will Doctrine 2 have behaviors?




                             Yes and No



Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
The No
• We won’t have any concept of “model
  behaviors”

• Behaviors were a made up concept for
  Doctrine 1 to work with its extremely
  intrusive architecture.

• It tries to do things that PHP does not allow
  and is the result of lots of problems in
  Doctrine 1
Doctrine 2   www.doctrine-project.org      www.sensiolabs.com
The Yes
• Everything you can do in Doctrine 1 you can
  do in Doctrine 2, just in a different way.

• “Behavior” like functionality will be bundled
  as extensions for Doctrine 2 and will just
  contain normal OO PHP code that wraps/
  extends Doctrine code or is meant to be
  wrapped or extended by your entities.



Doctrine 2   www.doctrine-project.org       www.sensiolabs.com
What did we use to build
                   Doctrine 2?




Doctrine 2    www.doctrine-project.org   www.sensiolabs.com
Doctrine 2 Tool Belt
•    phpUnit 3.4.10 - Unit Testing
•    Phing - Packaging and Distribution
•    Symfony YAML Component
•    Sismo - Continuous Integration
•    Subversion - Source Control
•    Jira - Issue Tracking and Management
•    Trac - Subversion Timeline, Source Code
     Browser, Changeset Viewer


Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Doctrine 2 Architecture
• Entities
• Lightweight persistent domain object
• Regular PHP class
• Does not extend any base Doctrine class
• Cannot be final or contain final methods
• Any two entities in a hierarchy of classes must not have a
  mapped property with the same name
• Supports inheritance, polymorphic associations and
  polymorphic queries.
• Both abstract and concrete classes can be entities
• Entities may extend non-entity classes as well as entity
  classes, and non-entity classes may extend entity classes


Doctrine 2    www.doctrine-project.org   www.sensiolabs.com
Doctrine 2 Architecture
• Your entities in Doctrine 2 don’t require
  that you extend a base class like in Doctrine
  1! No more imposing on your domain
  model!
                                namespace Entities;

                                class User
                                {
                                    private $id;
                                    private $name;
                                    private $address;
                                }

Doctrine 2    www.doctrine-project.org     www.sensiolabs.com
Doctrine 2 Architecture
• The EntityManager
• Central access point to the ORM functionality provided by
  Doctrine 2. API is used to manage the persistence of your
  objects and to query for persistent objects.
• Employes transactional write behind strategy that delays the
  execution of SQL statements in order to execute them in the
  most efficient way
• Execute at end of transaction so that all write locks are quickly
  releases
• Internally an EntityManager uses a UnitOfWork to keep track
  of your objects




Doctrine 2    www.doctrine-project.org   www.sensiolabs.com
Unit Testing
• Tests are ran against multiple DBMS types.
  This is something that was not possible
  with the Doctrine 1 test suite.

•    ...Sqlite
•    ...MySQL
•    ...Oracle
•    ...PgSQL
•    ...more to come

Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Unit Testing
• 859 Test Cases
• 2152 Assertions
• Tests run in a few seconds compared to
  30-40 seconds for Doctrine 1
• Much more granular and explicit unit tests
• Easier to debug failed tests
• Continuously integrated by Sismo :)




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Database Abstraction Layer
• Separate standalone package and
  namespace (DoctrineDBAL).

• Can be used standalone.

• Much improved over Doctrine 1 in regards
  to the API for database introspection and
  schema management.



Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
Database Abstraction Layer
• Hopefully Doctrine 2 DBAL can be the
  defacto standard DBAL for PHP 5.3 in the
  future like MDB and MDB2 were in PEAR

• Maybe we can make this happen for PEAR2?




Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
DBAL Data API
•    prepare($sql) - Prepare a given sql statement and return the DoctrineDBAL
     DriverStatement instance.
•    executeUpdate($sql, array $params) - Executes a prepared statement with the
     given sql and parameters and returns the affected rows count.
•    execute($sql, array $params) - Creates a prepared statement for the given sql and
     passes the parameters to the execute method, then returning the statement.
•    fetchAll($sql, array $params) - Execute the query and fetch all results into an array.
•    fetchArray($sql, array $params) - Numeric index retrieval of first result row of the
     given query.
•    fetchBoth($sql, array $params) - Both numeric and assoc column name retrieval of
     the first result row.
•    fetchColumn($sql, array $params, $colnum) - Retrieve only the given column of
     the first result row.
•    fetchRow($sql, array $params) - Retrieve assoc row of the first result row.
•    select($sql, $limit, $offset) - Modify the given query with a limit clause.
•    delete($tableName, array $identifier) - Delete all rows of a table matching the
     given identifier, where keys are column names.
•    insert($tableName, array $data) - Insert a row into the given table name using the

Doctrine 2       www.doctrine-project.org        www.sensiolabs.com
DBAL Introspection API
•    listDatabases()
•    listFunctions()
•    listSequences()
•    listTableColumns($tableName)
•    listTableConstraints($tableName)
•    listTableDetails($tableName)
•    listTableForeignKeys($tableName)
•    listTableIndexes($tableName)
•    listTables()
Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
DBAL Schema Representation
             $platform = $em->getConnection()->getDatabasePlatform();

             $schema = new DoctrineDBALSchemaSchema();
             $myTable = $schema->createTable("my_table");
             $myTable->addColumn("id", "integer", array("unsigned" => true));
             $myTable->addColumn("username", "string", array("length" => 32));
             $myTable->setPrimaryKey(array("id"));

             // get queries to create this schema.
             $queries = $schema->toSql($platform);


 Array
 (
   [0] => CREATE TABLE my_table (id INTEGER NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY("id"))
 )




Doctrine 2          www.doctrine-project.org          www.sensiolabs.com
DBAL Schema Representation
// ......

// get queries to safely delete this schema.
$dropSchema = $schema->toDropSql($platform);



                         Array
                         (
                           [0] => DROP TABLE my_table
                         )



  Does the reverse of what toSql() does, dropping the created tables



Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Comparing Schemas
• Lets take our original my_table schema as
  our “from schema”...
      $fromSchema = new DoctrineDBALSchemaSchema();
      $myTable = $fromSchema->createTable("my_table");
      $myTable->addColumn("id", "integer", array("unsigned" => true));
      $myTable->addColumn("username", "string", array("length" => 32));
      $myTable->setPrimaryKey(array("id"));




Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
Compare DBAL Schemas
• Then later you want to add a new column to
  the schema and easily deploy the change.

• Lets add an email column to the table:

      $toSchema = new DoctrineDBALSchemaSchema();
      $myTable = $toSchema->createTable("my_table");
      $myTable->addColumn("id", "integer", array("unsigned" => true));
      $myTable->addColumn("username", "string", array("length" => 32));
      $myTable->addColumn("email", "string", array("length" => 255));
      $myTable->setPrimaryKey(array("id"));




Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
Compare DBAL Schemas
• You can easily compare one schema to
  another to deploy the changes!
             $comparator = new DoctrineDBALSchemaComparator();
             $schemaDiff = $comparator->compare($fromSchema, $toSchema);

             // queries to get from one to another schema.
             $queries = $schemaDiff->toSql($platform);

             print_r($queries);


               Array
               (
                 [0] => ALTER TABLE my_table ADD email VARCHAR(255) NOT NULL
               )



Doctrine 2         www.doctrine-project.org    www.sensiolabs.com
Annotations
                    <?php

                    namespace Entities;

                    /**
                      * @Entity @Table(name="users")
                      */
                    class User
                    {
                         /** @Id @Column(type="integer") @GeneratedValue */
                         private $id;

                          /** @Column(length=50) */
                          private $name;

                          /** @OneToOne(targetEntity="Address") */
                          private $address;
                    }




Doctrine 2   www.doctrine-project.org                 www.sensiolabs.com
Things to Notice
• Entities no longer require you to extend a
  base class

• Your domain model has absolutely no
  magic

• Not imposed on by Doctrine and is defined
  by raw PHP objects and normal OO
  programming


Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
YAML
                                    EntitiesAddress:
                                      type: entity
                                      table: addresses
                                      id:
                                        id:
                                          type: integer
                                          generator:
                                            strategy: AUTO
                                      fields:
                                        street:
                                          type: string
                                          length: 255
                                      oneToOne:
                                        user:
                                          targetEntity: User
                                          mappedBy: address



Doctrine 2   www.doctrine-project.org            www.sensiolabs.com
XML
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                    http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

     <entity name="EntitiesUser" table="users">
         <id name="id" type="integer">
             <generator strategy="AUTO"/>
         </id>
         <field name="name" type="string" length="50"/>
         <one-to-one field="address" target-entity="Address">
             <join-column name="address_id" referenced-column-name="id"/>
         </one-to-one>
     </entity>

</doctrine-mapping>




Doctrine 2       www.doctrine-project.org       www.sensiolabs.com
Setup
• PHP “use” all necessary namespaces and
  classes

             use DoctrineCommonClassLoader,
                 DoctrineORMConfiguration,
                 DoctrineORMEntityManager,
                 DoctrineCommonCacheApcCache,
                 EntitiesUser,
                 EntitiesAddress;




Doctrine 2   www.doctrine-project.org      www.sensiolabs.com
Setup
• Require the Doctrine ClassLoader



      require '/path/to/doctrine/lib/Doctrine/Common/ClassLoader.php';




Doctrine 2     www.doctrine-project.org      www.sensiolabs.com
Setup
• Setup autoloading for Doctrine classes
• ...core classes
• ...entity classes
• ...proxy classes

$doctrineClassLoader = new ClassLoader('Doctrine', '/path/to/doctrine');
$doctrineClassLoader->register();

$entitiesClassLoader = new ClassLoader('Entities', '/path/to/entities');
$entitiesClassLoader->register();

$proxiesClassLoader = new ClassLoader('Proxies', '/path/to/proxies');
$proxiesClassLoader->register();



Doctrine 2   www.doctrine-project.org      www.sensiolabs.com
Setup
• Configure your Doctrine implementation

               // Set up caches
               $config = new Configuration;
               $cache = new ApcCache;
               $config->setMetadataCacheImpl($cache);
               $config->setQueryCacheImpl($cache);

               // Proxy configuration
               $config->setProxyDir('/path/to/proxies/Proxies');
               $config->setProxyNamespace('Proxies');




Doctrine 2   www.doctrine-project.org      www.sensiolabs.com
Setup
• Create your database connection and entity
  manager

             // Database connection information
             $connectionOptions = array(
                 'driver' => 'pdo_sqlite',
                 'path' => 'database.sqlite'
             );

             // Create EntityManager
             $em = EntityManager::create($connectionOptions, $config);




Doctrine 2        www.doctrine-project.org      www.sensiolabs.com
Setup
• In production you would lazily load the
  EntityManager
• Example: $em = function()
             {
                                 static $em;
                                 if (!$em)
                                 {
                                   $em = EntityManager::create($connectionOptions, $config);
                                 }
                                 return $em;
                             }


• In the real world I wouldn’t recommend that
  you use the above example
• Symfony DI would take care of this for us

Doctrine 2   www.doctrine-project.org               www.sensiolabs.com
use DoctrineCommonClassLoader,
                            DoctrineORMConfiguration,
                            DoctrineORMEntityManager,
                            DoctrineCommonCacheApcCache,
                            EntitiesUser,
                            EntitiesAddress;


                       require '/path/to/doctrine/lib/Doctrine/Common/ClassLoader.php';


                       $doctrineClassLoader = new ClassLoader('Doctrine', '/path/to/doctrine');
                       $doctrineClassLoader->register();


                       $entitiesClassLoader = new ClassLoader('Entities', '/path/to/entities');
                       $entitiesClassLoader->register();


                       $proxiesClassLoader = new ClassLoader('Proxies', '/path/to/proxies');
                       $proxiesClassLoader->register();


                       // Set up caches
                       $config = new Configuration;
                       $cache = new ApcCache;
                       $config->setMetadataCacheImpl($cache);
                       $config->setQueryCacheImpl($cache);


                       // Proxy configuration
                       $config->setProxyDir('/path/to/proxies/Proxies');
                       $config->setProxyNamespace('Proxies');


                       // Database connection information
                       $connectionOptions = array(
                            'driver' => 'pdo_sqlite',
                            'path' => 'database.sqlite'
                       );


                       // Create EntityManager
                       $em = EntityManager::create($connectionOptions, $config);


Doctrine 2   www.doctrine-project.org                           www.sensiolabs.com
Setup
• Now you can start using your models and
  persisting entities


             $user = new User;
             $user->setName('Jonathan H. Wage');

             $em->persist($user);
             $em->flush();




Doctrine 2   www.doctrine-project.org      www.sensiolabs.com
Insert Performance
• Inserting 20 records with Doctrine

             for ($i = 0; $i < 20; ++$i) {
                 $user = new User;
                 $user->name = 'Jonathan H. Wage';
                 $em->persist($user);
             }

             $s = microtime(true);
             $em->flush();
             $e = microtime(true);
             echo $e - $s;


Doctrine 2    www.doctrine-project.org   www.sensiolabs.com
Insert Performance
• Compare it to some raw PHP code


$s = microtime(true);
for ($i = 0; $i < 20; ++$i) {
    mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')",
$link);
}
$e = microtime(true);
echo $e - $s;




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Insert Performance
• The results might be surprising to you.
  Which do you think is faster?




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



             Doctrine 2                 0.0094 seconds

             mysql_query 0.0165 seconds




Doctrine 2   www.doctrine-project.org    www.sensiolabs.com
Insert Performance
• Doctrine 2 is faster than some raw PHP
  code? What?!?!?! HUH?

• It does a lot less, provides no features, no
  abstraction, etc.

• Why? The answer is transactions! Doctrine 2
  manages our transactions for us and
  efficiently executes all inserts in a single.
  The raw PHP code executes 1 transaction
  for each insert.
Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Insert Performance
• Doctrine 2 is not faster than some raw PHP
  code

• The example demonstrates that simple
  developer oversights and can cause
  significant performance problems




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Insert Performance
• Here is the same raw PHP code re-visited
  with proper transaction usage.

$s = microtime(true);
mysql_query('START TRANSACTION', $link);
for ($i = 0; $i < 20; ++$i) {
    mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')",
$link);
}
mysql_query('COMMIT', $link);
$e = microtime(true);
echo $e - $s;




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Insert Performance
• This time around it only takes 0.0028
  seconds compared to the previous 0.0165
  seconds. That’s a pretty huge improvement!

• You can read more about this on the
  Doctrine Blog

     http://www.doctrine-project.org/blog/transactions-and-performance




Doctrine 2    www.doctrine-project.org   www.sensiolabs.com
Doctrine Query Language
• DQL parser completely re-written from
  scratch

• ...DQL is parsed by a top down recursive
  descent parser that constructs an AST
  (abstract syntax tree).

• ...The AST is used to generate the SQL to
  execute for your DBMS
               http://www.doctrine-project.org/documentation/manual/2_0/en/dql-doctrine-query-language


Doctrine 2    www.doctrine-project.org                       www.sensiolabs.com
Doctrine Query Language
• Here is an example DQL query



      $q = $em->createQuery('select u from MyProjectEntitiesUser u');
      $users = $q->execute();




Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
Doctrine Query Language
• Here is that same DQL query using the
  QueryBuilder API

             $qb = $em->createQueryBuilder()
                 ->select('u')
                 ->from('MyProjectEntitiesUser', 'u');

             $q = $qb->getQuery();
             $users = $q->execute();


                          http://www.doctrine-project.org/documentation/manual/2_0/en/query-builder




Doctrine 2       www.doctrine-project.org                        www.sensiolabs.com
Doctrine Query Builder
• QueryBuilder API is the same as
  Doctrine_Query API in Doctrine 1
• Query building and query execution are
  separated
• True builder pattern used
• QueryBuilder is used to build instances of
  Query
• You don’t execute a QueryBuilder, you get
  the built Query instance from the
  QueryBuilder and execute it
Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Cache Drivers
• Public interface of all cache drivers

• fetch($id) - Fetches an entry from the
  cache.
• contains($id) - Test if an entry exists in the
  cache.
• save($id, $data, $lifeTime = false) - Puts
  data into the cache.
• delete($id) - Deletes a cache entry.

Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Cache Drivers
• Wrap existing Symfony, ZF, etc. cache driver
  instances with the Doctrine interface




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Cache Drivers
• deleteByRegex($regex) - Deletes cache
  entries where the key matches a regular
  expression

• deleteByPrefix($prefix) - Deletes cache
  entries where the key matches a prefix.

• deleteBySuffix($suffix) - Deletes cache
  entries where the key matches a suffix.


Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Cache Drivers
• Each driver extends the AbstractCache class
  which defines a few abstract protected
  methods that each of the drivers must
  implement to do the actual work

•    _doFetch($id)
•    _doContains($id)
•    _doSave($id, $data, $lifeTime = false)
•    _doDelete($id)

Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
APC Cache Driver
• To use the APC cache driver you must have
  it compiled and enabled in your php.ini


             $cacheDriver = new DoctrineCommonCacheApcCache();
             $cacheDriver->save('cache_id', 'my_data');




Doctrine 2      www.doctrine-project.org   www.sensiolabs.com
Memcache Cache Driver
• To use the memcache cache driver you
  must have it compiled and enabled in your
  php.ini

             $memcache = new Memcache();
             $memcache->connect('memcache_host', 11211);

             $cacheDriver = new DoctrineCommonCacheMemcacheCache();
             $cacheDriver->setMemcache($memcache);
             $cacheDriver->save('cache_id', 'my_data');




Doctrine 2         www.doctrine-project.org   www.sensiolabs.com
Xcache Cache Driver
• To use the xcache cache driver you must
  have it compiled and enabled in your
  php.ini

             $cacheDriver = new DoctrineCommonCacheXcacheCache();
             $cacheDriver->save('cache_id', 'my_data');




Doctrine 2        www.doctrine-project.org   www.sensiolabs.com
Result Cache
• First you need to configure the result cache
                $cacheDriver = new DoctrineCommonCacheApcCache();
                $config->setResultCacheImpl($cacheDriver);


• Then you can configure each query to use
  the result cache or not.
             $query = $em->createQuery('select u from EntitiesUser u');
             $query->useResultCache(true, 3600, 'my_query_name');


• Executing this query the first time would
  populate a cache entry in $cacheDriver
  named my_query_name
Doctrine 2          www.doctrine-project.org   www.sensiolabs.com
Result Cache
• Now you can clear the cache for that query
  by using the delete() method of the cache
  driver


             $cacheDriver->delete('my_query_name');




Doctrine 2    www.doctrine-project.org   www.sensiolabs.com
Command Line Interface
• Re-written command line interface to help
  developing with Doctrine




Doctrine 2    www.doctrine-project.org   www.sensiolabs.com
dbal:run-sql
• Execute a manually written SQL statement
• Execute multiple SQL statements from a file




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
orm:clear-cache
•    Clear   all query, result and metadata cache
•    Clear   only query cache
•    Clear   only result cache
•    Clear   only metadata cache
•    Clear   a single queries result cache
•    Clear   keys that match regular expression
•    Clear   keys that match a prefix
•    Clear   keys that match a suffix


Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
orm:convert-mapping
• Convert metadata information between
  formats
• Convert metadata information from an
  existing database to any supported format
  (yml, xml, annotations, etc.)
• Convert mapping information from xml to
  yml or vice versa
• Generate PHP classes from mapping
  information with mutators and accessors


Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
orm:ensure-production-settings
• Verify that Doctrine is properly configured
  for a production environment.

• Throws an exception when environment
  does not meet the production requirements




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
orm:generate-proxies
• Generate the proxy classes for entity
  classes.

• A proxy object is an object that is put in
  place or used instead of the "real" object. A
  proxy object can add behavior to the object
  being proxied without that object being
  aware of it. In Doctrine 2, proxy objects are
  used to realize several features but mainly
  for transparent lazy-loading.

Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
orm:run-dql
• Execute a DQL query from the command
  line




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
orm:schema-tool
• Drop, create and update your database
  schema.

• --create option creates the initial tables for
  your schema
• --drop option drops the the tables for your
  schema
• --update option compares your local
  schema information to the database and
  updates it accordingly
Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Inheritance
• Doctrine 2 fully supports inheritance. We
  allow the following types of inheritance:

• ...Mapped Superclasses
• ...Single Table Inheritance
• ...Class Table Inheritance




Doctrine 2   www.doctrine-project.org     www.sensiolabs.com
Mapped Superclasses
             /** @MappedSuperclass */
             class MappedSuperclassBase
             {
                 /** @Column(type="integer") */
                 private $mapped1;
                 /** @Column(type="string") */
                 private $mapped2;
                 /**
                  * @OneToOne(targetEntity="MappedSuperclassRelated1")
                  * @JoinColumn(name="related1_id", referencedColumnName="id")
                  */
                 private $mappedRelated1;

                     // ... more fields and methods
             }

             /** @Entity */
             class EntitySubClass extends MappedSuperclassBase
             {
                 /** @Id @Column(type="integer") */
                 private $id;
                 /** @Column(type="string") */
                 private $name;

                     // ... more fields and methods
             }




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


    CREATE TABLE EntitySubClass (mapped1 INTEGER NOT NULL,
    mapped2 TEXT NOT NULL,
    id INTEGER NOT NULL,
    name TEXT NOT NULL,
    related1_id INTEGER DEFAULT NULL,
    PRIMARY KEY(id))




             http://www.doctrine-project.org/documentation/manual/2_0/en/inheritance-mapping#mapped-superclasses

Doctrine 2        www.doctrine-project.org                      www.sensiolabs.com
Single Table Inheritance
         /**
           * @Entity
           * @InheritanceType("SINGLE_TABLE")
           * @DiscriminatorColumn(name="discr", type="string")
           * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
           */
         class Person
         {
              // ...
         }

         /**
           * @Entity
           */
         class Employee extends Person
         {
              // ...
         }




Doctrine 2        www.doctrine-project.org   www.sensiolabs.com
Single Table Inheritance
• All entities share one table.

• To distinguish which row represents which
  type in the hierarchy a so-called
  discriminator column is used.




             http://www.doctrine-project.org/documentation/manual/2_0/en/inheritance-mapping#single-table-inheritance


Doctrine 2         www.doctrine-project.org                        www.sensiolabs.com
Class Table Inheritance
 namespace MyProjectModel;

 /**
   * @Entity
   * @InheritanceType("JOINED")
   * @DiscriminatorColumn(name="discr", type="string")
   * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
   */
 class Person
 {
      // ...
 }

 /** @Entity */
 class Employee extends Person
 {
     // ...
 }
             http://www.doctrine-project.org/documentation/manual/2_0/en/inheritance-mapping#single-table-inheritance

Doctrine 2       www.doctrine-project.org                        www.sensiolabs.com
Class Table Inheritance
• Each class in a hierarchy is mapped to
  several tables: its own table and the tables
  of all parent classes.
• The table of a child class is linked to the
  table of a parent class through a foreign
  key constraint.
• A discriminator column is used in the
  topmost table of the hierarchy because this
  is the easiest way to achieve polymorphic
  queries.

Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Batch Processing
• Doctrine 2 offers the ability to do some
  batch processing by taking advantage of
  the transactional write-behind behavior of
  an EntityManager




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Bulk Inserts
• Insert 10000 objects with a batch size of 20


             $batchSize = 20;
             for ($i = 1; $i <= 10000; ++$i) {
                 $user = new CmsUser;
                 $user->setStatus('user');
                 $user->setUsername('user' . $i);
                 $user->setName('Mr.Smith-' . $i);
                 $em->persist($user);
                 if ($i % $batchSize == 0) {
                     $em->flush();
                     $em->clear(); // Detaches all objects from Doctrine!
                 }
             }




Doctrine 2       www.doctrine-project.org    www.sensiolabs.com
Bulk Update
• Bulk update with DQL



       $q = $em->createQuery('update MyProjectModelManager m set
       m.salary = m.salary * 0.9');
       $numUpdated = $q->execute();




Doctrine 2      www.doctrine-project.org   www.sensiolabs.com
Bulk Update
• Bulk update by iterating over the results
  using the Query::iterate() method to avoid
  loading everything into memory at once
             $batchSize = 20;
             $i = 0;
             $q = $em->createQuery('select u from MyProjectModelUser u');
             $iterableResult = $q->iterate();
             foreach($iterableResult AS $row) {
                 $user = $row[0];
                 $user->increaseCredit();
                 $user->calculateNewBonuses();
                 if (($i % $batchSize) == 0) {
                     $em->flush(); // Executes all updates.
                     $em->clear(); // Detaches all objects from Doctrine!
                 }
                 ++$i;
             }



Doctrine 2     www.doctrine-project.org        www.sensiolabs.com
Bulk Delete
• Bulk delete with DQL




       $q = $em->createQuery('delete from MyProjectModelManager m
       where m.salary > 100000');
       $numDeleted = $q->execute();




Doctrine 2     www.doctrine-project.org    www.sensiolabs.com
Bulk Delete
• Just like the bulk updates you can iterate
  over a query to avoid loading everything
  into memory all at once.

             $batchSize = 20;
             $i = 0;
             $q = $em->createQuery('select u from MyProjectModelUser u');
             $iterableResult = $q->iterate();
             while (($row = $iterableResult->next()) !== false) {
                 $em->remove($row[0]);
                 if (($i % $batchSize) == 0) {
                     $em->flush(); // Executes all deletions.
                     $em->clear(); // Detaches all objects from Doctrine!
                 }
                 ++$i;
             }



Doctrine 2        www.doctrine-project.org    www.sensiolabs.com
NativeQuery + ResultSetMapping
• The NativeQuery class is used to execute
  raw SQL queries

• The ResultSetMapping class is used to
  define how to hydrate the results of that
  query




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
NativeQuery + ResultSetMapping
• Here is a simple example
      $rsm = new ResultSetMapping;
      $rsm->addEntityResult('DoctrineTestsModelsCMSCmsUser', 'u');
      $rsm->addFieldResult('u', 'id', 'id');
      $rsm->addFieldResult('u', 'name', 'name');

      $query = $this->_em->createNativeQuery(
          'SELECT id, name FROM cms_users WHERE username = ?',
          $rsm
      );
      $query->setParameter(1, 'romanb');

      $users = $query->getResult();




Doctrine 2     www.doctrine-project.org   www.sensiolabs.com
NativeQuery + ResultSetMapping
• The result of $users would look like


             array(
                 [0] => User (Object)
             )




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
NativeQuery + ResultSetMapping
• This means you will always be able to
  fallback to the power of raw SQL without
  losing the ability to hydrate the data to your
  entities




Doctrine 2   www.doctrine-project.org   www.sensiolabs.com
Questions?
     Jonathan H. Wage
     jonathan.wage@sensio.com
     +1 415 992 5468

     sensiolabs.com | doctrine-project.org | sympalphp.org | jwage.com

         You should follow me on http://www.twitter.com/jwage for updates about Doctrine


      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

Más contenido relacionado

La actualidad más candente

Introduction to the intermediate Python - v1.1
Introduction to the intermediate Python - v1.1Introduction to the intermediate Python - v1.1
Introduction to the intermediate Python - v1.1Andrei KUCHARAVY
 
Modern Java Concurrency (OSCON 2012)
Modern Java Concurrency (OSCON 2012)Modern Java Concurrency (OSCON 2012)
Modern Java Concurrency (OSCON 2012)Martijn Verburg
 
A peek into Python's Metaclass and Bytecode from a Smalltalk User
A peek into Python's Metaclass and Bytecode from a Smalltalk UserA peek into Python's Metaclass and Bytecode from a Smalltalk User
A peek into Python's Metaclass and Bytecode from a Smalltalk UserKoan-Sin Tan
 
Polyglot and Functional Programming (OSCON 2012)
Polyglot and Functional Programming (OSCON 2012)Polyglot and Functional Programming (OSCON 2012)
Polyglot and Functional Programming (OSCON 2012)Martijn Verburg
 
Polyglot and functional (Devoxx Nov/2011)
Polyglot and functional (Devoxx Nov/2011)Polyglot and functional (Devoxx Nov/2011)
Polyglot and functional (Devoxx Nov/2011)Martijn Verburg
 
The State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila SzegediThe State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila SzegediZeroTurnaround
 
Scala Matsuri 2016: Japanese Text Mining with Scala and Spark
Scala Matsuri 2016: Japanese Text Mining with Scala and SparkScala Matsuri 2016: Japanese Text Mining with Scala and Spark
Scala Matsuri 2016: Japanese Text Mining with Scala and SparkEduardo Gonzalez
 
2.4 Optimizing your Visual COBOL Applications
2.4   Optimizing your Visual COBOL Applications2.4   Optimizing your Visual COBOL Applications
2.4 Optimizing your Visual COBOL ApplicationsMicro Focus
 

La actualidad más candente (10)

Introduction to JAVA
Introduction to JAVAIntroduction to JAVA
Introduction to JAVA
 
Introduction to the intermediate Python - v1.1
Introduction to the intermediate Python - v1.1Introduction to the intermediate Python - v1.1
Introduction to the intermediate Python - v1.1
 
Modern Java Concurrency (OSCON 2012)
Modern Java Concurrency (OSCON 2012)Modern Java Concurrency (OSCON 2012)
Modern Java Concurrency (OSCON 2012)
 
A peek into Python's Metaclass and Bytecode from a Smalltalk User
A peek into Python's Metaclass and Bytecode from a Smalltalk UserA peek into Python's Metaclass and Bytecode from a Smalltalk User
A peek into Python's Metaclass and Bytecode from a Smalltalk User
 
Polyglot and Functional Programming (OSCON 2012)
Polyglot and Functional Programming (OSCON 2012)Polyglot and Functional Programming (OSCON 2012)
Polyglot and Functional Programming (OSCON 2012)
 
Polyglot and functional (Devoxx Nov/2011)
Polyglot and functional (Devoxx Nov/2011)Polyglot and functional (Devoxx Nov/2011)
Polyglot and functional (Devoxx Nov/2011)
 
The State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila SzegediThe State of Managed Runtimes 2013, by Attila Szegedi
The State of Managed Runtimes 2013, by Attila Szegedi
 
Threads
ThreadsThreads
Threads
 
Scala Matsuri 2016: Japanese Text Mining with Scala and Spark
Scala Matsuri 2016: Japanese Text Mining with Scala and SparkScala Matsuri 2016: Japanese Text Mining with Scala and Spark
Scala Matsuri 2016: Japanese Text Mining with Scala and Spark
 
2.4 Optimizing your Visual COBOL Applications
2.4   Optimizing your Visual COBOL Applications2.4   Optimizing your Visual COBOL Applications
2.4 Optimizing your Visual COBOL Applications
 

Destacado

Configuracion de mysql
Configuracion de mysqlConfiguracion de mysql
Configuracion de mysqlescorpion2610
 
Configuracion de mysql
Configuracion de mysqlConfiguracion de mysql
Configuracion de mysqlescorpion2610
 
Reflexión y refracción de las ondas esfericas
Reflexión y refracción de las ondas esfericasReflexión y refracción de las ondas esfericas
Reflexión y refracción de las ondas esfericasAngel Cisneros
 
Ondas de radio
Ondas de radioOndas de radio
Ondas de radiodanicangri
 
Ondas de radio satelitales y microondas
Ondas de radio satelitales y microondasOndas de radio satelitales y microondas
Ondas de radio satelitales y microondasingdianabaquero
 
Refracción y difracción de las ondas
Refracción y difracción de las ondasRefracción y difracción de las ondas
Refracción y difracción de las ondasAlma Treviño
 

Destacado (10)

Configuracion de mysql
Configuracion de mysqlConfiguracion de mysql
Configuracion de mysql
 
Doctrine2
Doctrine2Doctrine2
Doctrine2
 
Manual doctrine jog
Manual doctrine jogManual doctrine jog
Manual doctrine jog
 
Configuracion de mysql
Configuracion de mysqlConfiguracion de mysql
Configuracion de mysql
 
Ondas de rádio
Ondas de rádioOndas de rádio
Ondas de rádio
 
Reflexión y refracción de las ondas esfericas
Reflexión y refracción de las ondas esfericasReflexión y refracción de las ondas esfericas
Reflexión y refracción de las ondas esfericas
 
Ondas de radio
Ondas de radioOndas de radio
Ondas de radio
 
Ondas de radio satelitales y microondas
Ondas de radio satelitales y microondasOndas de radio satelitales y microondas
Ondas de radio satelitales y microondas
 
Refracción y difracción de las ondas
Refracción y difracción de las ondasRefracción y difracción de las ondas
Refracción y difracción de las ondas
 
Ensayo
EnsayoEnsayo
Ensayo
 

Similar a Doctrine2 enterpice

Doctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php OrmDoctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php OrmJonathan Wage
 
Docker interview Questions-3.pdf
Docker interview Questions-3.pdfDocker interview Questions-3.pdf
Docker interview Questions-3.pdfYogeshwaran R
 
Docker in the Enterprise
Docker in the EnterpriseDocker in the Enterprise
Docker in the EnterpriseSaul Caganoff
 
Behat bdd training (php) course slides pdf
Behat bdd training (php) course slides pdfBehat bdd training (php) course slides pdf
Behat bdd training (php) course slides pdfseleniumbootcamp
 
Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015
Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015
Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015Jeremy Brown
 
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...Nilesh Panchal
 
Polyglot and Poly-paradigm Programming for Better Agility
Polyglot and Poly-paradigm Programming for Better AgilityPolyglot and Poly-paradigm Programming for Better Agility
Polyglot and Poly-paradigm Programming for Better Agilityelliando dias
 
Lucene Bootcamp - 2
Lucene Bootcamp - 2Lucene Bootcamp - 2
Lucene Bootcamp - 2GokulD
 
Doctrine Php Object Relational Mapper
Doctrine Php Object Relational MapperDoctrine Php Object Relational Mapper
Doctrine Php Object Relational MapperJonathan Wage
 
Stardog 1.1: An Easier, Smarter, Faster RDF Database
Stardog 1.1: An Easier, Smarter, Faster RDF DatabaseStardog 1.1: An Easier, Smarter, Faster RDF Database
Stardog 1.1: An Easier, Smarter, Faster RDF Databasekendallclark
 
Stardog 1.1: Easier, Smarter, Faster RDF Database
Stardog 1.1: Easier, Smarter, Faster RDF DatabaseStardog 1.1: Easier, Smarter, Faster RDF Database
Stardog 1.1: Easier, Smarter, Faster RDF DatabaseClark & Parsia LLC
 
TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...
TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...
TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...TAUS - The Language Data Network
 
Integrating Doctrine with Laravel
Integrating Doctrine with LaravelIntegrating Doctrine with Laravel
Integrating Doctrine with LaravelMark Garratt
 
Improving ad hoc and production workflows at Stitch Fix
Improving ad hoc and production workflows at Stitch FixImproving ad hoc and production workflows at Stitch Fix
Improving ad hoc and production workflows at Stitch FixStitch Fix Algorithms
 
Celery: The Distributed Task Queue
Celery: The Distributed Task QueueCelery: The Distributed Task Queue
Celery: The Distributed Task QueueRichard Leland
 
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)raja kvk
 
kafka simplicity and complexity
kafka simplicity and complexitykafka simplicity and complexity
kafka simplicity and complexityPaolo Platter
 

Similar a Doctrine2 enterpice (20)

Doctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php OrmDoctrine 2 - Not The Same Old Php Orm
Doctrine 2 - Not The Same Old Php Orm
 
Libertyvasion2010
Libertyvasion2010Libertyvasion2010
Libertyvasion2010
 
Docker interview Questions-3.pdf
Docker interview Questions-3.pdfDocker interview Questions-3.pdf
Docker interview Questions-3.pdf
 
Docker in the Enterprise
Docker in the EnterpriseDocker in the Enterprise
Docker in the Enterprise
 
Behat bdd training (php) course slides pdf
Behat bdd training (php) course slides pdfBehat bdd training (php) course slides pdf
Behat bdd training (php) course slides pdf
 
Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015
Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015
Browser Fuzzing with a Twist (and a Shake) -- ZeroNights 2015
 
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
 
Polyglot and Poly-paradigm Programming for Better Agility
Polyglot and Poly-paradigm Programming for Better AgilityPolyglot and Poly-paradigm Programming for Better Agility
Polyglot and Poly-paradigm Programming for Better Agility
 
Lucene Bootcamp - 2
Lucene Bootcamp - 2Lucene Bootcamp - 2
Lucene Bootcamp - 2
 
Doctrine Php Object Relational Mapper
Doctrine Php Object Relational MapperDoctrine Php Object Relational Mapper
Doctrine Php Object Relational Mapper
 
Stardog 1.1: An Easier, Smarter, Faster RDF Database
Stardog 1.1: An Easier, Smarter, Faster RDF DatabaseStardog 1.1: An Easier, Smarter, Faster RDF Database
Stardog 1.1: An Easier, Smarter, Faster RDF Database
 
Stardog 1.1: Easier, Smarter, Faster RDF Database
Stardog 1.1: Easier, Smarter, Faster RDF DatabaseStardog 1.1: Easier, Smarter, Faster RDF Database
Stardog 1.1: Easier, Smarter, Faster RDF Database
 
TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...
TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...
TAUS Moses Industry Roundtable 2014, Changes in Moses, Hieu Hoang, University...
 
Hibernate tutorial
Hibernate tutorialHibernate tutorial
Hibernate tutorial
 
Integrating Doctrine with Laravel
Integrating Doctrine with LaravelIntegrating Doctrine with Laravel
Integrating Doctrine with Laravel
 
Solr 4
Solr 4Solr 4
Solr 4
 
Improving ad hoc and production workflows at Stitch Fix
Improving ad hoc and production workflows at Stitch FixImproving ad hoc and production workflows at Stitch Fix
Improving ad hoc and production workflows at Stitch Fix
 
Celery: The Distributed Task Queue
Celery: The Distributed Task QueueCelery: The Distributed Task Queue
Celery: The Distributed Task Queue
 
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)
Advanced Object Oriented JavaScript (prototype, closure, scope, design patterns)
 
kafka simplicity and complexity
kafka simplicity and complexitykafka simplicity and complexity
kafka simplicity and complexity
 

Doctrine2 enterpice

  • 1. Doctrine 2 Enterprise Persistence Layer for PHP Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 2. What is different in Doctrine 2? Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 3. 100% re-written code Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 4. Requires PHP 5.3 Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 5. New concepts Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 6. New workflow Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 7. Fully Namespaced • Doctrine makes use of PHP 5.3 namespaces. Currently we have the following namespaces: – DoctrineCommon – DoctrineDBAL – DoctrineORM Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 8. Common • Standalone package containing all common code shared between DBAL and ORM – Cache drivers – Annotations Parser – Command Line Interface – Class Loaders – Lexer Parser – ...and other various utilities Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 9. DBAL • Database Abstraction Layer built on top of PDO. – Multiple DBMS supported • MySQL • Sqlite • Pgsql • etc. – Database Introspection – DDL Statment API Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 10. ORM • Object Relational Mapper built on top of Common and DBAL – Inheritance – Doctrine Query Language – XML, YAML or Annotations Metadata – Query Cache – Result Cache – ...much more Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 11. Complete separation of your domain model and persistence layer Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 12. We learned lots building Doctrine 1 and we used that to help us build Doctrine 2 Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 13. Some performance comparisons between Doctrine 1 and 2 Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 14. Performance of Doctrine 1 To hydrate 5000 records in Doctrine 1 it takes roughly 4.3 seconds. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 15. Performance of Doctrine 2 Under Doctrine 2, hydrating those same 5000 records only takes 1.4 seconds. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 16. Performance of Doctrine 2 ...and with 10000 records it still only takes about 3.5 seconds. Twice the data and still faster than Doctrine 1 Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 17. Why is it faster? • PHP 5.3 gives us a huge performance improvement when using a heavily OO framework like Doctrine • Better optimized hydration algorithm • Killed the magical aspect of Doctrine 1 • All around more explicit and less magical code results in better and faster code. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 18. Why kill the magic? • Eliminate the WTF factor of Doctrine 1 Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 19. The Doctrine 1 magical features are both a blessing and a curse Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 20. Blessing and a Curse • Magic is great when it works • The magic you love is also the cause of all the pain you’ve felt with Doctrine 1 • When it doesn’t work it is hard to debug • Edge cases are hard to fix • Edge cases are hard to work around • Edge cases, edge cases, edge cases • Everything is okay until you try and go outside the box the magic provides • ...magic is slow Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 21. How will we replace the magic? This new thing called OOP :) • Object Composition • Inheritance • Aggregation • Containment • Encapsulation • ...etc Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 22. Will Doctrine 2 have behaviors? Yes and No Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 23. The No • We won’t have any concept of “model behaviors” • Behaviors were a made up concept for Doctrine 1 to work with its extremely intrusive architecture. • It tries to do things that PHP does not allow and is the result of lots of problems in Doctrine 1 Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 24. The Yes • Everything you can do in Doctrine 1 you can do in Doctrine 2, just in a different way. • “Behavior” like functionality will be bundled as extensions for Doctrine 2 and will just contain normal OO PHP code that wraps/ extends Doctrine code or is meant to be wrapped or extended by your entities. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 25. What did we use to build Doctrine 2? Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 26. Doctrine 2 Tool Belt • phpUnit 3.4.10 - Unit Testing • Phing - Packaging and Distribution • Symfony YAML Component • Sismo - Continuous Integration • Subversion - Source Control • Jira - Issue Tracking and Management • Trac - Subversion Timeline, Source Code Browser, Changeset Viewer Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 27. Doctrine 2 Architecture • Entities • Lightweight persistent domain object • Regular PHP class • Does not extend any base Doctrine class • Cannot be final or contain final methods • Any two entities in a hierarchy of classes must not have a mapped property with the same name • Supports inheritance, polymorphic associations and polymorphic queries. • Both abstract and concrete classes can be entities • Entities may extend non-entity classes as well as entity classes, and non-entity classes may extend entity classes Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 28. Doctrine 2 Architecture • Your entities in Doctrine 2 don’t require that you extend a base class like in Doctrine 1! No more imposing on your domain model! namespace Entities; class User { private $id; private $name; private $address; } Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 29. Doctrine 2 Architecture • The EntityManager • Central access point to the ORM functionality provided by Doctrine 2. API is used to manage the persistence of your objects and to query for persistent objects. • Employes transactional write behind strategy that delays the execution of SQL statements in order to execute them in the most efficient way • Execute at end of transaction so that all write locks are quickly releases • Internally an EntityManager uses a UnitOfWork to keep track of your objects Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 30. Unit Testing • Tests are ran against multiple DBMS types. This is something that was not possible with the Doctrine 1 test suite. • ...Sqlite • ...MySQL • ...Oracle • ...PgSQL • ...more to come Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 31. Unit Testing • 859 Test Cases • 2152 Assertions • Tests run in a few seconds compared to 30-40 seconds for Doctrine 1 • Much more granular and explicit unit tests • Easier to debug failed tests • Continuously integrated by Sismo :) Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 32. Database Abstraction Layer • Separate standalone package and namespace (DoctrineDBAL). • Can be used standalone. • Much improved over Doctrine 1 in regards to the API for database introspection and schema management. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 33. Database Abstraction Layer • Hopefully Doctrine 2 DBAL can be the defacto standard DBAL for PHP 5.3 in the future like MDB and MDB2 were in PEAR • Maybe we can make this happen for PEAR2? Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 34. DBAL Data API • prepare($sql) - Prepare a given sql statement and return the DoctrineDBAL DriverStatement instance. • executeUpdate($sql, array $params) - Executes a prepared statement with the given sql and parameters and returns the affected rows count. • execute($sql, array $params) - Creates a prepared statement for the given sql and passes the parameters to the execute method, then returning the statement. • fetchAll($sql, array $params) - Execute the query and fetch all results into an array. • fetchArray($sql, array $params) - Numeric index retrieval of first result row of the given query. • fetchBoth($sql, array $params) - Both numeric and assoc column name retrieval of the first result row. • fetchColumn($sql, array $params, $colnum) - Retrieve only the given column of the first result row. • fetchRow($sql, array $params) - Retrieve assoc row of the first result row. • select($sql, $limit, $offset) - Modify the given query with a limit clause. • delete($tableName, array $identifier) - Delete all rows of a table matching the given identifier, where keys are column names. • insert($tableName, array $data) - Insert a row into the given table name using the Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 35. DBAL Introspection API • listDatabases() • listFunctions() • listSequences() • listTableColumns($tableName) • listTableConstraints($tableName) • listTableDetails($tableName) • listTableForeignKeys($tableName) • listTableIndexes($tableName) • listTables() Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 36. DBAL Schema Representation $platform = $em->getConnection()->getDatabasePlatform(); $schema = new DoctrineDBALSchemaSchema(); $myTable = $schema->createTable("my_table"); $myTable->addColumn("id", "integer", array("unsigned" => true)); $myTable->addColumn("username", "string", array("length" => 32)); $myTable->setPrimaryKey(array("id")); // get queries to create this schema. $queries = $schema->toSql($platform); Array ( [0] => CREATE TABLE my_table (id INTEGER NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY("id")) ) Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 37. DBAL Schema Representation // ...... // get queries to safely delete this schema. $dropSchema = $schema->toDropSql($platform); Array ( [0] => DROP TABLE my_table ) Does the reverse of what toSql() does, dropping the created tables Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 38. Comparing Schemas • Lets take our original my_table schema as our “from schema”... $fromSchema = new DoctrineDBALSchemaSchema(); $myTable = $fromSchema->createTable("my_table"); $myTable->addColumn("id", "integer", array("unsigned" => true)); $myTable->addColumn("username", "string", array("length" => 32)); $myTable->setPrimaryKey(array("id")); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 39. Compare DBAL Schemas • Then later you want to add a new column to the schema and easily deploy the change. • Lets add an email column to the table: $toSchema = new DoctrineDBALSchemaSchema(); $myTable = $toSchema->createTable("my_table"); $myTable->addColumn("id", "integer", array("unsigned" => true)); $myTable->addColumn("username", "string", array("length" => 32)); $myTable->addColumn("email", "string", array("length" => 255)); $myTable->setPrimaryKey(array("id")); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 40. Compare DBAL Schemas • You can easily compare one schema to another to deploy the changes! $comparator = new DoctrineDBALSchemaComparator(); $schemaDiff = $comparator->compare($fromSchema, $toSchema); // queries to get from one to another schema. $queries = $schemaDiff->toSql($platform); print_r($queries); Array ( [0] => ALTER TABLE my_table ADD email VARCHAR(255) NOT NULL ) Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 41. Annotations <?php namespace Entities; /** * @Entity @Table(name="users") */ class User { /** @Id @Column(type="integer") @GeneratedValue */ private $id; /** @Column(length=50) */ private $name; /** @OneToOne(targetEntity="Address") */ private $address; } Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 42. Things to Notice • Entities no longer require you to extend a base class • Your domain model has absolutely no magic • Not imposed on by Doctrine and is defined by raw PHP objects and normal OO programming Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 43. YAML EntitiesAddress: type: entity table: addresses id: id: type: integer generator: strategy: AUTO fields: street: type: string length: 255 oneToOne: user: targetEntity: User mappedBy: address Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 44. XML <?xml version="1.0" encoding="UTF-8"?> <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> <entity name="EntitiesUser" table="users"> <id name="id" type="integer"> <generator strategy="AUTO"/> </id> <field name="name" type="string" length="50"/> <one-to-one field="address" target-entity="Address"> <join-column name="address_id" referenced-column-name="id"/> </one-to-one> </entity> </doctrine-mapping> Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 45. Setup • PHP “use” all necessary namespaces and classes use DoctrineCommonClassLoader, DoctrineORMConfiguration, DoctrineORMEntityManager, DoctrineCommonCacheApcCache, EntitiesUser, EntitiesAddress; Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 46. Setup • Require the Doctrine ClassLoader require '/path/to/doctrine/lib/Doctrine/Common/ClassLoader.php'; Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 47. Setup • Setup autoloading for Doctrine classes • ...core classes • ...entity classes • ...proxy classes $doctrineClassLoader = new ClassLoader('Doctrine', '/path/to/doctrine'); $doctrineClassLoader->register(); $entitiesClassLoader = new ClassLoader('Entities', '/path/to/entities'); $entitiesClassLoader->register(); $proxiesClassLoader = new ClassLoader('Proxies', '/path/to/proxies'); $proxiesClassLoader->register(); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 48. Setup • Configure your Doctrine implementation // Set up caches $config = new Configuration; $cache = new ApcCache; $config->setMetadataCacheImpl($cache); $config->setQueryCacheImpl($cache); // Proxy configuration $config->setProxyDir('/path/to/proxies/Proxies'); $config->setProxyNamespace('Proxies'); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 49. Setup • Create your database connection and entity manager // Database connection information $connectionOptions = array( 'driver' => 'pdo_sqlite', 'path' => 'database.sqlite' ); // Create EntityManager $em = EntityManager::create($connectionOptions, $config); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 50. Setup • In production you would lazily load the EntityManager • Example: $em = function() { static $em; if (!$em) { $em = EntityManager::create($connectionOptions, $config); } return $em; } • In the real world I wouldn’t recommend that you use the above example • Symfony DI would take care of this for us Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 51. use DoctrineCommonClassLoader, DoctrineORMConfiguration, DoctrineORMEntityManager, DoctrineCommonCacheApcCache, EntitiesUser, EntitiesAddress; require '/path/to/doctrine/lib/Doctrine/Common/ClassLoader.php'; $doctrineClassLoader = new ClassLoader('Doctrine', '/path/to/doctrine'); $doctrineClassLoader->register(); $entitiesClassLoader = new ClassLoader('Entities', '/path/to/entities'); $entitiesClassLoader->register(); $proxiesClassLoader = new ClassLoader('Proxies', '/path/to/proxies'); $proxiesClassLoader->register(); // Set up caches $config = new Configuration; $cache = new ApcCache; $config->setMetadataCacheImpl($cache); $config->setQueryCacheImpl($cache); // Proxy configuration $config->setProxyDir('/path/to/proxies/Proxies'); $config->setProxyNamespace('Proxies'); // Database connection information $connectionOptions = array( 'driver' => 'pdo_sqlite', 'path' => 'database.sqlite' ); // Create EntityManager $em = EntityManager::create($connectionOptions, $config); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 52. Setup • Now you can start using your models and persisting entities $user = new User; $user->setName('Jonathan H. Wage'); $em->persist($user); $em->flush(); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 53. Insert Performance • Inserting 20 records with Doctrine for ($i = 0; $i < 20; ++$i) { $user = new User; $user->name = 'Jonathan H. Wage'; $em->persist($user); } $s = microtime(true); $em->flush(); $e = microtime(true); echo $e - $s; Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 54. Insert Performance • Compare it to some raw PHP code $s = microtime(true); for ($i = 0; $i < 20; ++$i) { mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')", $link); } $e = microtime(true); echo $e - $s; Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 55. Insert Performance • The results might be surprising to you. Which do you think is faster? Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 56. Insert Performance Doctrine 2 0.0094 seconds mysql_query 0.0165 seconds Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 57. Insert Performance • Doctrine 2 is faster than some raw PHP code? What?!?!?! HUH? • It does a lot less, provides no features, no abstraction, etc. • Why? The answer is transactions! Doctrine 2 manages our transactions for us and efficiently executes all inserts in a single. The raw PHP code executes 1 transaction for each insert. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 58. Insert Performance • Doctrine 2 is not faster than some raw PHP code • The example demonstrates that simple developer oversights and can cause significant performance problems Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 59. Insert Performance • Here is the same raw PHP code re-visited with proper transaction usage. $s = microtime(true); mysql_query('START TRANSACTION', $link); for ($i = 0; $i < 20; ++$i) { mysql_query("INSERT INTO users (name) VALUES ('Jonathan H. Wage')", $link); } mysql_query('COMMIT', $link); $e = microtime(true); echo $e - $s; Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 60. Insert Performance • This time around it only takes 0.0028 seconds compared to the previous 0.0165 seconds. That’s a pretty huge improvement! • You can read more about this on the Doctrine Blog http://www.doctrine-project.org/blog/transactions-and-performance Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 61. Doctrine Query Language • DQL parser completely re-written from scratch • ...DQL is parsed by a top down recursive descent parser that constructs an AST (abstract syntax tree). • ...The AST is used to generate the SQL to execute for your DBMS http://www.doctrine-project.org/documentation/manual/2_0/en/dql-doctrine-query-language Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 62. Doctrine Query Language • Here is an example DQL query $q = $em->createQuery('select u from MyProjectEntitiesUser u'); $users = $q->execute(); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 63. Doctrine Query Language • Here is that same DQL query using the QueryBuilder API $qb = $em->createQueryBuilder() ->select('u') ->from('MyProjectEntitiesUser', 'u'); $q = $qb->getQuery(); $users = $q->execute(); http://www.doctrine-project.org/documentation/manual/2_0/en/query-builder Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 64. Doctrine Query Builder • QueryBuilder API is the same as Doctrine_Query API in Doctrine 1 • Query building and query execution are separated • True builder pattern used • QueryBuilder is used to build instances of Query • You don’t execute a QueryBuilder, you get the built Query instance from the QueryBuilder and execute it Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 65. Cache Drivers • Public interface of all cache drivers • fetch($id) - Fetches an entry from the cache. • contains($id) - Test if an entry exists in the cache. • save($id, $data, $lifeTime = false) - Puts data into the cache. • delete($id) - Deletes a cache entry. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 66. Cache Drivers • Wrap existing Symfony, ZF, etc. cache driver instances with the Doctrine interface Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 67. Cache Drivers • deleteByRegex($regex) - Deletes cache entries where the key matches a regular expression • deleteByPrefix($prefix) - Deletes cache entries where the key matches a prefix. • deleteBySuffix($suffix) - Deletes cache entries where the key matches a suffix. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 68. Cache Drivers • Each driver extends the AbstractCache class which defines a few abstract protected methods that each of the drivers must implement to do the actual work • _doFetch($id) • _doContains($id) • _doSave($id, $data, $lifeTime = false) • _doDelete($id) Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 69. APC Cache Driver • To use the APC cache driver you must have it compiled and enabled in your php.ini $cacheDriver = new DoctrineCommonCacheApcCache(); $cacheDriver->save('cache_id', 'my_data'); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 70. Memcache Cache Driver • To use the memcache cache driver you must have it compiled and enabled in your php.ini $memcache = new Memcache(); $memcache->connect('memcache_host', 11211); $cacheDriver = new DoctrineCommonCacheMemcacheCache(); $cacheDriver->setMemcache($memcache); $cacheDriver->save('cache_id', 'my_data'); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 71. Xcache Cache Driver • To use the xcache cache driver you must have it compiled and enabled in your php.ini $cacheDriver = new DoctrineCommonCacheXcacheCache(); $cacheDriver->save('cache_id', 'my_data'); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 72. Result Cache • First you need to configure the result cache $cacheDriver = new DoctrineCommonCacheApcCache(); $config->setResultCacheImpl($cacheDriver); • Then you can configure each query to use the result cache or not. $query = $em->createQuery('select u from EntitiesUser u'); $query->useResultCache(true, 3600, 'my_query_name'); • Executing this query the first time would populate a cache entry in $cacheDriver named my_query_name Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 73. Result Cache • Now you can clear the cache for that query by using the delete() method of the cache driver $cacheDriver->delete('my_query_name'); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 74. Command Line Interface • Re-written command line interface to help developing with Doctrine Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 75. dbal:run-sql • Execute a manually written SQL statement • Execute multiple SQL statements from a file Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 76. orm:clear-cache • Clear all query, result and metadata cache • Clear only query cache • Clear only result cache • Clear only metadata cache • Clear a single queries result cache • Clear keys that match regular expression • Clear keys that match a prefix • Clear keys that match a suffix Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 77. orm:convert-mapping • Convert metadata information between formats • Convert metadata information from an existing database to any supported format (yml, xml, annotations, etc.) • Convert mapping information from xml to yml or vice versa • Generate PHP classes from mapping information with mutators and accessors Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 78. orm:ensure-production-settings • Verify that Doctrine is properly configured for a production environment. • Throws an exception when environment does not meet the production requirements Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 79. orm:generate-proxies • Generate the proxy classes for entity classes. • A proxy object is an object that is put in place or used instead of the "real" object. A proxy object can add behavior to the object being proxied without that object being aware of it. In Doctrine 2, proxy objects are used to realize several features but mainly for transparent lazy-loading. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 80. orm:run-dql • Execute a DQL query from the command line Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 81. orm:schema-tool • Drop, create and update your database schema. • --create option creates the initial tables for your schema • --drop option drops the the tables for your schema • --update option compares your local schema information to the database and updates it accordingly Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 82. Inheritance • Doctrine 2 fully supports inheritance. We allow the following types of inheritance: • ...Mapped Superclasses • ...Single Table Inheritance • ...Class Table Inheritance Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 83. Mapped Superclasses /** @MappedSuperclass */ class MappedSuperclassBase { /** @Column(type="integer") */ private $mapped1; /** @Column(type="string") */ private $mapped2; /** * @OneToOne(targetEntity="MappedSuperclassRelated1") * @JoinColumn(name="related1_id", referencedColumnName="id") */ private $mappedRelated1; // ... more fields and methods } /** @Entity */ class EntitySubClass extends MappedSuperclassBase { /** @Id @Column(type="integer") */ private $id; /** @Column(type="string") */ private $name; // ... more fields and methods } Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 84. Mapped Superclasses CREATE TABLE EntitySubClass (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related1_id INTEGER DEFAULT NULL, PRIMARY KEY(id)) http://www.doctrine-project.org/documentation/manual/2_0/en/inheritance-mapping#mapped-superclasses Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 85. Single Table Inheritance /** * @Entity * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"}) */ class Person { // ... } /** * @Entity */ class Employee extends Person { // ... } Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 86. Single Table Inheritance • All entities share one table. • To distinguish which row represents which type in the hierarchy a so-called discriminator column is used. http://www.doctrine-project.org/documentation/manual/2_0/en/inheritance-mapping#single-table-inheritance Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 87. Class Table Inheritance namespace MyProjectModel; /** * @Entity * @InheritanceType("JOINED") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({"person" = "Person", "employee" = "Employee"}) */ class Person { // ... } /** @Entity */ class Employee extends Person { // ... } http://www.doctrine-project.org/documentation/manual/2_0/en/inheritance-mapping#single-table-inheritance Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 88. Class Table Inheritance • Each class in a hierarchy is mapped to several tables: its own table and the tables of all parent classes. • The table of a child class is linked to the table of a parent class through a foreign key constraint. • A discriminator column is used in the topmost table of the hierarchy because this is the easiest way to achieve polymorphic queries. Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 89. Batch Processing • Doctrine 2 offers the ability to do some batch processing by taking advantage of the transactional write-behind behavior of an EntityManager Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 90. Bulk Inserts • Insert 10000 objects with a batch size of 20 $batchSize = 20; for ($i = 1; $i <= 10000; ++$i) { $user = new CmsUser; $user->setStatus('user'); $user->setUsername('user' . $i); $user->setName('Mr.Smith-' . $i); $em->persist($user); if ($i % $batchSize == 0) { $em->flush(); $em->clear(); // Detaches all objects from Doctrine! } } Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 91. Bulk Update • Bulk update with DQL $q = $em->createQuery('update MyProjectModelManager m set m.salary = m.salary * 0.9'); $numUpdated = $q->execute(); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 92. Bulk Update • Bulk update by iterating over the results using the Query::iterate() method to avoid loading everything into memory at once $batchSize = 20; $i = 0; $q = $em->createQuery('select u from MyProjectModelUser u'); $iterableResult = $q->iterate(); foreach($iterableResult AS $row) { $user = $row[0]; $user->increaseCredit(); $user->calculateNewBonuses(); if (($i % $batchSize) == 0) { $em->flush(); // Executes all updates. $em->clear(); // Detaches all objects from Doctrine! } ++$i; } Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 93. Bulk Delete • Bulk delete with DQL $q = $em->createQuery('delete from MyProjectModelManager m where m.salary > 100000'); $numDeleted = $q->execute(); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 94. Bulk Delete • Just like the bulk updates you can iterate over a query to avoid loading everything into memory all at once. $batchSize = 20; $i = 0; $q = $em->createQuery('select u from MyProjectModelUser u'); $iterableResult = $q->iterate(); while (($row = $iterableResult->next()) !== false) { $em->remove($row[0]); if (($i % $batchSize) == 0) { $em->flush(); // Executes all deletions. $em->clear(); // Detaches all objects from Doctrine! } ++$i; } Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 95. NativeQuery + ResultSetMapping • The NativeQuery class is used to execute raw SQL queries • The ResultSetMapping class is used to define how to hydrate the results of that query Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 96. NativeQuery + ResultSetMapping • Here is a simple example $rsm = new ResultSetMapping; $rsm->addEntityResult('DoctrineTestsModelsCMSCmsUser', 'u'); $rsm->addFieldResult('u', 'id', 'id'); $rsm->addFieldResult('u', 'name', 'name'); $query = $this->_em->createNativeQuery( 'SELECT id, name FROM cms_users WHERE username = ?', $rsm ); $query->setParameter(1, 'romanb'); $users = $query->getResult(); Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 97. NativeQuery + ResultSetMapping • The result of $users would look like array( [0] => User (Object) ) Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 98. NativeQuery + ResultSetMapping • This means you will always be able to fallback to the power of raw SQL without losing the ability to hydrate the data to your entities Doctrine 2 www.doctrine-project.org www.sensiolabs.com
  • 99. Questions? Jonathan H. Wage jonathan.wage@sensio.com +1 415 992 5468 sensiolabs.com | doctrine-project.org | sympalphp.org | jwage.com You should follow me on http://www.twitter.com/jwage for updates about Doctrine 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