Successfully reported this slideshow.

More Related Content

Related Audiobooks

Free with a 14 day trial from Scribd

See all

Libertyvasion2010

  1. 1. Doctrine 2.0 Enterprise Object Relational Mapper for PHP 5.3 Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  2. 2. Jonathan H. Wage • Web developer for over a decade • Tech junky for even longer • Open Source Evangelist • Published Author • Contributes to... • ...Doctrine • ...Symfony • ...and more • Works full-time for Sensio Labs Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  3. 3. Jonathan H. Wage • http://www.twitter.com/jwage • http://www.jwage.com • http://www.facebook.com/jwage 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.0 www.doctrine-project.org www.sensiolabs.org
  4. 4. Project History • First commit April 13th 2006 • First stable version finished and Released September 1st 2008 • One of the first ORM implementations for PHP • 1.0 is First LTS(long term support) release. Maintained until March 1st 2010 • Integrated with many popular frameworks: Symfony, Zend Framework, Code Igniter, etc. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  5. 5. The Team • Roman S. Borschel • Guilherme Blanco • Benjamin Eberlei • Bulat Shakirzyanov • Jonathan H. Wage Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  6. 6. Object Relational Mapper What is it? Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  7. 7. Object-relational mapping (ORM, O/RM, and O/R mapping) in computer software is a programming technique for converting data between incompatible type systems in object-oriented programming languages. This creates, in effect, a "virtual object database" that can be used from within the programming language. There are both free and commercial packages available that perform object-relational mapping, although some programmers opt to create their own ORM tools. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  8. 8. Doctrine1 vs Doctrine2 Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  9. 9. The Doctrine1 Way class User extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('username', 'string'); $this->hasColumn('password', 'string'); } } Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  10. 10. The Doctrine1 Way $user = new User(); $user->setUsername('jwage'); $user->setPassword('password'); $user->save(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  11. 11. Problems • Domain is bound to persistence layer • Complexity of domain entities limited by persistence layer • $model->save() is a bottle neck for persisting large numbers of objects • Testing your domain model requires mocking the persistence layer Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  12. 12. The Doctrine2 Way How does Doctrine2 do it? Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  13. 13. No base class to extend Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  14. 14. /** * @Entity * @Table(name="users") */ class User { /** * @Id */ private $id; /** * @Column(type="string", length=255) */ private $username; public function setUsername($username) { $this->username = $username; } // ... } Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  15. 15. Mapping Information Specify your mapping information with XML, YAML or DocBlock Annotations Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  16. 16. YAML User: type: entity table: users fields: id: type: integer id: true generator: strategy: AUTO username: type: string(255) password: type: string(255) Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  17. 17. XML <?xml version="1.0" encoding="utf-8"?> <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine- mapping" xsi="http://www.w3.org/2001/XMLSchema-instance" schemaLocation="http:// doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> <entity name="User" table="users"> <id name="id" type="integer" column="id"> <generator strategy="AUTO"/> </id> <field name="username" type="string" column="username" length="255" /> <field name="password" type="string" column="password" length="255"> </entity> </doctrine-mapping> Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  18. 18. PHP use DoctrineORMMappingClassMetadataInfo; $metadata->setInheritanceType(ClassMetadataInfo::INHERITANCE_TYPE_NONE); $metadata->setPrimaryTable(array( 'name' => 'users', )); $metadata->mapField(array( 'fieldName' => 'id', 'type' => 'integer', 'id' => true, 'columnName' => 'id', )); $metadata->mapField(array( 'fieldName' => 'username', 'type' => 'string', 'length' => '255', 'columnName' => 'username', )); $metadata->mapField(array( 'fieldName' => 'password', 'type' => 'string', 'length' => '255', 'columnName' => 'password', )); $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  19. 19. Transparent Persistence Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  20. 20. $user = new User(); $user->setUsername('jwage'); $user->setPassword('password'); $em->persist($user); $em->flush(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  21. 21. Single Flush Operation • Batch inserts • Best to build up all object changes in your application and flush no more than 1 or 2 times • All managed objects are tracked and changesets generated on flush and used to persist to RDBMS, MongoDB, etc. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  22. 22. $user = $em->getRepository('User') ->findBy(array('username' => 'jwage')); $user->setPassword('newpassword'); // Issues SQL update setting the new password $em->flush(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  23. 23. Why Transparency? • Better performance • Easier to cache regular PHP objects that are not bound to the persistence layer • Easier to test your domain, no mocking required • Ultimate flexibility over the complexity of your domain entities without being imposed on by your persistence layer Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  24. 24. Performance • Less abstraction on domain entities improves performance when working with them. • Physical accessors and getters are faster. • Lighter and no required dependencies. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  25. 25. PHP 5.3 Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  26. 26. PHP 5.3 is Fast Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  27. 27. Doctrine1 Doctrine1 benefits from using PHP 5.3. Test suite uses 30% less memory and runs 20% faster Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  28. 28. Doctrine2 Performance Doctrine 1.1 4.3 seconds for 5000 records Doctrine 2.0 1.4 seconds for 5000 records Doctrine 2.0 3.5 seconds for 10000 records Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  29. 29. Uses Namespaces Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  30. 30. Namespaces namespace DoctrineORM; use DoctrineORMQueryExpr, DoctrineCommonDoctrineException; /** * This class is responsible for building DQL query strings via an object oriented * PHP interface. * * @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @link www.doctrine-project.org * @since 2.0 * @version $Revision$ * @author Guilherme Blanco <guilhermeblanco@hotmail.com> * @author Jonathan Wage <jonwage@gmail.com> * @author Roman Borschel <roman@code-factory.org> */ class QueryBuilder { // ... Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  31. 31. Using Namespaces use DoctrineORMQueryBuilder; $qb = new QueryBuilder($em); $qb->select('u') ->from('ModelsUser', 'u') ->orderBy('u.username', 'ASC'); $q = $qb->getQuery(); $users = $q->execute(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  32. 32. Follow PHP 5.3 Interoperability Standards http://groups.google.com/group/php-standards Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  33. 33. Benefits • PHP libraries will be able to be mixed without autoloader issues and conflict. • Symfony2 + Doctrine2 + ZendFramework2 • Load classes from 3 different libraries with one autoloader and one include path Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  34. 34. Doctrine code is divided into a few different packages Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  35. 35. DoctrineCommon • Common functionality shared across packages • Events • Annotations Library • Lexer Parser that is used for parsing the Doctrine Query Language (DQL) • Other various convenience tools Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  36. 36. DoctrineDBAL • Relational database abstraction layer • MySQL • Sqlite • PostgreSQL • Oracle • MsSQL Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  37. 37. DBAL is Standalone Use the DBAL without the ORM Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  38. 38. DBAL History • The Doctrine DBAL is a very powerful project in itself • Based off of code forked from other projects • PEAR MDB2 • Zend_Db Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  39. 39. DBAL • Using the Doctrine DBAL standalone is a good option for your PHP projects if a fully featured ORM is not needed • API for performing DDL statements, executing queries, etc. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  40. 40. DBAL Example $params = array( 'driver' => 'pdo_mysql', 'host' => 'localhost', 'user' => 'root', 'password' => '', 'dbname' => 'doctrine2dbal' ); $conn = DoctrineDBALDriverManager::getConnection($params); Execute queries against your database using $conn. The API is very similar to that of PDO and adds some extra conveniences. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  41. 41. Schema Manager $sm = $conn->getSchemaManager(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  42. 42. Schema Manager • Issue DDL statements through intuitive API: createTable(), dropTable(), createForeignKey(), etc. • Introspect your database schema as well: listTables(), listTableColumns(), listUsers(), etc. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  43. 43. Drop and Create Table $columns = array( 'id' => array( 'type' => Type::getType('integer'), 'autoincrement' => true, 'primary' => true, 'notnull' => true ), 'name' => array( 'type' => Type::getType('string'), 'length' => 255 ), ); $sm->dropAndCreateTable('user', $columns); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  44. 44. Create Foreign Key $definition = array( 'name' => 'user_id_fk', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user' ); $sm->createForeignKey('profile', $definition); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  45. 45. DoctrineORM • Object Relational Mapper • Built on top of the DBAL • Provides transparent domain object persistence to relational databases Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  46. 46. Persisting to Other Databases Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  47. 47. DoctrineODMMongoDB Doctrine Object Document Mapper (ODM) for MongoDB Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  48. 48. DoctrineODMMongoDB • Provides transparent domain object persistence to MongoDB • Same architecture and design as the ORM • New addition to the Doctrine project • Umbrella of project widened to offer Doctrine style persistence layers for other popular open source databases. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  49. 49. Architecture The architecture of the Doctrine object persistence layers Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  50. 50. The ObjectManager EntityManager and DocumentManager Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  51. 51. API Simple API for managing the persistent state of objects Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  52. 52. Object States • A NEW object instance has no persistent identity, and is not yet associated with a ObjectManager (i.e. those just created with the "new" operator). • A MANAGED object instance is an instance with a persistent identity that is associated with an ObjectManager and whose persistence is thus managed. • A DETACHED object instance is an instance with a persistent identity that is not (or no longer) associated with an ObjectManager. • A REMOVED object instance is an instance with a persistent identity, associated with an ObjectManager, that will be removed from the database upon transaction commit. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  53. 53. Creating EntityManager $config = new DoctrineORMConfiguration(); $config->setMetadataCacheImpl(new DoctrineCommonCacheArrayCache); $driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Entities")); $config->setMetadataDriverImpl($driverImpl); $config->setProxyDir(__DIR__ . '/Proxies'); $config->setProxyNamespace('Proxies'); $connectionOptions = array( 'driver' => 'pdo_sqlite', 'path' => 'database.sqlite' ); $em = DoctrineORMEntityManager::create($connectionOptions, $config); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  54. 54. Creating DocumentManager $config = new DoctrineODMMongoDBConfiguration(); $config->setMetadataCacheImpl(new DoctrineCommonCacheArrayCache); $driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__."/Documents")); $config->setMetadataDriverImpl($driverImpl); $config->setProxyDir(__DIR__ . '/Proxies'); $config->setProxyNamespace('Proxies'); $mongo = new DoctrineODMMongoDBMongo(); $dm = DoctrineORMDocumentManager::create($mongo, $config); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  55. 55. Managing the State Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  56. 56. Persisting $user = new User(); $user->setUsername('jwage'); $user->setPassword('password'); // Persist the new object so it is // saved to the database $em->persist($user); $em->flush(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  57. 57. Updating $user = $em->getRepository('User') ->find(array('username' => 'jwage')); // modify the already managed object $user->setPassword('changed'); $em->flush(); // issues update Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  58. 58. Removing $user = $em->getRepository('User') ->find(array('username' => 'jwage')); // schedule for deletion $em->remove($user); $em->flush(); // issues delete Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  59. 59. Detaching $user = $em->getRepository('User') ->find(array('username' => 'jwage')); $user->setUsername('changed'); // detach the object $em->detach($user); $em->flush(); // does nothing Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  60. 60. Doctrine Query Language The killer ORM feature Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  61. 61. Propietary Object Query Language Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  62. 62. Parsed by Recursive Descent Parser Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  63. 63. Constructs AST Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  64. 64. AST = Abstract Syntax Tree Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  65. 65. Tree representation of the syntactical structure of a source language Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  66. 66. PHP class names of DQL parser directly represent the language itself • OrderByClause.php • SelectClause.php • SelectExpression.php • Subselect.php • DeleteClause.php Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  67. 67. • Easy to use • Easy to expand and add new features • Easy to use and understand the parsing of a DQL string • Expand the DQL parser with your own functionality and add to the DQL language Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  68. 68. Parsing of DQL is Cached In a production environment a DQL query is only ever parsed and transformed to SQL once so performance is not an issue. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  69. 69. Sample DQL Query $query = $em->createQuery( 'SELECT u, g, FROM User u ' . 'LEFT JOIN u.Groups g ' . 'ORDER BY u.name ASC, g.name ASC' ); $users = $query->execute(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  70. 70. QueryBuilder API $qb = $em->createQueryBuilder() ->select('u, g') ->from('User', 'u') ->leftJoin('u.Groups', 'g') ->orderBy('u.name', 'ASC') ->addOrderBy('g.name', 'ASC'); $query = $qb->getQuery(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  71. 71. Executing Queries $users = $query->execute(); foreach ($users as $user) { // ... foreach ($user->getGroups() as $group) { // ... } } Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  72. 72. Result Cache $query = $em->createQuery('SELECT u FROM ModelsUser u'); $query->useResultCache(true, 3600, 'user_query'); $users = $query->execute(); Execute query again and the results are retrieved from the cache $users = $query->execute(); Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  73. 73. Symfony2 Integration The Doctrine features are tightly integrated with Symfony2 Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  74. 74. Enabling the DBAL Enable the DBAL in your application configuration # config/config.yml doctrine.dbal: driver: PDOMySql dbname: Symfony2 user: root password: null Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  75. 75. Using the DBAL Use the DBAL connection in your controllers class UserController extends Controller { public function indexAction() { $conn = $this->container->getService('database_connection'); $users = $conn->fetchAll('SELECT * FROM users'); } } Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  76. 76. Enabling the ORM Enable the ORM in your application configuration # config/config.yml doctrine.orm: ~ Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  77. 77. Creating an Entity Application/HelloBundle/Entity/User.php namespace ApplicationHelloBundleEntity; /** * @Entity */ class User { /** @Id */ public $id; /** @Column(type="string", length="255") */ public $username; /** @Column(type="string", length="255") */ public $password; } Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  78. 78. Create database schema $ php hello/console doctrine:schema:create Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  79. 79. Using the ORM Use the ORM EntityManager in your controllers use ApplicationHelloBundleEntitiesUser; class UserController extends Controller { public function createAction() { $user = new User(); $user->setName('Jonathan H. Wage'); $em = $this->container->getService('doctrine.orm.entity_manager'); $em->persist($user); $em->flush(); // ... } } Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  80. 80. Conclusion Why use an ORM? Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  81. 81. Encapsulation Encapsulate all your domain logic in one place, in an object oriented way Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  82. 82. Maintainability The organization of the domain logic in an OO way improves maintainability Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  83. 83. Testability Keeping a clean OO domain model makes your business logic easily testable for improved stability Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  84. 84. Portability Write portable and thin application controller code and fat models. Doctrine 2.0 www.doctrine-project.org www.sensiolabs.org
  85. 85. Questions? Jonathan H. Wage jonwage@gmail.com http://www.twitter.com/jwage +1 615 513 9185 sensiolabs.com | doctrine-project.org | jwage.com 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.0 www.doctrine-project.org www.sensiolabs.org

×