Guilherme Blanco, Yahoo!


          Doctrine 2
           Camada de Persistência para PHP 5.3+




sábado, 26 de junho de...
Quem sou eu?
        Web developer a mais de 10 anos

        Evangelista Open Source

        Trabalha para Yahoo!

  ...
Quem sou eu?
        http://www.twitter.com/guilhermeblanco

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




sábado,...
Doctrine 2



sábado, 26 de junho de 2010
Doctrine 2
        PHP 5.3+

        100% do código reescrito

        Código totalmente em namespaces




sábado, 26 d...
Doctrine 2
        Ferramentas usadas:
            phpUnit  Unit test
            Phing Pacotes e distribuição
        ...
Doctrine 2
        Três principais pacotes:
            Common


            DBAL


            ORM




sábado, 26 de ...
DoctrineCommon
     git@github.com:doctrine/common.git

        Cache Drivers




sábado, 26 de junho de 2010
DoctrineCommonCache
        Drivers Suportados:
            APCCache
     $cacheDriver = new DoctrineCommonCacheApcCache...
DoctrineCommonCache
        Cache Drivers Interface:
     interface DoctrineCommonCacheCache {
       function setNamespa...
DoctrineCommon
     git@github.com:doctrine/common.git

        Cache Drivers

        Class Loader




sábado, 26 de ju...
DoctrineCommonClassLoader
        Implements PSR #0
            PSR       = PHP Standards Recommendation

            I...
DoctrineCommonClassLoader
        Como usar:

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

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

        Cache Drivers

        Class Loader

        Collection...
DoctrineCommonCollections
        Solução inspirada na interface java.util.Collection

        Array simples em PHP são ...
DoctrineCommon
     git@github.com:doctrine/common.git

        Cache Drivers

        Class Loader

        Collection...
DoctrineCommon
     git@github.com:doctrine/common.git

        Cache Drivers

        Class Loader

        Collection...
DoctrineCommonAnnotations
        Suporte à Annotations similar ao Java

        Define informações de metadados em clas...
DoctrineCommonAnnotations
     Annotations              ::=   Annotation {[ "*" ]* [Annotation]}*
     Annotation         ...
DoctrineCommonAnnotations
        Criando classes de Annotations:
     final class DoctrineORMMappingEntity
         exte...
DoctrineCommonAnnotations
        Lendo Annotations:
     $reader = new DoctrineCommonAnnotationsAnnotationReader(
      ...
DoctrineCommonAnnotations
     interface DoctrineCommonAnnotationsAnnotationReader {
       function setDefaultAnnotationN...
DoctrineDBAL
     git@github.com:doctrine/dbal.git

        DataBase Abstraction Layer construído sobre a PDO e
         ...
DoctrineDBAL
        API para introspecção e gerenciamento de
         schemas de Bancos de Dados melhorado

        Pod...
DoctrineDBAL
     interface DoctrineDBALConnection {
       // API para manipulação de dados

        /* Executa um SQL DE...
DoctrineDBAL
        // API para Transação

        /* Retorna o nível de profundidade da transação corrente. */
        f...
DoctrineDBAL
         // API para obtenção de dados

         /* Executa consulta SQL e retorna a 1a. linha num array asso...
DoctrineDBALTypes
        Ponto centralizado para conversão de tipos
            Do Banco de Dados para PHP
           ...
DoctrineDBALTypes
        Novo tipo é só implementar uma classe abstrata:
    interface DoctrineDBALTypesType {
        f...
DoctrineDBAL
     class MyProjectDataTypesMyObjectType extends DoctrineDBALTypesType
     {
       public function getSqlD...
DoctrineDBALTypes
        Finalmente, faça o Doctrine saber sobre seu tipo:
    DoctrineDBALTypesType::addType(
        "...
DoctrineDBAL
        Criando um schema:
    $platform = $em->getConnection()->getDatabasePlatform();

    $schema = new D...
DoctrineDBAL
        Removendo um schema:
    // obtém as queries para remover o schema em segurança.
    $queries = $sch...
DoctrineDBAL
        Comparando schemas:
    $platform = $em->getConnection()->getDatabasePlatform();

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

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

    $comparator = ...
Performance em Inserções
        Inserindo 20 entradas com Doctrine 2:
    for ($i = 0; $i < 20; $i++) {
        $user = ...
Performance em Inserções
        Inserindo 20 entradas com código PHP “crú”:
    $start = microtime(0);

    for ($i = 0;...
Performance em Inserções
        Sem palhaçada aqui! =P
         Qual deles vocês acham que é mais rápido?
            D...
Performance em Inserções
        Doctrine 2 *NÃO É* mais rápido que código PHP
         puro

        Desenvolvedores pa...
Performance em Inserções
        Inserindo 20 entradas com código PHP “crú”:
    $start = microtime(0);

    mysql_query(...
Performance em Inserções
        Informações finais de performance...
            Doctrine          2
                 ...
DoctrineORM
        O que aprendemos com Doctrine 1?
            Camada   de Persistência != Modelo de Domínio
         ...
DoctrineORM
        Comparação de performance
            Hidratar         5000 registros
                  Doctrine 1....
DoctrineORM
        Por que é mais rápido?
            Otimizações      do PHP 5.3!
                  30% menos recurso...
DoctrineORM
        Por que extingüir a mágica?
            Eliminar         o fator PQP/minuto

            Difícil
  ...
DoctrineORM
        Como extingüir a mágica?
            Nós      chamamos de POO!

            Composição
           ...
DoctrineORM
        DataMapper ao invés de ActiveRecord

        Densamente inspirado em JSR-317/JPA v2.0

        Java...
DoctrineORM
        Entidades
            Classe PHP regular
            Objeto persistente de domínio enxuto
         ...
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
        Mapeamento de Colunas
            type
            length
            scale, precision
           ...
DoctrineORM
        Campos identificadores
            Suporta          diferentes estratégias:
                  AUTO
...
DoctrineORM
        Campos de associação
              OneToOne
    /** @OneToOne(targetEntity="Shipping") */
    privat...
DoctrineORM
        Herança
            Concrete         Table Inheritance
                  Sem colunas irrelevantes
 ...
DoctrineORM
     /** @MappedSuperclass */
     class MappedSuperclassBase {
         /** @Column(type="string") */
       ...
DoctrineORM
     CREATE TABLE users (
         mapped TEXT NOT NULL,
         id INTEGER NOT NULL,
         name TEXT NOT ...
DoctrineORM
        Herança
            Single       Table Inheritance
                  Somente uma tabela na base de ...
DoctrineORM
     namespace MyProjectEntity;

     /**
       * @Entity
       * @InheritanceType("SINGLE_TABLE")
       * ...
DoctrineORM
        Herança
            Class       Table Inheritance
                  Fácil de entender
             ...
DoctrineORM
     namespace MyProjectEntity;

     /**
       * @Entity
       * @InheritanceType("JOINED")
       * @Discr...
DoctrineORM
        Proxies
            Carga-tardia dos dados da Entidade
            Provê a possibilidade de obter u...
DoctrineORM
        EntityManager
            Ponto   central da funcionalidade ORM
            Aplica a estratégia de ...
DoctrineORM
     interface DoctrineORMEntityManager {
         // Transaction API

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

           /* Creates a new Query object. */
           function createQuery($dql);

...
DoctrineORM
           // Object Manipulation API

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

           /* Gets the EventManager used by the En...
DoctrineORM
        Trabalhando com Entidades no EntityManager
              Criando o EntityManager
    $config = new D...
DoctrineORM
        Trabalhando com Entidades no EntityManager
              Persistindo Entidades
    try {
        $em...
DoctrineORM
        Trabalhando com Entidades no EntityManager
              Atualizando Entidades
    try {
        $em...
DoctrineORM
        Trabalhando com Entidades no EntityManager
              Removendo Entidades
    try {
        $em->...
DoctrineORM
        Doctrine Query Language (DQL)
            Implementação   de uma OQL
            Fortemente influen...
DoctrineORM
        Native Query
            Possibilitavoltar ao poder da SQL sem perder a
              habilidade de ...
DoctrineORM
        QueryBuilder
            Implementação  de um Builder
            Construção e execução são separad...
DoctrineORM
        Doctrine suporta diferentes níveis de cache
            Metadata           cache
    $config->setMet...
DoctrineORM
        Console
            Usa o componente Symfony 2 Console
            Auxilia a desenvolver com Doctri...
DoctrineORM
        Comandos disponíveis:
              DoctrineDBALToolsConsoleCommandRunSqlCommand
              Doct...
Future
        DBAL
            QueryBuilder
            Concluir o driver MSSQL Server



        DQL
            Su...
Questions?
        Guilherme Blanco
            Informações       de contato:

                    @guilhermeblanco

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

Doctrine2 Seminário PHP

7,246

Published on

Published in: Technology

Transcript of "Doctrine2 Seminário PHP"

  1. 1. Guilherme Blanco, Yahoo! Doctrine 2 Camada de Persistência para PHP 5.3+ sábado, 26 de junho de 2010
  2. 2. Quem sou eu?  Web developer a mais de 10 anos  Evangelista Open Source  Trabalha para Yahoo!  Contribui para...  ...Doctrine  ...Zend Framework  ...Symfony  ...PHP  etc  Gosta de cantar e pescar no tempo livre! =) sábado, 26 de junho de 2010
  3. 3. Quem sou eu?  http://www.twitter.com/guilhermeblanco  http://www.facebook.com/guilhermeblanco sábado, 26 de junho de 2010
  4. 4. Doctrine 2 sábado, 26 de junho de 2010
  5. 5. Doctrine 2  PHP 5.3+  100% do código reescrito  Código totalmente em namespaces sábado, 26 de junho de 2010
  6. 6. Doctrine 2  Ferramentas usadas:  phpUnit Unit test  Phing Pacotes e distribuição  Symfony Components  YAML  Console  Sismo Continuous Integration  GIT Controle de versão do código  JIRA Gerenciamento de bugs  Trac Timeline, código fonte & visualizar alterações sábado, 26 de junho de 2010
  7. 7. Doctrine 2  Três principais pacotes:  Common  DBAL  ORM sábado, 26 de junho de 2010
  8. 8. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers sábado, 26 de junho de 2010
  9. 9. DoctrineCommonCache  Drivers Suportados:  APCCache $cacheDriver = new DoctrineCommonCacheApcCache();  MemcacheCache $memcache = new Memcache(); $memcache->addServer('memcache_host', 11211); $cacheDriver = new DoctrineCommonCacheMemcacheCache(); $cacheDriver->setMemcache($memcache);  XcacheCache $cacheDriver = new DoctrineCommonCacheXcacheCache(); sábado, 26 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); } sábado, 26 de junho de 2010
  11. 11. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader sábado, 26 de junho de 2010
  12. 12. DoctrineCommonClassLoader  Implements PSR #0  PSR = PHP Standards Recommendation  Interoperabilidade Técnica entre bibliotecas  Symfony, Zend Framework, Doctrine, Agavi, PEAR2/Pyrus, Lithium, Flow3, Solar, etc  Possível merge no core do PHP: SplClassLoader  http://wiki.php.net/rfc/splclassloader sábado, 26 de junho de 2010
  13. 13. DoctrineCommonClassLoader  Como usar: require_once '/path/to/lib/Doctrine/Common/ClassLoader.php'; $doctrineClassLoader = new DoctrineCommonClassLoader( 'Doctrine', '/path/to/lib/Doctrine' ); $doctrineClassLoader->register(); sábado, 26 de junho de 2010
  14. 14. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections sábado, 26 de junho de 2010
  15. 15. DoctrineCommonCollections  Solução inspirada na interface java.util.Collection  Array simples em PHP são difíceis de manipular  ...mas implementações de array customizadas não são compatíveis com as funções de array_*  Uso intenso de Closures  Implementação SplArray do usuário  Onde estão os desenvolvedores do PHP? sábado, 26 de junho de 2010
  16. 16. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections  Lexer sábado, 26 de junho de 2010
  17. 17. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections  Lexer  Annotations Parser sábado, 26 de junho de 2010
  18. 18. DoctrineCommonAnnotations  Suporte à Annotations similar ao Java  Define informações de metadados em classes  Extremamente extensível e reutilizável  Supre uma funcionalidade inexistente no PHP  Novamente, onde estão os desenvolvedores do PHP?  RFC já escrito: http://wiki.php.net/rfc/annotations sábado, 26 de junho de 2010
  19. 19. 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 sábado, 26 de junho de 2010
  20. 20. DoctrineCommonAnnotations  Criando classes de Annotations: final class DoctrineORMMappingEntity extends DoctrineCommonAnnotationsAnnotation { public $repositoryClass; }  Usando as Annotations: namespace MyProjectEntity; /** * @Entity(repositoryClass="RepositoryUserRepository") */ class User { // ... } sábado, 26 de junho de 2010
  21. 21. DoctrineCommonAnnotations  Lendo Annotations: $reader = new DoctrineCommonAnnotationsAnnotationReader( new DoctrineCommonCacheArrayCache() ); $reader->setDefaultAnnotationNamespace( 'DoctrineORMMapping' ); $class = new ReflectionClass('MyProjectEntityUser'); $classAnnotations = $reader->getClassAnnotations($class); echo $classAnnotations['DoctrineORMMappingEntity'] ->repositoryClass; sábado, 26 de junho de 2010
  22. 22. 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); } sábado, 26 de junho de 2010
  23. 23. DoctrineDBAL git@github.com:doctrine/dbal.git  DataBase Abstraction Layer construído sobre a PDO e drivers proprietários  Drivers suportados:  DB2  Microsoft SQL Server (pdo_sqlsrv & sqlsrv)  MySQL  PostgreSQL  Oracle  SQLite sábado, 26 de junho de 2010
  24. 24. DoctrineDBAL  API para introspecção e gerenciamento de schemas de Bancos de Dados melhorado  Pode se tornar um padrão para DBAL em PHP 5.3 no futuro, tal como MDB2 para PEAR1  Inspirado em ezcDatabase, MDB2 e Zend_Db  Talvez podemos fazer acontecer para a PEAR2 sábado, 26 de junho de 2010
  25. 25. DoctrineDBAL interface DoctrineDBALConnection { // API para manipulação de dados /* Executa um SQL DELETE statement numa tabela. */ function delete($tableName, array $identifier); /* Executa um SQL UPDATE statement numa tabela. */ function update($tableName, array $data, array $identifier); /* Insere uma linha na tabela com os dados especificados. */ function insert($tableName, array $data); /* Prepara um SQL statement. Retorna um DBALStatement */ function prepare($statement); /* Aplica um SQL statement e retorna # linhas afetadas. */ function exec($statement); // ... sábado, 26 de junho de 2010
  26. 26. DoctrineDBAL // API para Transação /* Retorna o nível de profundidade da transação corrente. */ function getTransactionNestingLevel(); /* Executa uma função em uma transação. */ function transactional(Closure $func); /* Inicia uma transação suspendendo o modo auto-commit. */ function beginTransaction(); /* Aplica a transação corrente. */ function commit(); /* Cancela qualquer alteração na base da transação corrente. */ function rollback(); /* Checa se a transação corrente é marcada como somente rollback. */ function isRollbackOnly(); // ... sábado, 26 de junho de 2010
  27. 27. DoctrineDBAL // API para obtenção de dados /* Executa consulta SQL e retorna a 1a. linha num array assoc. */ function fetchAssoc($statement, array $params = array()); /* Executa consulta SQL e retorna a 1a. linha num array numérico. */ function fetchArray($statement, array $params = array()); /* Executa consulta SQL e retorna o valor da 1a. coluna. */ function fetchColumn( $statement, array $params = array(), $colnum = 0 ); /* Executa consulta SQL e retorna todo resultado num array assoc. */ function fetchAll($sql, array $params = array()); } sábado, 26 de junho de 2010
  28. 28. DoctrineDBALTypes  Ponto centralizado para conversão de tipos  Do Banco de Dados para PHP  Do PHP para o Banco de Dados  Independente do Banco de Dados  Acesso ao dialeto específico da Base via Platforma  Extensível sábado, 26 de junho de 2010
  29. 29. DoctrineDBALTypes  Novo tipo é só implementar uma classe abstrata: interface DoctrineDBALTypesType { function convertToDatabaseValue( $value, AbstractPlatform $platform ); function convertToPHPValue( $value, AbstractPlatform $platform ); function getSqlDeclaration( array $fieldDeclaration, AbstractPlatform $platform ); function getName(); function getBindingType(); } sábado, 26 de junho de 2010
  30. 30. 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"; } } sábado, 26 de junho de 2010
  31. 31. DoctrineDBALTypes  Finalmente, faça o Doctrine saber sobre seu tipo: DoctrineDBALTypesType::addType( "my-object", "MyProjectDataTypesMyObjectType" );  Então você pode usar nas suas Entidades! /** * @Entity * @Table(name="files") */ class File { // ... /** * @Column(type="my-object") */ protected $content; } sábado, 26 de junho de 2010
  32. 32. DoctrineDBAL  Criando um 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")); // obtenha as consultas para criar este schema. $queries = $schema->toSql($platform); Array( 0 => 'CREATE TABLE users ( id INTEGER NOT NULL, name VARCHAR(32) NOT NULL, PRIMARY KEY("id") )' ) sábado, 26 de junho de 2010
  33. 33. DoctrineDBAL  Removendo um schema: // obtém as queries para remover o schema em segurança. $queries = $schema->toDropSql($platform); Array( 0 => 'DROP TABLE users' )  Faz o inverso que ->toSql() faz sábado, 26 de junho de 2010
  34. 34. DoctrineDBAL  Comparando 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")); sábado, 26 de junho de 2010
  35. 35. DoctrineDBAL  Comparando 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")); sábado, 26 de junho de 2010
  36. 36. DoctrineDBAL  Comparando schemas: $platform = $em->getConnection()->getDatabasePlatform(); $comparator = new DoctrineDBALSchemaComparator(); $schemaDiff = $comparator->compare($fromSchema, $toSchema); // queries para alterar de um schema para outro. $queries = $schemaDiff->toSql($platform); Array( 0 => 'ALTER TABLE users ADD email VARCHAR(255) NOT NULL' ) sábado, 26 de junho de 2010
  37. 37. Performance em Inserções  Inserindo 20 entradas com 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; sábado, 26 de junho de 2010
  38. 38. Performance em Inserções  Inserindo 20 entradas com código PHP “crú”: $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; sábado, 26 de junho de 2010
  39. 39. Performance em Inserções  Sem palhaçada aqui! =P Qual deles vocês acham que é mais rápido?  Doctrine 2  Tempo: 0.0094 segundos  Código PHP  Tempo: 0.0165 segundos  PQP?!?! Doctrine + rápido que código PHP puro?  Provê muito menos, não provê recursos, sem abstração!  A resposta é TRANSAÇÃO! Doctrine 2 gerencia nossas transações e executa todos os comandos de forma eficiente numa única. sábado, 26 de junho de 2010
  40. 40. Performance em Inserções  Doctrine 2 *NÃO É* mais rápido que código PHP puro  Desenvolvedores passam por cima de pequenos detalhes e podem causar problemas significantes de performance! sábado, 26 de junho de 2010
  41. 41. Performance em Inserções  Inserindo 20 entradas com código PHP “crú”: $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; sábado, 26 de junho de 2010
  42. 42. Performance em Inserções  Informações finais de performance...  Doctrine 2  Tempo: 0.0094 segundos  Código PHP  Tempo: 0.0165 segundos  Código PHP (revisitado)  Tempo: 0.0028 segundos  Você pode ler mais sobre isto no blog do Doctrine  http://www.doctrine-project.org/blog/transactions-and-performance sábado, 26 de junho de 2010
  43. 43. DoctrineORM  O que aprendemos com Doctrine 1?  Camada de Persistência != Modelo de Domínio  Foco no propósito chave, a Camada de Persistência  “You’re doing it wrong!”  Extingüir a mágica sábado, 26 de junho de 2010
  44. 44. DoctrineORM  Comparação de performance  Hidratar 5000 registros  Doctrine 1.2: 4.3 segundos  Doctrine 2.0-DEV: 1.4 segundos  Hidratar 10000 registros  Doctrine 2.0-DEV: 3.5 segundos  Duas vezes mais registros e ainda assim mais rápido que o Doctrine 1! sábado, 26 de junho de 2010
  45. 45. DoctrineORM  Por que é mais rápido?  Otimizações do PHP 5.3!  30% menos recursos, 20% mais rápido  5.3-DEV (lazy bucket alloc, interned strings, runtime cache), Doctrine 2 pode rodar 50% mais rápido!  Melhor algoritmo de hidratação  Ordenação Topológica  Entidades enxutas  Aspectos mágicos do Doctrine 1 extintos sábado, 26 de junho de 2010
  46. 46. DoctrineORM  Por que extingüir a mágica?  Eliminar o fator PQP/minuto  Difícil de debugar  Casos extremos são difíceis de corrigir  Casos extremos são difíceis de se contornar  Tudo funciona até você sair fora da caixa  ...e a mágina é lenta! Eu posso provar, olha!  __set é ~87% mais lento que um set normal  __get é ~150% mais lento que um get normal sábado, 26 de junho de 2010
  47. 47. DoctrineORM  Como extingüir a mágica?  Nós chamamos de POO!  Composição  Herança  Agregação  Polimorfismo  Encapsulamento  etc sábado, 26 de junho de 2010
  48. 48. DoctrineORM  DataMapper ao invés de ActiveRecord  Densamente inspirado em JSR-317/JPA v2.0  Java... QUÊ?!?! #$@&*!  PHP ainda peca pela falta de padronização  PHP Standards Group pode nos socorrer?!  Versão final 2.0.0 esperada para Setembro sábado, 26 de junho de 2010
  49. 49. DoctrineORM  Entidades  Classe PHP regular  Objeto persistente de domínio enxuto  Não necessita extender uma classe base!  Não pode ser final ou conter métodos final  Duas entidades na hierarquia de classes não pode mapear uma propriedade com o mesmo nome  Classes concretas e abstratas podem ser Entidades  Entidades podem extender classes não-entidades bem como classes entidades  Classes não-entidade podem extender classes entidades sábado, 26 de junho de 2010
  50. 50. 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 } sábado, 26 de junho de 2010
  51. 51. DoctrineORM EntityUser: type: entity table: users id: id: type: integer generator: strategy: AUTO fields: name: type: string length: 32 sábado, 26 de junho de 2010
  52. 52. 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> sábado, 26 de junho de 2010
  53. 53. DoctrineORM  Mapeamento de Colunas  type  length  scale, precision  nullable  unique  name (DB)  options  columnDefinition /** * @Column(type="string", length=32, unique=true) */ protected $foo; sábado, 26 de junho de 2010
  54. 54. DoctrineORM  Campos identificadores  Suporta diferentes estratégias:  AUTO  SEQUENCE  TABLE  NONE /** * @Id @GeneratedValue(strategy="AUTO") * @Column(type="integer") */ protected $id; sábado, 26 de junho de 2010
  55. 55. DoctrineORM  Campos de associação  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; sábado, 26 de junho de 2010
  56. 56. DoctrineORM  Herança  Concrete Table Inheritance  Sem colunas irrelevantes  Sem problemas de colisão  Difícil para lidar com chaves primárias  Pesquisa na superclasse significa pesquisar em todas as tabelas (muitas queries ou umjoin maluco)  Refatoração nos campos significa um update em algumas ou todas as tabelas sábado, 26 de junho de 2010
  57. 57. 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; } sábado, 26 de junho de 2010
  58. 58. DoctrineORM CREATE TABLE users ( mapped TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related_id INTEGER DEFAULT NULL, PRIMARY KEY(id) ); sábado, 26 de junho de 2010
  59. 59. DoctrineORM  Herança  Single Table Inheritance  Somente uma tabela na base de dados  Sem joins  Refatoração de campos não muda o schema da tabela  Disperdício de espaço na base de dados  Muitos locks devido aos inúmeros acessos  Sem duplicação de nome de campos com diferentes significados sábado, 26 de junho de 2010
  60. 60. DoctrineORM namespace MyProjectEntity; /** * @Entity * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({ * "user" = "User", "employee" = "Employee" * }) */ class User { // ... } /** @Entity */ class Employee extends User { // ... } sábado, 26 de junho de 2010
  61. 61. DoctrineORM  Herança  Class Table Inheritance  Fácil de entender  Espaço na tabela é otimizado devido à normalização  Relacionamento direto entre o Modelo de Domínio e a base  Muitos joins  Refatoração de campos precisa de um update no schema  Tabela supertipo é muito acessado, pode estar em lock sábado, 26 de junho de 2010
  62. 62. DoctrineORM namespace MyProjectEntity; /** * @Entity * @InheritanceType("JOINED") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({ * "user" = "User", "employee" = "Employee" * }) */ class User { // ... } /** @Entity */ class Employee extends User { // ... } sábado, 26 de junho de 2010
  63. 63. DoctrineORM  Proxies  Carga-tardia dos dados da Entidade  Provê a possibilidade de obter uma referência à Entidade sem acesso à base de dados  Pode ser gerado em tempo de execução ou via ferramenta de linha de comando $proxyUser = $em->getReference("User", 1); sábado, 26 de junho de 2010
  64. 64. DoctrineORM  EntityManager  Ponto central da funcionalidade ORM  Aplica a estratégia de Transaction Write Behind que atrasa a execução de comandos SQL  ...isto significa, eficiência!  ...e também significa que os locks de escrita são rapidamente liberados!  Internamante, ele usa UnitOfWork para manter informações de estado dos objetos sábado, 26 de junho de 2010
  65. 65. 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); // ... sábado, 26 de junho de 2010
  66. 66. 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); // ... sábado, 26 de junho de 2010
  67. 67. 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); // ... sábado, 26 de junho de 2010
  68. 68. 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(); } sábado, 26 de junho de 2010
  69. 69. DoctrineORM  Trabalhando com Entidades no EntityManager  Criando o 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 ); sábado, 26 de junho de 2010
  70. 70. DoctrineORM  Trabalhando com Entidades no EntityManager  Persistindo Entidades try { $em->transactional(function ($em) { $user = new MyProjectEntityUser(); $user->name = "Guilherme Blanco"; $em->persist($user); }); } catch (Exception $e) { // ... } sábado, 26 de junho de 2010
  71. 71. DoctrineORM  Trabalhando com Entidades no EntityManager  Atualizando Entidades try { $em->transactional(function ($em) { $user = $em->find("MyProjectEntityUser", 1); $user->name = "Benjamin Eberlei"; $em->persist($user); }); } catch (Exception $e) { // ... } sábado, 26 de junho de 2010
  72. 72. DoctrineORM  Trabalhando com Entidades no EntityManager  Removendo Entidades try { $em->transactional(function ($em) { $user = $em->getReference("MyProjectEntityUser", 1); $em->remove($user); }); } catch (Exception $e) { // ... } sábado, 26 de junho de 2010
  73. 73. DoctrineORM  Doctrine Query Language (DQL)  Implementação de uma OQL  Fortemente influenciada por Hibernate QL  Top-down recursive descent parser LL(*), construindo uma árvore de abstração sintática (AST)  AST é então usada para gerar SQL dependente $query = $em->createQuery( "SELECT u FROM MyProjectEntityUser u" ); $users = $query->execute(); sábado, 26 de junho de 2010
  74. 74. DoctrineORM  Native Query  Possibilitavoltar ao poder da SQL sem perder a habilidade de hidratar seus dados na sua Entidade $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(); sábado, 26 de junho de 2010
  75. 75. DoctrineORM  QueryBuilder  Implementação de um Builder  Construção e execução são separadas  QueryBuilder não pode ser executada; ao invés disso, obtenha uma instância de Query e execute-a $qb = $em->createQueryBuilder() ->select("u") ->from("MyProjectEntityUser", "u"); $users = $qb->getQuery()->execute(); sábado, 26 de junho de 2010
  76. 76. DoctrineORM  Doctrine suporta diferentes níveis de cache  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"); sábado, 26 de junho de 2010
  77. 77. DoctrineORM  Console  Usa o componente Symfony 2 Console  Auxilia a desenvolver com Doctrine  Tarefas disponíveis em todos os pacotes $helperSet = $cli->getHelperSet(); $helperSet->set( new DoctrineDBALToolsConsoleHelperConnectionHelper( $em->getConnection() ), 'db' ); $helperSet->set( new DoctrineORMToolsConsoleHelperEntityManagerHelper( $em ), 'em' ); $cli->addCommands(array(...)); sábado, 26 de junho de 2010
  78. 78. DoctrineORM  Comandos disponíveis:  DoctrineDBALToolsConsoleCommandRunSqlCommand  DoctrineDBALToolsConsoleCommandImportCommand  DoctrineORMToolsConsoleCommandClearCacheMetadataCommand  DoctrineORMToolsConsoleCommandClearCacheResultCommand  DoctrineORMToolsConsoleCommandClearCacheQueryCommand  DoctrineORMToolsConsoleCommandSchemaToolCreateCommand  DoctrineORMToolsConsoleCommandSchemaToolUpdateCommand  DoctrineORMToolsConsoleCommandSchemaToolDropCommand  DoctrineORMToolsConsoleCommandConvertDoctrine1SchemaCommand  DoctrineORMToolsConsoleCommandConvertMappingCommand  DoctrineORMToolsConsoleCommandGenerateRepositoriesCommand  DoctrineORMToolsConsoleCommandGenerateEntitiesCommand  DoctrineORMToolsConsoleCommandGenerateProxiesCommand  DoctrineORMToolsConsoleCommandEnsureProductionSettingsCommand  DoctrineORMToolsConsoleCommandValidateSchemaCommand  DoctrineORMToolsConsoleCommandRunDqlCommand sábado, 26 de junho de 2010
  79. 79. Future  DBAL  QueryBuilder  Concluir o driver MSSQL Server  DQL  Suporte a TYPE()  Adicionar múltiplos FROM  Embedded Values  ODM  Extrair a interface de DocumentManager  Estabilizar o driver de MongoDB  Implementar outros drivers (CouchDB, SimpleDB, ...) sábado, 26 de junho de 2010
  80. 80. Questions?  Guilherme Blanco  Informações de contato:  @guilhermeblanco  guilhermeblanco@php.net  http://www.facebook.com/guilhermeblanco  +55 16 9215.8480  OBRIGADO PELA PACIÊNCIA!!! =) sábado, 26 de junho de 2010
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×