SlideShare uma empresa Scribd logo
1 de 80
Baixar para ler offline
Guilherme Blanco, Yahoo!


          Doctrine 2
           Camada de Persistência para PHP 5.3+




sábado, 26 de junho de 2010
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
Quem sou eu?
        http://www.twitter.com/guilhermeblanco

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




sábado, 26 de junho de 2010
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 de junho de 2010
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
Doctrine 2
        Três principais pacotes:
            Common


            DBAL


            ORM




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

        Cache Drivers




sábado, 26 de junho de 2010
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
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
DoctrineCommon
     git@github.com:doctrine/common.git

        Cache Drivers

        Class Loader




sábado, 26 de junho de 2010
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
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
DoctrineCommon
     git@github.com:doctrine/common.git

        Cache Drivers

        Class Loader

        Collections




sábado, 26 de junho de 2010
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
DoctrineCommon
     git@github.com:doctrine/common.git

        Cache Drivers

        Class Loader

        Collections

        Lexer




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

        Cache Drivers

        Class Loader

        Collections

        Lexer

        Annotations Parser

sábado, 26 de junho de 2010
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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

Mais conteúdo relacionado

Mais procurados

LabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - FunçõesLabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - Funções
Carlos Santos
 

Mais procurados (20)

PHP na Tela Escura: Aplicações Poderosas em Linha de Comando
PHP na Tela Escura: Aplicações Poderosas em Linha de ComandoPHP na Tela Escura: Aplicações Poderosas em Linha de Comando
PHP na Tela Escura: Aplicações Poderosas em Linha de Comando
 
Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014
 
Introdução ao Zend Framework 2
Introdução ao Zend Framework 2Introdução ao Zend Framework 2
Introdução ao Zend Framework 2
 
Abstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP DoctrineAbstração do banco de dados com PHP Doctrine
Abstração do banco de dados com PHP Doctrine
 
Introdução a JPA (2010)
Introdução a JPA (2010)Introdução a JPA (2010)
Introdução a JPA (2010)
 
PHP GERAL
PHP GERALPHP GERAL
PHP GERAL
 
PHP Jedi - Boas Práticas e Alta Performance
PHP Jedi - Boas Práticas e Alta PerformancePHP Jedi - Boas Práticas e Alta Performance
PHP Jedi - Boas Práticas e Alta Performance
 
Python 03
Python 03Python 03
Python 03
 
Java script aula 05 - funções
Java script   aula 05 - funçõesJava script   aula 05 - funções
Java script aula 05 - funções
 
Python 08
Python 08Python 08
Python 08
 
Python 04
Python 04Python 04
Python 04
 
Java script aula 02 - operadores
Java script   aula 02 - operadoresJava script   aula 02 - operadores
Java script aula 02 - operadores
 
Desenvolvendo Extensões PECL
Desenvolvendo Extensões PECLDesenvolvendo Extensões PECL
Desenvolvendo Extensões PECL
 
Curso Desenvolvimento WEB com PHP - PHP (parte 1)
Curso Desenvolvimento WEB com PHP - PHP (parte 1)Curso Desenvolvimento WEB com PHP - PHP (parte 1)
Curso Desenvolvimento WEB com PHP - PHP (parte 1)
 
Programando Melhor - Flisol
Programando Melhor - FlisolProgramando Melhor - Flisol
Programando Melhor - Flisol
 
Desenvolvendo uma Aplicação WEB usando o Python e o CherryPy
Desenvolvendo uma Aplicação WEB usando o Python e o CherryPyDesenvolvendo uma Aplicação WEB usando o Python e o CherryPy
Desenvolvendo uma Aplicação WEB usando o Python e o CherryPy
 
Threads 07: Sincronizadores
Threads 07: SincronizadoresThreads 07: Sincronizadores
Threads 07: Sincronizadores
 
LabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - FunçõesLabMM4 (T13 - 12/13) - Funções
LabMM4 (T13 - 12/13) - Funções
 
Linguagem PHP
Linguagem PHPLinguagem PHP
Linguagem PHP
 
PHP Day - PHP para iniciantes
PHP Day - PHP para iniciantesPHP Day - PHP para iniciantes
PHP Day - PHP para iniciantes
 

Semelhante a Doctrine2 Seminário PHP

Como usar a documentação da API Java 2
Como usar a documentação da API Java 2Como usar a documentação da API Java 2
Como usar a documentação da API Java 2
Denis L Presciliano
 
Java introdução ao java
Java   introdução ao javaJava   introdução ao java
Java introdução ao java
Armando Daniel
 
Linguagens Poo
Linguagens PooLinguagens Poo
Linguagens Poo
Infogenius
 
Java aprendendo linguagem.ppt
Java aprendendo linguagem.pptJava aprendendo linguagem.ppt
Java aprendendo linguagem.ppt
Emerson Cardoso
 

Semelhante a Doctrine2 Seminário PHP (20)

Ecosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_javEcosistema spring a_plataforma_enterprise_jav
Ecosistema spring a_plataforma_enterprise_jav
 
Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012Oficina PostgreSQL Básico Latinoware 2012
Oficina PostgreSQL Básico Latinoware 2012
 
Git, GitHub e OO
Git, GitHub e OOGit, GitHub e OO
Git, GitHub e OO
 
Aula5
Aula5Aula5
Aula5
 
Aula5
Aula5Aula5
Aula5
 
Spring framework 2.5
Spring framework 2.5Spring framework 2.5
Spring framework 2.5
 
Como usar a documentação da API Java 2
Como usar a documentação da API Java 2Como usar a documentação da API Java 2
Como usar a documentação da API Java 2
 
Java introdução ao java
Java   introdução ao javaJava   introdução ao java
Java introdução ao java
 
Dependency injection WTF? - PHPSC Conference 2012
Dependency injection WTF? - PHPSC Conference 2012Dependency injection WTF? - PHPSC Conference 2012
Dependency injection WTF? - PHPSC Conference 2012
 
Cakephp 2.0 - O que mudou
Cakephp 2.0 - O que mudouCakephp 2.0 - O que mudou
Cakephp 2.0 - O que mudou
 
PHP FrameWARks - FISL
PHP FrameWARks - FISLPHP FrameWARks - FISL
PHP FrameWARks - FISL
 
Aprofunde se no php 5.3
Aprofunde se no php 5.3Aprofunde se no php 5.3
Aprofunde se no php 5.3
 
Qualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnitQualidade no desenvolvimento de software com PHPUnit
Qualidade no desenvolvimento de software com PHPUnit
 
PHP 5.3 - What's new?
PHP 5.3 - What's new?PHP 5.3 - What's new?
PHP 5.3 - What's new?
 
Linguagens Poo
Linguagens PooLinguagens Poo
Linguagens Poo
 
Java aprendendo linguagem.ppt
Java aprendendo linguagem.pptJava aprendendo linguagem.ppt
Java aprendendo linguagem.ppt
 
Fundamentos da Programação PHP OO - Aula 3
Fundamentos da Programação PHP OO - Aula 3Fundamentos da Programação PHP OO - Aula 3
Fundamentos da Programação PHP OO - Aula 3
 
Modulos SNEP
Modulos SNEPModulos SNEP
Modulos SNEP
 
Java1
Java1Java1
Java1
 
Java annotation
Java annotationJava annotation
Java annotation
 

Mais de Guilherme Blanco

Mais de Guilherme Blanco (11)

Enterprise php
Enterprise phpEnterprise php
Enterprise php
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object CalisthenicsPHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object Calisthenics
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object Calisthenics
 
ORM dont kill your DB, developers do
ORM dont kill your DB, developers doORM dont kill your DB, developers do
ORM dont kill your DB, developers do
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHPObject Calisthenics Applied to PHP
Object Calisthenics Applied to PHP
 
PHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPPHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHP
 
Javascript para adultos
Javascript para adultosJavascript para adultos
Javascript para adultos
 
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHPIPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
 
Doctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHPDoctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHP
 
PHP, Daemons e Multimedia
PHP, Daemons e MultimediaPHP, Daemons e Multimedia
PHP, Daemons e Multimedia
 
Doctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHPDoctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHP
 

Último

Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Dirceu Resende
 

Último (6)

Concurso Caixa TI - Imersão Final - Rogério Araújo.pdf
Concurso Caixa TI - Imersão Final - Rogério Araújo.pdfConcurso Caixa TI - Imersão Final - Rogério Araújo.pdf
Concurso Caixa TI - Imersão Final - Rogério Araújo.pdf
 
[ServiceNow] Upgrade de versão - 2ª edição (Revisada, atualizada e ampliada)
[ServiceNow] Upgrade de versão - 2ª edição (Revisada, atualizada e ampliada)[ServiceNow] Upgrade de versão - 2ª edição (Revisada, atualizada e ampliada)
[ServiceNow] Upgrade de versão - 2ª edição (Revisada, atualizada e ampliada)
 
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
Apresentação Power Embedded - Descubra uma nova forma de compartilhar relatór...
 
Certificado - Data Analytics - CoderHouse.pdf
Certificado - Data Analytics - CoderHouse.pdfCertificado - Data Analytics - CoderHouse.pdf
Certificado - Data Analytics - CoderHouse.pdf
 
Apresentação Comercial VITAL DATA 2024.pdf
Apresentação Comercial VITAL DATA 2024.pdfApresentação Comercial VITAL DATA 2024.pdf
Apresentação Comercial VITAL DATA 2024.pdf
 
From_SEH_Overwrite_with_Egg_Hunter_to_Get_a_Shell_PT-BR.pdf
From_SEH_Overwrite_with_Egg_Hunter_to_Get_a_Shell_PT-BR.pdfFrom_SEH_Overwrite_with_Egg_Hunter_to_Get_a_Shell_PT-BR.pdf
From_SEH_Overwrite_with_Egg_Hunter_to_Get_a_Shell_PT-BR.pdf
 

Doctrine2 Seminário PHP

  • 1. Guilherme Blanco, Yahoo! Doctrine 2 Camada de Persistência para PHP 5.3+ sábado, 26 de junho de 2010
  • 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. Quem sou eu?  http://www.twitter.com/guilhermeblanco  http://www.facebook.com/guilhermeblanco sábado, 26 de junho de 2010
  • 4. Doctrine 2 sábado, 26 de junho de 2010
  • 5. Doctrine 2  PHP 5.3+  100% do código reescrito  Código totalmente em namespaces sábado, 26 de junho de 2010
  • 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. Doctrine 2  Três principais pacotes:  Common  DBAL  ORM sábado, 26 de junho de 2010
  • 8. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers sábado, 26 de junho de 2010
  • 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. 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. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader sábado, 26 de junho de 2010
  • 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. 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. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections sábado, 26 de junho de 2010
  • 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. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections  Lexer sábado, 26 de junho de 2010
  • 17. DoctrineCommon git@github.com:doctrine/common.git  Cache Drivers  Class Loader  Collections  Lexer  Annotations Parser sábado, 26 de junho de 2010
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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