Guilherme Blanco, Yahoo!


           Doctrine 2
           Enterprise Persistence Layer for PHP




quarta-feira, 2 de ju...
Who am I?
         10+ years web developer

         Open Source evangelist

         Works for Yahoo!

         Contr...
Who am I?
         http://www.twitter.com/guilhermeblanco

         http://www.facebook.com/guilhermeblanco




quarta-f...
Doctrine 2



quarta-feira, 2 de junho de 2010
Doctrine 2
         PHP 5.3+

         100% code rewritten

         Fully namespaced code




quarta-feira, 2 de junho...
Doctrine 2
         Tools used:
             phpUnit  Unit testing
             Phing Packaging and distribution
      ...
Doctrine 2
         Three main packages:
             Common


             DBAL


             ORM




quarta-feira, ...
DoctrineCommon
     git@github.com:doctrine/common.git

         Cache Drivers




quarta-feira, 2 de junho de 2010
DoctrineCommonCache
         Supported Drivers:
             APCCache
     $cacheDriver = new DoctrineCommonCacheApcCach...
DoctrineCommonCache
         Cache Drivers Interface:
     interface DoctrineCommonCacheCache {
       function setNamesp...
DoctrineCommon
     git@github.com:doctrine/common.git

         Cache Drivers

         Class Loader




quarta-feira, ...
DoctrineCommonClassLoader
         Implements PSR #0
             PSR        = PHP Standards Recommendation

           ...
DoctrineCommonClassLoader
        Usage:

     require_once '/path/to/lib/Doctrine/Common/ClassLoader.php';

     $doctri...
DoctrineCommon
     git@github.com:doctrine/common.git

         Cache Drivers

         Class Loader

         Collect...
DoctrineCommonCollections
         Solution inspired in java.util.Collection interface

         Plain PHP arrays are ha...
DoctrineCommon
     git@github.com:doctrine/common.git

         Cache Drivers

         Class Loader

         Collect...
DoctrineCommonAnnotations
         Java like Annotations

         Define metadata information in classes

         Reu...
DoctrineCommonAnnotations
     Annotations                   ::=   Annotation {[ "*" ]* [Annotation]}*
     Annotation    ...
DoctrineCommonAnnotations
         Creating Annotations classes:
     final class DoctrineORMMappingEntity
         exten...
DoctrineCommonAnnotations
         Reading Annotations:
     $reader = new DoctrineCommonAnnotationsAnnotationReader(
   ...
DoctrineCommonAnnotations
     interface DoctrineCommonAnnotationsAnnotationReader {
       function setDefaultAnnotationN...
DoctrineDBAL
     git@github.com:doctrine/dbal.git

         Database Abstraction Layer built at the top of PDO and
     ...
DoctrineDBAL
         Improved API for Database introspection and
          schema management

         Hopefully it can...
DoctrineDBAL
     interface DoctrineDBALConnection {
       // Data manipulation API

         /* Executes an SQL DELETE s...
DoctrineDBAL
         // Transaction API

         /* Returns the current transaction nesting level. */
         function ...
DoctrineDBAL
         // Data fetching API

         /* Executes a SQL query and returns first row as an assoc array. */
 ...
DoctrineDBALTypes
         Centralized point to convert values
             From Database to PHP
             From PHP ...
DoctrineDBALTypes
         New DataType is just implement an abstract class:
    interface DoctrineDBALTypesType {
      ...
DoctrineDBAL
     class MyProjectDataTypesMyObjectType extends DoctrineDBALTypesType
     {
       public function getSqlD...
DoctrineDBALTypes
         Finally, make Doctrine know about your DataType:
    DoctrineDBALTypesType::addType(
        "...
DoctrineDBAL
         Creating a schema:
    $platform = $em->getConnection()->getDatabasePlatform();

    $schema = new ...
DoctrineDBAL
         Deleting a schema:
    // get queries to safely delete the schema.
    $queries = $schema->toDropSq...
DoctrineDBAL
         Comparing schemas:
    $platform = $em->getConnection()->getDatabasePlatform();

    $fromSchema = ...
DoctrineDBAL
        Comparing schemas:
    $platform = $em->getConnection()->getDatabasePlatform();

    $toSchema = new...
DoctrineDBAL
         Comparing schemas:
    $platform = $em->getConnection()->getDatabasePlatform();

    $comparator = ...
Insert Performance
         Inserting 20 entries with Doctrine 2:
    for ($i = 0; $i < 20; $i++) {
        $user = new U...
Insert Performance
         Inserting 20 entries with raw PHP code:
    $start = microtime(0);

    for ($i = 0; $i < 20;...
Insert Performance
         We are not kidding here! =P
          Which one do you think it is faster?
             Doct...
Insert Performance
         Doctrine 2 *IS NOT* faster than raw PHP code

         Simple developers oversights can caus...
Insert Performance
         Inserting 20 entries with raw PHP code (revisited):
    $start = microtime(0);

    mysql_que...
Insert Performance
         Final performance information...
             Doctrine             2
                     T...
DoctrineORM
         What have we learned from Doctrine 1?
             Persistence Layer != Domain Model
             ...
DoctrineORM
         Performance comparison
             Hydrating            5000 records
                   Doctrine ...
DoctrineORM
         Why is it faster?
             PHP        5.3 optimizations!
                   30% less resources...
DoctrineORM
         Why kill magic?
             Eliminate            the WTF/minute (WTF factor)

             Hard t...
DoctrineORM
         How we kill magic?
             We       call it OOP!

             Object Composition
           ...
DoctrineORM
         DataMapper instead of ActiveRecord

         Heavily inspired by JSR-317, a.k.a. JPA v2.0

       ...
DoctrineORM
         Entities
             Regular  PHP class
             Lightweight persistent domain object
       ...
DoctrineORM
     namespace Entity;

     /**
      * @Entity
      * @Table(name="users")
      */
     class User {
     ...
DoctrineORM
    EntityUser:
      type: entity
      table: users
      id:
        id:
          type: integer
          ...
DoctrineORM
    <?xml version="1.0" encoding="UTF-8"?>
    <doctrine-mapping
       xmlns="http://doctrine-project.org/sch...
DoctrineORM
        Column mapping
             type
             length
             scale, precision
             n...
DoctrineORM
        Identifier fields
             Supports             different strategies:
                   AUTO
 ...
DoctrineORM
        Association fields
               OneToOne
    /** @OneToOne(targetEntity="Shipping") */
    private...
DoctrineORM
         Inheritance
             Concrete             Table Inheritance
                   No irrelevant c...
DoctrineORM
     /** @MappedSuperclass */
     class MappedSuperclassBase {
         /** @Column(type="string") */
       ...
DoctrineORM
     CREATE TABLE users (
         mapped TEXT NOT NULL,
         id INTEGER NOT NULL,
         name TEXT NOT ...
DoctrineORM
         Inheritance
             Single         Table Inheritance
                   Only one table on dat...
DoctrineORM
     namespace MyProjectEntity;

     /**
       * @Entity
       * @InheritanceType("SINGLE_TABLE")
       * ...
DoctrineORM
         Inheritance
             Class        Table Inheritance
                   Easy to understand
    ...
DoctrineORM
     namespace MyProjectEntity;

     /**
       * @Entity
       * @InheritanceType("JOINED")
       * @Discr...
DoctrineORM
         Proxies
             Lazy-load Entity data
             Provide the possibility to get an Entity r...
DoctrineORM
         EntityManager
             Central  point of ORM functionality
             Employes Transaction W...
DoctrineORM
     interface DoctrineORMEntityManager {
         // Transaction API

            /* Starts a transaction on ...
DoctrineORM
            // Query API

            /* Creates a new Query object. */
            function createQuery($dql)...
DoctrineORM
            // Object Manipulation API

            /* Tells EntityManager to make instance managed and persis...
DoctrineORM
            // Repository, Configuration, EventManager, etc

            /* Gets the EventManager used by the ...
DoctrineORM
        Working with Entities in EntityManager
               Creating an EntityManager
    $config = new Do...
DoctrineORM
        Working with Entities in EntityManager
               Persisting Entities
    try {
        $em->tra...
DoctrineORM
        Working with Entities in EntityManager
               Updating Entities
    try {
        $em->trans...
DoctrineORM
        Working with Entities in EntityManager
               Deleting Entities
    try {
        $em->trans...
DoctrineORM
         Doctrine Query Language (DQL)
             Implementation   of an OQL
             Heavily influen...
DoctrineORM
         Native Query
             Allow   you the possibility to fallback to the power of
                S...
DoctrineORM
         QueryBuilder
             Builder implementation
             Building and execution are separated...
DoctrineORM
         Doctrine supports different cache levels
             Metadata             cache
    $config->setMe...
DoctrineORM
         Console
             Uses Symfony 2 Console component
             Help developing with Doctrine
 ...
DoctrineORM
         Available Commands:
               DoctrineDBALToolsConsoleCommandRunSqlCommand
               Doc...
Future
         DBAL
             QueryBuilder
             Finish MSSQL Server driver



         DQL
             S...
Questions?
         Guilherme Blanco
             Contact              Info:

                     @guilhermeblanco

  ...
Upcoming SlideShare
Loading in...5
×

IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

6,262

Published on

Talk given at IPC 2010 Spring Edition at Berlim, Germany

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,262
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
54
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

  1. 1. Guilherme Blanco, Yahoo! Doctrine 2 Enterprise Persistence Layer for PHP quarta-feira, 2 de junho de 2010
  2. 2. Who am I?  10+ years web developer  Open Source evangelist  Works for Yahoo!  Contributes to...  ...Doctrine  ...Zend Framework  ...Symfony  ...PHP  etc  Likes to sing and also fish on spare time! =) quarta-feira, 2 de junho de 2010
  3. 3. Who am I?  http://www.twitter.com/guilhermeblanco  http://www.facebook.com/guilhermeblanco quarta-feira, 2 de junho de 2010
  4. 4. Doctrine 2 quarta-feira, 2 de junho de 2010
  5. 5. Doctrine 2  PHP 5.3+  100% code rewritten  Fully namespaced code quarta-feira, 2 de junho de 2010
  6. 6. Doctrine 2  Tools used:  phpUnit Unit testing  Phing Packaging and distribution  Symfony Components  YAML  Console  Sismo Continuous Integration  GIT Source version control  JIRA Issue tracking and management  Trac Timeline, source code & changeset viewer quarta-feira, 2 de junho de 2010
  7. 7. Doctrine 2  Three main packages:  Common  DBAL  ORM quarta-feira, 2 de junho de 2010
  8. 8. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers quarta-feira, 2 de junho de 2010
  9. 9. DoctrineCommonCache  Supported Drivers:  APCCache $cacheDriver = new DoctrineCommonCacheApcCache();  MemcacheCache $memcache = new Memcache(); $memcache->addServer('memcache_host', 11211); $cacheDriver = new DoctrineCommonCacheMemcacheCache(); $cacheDriver->setMemcache($memcache);  XcacheCache $cacheDriver = new DoctrineCommonCacheXcacheCache(); quarta-feira, 2 de junho de 2010
  10. 10. DoctrineCommonCache  Cache Drivers Interface: interface DoctrineCommonCacheCache { function setNamespace($namespace); function getIds(); function fetch($id); function contains($id); function save($id, $data, $lifeTime = 0); function delete($id); function deleteAll(); function deleteByRegex($regex); function deleteByPrefix($prefix); function deleteBySuffix($suffix); } quarta-feira, 2 de junho de 2010
  11. 11. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader quarta-feira, 2 de junho de 2010
  12. 12. DoctrineCommonClassLoader  Implements PSR #0  PSR = PHP Standards Recommendation  Technical Interoperability between libraries  Symfony, Zend Framework, Doctrine, Agavi, PEAR2/Pyrus, Lithium, Flow3, Solar, etc  Possible merge in PHP core: SplClassLoader  http://wiki.php.net/rfc/splclassloader quarta-feira, 2 de junho de 2010
  13. 13. DoctrineCommonClassLoader  Usage: require_once '/path/to/lib/Doctrine/Common/ClassLoader.php'; $doctrineClassLoader = new DoctrineCommonClassLoader( 'Doctrine', '/path/to/lib/Doctrine' ); $doctrineClassLoader->register(); quarta-feira, 2 de junho de 2010
  14. 14. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections quarta-feira, 2 de junho de 2010
  15. 15. DoctrineCommonCollections  Solution inspired in java.util.Collection interface  Plain PHP arrays are hard to manipulate  ..but custom array implementations are not compatible with array_* functions  Heavily usage of Closures  User-land SplArray  Where are the PHP devs? quarta-feira, 2 de junho de 2010
  16. 16. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections  Lexer  Annotations Parser quarta-feira, 2 de junho de 2010
  17. 17. DoctrineCommonAnnotations  Java like Annotations  Define metadata information in classes  Reusable and highly extendable  Suppress missing PHP functionality  Again, where are the PHP devs?  RFC already written: http://wiki.php.net/rfc/annotations quarta-feira, 2 de junho de 2010
  18. 18. DoctrineCommonAnnotations Annotations ::= Annotation {[ "*" ]* [Annotation]}* Annotation ::= "@" AnnotationName ["(" [Values] ")"] AnnotationName ::= QualifiedName | SimpleName | AliasedName QualifiedName ::= NameSpacePart "" {NameSpacePart ""}* SimpleName AliasedName ::= Alias ":" SimpleName NameSpacePart ::= identifier SimpleName ::= identifier Alias ::= identifier Values ::= Array | Value {"," Value}* Value ::= PlainValue | FieldAssignment PlainValue ::= integer | string | float | boolean | Array | Annotation FieldAssignment ::= FieldName "=" PlainValue FieldName ::= identifier Array ::= "{" ArrayEntry {"," ArrayEntry}* "}" ArrayEntry ::= Value | KeyValuePair KeyValuePair ::= Key "=" PlainValue Key ::= string | integer quarta-feira, 2 de junho de 2010
  19. 19. DoctrineCommonAnnotations  Creating Annotations classes: final class DoctrineORMMappingEntity extends DoctrineCommonAnnotationsAnnotation { public $repositoryClass; }  Using Annotations: namespace MyProjectEntity; /** * @Entity(repositoryClass="RepositoryUserRepository") */ class User { // ... } quarta-feira, 2 de junho de 2010
  20. 20. DoctrineCommonAnnotations  Reading Annotations: $reader = new DoctrineCommonAnnotationsAnnotationReader( new DoctrineCommonCacheArrayCache() ); $reader->setDefaultAnnotationNamespace( 'DoctrineORMMapping' ); $class = new ReflectionClass('MyProjectEntityUser'); $classAnnotations = $reader->getClassAnnotations($class); echo $classAnnotations['DoctrineORMMappingEntity'] ->repositoryClass; quarta-feira, 2 de junho de 2010
  21. 21. DoctrineCommonAnnotations interface DoctrineCommonAnnotationsAnnotationReader { function setDefaultAnnotationNamespace($defaultNamespace); function setAnnotationNamespaceAlias($namespace, $alias); function getClassAnnotations(ReflectionClass $class); function getClassAnnotation(ReflectionClass $class, $annot); function getPropertyAnnotations(ReflectionProperty $property); function getPropertyAnnotation( ReflectionProperty $property, $annot ); function getMethodAnnotations(ReflectionMethod $method); function getMethodAnnotation(ReflectionMethod $method, $annot); } quarta-feira, 2 de junho de 2010
  22. 22. DoctrineDBAL git@github.com:doctrine/dbal.git  Database Abstraction Layer built at the top of PDO and proprietary drivers  Supported drivers:  DB2  Microsoft SQL Server (pdo_sqlsrv & sqlsrv)  MySQL  PostgreSQL  Oracle  SQLite quarta-feira, 2 de junho de 2010
  23. 23. DoctrineDBAL  Improved API for Database introspection and schema management  Hopefully it can be a defacto standard DBAL for PHP 5.3 in the future, like MDB2 for PEAR1  Inspired in ezcDatabase, MDB2 and Zend_Db  Maybe we can make this happen for PEAR2 quarta-feira, 2 de junho de 2010
  24. 24. DoctrineDBAL interface DoctrineDBALConnection { // Data manipulation API /* Executes an SQL DELETE statement on a table. */ function delete($tableName, array $identifier); /* Executes an SQL UPDATE statement on a table. */ function update($tableName, array $data, array $identifier); /* Inserts a table row with specified data. */ function insert($tableName, array $data); /* Prepares an SQL statement. Returns a DBALStatement */ function prepare($statement); /* Applies a SQL statement and return # of affected rows. */ function exec($statement); // ... quarta-feira, 2 de junho de 2010
  25. 25. DoctrineDBAL // Transaction API /* Returns the current transaction nesting level. */ function getTransactionNestingLevel(); /* Executes a function in a transaction. */ function transactional(Closure $func); /* Starts a transaction by suspending auto-commit mode. */ function beginTransaction(); /* Commits the current transaction. */ function commit(); /* Cancel any database changes done during current transaction. */ function rollback(); /* Check if current transaction is marked for rollback only. */ function isRollbackOnly(); // ... quarta-feira, 2 de junho de 2010
  26. 26. DoctrineDBAL // Data fetching API /* Executes a SQL query and returns first row as an assoc array. */ function fetchAssoc($statement, array $params = array()); /* Executes a SQL query and returns first row as a numeric array. */ function fetchArray($statement, array $params = array()); /* Executes a SQL query and returns first column value of result. */ function fetchColumn( $statement, array $params = array(), $colnum = 0 ); /* Executes a SQL query and returns the result as an assoc array. */ function fetchAll($sql, array $params = array()); } quarta-feira, 2 de junho de 2010
  27. 27. DoctrineDBALTypes  Centralized point to convert values  From Database to PHP  From PHP to Database  Database agnostic  Accessing specific DB dialect called Platform  Extendable quarta-feira, 2 de junho de 2010
  28. 28. DoctrineDBALTypes  New DataType is just implement an abstract class: interface DoctrineDBALTypesType { function convertToDatabaseValue( $value, AbstractPlatform $platform ); function convertToPHPValue( $value, AbstractPlatform $platform ); function getSqlDeclaration( array $fieldDeclaration, AbstractPlatform $platform ); function getName(); function getBindingType(); } quarta-feira, 2 de junho de 2010
  29. 29. DoctrineDBAL class MyProjectDataTypesMyObjectType extends DoctrineDBALTypesType { public function getSqlDeclaration( array $fieldDeclaration, AbstractPlatform $platform ) { return $platform->getClobTypeDeclarationSQL($fieldDeclaration); } public function convertToDatabaseValue( $value, AbstractPlatform $platform ) { return serialize($value); } public function convertToPHPValue($value, AbstractPlatform $platform) { $value = (is_resource($value)) ? stream_get_contents($value) : $value; return unserialize($value); } public function getName() { return "my-object"; } } quarta-feira, 2 de junho de 2010
  30. 30. DoctrineDBALTypes  Finally, make Doctrine know about your DataType: DoctrineDBALTypesType::addType( "my-object", "MyProjectDataTypesMyObjectType" );  Then you can use it in your Entities! /** * @Entity * @Table(name="files") */ class File { // ... /** * @Column(type="my-object") */ protected $content; } quarta-feira, 2 de junho de 2010
  31. 31. DoctrineDBAL  Creating a schema: $platform = $em->getConnection()->getDatabasePlatform(); $schema = new DoctrineDBALSchemaSchema(); $table = $schema->createTable("users"); $table->addColumn("id", "integer", array("unsigned" => true)); $table->addColumn("name", "string", array("length" => 32)); $table->setPrimaryKey(array("id")); // get queries to create this schema. $queries = $schema->toSql($platform); Array( 0 => 'CREATE TABLE users ( id INTEGER NOT NULL, name VARCHAR(32) NOT NULL, PRIMARY KEY("id") )' ) quarta-feira, 2 de junho de 2010
  32. 32. DoctrineDBAL  Deleting a schema: // get queries to safely delete the schema. $queries = $schema->toDropSql($platform); Array( 0 => 'DROP TABLE users' )  It does the reverse of what ->toSql() does quarta-feira, 2 de junho de 2010
  33. 33. DoctrineDBAL  Comparing schemas: $platform = $em->getConnection()->getDatabasePlatform(); $fromSchema = new DoctrineDBALSchemaSchema(); $table = $fromSchema->createTable("users"); $table->addColumn("id", "integer", array("unsigned" => true)); $table->addColumn("name", "string", array("length" => 32)); $table->setPrimaryKey(array("id")); quarta-feira, 2 de junho de 2010
  34. 34. DoctrineDBAL  Comparing schemas: $platform = $em->getConnection()->getDatabasePlatform(); $toSchema = new DoctrineDBALSchemaSchema(); $table = $toSchema->createTable("users"); $table->addColumn("id", "integer", array("unsigned" => true)); $table->addColumn("name", "string", array("length" => 32)); $table->addColumn("email", "string", array("length" => 255)); $table->setPrimaryKey(array("id")); quarta-feira, 2 de junho de 2010
  35. 35. DoctrineDBAL  Comparing schemas: $platform = $em->getConnection()->getDatabasePlatform(); $comparator = new DoctrineDBALSchemaComparator(); $schemaDiff = $comparator->compare($fromSchema, $toSchema); // queries to get from one to another schema. $queries = $schemaDiff->toSql($platform); Array( 0 => 'ALTER TABLE users ADD email VARCHAR(255) NOT NULL' ) quarta-feira, 2 de junho de 2010
  36. 36. Insert Performance  Inserting 20 entries with Doctrine 2: for ($i = 0; $i < 20; $i++) { $user = new User(); $user->name = 'Guilherme Blanco'; $em->persist($user); } $start = microtime(0); $em->flush(); $end = microtime(0); echo $end - $start; quarta-feira, 2 de junho de 2010
  37. 37. Insert Performance  Inserting 20 entries with raw PHP code: $start = microtime(0); for ($i = 0; $i < 20; $i++) { mysql_query( "INSERT INTO users (name) VALUES ('Guilherme Blanco')", $db_link ); } $end = microtime(0); echo $end - $start; quarta-feira, 2 de junho de 2010
  38. 38. Insert Performance  We are not kidding here! =P Which one do you think it is faster?  Doctrine 2  Took: 0.0094 seconds  PHP code  Took: 0.0165 seconds  WTH?!?! Doctrine 2 is faster than raw PHP?  Itdoes a lot less, provides no features, no abstraction!  Answer is TRANSACTIONS! Doctrine 2 manages our transactions and efficiently executes all inserts in a single. quarta-feira, 2 de junho de 2010
  39. 39. Insert Performance  Doctrine 2 *IS NOT* faster than raw PHP code  Simple developers oversights can cause significant performance problems! quarta-feira, 2 de junho de 2010
  40. 40. Insert Performance  Inserting 20 entries with raw PHP code (revisited): $start = microtime(0); mysql_query("START TRANSACTION", $db_link); for ($i = 0; $i < 20; $i++) { mysql_query( "INSERT INTO users (name) VALUES ('Guilherme Blanco')", $db_link ); } mysql_query("COMMIT", $db_link); $end = microtime(0); echo $end - $start; quarta-feira, 2 de junho de 2010
  41. 41. Insert Performance  Final performance information...  Doctrine 2  Took: 0.0094 seconds  PHP code  Took: 0.0165 seconds  PHP code (revisited)  Took: 0.0028 seconds  You can read more about this on Doctrine Blog  http://www.doctrine-project.org/blog/transactions-and-performance quarta-feira, 2 de junho de 2010
  42. 42. DoctrineORM  What have we learned from Doctrine 1?  Persistence Layer != Domain Model  Focus on our key purpose, the Persistence Layer  “You’re doing it wrong!”  Kill magic quarta-feira, 2 de junho de 2010
  43. 43. DoctrineORM  Performance comparison  Hydrating 5000 records  Doctrine 1.2: 4.3 seconds  Doctrine 2.0-DEV: 1.4 seconds  Hydrating 10000 records  Doctrine 2.0-DEV: 3.5 seconds  Twice records and still faster than Doctrine 1! quarta-feira, 2 de junho de 2010
  44. 44. DoctrineORM  Why is it faster?  PHP 5.3 optimizations!  30% less resources usage, 20% faster  5.3-DEV (lazy bucket alloc, interned strings, runtime cache), Doctrine 2 can run 50% faster!  Better Hydration algorithm  Topological Sorting  Slim Entities  Killed magic aspects of Doctrine 1 quarta-feira, 2 de junho de 2010
  45. 45. DoctrineORM  Why kill magic?  Eliminate the WTF/minute (WTF factor)  Hard to debug  Edge cases are hard to fix  Edge cases are hard to workaround  Everything works until you go outside the box  ...and magic is slow! I can prove it!  __set is ~87% slower than normal set  __get is ~150% slower than normal get quarta-feira, 2 de junho de 2010
  46. 46. DoctrineORM  How we kill magic?  We call it OOP!  Object Composition  Inheritance  Aggregation  Containment  Encapsulation  etc quarta-feira, 2 de junho de 2010
  47. 47. DoctrineORM  DataMapper instead of ActiveRecord  Heavily inspired by JSR-317, a.k.a. JPA v2.0  Java... WHAT?!?! #$@&*!  PHP still lacks of standards  PHP Standards Group can rescue us?!  Final 2.0.0 version expected for September 1st quarta-feira, 2 de junho de 2010
  48. 48. DoctrineORM  Entities  Regular PHP class  Lightweight persistent domain object  Do not extend any base class!  Cannot be final or contain final methods  Two entities in a hierarchy of classes can not map property with the same name  Abstract and concrete classes can be Entities  Entities may extend non-entity classes as well as entity classes  Non-entity classes may also extend entity classes quarta-feira, 2 de junho de 2010
  49. 49. DoctrineORM namespace Entity; /** * @Entity * @Table(name="users") */ class User { /** * @Id @GeneratedValue * @Column(type="integer") */ protected $id; /** * @Column(type="string", length=32) */ protected $name; // ... getters and setters } quarta-feira, 2 de junho de 2010
  50. 50. DoctrineORM EntityUser: type: entity table: users id: id: type: integer generator: strategy: AUTO fields: name: type: string length: 32 quarta-feira, 2 de junho de 2010
  51. 51. DoctrineORM <?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="EntityUser" table="users"> <id name="id" type="integer"> <generator strategy="AUTO"/> </id> <field name="name" type="string" length="50"/> </entity> </doctrine-mapping> quarta-feira, 2 de junho de 2010
  52. 52. DoctrineORM  Column mapping  type  length  scale, precision  nullable  unique  name (DB)  options  columnDefinition /** * @Column(type="string", length=32, unique=true) */ protected $foo; quarta-feira, 2 de junho de 2010
  53. 53. DoctrineORM  Identifier fields  Supports different strategies:  AUTO  SEQUENCE  TABLE  NONE /** * @Id @GeneratedValue(strategy="AUTO") * @Column(type="integer") */ protected $id; quarta-feira, 2 de junho de 2010
  54. 54. DoctrineORM  Association fields  OneToOne /** @OneToOne(targetEntity="Shipping") */ private $shipping;  OneToMany  ManyToOne  ManyToMany /** * @ManyToMany(targetEntity="Group") * @JoinTable(name="users_groups", joinColumns={ * @JoinColumn(name="user_id", referencedColumnName="id") * }, inverseJoinColumns={ * @JoinColumn(name="group_id", referencedColumnName="id") * }) */ private $groups; quarta-feira, 2 de junho de 2010
  55. 55. DoctrineORM  Inheritance  Concrete Table Inheritance  No irrelevant columns  No locking problems  Difficult to deal with Primary Keys  No relations in base class  Search on superclass means search in all tables (too much queries or a weird join)  Refactoring of fields means update a few or all table quarta-feira, 2 de junho de 2010
  56. 56. DoctrineORM /** @MappedSuperclass */ class MappedSuperclassBase { /** @Column(type="string") */ protected $mapped; /** * @OneToOne(targetEntity="MappedSuperclassRelated") * @JoinColumn(name="related_id", referencedColumnName="id") */ protected $related; } /** @Entity @Table(name="users") */ class User extends MappedSuperclassBase { /** @Id @Column(type="integer") */ protected $id; /** @Column(type="string", length=32) */ protected $name; } quarta-feira, 2 de junho de 2010
  57. 57. DoctrineORM CREATE TABLE users ( mapped TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related_id INTEGER DEFAULT NULL, PRIMARY KEY(id) ); quarta-feira, 2 de junho de 2010
  58. 58. DoctrineORM  Inheritance  Single Table Inheritance  Only one table on database  No joins  Refactoring of fields do not change DB schema  Waste of space on database  Too many locks due to many accesses  No duplicated name of fields with different meaning quarta-feira, 2 de junho de 2010
  59. 59. DoctrineORM namespace MyProjectEntity; /** * @Entity * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({ * "user" = "User", "employee" = "Employee" * }) */ class User { // ... } /** @Entity */ class Employee extends User { // ... } quarta-feira, 2 de junho de 2010
  60. 60. DoctrineORM  Inheritance  Class Table Inheritance  Easy to understand  DB space is optimized due to normalization  Direct relationship between Domain Model and database  Too many joins  Refactoring of fields need a database schema update  Supertype table accessed a lot, may be in lock mode quarta-feira, 2 de junho de 2010
  61. 61. DoctrineORM namespace MyProjectEntity; /** * @Entity * @InheritanceType("JOINED") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({ * "user" = "User", "employee" = "Employee" * }) */ class User { // ... } /** @Entity */ class Employee extends User { // ... } quarta-feira, 2 de junho de 2010
  62. 62. DoctrineORM  Proxies  Lazy-load Entity data  Provide the possibility to get an Entity reference without database access  Can be generated on-the-fly (during script execution) or via a Console tool $proxyUser = $em->getReference("User", 1); quarta-feira, 2 de junho de 2010
  63. 63. DoctrineORM  EntityManager  Central point of ORM functionality  Employes Transaction Write Behind strategy that delays executions of SQL statements  ...this means, efficiency!  ...and also means that write locks are quickly released!  Internally, it uses a UnitOfWork to keep track of your objects state quarta-feira, 2 de junho de 2010
  64. 64. DoctrineORM interface DoctrineORMEntityManager { // Transaction API /* Starts a transaction on the underlying database connection. */ function beginTransaction(); /* Commits a transaction on underlying database connection. */ function commit(); /* Flushes all changes to queued objects to the database. */ function flush(); /* Performs a rollback on the underlying database connection. */ function rollback(); /* Executes a function in a transaction. */ function transactional(Closure $func); // ... quarta-feira, 2 de junho de 2010
  65. 65. DoctrineORM // Query API /* Creates a new Query object. */ function createQuery($dql); /* Creates a native SQL query. */ function createNativeQuery( $sql, DoctrineORMQueryResultSetMapping $rsm ); /* Create a QueryBuilder instance. */ function createQueryBuilder(); /* Finds an Entity by its identifier. */ function find($entityName, $identifier, $lockMode = LockMode::NONE, $lockVersion = null); /* Gets a reference to the entity identified by the given type and identifier without actually loading it. */ function getReference($entityName, $identifier); // ... quarta-feira, 2 de junho de 2010
  66. 66. DoctrineORM // Object Manipulation API /* Tells EntityManager to make instance managed and persistent. */ function persist($entity); /* Removes an entity instance. */ function remove($entity); /* Refresh state of entity from database, overrides changes. */ function refresh($entity); /* Detaches an entity from the EntityManager. */ function detach($entity); /* Merges state of detached entity into persistence context. */ function merge($entity); // ... quarta-feira, 2 de junho de 2010
  67. 67. DoctrineORM // Repository, Configuration, EventManager, etc /* Gets the EventManager used by the EntityManager. */ function getEventManager(); /* Gets the Configuration used by the EntityManager. */ function getConfiguration(); /* Gets the repository for an entity class. */ function getRepository($entityName); /* Returns the metadata for a class. */ function getClassMetadata($className); /* Gets database connection object used by the EntityManager. */ function getConnection(); } quarta-feira, 2 de junho de 2010
  68. 68. DoctrineORM  Working with Entities in EntityManager  Creating an EntityManager $config = new DoctrineORMConfiguration(); $config->setMetadataCacheImpl($cacheDriver); $config->setQueryCacheImpl($cacheDriver); $config->setProxyDir("/path/to/MyProject/Proxies"); $config->setProxyNamespace("MyProjectProxies"); $connectionOptions = array( "driver" => "pdo_sqlite", "path" => "database.sqlite" ); // Creating the EntityManager $em = DoctrineORMEntityManager::create( $connectionOptions, $config ); quarta-feira, 2 de junho de 2010
  69. 69. DoctrineORM  Working with Entities in EntityManager  Persisting Entities try { $em->transactional(function ($em) { $user = new MyProjectEntityUser(); $user->name = "Guilherme Blanco"; $em->persist($user); }); } catch (Exception $e) { // ... } quarta-feira, 2 de junho de 2010
  70. 70. DoctrineORM  Working with Entities in EntityManager  Updating Entities try { $em->transactional(function ($em) { $user = $em->find("MyProjectEntityUser", 1); $user->name = "Benjamin Eberlei"; $em->persist($user); }); } catch (Exception $e) { // ... } quarta-feira, 2 de junho de 2010
  71. 71. DoctrineORM  Working with Entities in EntityManager  Deleting Entities try { $em->transactional(function ($em) { $user = $em->getReference("MyProjectEntityUser", 1); $em->remove($user); }); } catch (Exception $e) { // ... } quarta-feira, 2 de junho de 2010
  72. 72. DoctrineORM  Doctrine Query Language (DQL)  Implementation of an OQL  Heavily influenced by Hibernate QL  Parsed by a top-down recursive descent parser LL(*), constructing an abstract syntax tree (AST)  AST is then used to generate vendor dependent SQL $query = $em->createQuery( "SELECT u FROM MyProjectEntityUser u" ); $users = $query->execute(); quarta-feira, 2 de junho de 2010
  73. 73. DoctrineORM  Native Query  Allow you the possibility to fallback to the power of SQL without losing the ability to hydrate the data to your Entities $rsm = new DoctrineORMQueryResultSetMapping(); $rsm->addEntityResult("MyProjectEntityUser", "u"); $rsm->addFieldResult("u", "id", "id"); $rsm->addFieldResult("u", "name", "name"); $query = $em->createNativeQuery( "SELECT id, name FROM users WHERE username = ?", $rsm ); $query->setParameter(1, "guilhermeblanco"); $users = $query->getResult(); quarta-feira, 2 de junho de 2010
  74. 74. DoctrineORM  QueryBuilder  Builder implementation  Building and execution are separated  QueryBuilder cannot be executed; instead, get the Query instance from it and execute $qb = $em->createQueryBuilder() ->select("u") ->from("MyProjectEntityUser", "u"); $users = $qb->getQuery()->execute(); quarta-feira, 2 de junho de 2010
  75. 75. DoctrineORM  Doctrine supports different cache levels  Metadata cache $config->setMetadataCacheImpl($cacheDriver);  Query cache $config->setQueryCacheImpl($cacheDriver);  Result cache $config->setResultCacheImpl($cacheDriver); $query = $em->createQuery( "SELECT u FROM MyProjectEntityUser u" ); $query->useResultCache(true, 3600, "my_custom_name"); quarta-feira, 2 de junho de 2010
  76. 76. DoctrineORM  Console  Uses Symfony 2 Console component  Help developing with Doctrine  Tasks available in all packages $helperSet = $cli->getHelperSet(); $helperSet->set( new DoctrineDBALToolsConsoleHelperConnectionHelper( $em->getConnection() ), 'db' ); $helperSet->set( new DoctrineORMToolsConsoleHelperEntityManagerHelper( $em ), 'em' ); $cli->addCommands(array(...)); quarta-feira, 2 de junho de 2010
  77. 77. DoctrineORM  Available Commands:  DoctrineDBALToolsConsoleCommandRunSqlCommand  DoctrineDBALToolsConsoleCommandImportCommand  DoctrineORMToolsConsoleCommandClearCacheMetadataCommand  DoctrineORMToolsConsoleCommandClearCacheResultCommand  DoctrineORMToolsConsoleCommandClearCacheQueryCommand  DoctrineORMToolsConsoleCommandSchemaToolCreateCommand  DoctrineORMToolsConsoleCommandSchemaToolUpdateCommand  DoctrineORMToolsConsoleCommandSchemaToolDropCommand  DoctrineORMToolsConsoleCommandConvertDoctrine1SchemaCommand  DoctrineORMToolsConsoleCommandConvertMappingCommand  DoctrineORMToolsConsoleCommandGenerateRepositoriesCommand  DoctrineORMToolsConsoleCommandGenerateEntitiesCommand  DoctrineORMToolsConsoleCommandGenerateProxiesCommand  DoctrineORMToolsConsoleCommandEnsureProductionSettingsCommand  DoctrineORMToolsConsoleCommandValidateSchemaCommand  DoctrineORMToolsConsoleCommandRunDqlCommand quarta-feira, 2 de junho de 2010
  78. 78. Future  DBAL  QueryBuilder  Finish MSSQL Server driver  DQL  Support for TYPE()  Add multiple FROM Entities support  Embedded Values  ODM  Extract DocumentManager interface  Stabilize the MongoDB driver  Implement other drivers (CouchDB, SimpleDB, ...) quarta-feira, 2 de junho de 2010
  79. 79. Questions?  Guilherme Blanco  Contact Info:  @guilhermeblanco  guilhermeblanco@php.net  http://www.facebook.com/guilhermeblanco  +55 16 9215.8480  THANK YOU FOR YOUR PATIENCE!!! =) quarta-feira, 2 de junho de 2010
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×