Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP

6,846 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

×