Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Doctrine for dummies

393 visualizaciones

Publicado el

Apresentação realizada na PHP Conference Brasil 2017 <www.phpconference.com.br> (12º edição), no dia 7/12/2017 às 15h 30min.

Publicado en: Tecnología
  • Sé el primero en comentar

Doctrine for dummies

  1. 1. Bacharel em Informática com ênfase em Análise de Sistemas (Unisinos), estudou na Universidade Técnica de Lisboa (Portugal), é Zend Certified Engineer (PHP 5.3), Zend Certified PHP Engineer (PHP 5.5), Rogue Wave Zend Certified Engineer 2017-PHP (PHP 7.1), Zend Framework 2 Certified Architect (ZFCA), Certified ScrumMaster pela Scrum Alliance, Microsoft Certified Professional (MCP), idealizador do curso Certificamp, autor do "Guia Preparatório para a Certificação PHP", consultor web e PHP evangelist. Atualmente é discente de pós-graduação em Computação Forense & Perícia Digital, mantenedor do site www.perito.inf.br e criador do TopTrumPHPs - SuperTrunfo de frameworks PHP www.toptrumphps.com. Ari Stopassola Junior
  2. 2. Dummy ≠ Dumb
  3. 3. Passeios Nome Descrição Preço Distância ... Objetos Base relacional Nome Descrição Preço Distância Classe Passeios Tabela Passeios ORM
  4. 4. #SQN
  5. 5. Herança
  6. 6. Associação
  7. 7. Composição Onde a parte é exclusiva do todo
  8. 8. Agregação Onde a parte não é exclusiva do todo
  9. 9. Mapeamento Objeto Relacional (ORM) • Persistir o objeto numa estrutura de dados relacional • Tradução para tabelas, campos, linhas e relacionamentos • Conversões de tipo • ORM mascara detalhes obscuros • Overhead • Requer aprendizagem de outras tencnologias. Ex.: DQL (Doctrine), Propel, Eloquent etc. http://www.edzynda.com/use-laravels-eloquent-orm-outside-of-laravel/
  10. 10. Capítulo 3: A Self-Made ORM
  11. 11. Fontes: https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch http://blogs.tedneward.com/post/the-vietnam-of-computer-science Impedance mismatch
  12. 12. Ferramentas de Object-relational mapping
  13. 13. Quem usa Doctrine? GitHub Doctrine Propel Commits 11.010 4.241 Branches 17 3 Releases 75 7 Contributors 537 148 Watch 317 85 Star 3.785 998 Fork 1.815 300 Extraídodia12/10/2017
  14. 14. Doctrine Vantagens • Estabilidade • Comunidade • Integração com os principais frameworks Desvantagens •Curva de aprendizado •Performance
  15. 15. • Object Relational Mapping (ORM) • Database Abstraction Layer (DBAL) • Common • Annotations • Collections • Cache • Inflector • Lexer Projetos correlacionados
  16. 16. https://github.com/guilhermeblanco
  17. 17. Roadmap • Modelo de domínio • Database Abstraction Layer (DBAL) • Object Relational Mapping (ORM) • Entities • Entity manager • Mapping • Repositories • Life cicle events • Query Builder • Caching • Proxies • Event subsystem Fonte:https://flic.kr/p/UagSBp
  18. 18. composer require doctrine/orm
  19. 19. Auto-carregamento { "require": { "doctrine/orm": "^2.5" }, "autoload": { "classmap": ["src/"] } } composer dump Mais informações em: https://getcomposer.org/doc/04-schema.md
  20. 20. Eloquent implementa Active Record class Passeios extends Eloquent { } $passeio = Passeios::find(32); $passeio->name = "Tour Uva e Vinho"; $passeio->save(); Fonte: http://www.martinfowler.com/eaaCatalog/activeRecord.html
  21. 21. Doctrine 2 implementa Data Mapper Fonte: http://martinfowler.com/eaaCatalog/dataMapper.html
  22. 22. Data Mapper • Camada de software que separa objetos em memória do banco de dados • Sua responsabilidade é transmitir dados entre ambos e isolar um do outro • Objetos desconhecem o esquema do banco de dados, tão pouco usam SQL https://2013.nosql-matters.org/cgn/index.html%3Fp=2156.html
  23. 23. <?php /** * @Entity * @Table(name="passeios") */ class Passeio { /** * @Id * @GeneratedValue(strategy="AUTO") * @Column(type="integer") */ private $id; /** * @Column(type="string", length=255, nullable=true) */ private $nome; }
  24. 24. Annotations • Instruções declarativas dentro de blocos de documentação • Doctrine usa anotações para definir o mapeamento objeto- relacional • Annotations são metadados que descrevem a entidade, como ela deve ser armazenada, que tipo de colunas serão usadas etc. • Inspirado no PHPDocumentor www.phpdoc.org • Definida sempre acima do nome da classe e de cada atributo • Entre /** xxx */ e começam com o simbolo @ /** * Produto * * @Entity * @Table(name="produtos") */
  25. 25. Anotações obrigatórias "Learning Doctrine" by Doug Bierer (O'Reilly)
  26. 26. @Column(type="xxxx") • smallint, integer, bigint • decimal, float • string, text, guid • binary, blob, boolean • date, date time, datetimez, time • array, simple_array, json_array, object http://doctrine- dbal.readthedocs.io/en/latest/reference/types.html
  27. 27. Mapeandos os tipos de dados Tipos do Doctrine Tipos SQL Tipos PHP string VARCHAR string integer INT integer smallint SMALLINT integer bigint BIGINT string boolean BOOLEAN boolean decimal DECIMAL double date DATETIME DateTime time TIME DateTime datetime DATETIME/TIMESTAMP DateTime text CLOB string
  28. 28. Entity Manager $passeio = new Passeio; $passeio->setName("Tour Itaimbezinho"); EntityManager::persist($passeio); EntityManager::flush();
  29. 29. Entity Manager $passeio = new Passeio; $passeio->setName("Tour Itaimbezinho"); EntityManager::persist($passeio); EntityManager::flush();
  30. 30. Fotohttps://www.flickr.com/photos/pragdave/173640462
  31. 31. Unit of Work Fonte: http://martinfowler.com/eaaCatalog/unitOfWork.html • Estratégia transactional write-behind • Retarda a execução de cláusulas SQL para executá-las posteriormente de forma mais eficiente • Executa numa ordem tal de modo a liberar o mais rápido possível as tabelas em questão (write locks), ao fim da transação
  32. 32. Herança
  33. 33. Herança: estratégia single table /** * @Entity * @Table(name="pessoas") * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="diferencia", type="string") * @DiscriminatorMap({"pessoa"="Pessoa","autor"="Autor","editor"="Editor"}) */ class Pessoa { ... } /** * @Entity */ class Editor extends Pessoa { ... } /** * @Entity */ class Autor extends Pessoa { ... }
  34. 34. Herança: estratégia single table
  35. 35. Herança: estratégia Single Table /** * @Entity * @InheritanceType("SINGLE_TABLE") * @DiscriminatorColumn(name="discr", type="string") * @DiscriminatorMap({"person"="Usuario","employee"="Colaborador"}) */ Revistaphp|architect,ediçãomarço/2016.
  36. 36. Herança: estratégia Class Table Id Email Senha Nome Distingue Pessoa Id Curriculo Participacao Autor Id Especialidade Editor
  37. 37. Herança: Class Table /** * @Entity * @Table(name="pessoa") * @InheritanceType("JOINED") * @DiscriminatorColumn(name="distingue", type="string") * @DiscriminatorMap({"comum"="Pessoa","autor"="Autor","editor"="Editor"}) */ class Pessoa
  38. 38. Hidratação $produto = $entityManager->find('Produto', 5);
  39. 39. Workflow 1) Crie as entidades com suas respectivas annotations 2) Implemente o cli-config.php (na raiz do projeto) que chama o bootstrap.php – de acordo com o exemplo a seguir 3) Realize a varredura nas annotations e crie as respectivas tabelas: vendor/bin/doctrine orm:schema-tool:create • Verifique incoerências das classes mediante o BD: vendor/bin/doctrine orm:validate-schema • vendor/bin/doctrine orm:schema-tool:update --force
  40. 40. <?php require_once "vendor/autoload.php"; use DoctrineORMToolsSetup; use DoctrineORMEntityManager; $config = Setup::createAnnotationMetadataConfiguration(array("./src")); //Configura a base de dados $conexao = array( 'driver' => 'pdo_mysql', 'host' => 'localhost', 'dbname' => 'tutorial-doctrine', 'user’ => 'root', 'password' => 'root' ); //Disponibiliza o EntityManager $entityManager = EntityManager::create($conexao, $config); bootstrap.php
  41. 41. cli-config.php <?php require_once "bootstrap.php"; //Precisamos prover ao entityManager uma interface via linha de comando //A interface CLI nos permite interagir com o banco de dados como, por exemplo //criar e atualizar esquemas de BD return DoctrineORMToolsConsoleConsoleRunner::createHelperSet($entityManager);
  42. 42. Livro http://leanpub.com/certificacaophp
  43. 43. Modelo de domínio
  44. 44. Relacionamentos Fonte:https://flic.kr/p/jagpmg
  45. 45. Hóspede $id $nome Hóspede $id $nome Hotel $id $hospedes[] Hóspede $id $hotel Owning side Inverse side /** * @OneToMany(targetEntity="Hospede", mappedBy="hotel") */ protected $hospedes; Relação 1:N (um-para-ene) “Um hotel hospeda vários hóspedes”
  46. 46. /** * um usuário:muitas correções * @OneToMany(targetEntity="Correcao", mappedBy="usuario") */ private $correcoes;
  47. 47. class Usuario { /** * @Id * @GeneratedValue * @Column(type="bigint") */ private $id; /** * @Column(name="email", type="string", length=255, nullable=false) */ private $email; /** * @Column(name="senha", type="string", length=255, nullable=false) */ private $senha; /** * @Column(name="nome", type="string", length=255) */ private $nome;
  48. 48. vendor/bin/doctrine orm:validate-schema
  49. 49. vendor/bin/doctrine orm:schema-tool:create
  50. 50. usuarioscorrecoes
  51. 51. use DoctrineCommonCollectionsArrayCollection; ... public function __construct() { parent::__construct(); $this->correcoes = new ArrayCollection(); } public function setCorrecoes($correcao) { $this->correcoes[] = $correcao; } Classe: usuario
  52. 52. Relação 1:1 (lê-se um-para-um) “cada colaborador trabalha para uma empresa parceira” Colaborador $id $parceiro Parceiro $id Owning side Inverse side /** * @OneToOne(targetEntity="Parceiro") * @JoinColumn(name="parceiro", referencedColumnName="id") */ protected $parceiro;
  53. 53. id nome preco duracao 1 Tour Uva e Vinho 99 12 2 Noite Gaúcha 110 4 3 Alpen Park 30 3 4 Canyon Itaimbezinho 99 10 5 Parques de Gramado 35 5 pacotes_id passeios_id 1 1 1 2 2 3 2 4 3 3 4 1 4 5 Passeios Relação N:M (ene-para-eme) “Pacotes têm passeios e o mesmo passeio compõe vários pacotes” id nome 1 Serra Gaúcha Tradicional 2 Aventura 3 Serra com as Crianças 4 Italiana e Alemã Pacotes
  54. 54. Pacote $id $passeios[] Pacote $id $passeios[] Hóspede $id $nome Hóspede $id $nome Pacote $id $passeios[] Passeio $id $pacotes[] Owning side Inverse side /** * @ManyToMany(targetEntity="Passeio", mappedBy="pacotes") * @JoinTable(name="pacotes_has_passeios", * joinColumns={@JoinColumn(name="pacotes_id", "id")}, * inverseJoinColumns={@JoinColumn(name="passeios_id", "id")}) */ protected $passeios; Relação N:M (ene-para-eme) “Pacotes têm passeios e o mesmo passeio compõe vários pacotes”
  55. 55. N:M Pacote $id $passeios[] Pacote $id $passeios[] Hóspede $id $nome Hóspede $id $nome Usuário $id $livros[] Livro $id $usuarios[] Owning side Inverse side /** * Muitos usuário:muitos livros * @ManyToMany(targetEntity="Livro", mappedBy="usuarios") */ private $livros; Identifica a coluna no inverse side que referencia de volta o owning side
  56. 56. N:M Pacote $id $passeios[] Pacote $id $passeios[] Hóspede $id $nome Hóspede $id $nome Usuário $id $livros[] Livro $id $usuarios[] Owning side Inverse side /** * Muitos livros:muitos usuários * @ManyToMany(targetEntity="Usuario", inversedBy="livros") */ private $usuarios;
  57. 57. usuarioscorrecoeslivros livro_usuario Criação automática do schema...
  58. 58. Relações •One-to-one •One-to-many •Many-to-many  Unidirecional  Bidirecional  Self- Referencing
  59. 59. Lifecycle Events
  60. 60. Lifecycle Events: eventos • preRemove e postRemove • prePersist e postPersist • preUpdate e postUpdate • postLoad • preFlush, onFlush e postFlush Fonte: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html
  61. 61. /** * @Entity * @HasLifecycleCallbacks * @Table(name="usuarios") */ class Usuario { /** @PrePersist */ public function geraSenhaRandomica() { for($i = 1; $i <= 6; $i++) { $this->senha .= chr(rand(65, 90)); //65 -> A, 90 -> Z } }
  62. 62. Fonte: http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/introduction.html
  63. 63. PDO x DBAL Data-access Layer • Permite a troca de banco de dados utilizando as mesmas chamadas de métodos • Não reescreve SQL • Tão pouco emula funcionalidades inexistentes Database Abstraction Layer • Agnóstico • Manipulação por meio de uma API Orientada à Objetos • Traz maior consistência na manipulação do BD • Doctrine usa DBAL, mas você pode usar DBAL sem Doctrine • DBAL utiliza PDO internamente
  64. 64. ExemplodeDBAL <?php include __DIR__ . '/doctrine_autoloader.php'; use DoctrineDBALConfiguration; use DoctrineDBALDriverManager; //Obtém a conexão $dbParams = include __DIR__ . '/database.params.php'; $conn = DriverManager::getConnection($dbParams, new Configuration()); $sql = "SELECT * FROM orcamentos WHERE sobrenome = ?"; $stmt = $conn->prepare($sql); $stmt->execute(array('STOPASSOLA')); //OU utilizando QueryBuilder $qb = $conn->createQueryBuilder(); $qb->select('*')->from('orcamentos')->where('sobrenome = :name'); $data = array(':name' => 'STOPASSOLA'); while ($tupla = $stmt->fetch()) { var_dump($tupla); }
  65. 65. Namespaces //Cria um novo livro $livro = new PublicacoesLivro(); $livro->setNome("Guia preparatório para a Certificação PHP"); $livro->setEdicao(1); //Persiste no banco de dados $entityManager->persist($livro); $entityManager->flush();
  66. 66. Repository Pattern //Obtem TODOS os livros com o método findAll //Obs.: uso do namespace é imprescindível $livros = $em->getRepository('PublicacoesLivro')->findAll(); echo "<strong>Listando todos os livros</strong><br>"; foreach($livros as $livro){ echo $livro->getNome()."<br>"; } Instância de EntityManager Fonte: https://tommcfarlin.com/repository-pattern-benefits/
  67. 67. Repository: find() $livro = $em->getRepository('PublicacoesLivro')->find(1); echo $livro->getNome(); Busca pelo ID
  68. 68. Busca por critério $livros = $em->getRepository('Livro')->findBy(array('edicao' => 1), array('nome' => 'ASC')); $livro = $em->getRepository('Livro')->findOneBy(array('isbn' => '978-1-4842-2558-5')); $livro = $em->getRepository('Livro')->findOneByIsbn('978-1-4842-2558-5'); Magic finders
  69. 69. Doctrine Query Language – DQL $query = EntityManager::createQuery("select p from VendaBalcaoEntitiesPasseios p where p.preco >= 90 AND p.preco <= 150"); $passeios = $query->getResult();
  70. 70. Delete $livro = $em->getRepository('PublicacoesLivro')->find(27); $em->remove($livro); $em->flush(); $livro = $em->find('PublicacoesLivro', 27); $em->remove($livro); $em->flush();
  71. 71. SHOW ME THE CODE! https://github.com/stopassola/doctrine_lab
  72. 72. Lab: https://github.com/stopassola/doctrine_lab
  73. 73. Referências
  74. 74. DUAS cortesias https://leanpub.com/doctrine-na-pratica
  75. 75. E-mail: arijunior@gmail.com Twitter: @stopassola Skype: stopassola LinkedIn: http://pt.linkedin.com/in/stopassola Facebook: http://www.facebook.com/arijunior Sites: http://slideshare.net/arijunior http://www.perito.inf.br http://www.certificamp.com http://www.rumoacertificacaophp.com Contatos

×