Bacharel em Informática com ênfase em Análise de
Sistemas pela Unisinos, cursou mestrado em Engenharia
Informática e de Computadores pelo Instituto Superior
Técnico da Universidade Técnica de Lisboa (Portugal),
perito judicial ad hoc especializado em TI (mantenedor do
site PERITO.inf.br), Zend Certified Engineer (PHP 5.3), Zend
Certified PHP Engineer (PHP 5.5) e Zend Framework 2
Certified Architect (ZFCA) #ZEND004019, Certified
ScrumMaster pela Scrum Alliance #203613, Microsoft
Certified Professional (MCP), idealizador do projeto
Certificamp, consultor web e PHP evangelist.
Ari Stopassola Junior
Dummy
≠
Dumb
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/
Fontes: https://en.wikipedia.org/wiki/Object-relational_impedance_mismatch
http://blogs.tedneward.com/post/the-vietnam-of-computer-science
impedance mismatch
Ferramentas de Object-relational mapping
https://github.com/guilhermeblanco
Doctrine
Vantagens
• Estabilidade
• Comunidade
• Integração com os
principais frameworks
Desvantagens
•Curva de aprendizado
•Performance
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
Passeios
Nome
Descrição
Preço
Distância
...
Objetos Base relacional
Nome Descrição Preço Distância
Classe Passeios Tabela Passeios
ORM
composer require doctrine/orm
Fonte: http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/introduction.html
PDO x DBAL
Data-access Layer
• Permite a troca de banco de
dados utlizando 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
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);
}
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
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
Doctrine 2 implementa Data Mapper
Fonte: http://martinfowler.com/eaaCatalog/dataMapper.html
<?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;
}
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")
*/
Anotações obrigatórias
"Learning Doctrine" by Doug Bierer (O'Reilly)
@ORMColumn(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
Schema
Laravel ➡ Migrations
public function up()
{
Schema::create('passeios', function(Blueprint $table)
{
$table->increments('id');
$table->string('nome');
$table->text('descricao');
$table->timestamps();
});
}
$ php artisan migrate
$ php artisan make:migration create_passeios_table --create="passeios"
Entity Manager
$passeio = new Passeio;
$passeio->setName("Tour Itaimbezinho");
EntityManager::persist($passeio);
EntityManager::flush();
Entity Manager
$passeio = new Passeio;
$passeio->setName("Tour Itaimbezinho");
EntityManager::persist($passeio);
EntityManager::flush();
Fotohttps://www.flickr.com/photos/pragdave/173640462
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
Doctrine Query Language – DQL
$query = EntityManager::createQuery("select p from
VendaBalcaoEntitiesPasseios p where p.preco >= 90
AND p.preco <= 150");
$passeios = $query->getResult();
Lab: https://github.com/stopassola/doctrine_lab
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.
Herança: estratégia Class Table
/**
* @Entity
* @InheritanceType("TABLE_PER_CLASS")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person"="Usuario","employee"="Colaborador"})
*/
Revistaphp|architect,ediçãomarço/2016.
Hidratação
$produto = $entityManager->find('Produto', 5);
Possível workflow
1) Crie as entidades com suas respectivas annotations
2) Verifique incoerências das classes mediante o BD:
$ vendor/bin/doctrine orm:validate-schema
3) Realize a varredura nas annotations e crie as respectivas tabelas:
$ vendor/bin/doctrine orm:schema-tool:update --force
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;
Hóspede
$id
$nome
Hóspede
$id
$nome
Hotel
$id
$hospedes[]
Hóspede
$id
$hotel
Owning side Inverse side
/**
* @var DoctrineCommonCollectionsCollection
* @OneToMany(targetEntity="Hospede", mappedBy="hotel")
*/
protected $hospedes;
Relação 1:N (um-para-ene)
“Um hotel hospeda vários hóspedes”
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
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”
Referências
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

Doctrine for Dummies

Notas do Editor

  • #5 Reduzir a impedância. Experimente fazer um left outer join num ORM, ou uma função de agregação como média. Alguns falharam ao executar transações, passando a responsabilidade para a aplicação. Não há necessidade de cache, pois o mongoDB já fica em memório – o quanto houver de RAM disponível. Usar monboDB simplifica o desenvolvimento da aplicação pois não requer tratar de atualizações de registros, cache expirado etc.
  • #8 Hibernate do Java e ao ActiveRecord do Rails. Mapeamento em arquivos .ini ou XML Propel e Doctrine usam o design pattern ActiveRecord, enquanto que o Zend_Db_Table usa Table Data Gateway pattern e Row Data Gateway pattern. Livro "Patterns of Enterprise Application Architecture" do Martin Fowler de 2003. CakePHP Doctrine é a mais popular.
  • #9 Top 5 contributors do projeto: https://github.com/doctrine/doctrine2/graphs/contributors
  • #11 Inspirado no Hibernate do Java
  • #12 E como ficam as agregações, composições de objetos?
  • #13 O Doctrine é uma coleção de sub-projetos como, por exemplo, DBAL, cache, Annotations etc.
  • #14 Instala também o Doctrine Commons.
  • #15 Evita utilizar um ”dialeto” SQL específico de cada banco. Não que necessariamente o BD será trocado o tempo todo, mas traz maior consistência. Esconde detalhes de cada banco. Ex.: PostreSQL CREATE SEQUENCE serial; SELECT nextval('serial'); JSON em BD também é um recurso interessantíssimo do PostgreSQL Padroniza o acesso via OO. Conexão via DBAL é semelhante ao que seria feito através de PDO. Inclusive os nomes dos métodos são semelhantes, para diminuir a curva de aprendizado. Usa interface fluente. Ex.: $obj->metodoA()->metodoB()->metodoC();
  • #18 Herda toda a lógica de persistência do ORM, gerando overhead.
  • #20 Pode-se utilizar YAML, XML e o próprio PHP.
  • #21 Annotations são metadados que descrevem a entidade, como ela deve ser armazenada, tipo de colunas serão usadas etc.
  • #22 @Entity identifica a classe como uma entidade para o EntityManager @Table informa o nome da tabela, embora seja dispensável caso a tabela tenha o mesmo nome da classe. @Column identifica uma propriedade do objeto como um campo da tabela. Podem haver outras propriedades que não sejam mapeadas. Se o nome for diferente, usa-se o atributo ”name”. Caso o nome do campo mude na tabela, basta apontar na annotation da respectiva classe É um componente muito utilizado em outros projetos, além do Doctrine.
  • #26 Mecanismo que lida com a persistência dos objetos. Registrar uma entidade.
  • #27 Mecanismo que lida com a persistência dos objetos.
  • #29 Executa quando ocorre o flush. Útil para quem utiliza Testes unitários, onde os testes são feitos encapsulados em uma transação e depois desfeitos no fim – de modo a não alterar o BD. Cada insert, se único, será encapsulado numa transação.
  • #30 Inspirado do Hibernate do Java (HQL), é um ”dialeto” de SQL orientado à objetos. Mais controle sobre as querys. Pensar nas consultas sob o ponto de vista de objetos ao invés de relacionamentos. Ver Expression. As consultas trazem objetos.
  • #32 Mapped Superclasses TABLE_PER_CLASS
  • #35 orm:schema-tool:update --dump-sql mostra a query que deverá ser executada no BD para alinhar com as classes registradas (entidades) [Database] FAIL - The database schema is not in sync with the current mapping file.
  • #36 Uma e somente uma…
  • #37 Uma e somente uma…
  • #39 Uma e somente uma…
  • #41 entregar adesivos!