Successfully reported this slideshow.

IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

6,796 views

Published on

Talk given at IPC 2010 Spring Edition at Berlim, Germany

Published in: Technology
  • Be the first to comment

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

×