O documento apresenta o mapeamento objeto-relacional com PHP, discutindo problemas com persistência de dados, soluções como padrões de projeto e frameworks ORM, e demonstrando o uso do framework Propel através de um exemplo com livros e categorias.
Mapeamento Objeto Relacional com PHP - PHP Conference Brasil 2010
1. Flávio Lisboa - PHP Conference 2010
Mapeamento Objeto Relacional com PHP
Flávio Gomes da Silva Lisboa
@fgsl
www.fgsl.eti.br
@fgsl
A reprodução é livre, apenas cite a fonte
2. Flávio Lisboa - PHP Conference 2010
Quem sou eu
2007
2008 2009
A reprodução é livre, apenas cite a fonte
@fgsl
3. Flávio Lisboa - PHP Conference 2010
►Problemas
►Soluções
►Opções:
Mapeamento Objeto Relacional
A reprodução é livre, apenas cite a fonte
@fgsl
4. Flávio Lisboa - PHP Conference 2010
Problemas
A maioria das aplicações Web persistem dados
em um banco de dados.
A reprodução é livre, apenas cite a fonte
@fgsl
5. Flávio Lisboa - PHP Conference 2010
Problemas
O processo de desenvolvimento utiliza conexões
diferentes (desenvolvimento, teste, homologação
e produção).
Adaptado de sofist.com.br
A reprodução é livre, apenas cite a fonte
@fgsl
6. Flávio Lisboa - PHP Conference 2010
Problemas
Uma aplicação pode utilizar-se de várias fontes
de dados diferentes ao mesmo tempo.
A reprodução é livre, apenas cite a fonte
@fgsl
7. Flávio Lisboa - PHP Conference 2010
Problemas
E ela também pode ser distribuída para trabalhar
com bases de dados que tem a mesma estrutura,
mas são fornecidas por fabricantes diferentes, por
exemplo, MySQL e PostgreSQL.
A reprodução é livre, apenas cite a fonte
@fgsl
8. Flávio Lisboa - PHP Conference 2010
Problemas
Por isso, código específico para manipular um
determinado mecanismo de persistência e
recuperação de dados não deve ficar espalhado
pela aplicação.
A reprodução é livre, apenas cite a fonte
@fgsl
9. Flávio Lisboa - PHP Conference 2010
Problemas
Além disso, o banco de dados deve ficar
desacoplado da aplicação, para que mudanças
no banco (como alterações em nomes de campos
de tabelas) não gerem trabalho de recodificação.
infoescola.com
A reprodução é livre, apenas cite a fonte
@fgsl
10. Flávio Lisboa - PHP Conference 2010
Soluções
Mapear dados de objetos para bancos de dados relacionais
Referência:
Padrões de Arquitetura
de Aplicações Corporativas
Martin Fowler,
arquiteto de software
e
consultor
A reprodução é livre, apenas cite a fonte
@fgsl
11. Flávio Lisboa - PHP Conference 2010
Momento Cultural
O que é um arquiteto de software?
A reprodução é livre, apenas cite a fonte
12. Flávio Lisboa - PHP Conference 2010
Momento Cultural
E o que é um consultor?
* to con: enganar
* demeaning: degradante
Dilbert, by Scott Adams
A reprodução é livre, apenas cite a fonte
13. Flávio Lisboa - PHP Conference 2010
Momento Cultural
E o que é um consultor?
A reprodução é livre, apenas cite a fonte
14. Flávio Lisboa - PHP Conference 2010
Momento Cultural
E o que é um consultor?
Dilbert, by Scott Adams
A reprodução é livre, apenas cite a fonte
15. Flávio Lisboa - PHP Conference 2010
Soluções
Embora existam várias técnicas
para embutir SQL em uma
linguagem de programação,
elas são todas um pouco
deselegantes.
A reprodução é livre, apenas cite a fonte
@fgsl
16. Flávio Lisboa - PHP Conference 2010
Soluções
Seria melhor acessar os dados
usando mecanismos que se
encaixem com a linguagem de
desenvolvimento da aplicação.
A reprodução é livre, apenas cite a fonte
@fgsl
17. Flávio Lisboa - PHP Conference 2010
Soluções
Por essas razões, é sábio
separar o acesso SQL da lógica
de domínio e colocá-las em
classes separadas.
A reprodução é livre, apenas cite a fonte
@fgsl
18. Flávio Lisboa - PHP Conference 2010
Soluções
Padrões de Projeto: soluções reutilizáveis de
software orientado a objetos
The Greatest American Hero, by Stephen J. Cannell, starring William Kat
A reprodução é livre, apenas cite a fonte
@fgsl
19. Flávio Lisboa - PHP Conference 2010
Soluções
Padrões de Projeto: soluções reutilizáveis de
software orientado a objetos
Abin Sur, Hal Jordan, Green Lanterns created by John Broome and Gil Kane
A reprodução é livre, apenas cite a fonte
@fgsl
20. Flávio Lisboa - PHP Conference 2010
Soluções
Padrão Básico
Gateway
Um objeto que encapsula o acesso a um sistema
ou recurso externo
A reprodução é livre, apenas cite a fonte
@fgsl
21. Flávio Lisboa - PHP Conference 2010
Soluções
Gateway
API simples para lidar de forma orientada a
objetos com coisas que não são objetos
A reprodução é livre, apenas cite a fonte
@fgsl
22. Flávio Lisboa - PHP Conference 2010
Soluções
Padrões de Mapeamento Objeto Relacional
Row Data Gateway
Um objeto para cada linha retornada por uma
consulta
Utilidade: trabalhar com um registro específico
Table Data Gateway
Um objeto para cada tabela
Utilidade: trabalhar com um conjunto de registros
A reprodução é livre, apenas cite a fonte
@fgsl
23. Flávio Lisboa - PHP Conference 2010
Soluções
Padrões de Mapeamento Objeto Relacional
Active Record
Um objeto de domínio cliente sabe como interagir
com tabelas do banco de dados
Data Mapper
Isola os objetos do domínio do banco de dados
A reprodução é livre, apenas cite a fonte
@fgsl
24. Flávio Lisboa - PHP Conference 2010
Soluções
Diferenças
Active Record
O objeto de domínio sabe como incluir, alterar,
excluir e pesquisar.
Data Mapper
O objeto de domínio invoca um objeto que sabe
como incluir, alterar, excluir e pesquisar.
A reprodução é livre, apenas cite a fonte
@fgsl
25. Flávio Lisboa - PHP Conference 2010
Soluções
Preciso
implementar
tudo isso?
A reprodução é livre, apenas cite a fonte
@fgsl
26. Flávio Lisboa - PHP Conference 2010
Soluções
A reprodução é livre, apenas cite a fonte
@fgsl
27. Flávio Lisboa - PHP Conference 2010
Soluções
A reprodução é livre, apenas cite a fonte
@fgsl
Use um framework ORM
framework... ...abstração que une códigos
comuns entre vários projetos de software
provendo uma funcionalidade genérica...
Fonte: http://pt.wikipedia.org/wiki/Framework
Aplicações
Camada de ModeloCamada de Modelo
Objeto de domínio
Framework ORM
28. Flávio Lisboa - PHP Conference 2010
Opções
A reprodução é livre, apenas cite a fonte
@fgsl
29. Flávio Lisboa - PHP Conference 2010
Opções
A reprodução é livre, apenas cite a fonte
@fgsl
Estudo de caso:
cadastro de livros e categorias de livros
30. Flávio Lisboa - PHP Conference 2010
Opções
A reprodução é livre, apenas cite a fonte
@fgsl
Estudo de caso:
cadastro de livros e categorias de livros
CREATE TABLE `livrosdb`.`livros` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`titulo` VARCHAR( 80 ) NOT NULL ,
`id_categoria` INT UNSIGNED NOT NULL ,
PRIMARY KEY ( `id` ) ,
INDEX ( `titulo` , `id_categoria` ) ) ENGINE = InnoDB
CREATE DATABASE `livrosdb` ;
CREATE TABLE `livrosdb`.`categorias` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`nome` VARCHAR( 80 ) NOT NULL ,
PRIMARY KEY ( `id` ) ,
INDEX ( `nome` ) ) ENGINE = InnoDB
31. Flávio Lisboa - PHP Conference 2010
Opções
A reprodução é livre, apenas cite a fonte
@fgsl
Projeto PHP com três implementações:
propel
doctrine
zenddb
exemploormphp
32. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
http://www.propelorm.org
Pode ser instalado pelo Depende de
PHing Is Not GNU make
baseado em
que também pode instalar
►Versão 1.5.2 requer PHP 5.2.4
►Usa PDO
►É usado pelo
http://www.phing.info
33. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Possui dois componentes:
Um gerador de modelos: não obrigatório.
(mas se não usar vai ficar muito difícil...)
propel-1.5.2/generator/bin/propel-gen (Linux)
propel-1.5.2/generator/bin/propel-gen.bat (Windows)
Uma biblioteca de classes: necessária
34. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Neste caso, foram instalados manualmente o
propel 1.5.2 e o phing 2.4.2 no Linux.
Foram criados links simbólicos para os scripts do
Propel e do Phing no diretório /usr/bin. O script
do Phing precisa de permissão de execução para
ser chamado pelo Propel.
35. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Diretiva Valor
ze1_compatibility_mode Off
magic_quotes_gpc Off
magic_quotes_sybase Off
Configuração do php.ini
37. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
build.properties (raiz do projeto)
# Database driver
propel.database = mysql
# Project name
propel.project = propel
38. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Entre no diretório do projeto e execute o
comando:
propel-gen om
40. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Pra cada tabela, Propel cria 3 arquivos
(que você vai utilizar diretamente):
Uma classe modelo que representa uma linha
no banco de dados;
Uma classe peer com constantes estáticas e
métodos para compatibilidade com versões
anteriores de Propel;
Uma classe query, para operar sobre a tabela
para recuperar e atualizar registros
41. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Propel pode gerar o script SQL das tabelas com o
comando:
propel-gen sql
O script é gravado no arquivo
build/sql/schema.sql
42. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Propel também pode criar as tabelas no banco,
configurando a conexão no build.properties.
propel.database.url = [DSN padrão PDO]
propel.database.user =
propel.database.password =
propel-gen sql
43. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
É preciso criar o arquivo runtime-conf.xml na
raiz do projeto, com as conexões a serem usadas
em tempo de execução
<?xml version="1.0" encoding="UTF-8"?>
<config>
<propel>
<datasources default="livrosdb">
<datasource id="livrosdb">
<adapter>mysql</adapter> <!-- sqlite, mysql, myssql, oracle, or
pgsql -->
<connection>
<dsn>mysql:host=localhost;dbname=livrosdb</dsn>
<user>root</user>
<password>admin</password>
</connection>
</datasource>
</datasources>
</propel>
</config>
44. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Por questão de performance (tempo de parsing
do XML), Propel usa uma versão PHP do arquivo
runtime-conf.xml.
Essa versão é gerada com o comando:
propel-gen convert-conf
45. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Para usar o Propel na aplicação, você precisa:
1)Adicionar o diretório runtime/lib do Propel no include_path do
PHP
2)Importar o arquivo Propel.php
3)Carregar a configuração das conexões
4)Adicionar o diretório build/classes da aplicação no include_path
do PHP
46. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Algo assim:
<?php
define(BASE_PATH,
substr(realpath(__FILE__),0,strpos(realpath(__FILE__),'exemploormphp')));
define(APPLICATION, 'exemploormphp/propel');
set_include_path(get_include_path() . PATH_SEPARATOR . BASE_PATH.'propel-
1.5.2/runtime/lib');
// Inclui o script principal do Propel
require_once 'Propel.php';
// Inicia a configuração de tempo de execução
Propel::init(BASE_PATH.APPLICATION.'/build/conf/propel-conf.php');
// Adiciona o diretório 'classes' ao include path
set_include_path(BASE_PATH.APPLICATION.'/build/classes' . PATH_SEPARATOR .
get_include_path());
exemploormphp/propel/init.php
47. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de inclusão
exemploormphp/propel/create.php
require_once 'init.php';
$nome = (string) $_GET['nome'];
$categoria = new Categoria();
$categoria->setNome($nome);
$categoria->save();
unset($categoria);
48. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta
exemploormphp/propel/recover.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
if (!empty($id))
$categoria = CategoriaQuery::create()->findPk($id);
if (!empty($nome))
$categoria = CategoriaQuery::create()->findOneByNome($nome);
echo 'Nome: ' . $categoria->getNome();
49. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de alteração
exemploormphp/propel/update.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
if (!empty($id))
$categoria = CategoriaQuery::create()->findPk($id);
if (!empty($nome))
$categoria = CategoriaQuery::create()->findOneByNome($nome);
$categoria->setNome('Huguinho');
$categoria->save();
$id = $categoria->getId();
unset($categoria);
$categoria = CategoriaQuery::create()->findPk($id);
echo 'Nome: ' . $categoria->getNome();
50. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de exclusão
exemploormphp/propel/delete.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
if (!empty($id))
$categoria = CategoriaQuery::create()->findPk($id);
if (!empty($nome))
$categoria = CategoriaQuery::create()->findOneByNome($nome);
print_r($categoria);
$categoria->delete();
print_r($categoria);
O objeto ainda existe, mas não
é mais persistente. O estado pode ser
verificado com o método isDeleted().
51. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta a vários registros
exemploormphp/propel/listing.php
require_once 'init.php';
$categoria = CategoriaQuery::create()-
>findOneByNome('suspense');
$livros = LivroQuery::create()-
>filterByCategoria($categoria)->orderByTitulo()->find();
foreach($livros as $livro)
{
print_r($livro);
}
52. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta SQL customizada
exemploormphp/propel/sqlisting.php
require_once 'init.php';
$con = Propel::getConnection(LivroPeer::DATABASE_NAME);
$sql = 'SELECT l.id, l.titulo,c.nome ';
$sql .= 'FROM livros as l INNER JOIN categorias as c ';
$sql .= 'ON l.id_categoria = c.id ';
$sql .= 'WHERE c.nome = :name';
$stmt = $con->prepare($sql);
$stmt->execute(array(':name' => 'suspense'));
$formatter = new PropelObjectFormatter();
$formatter->setClass('Livro');
$formatter->setPeer('LivroPeer');
$livros = $formatter->format($stmt);
foreach($livros as $livro)
{
print_r($livro);
}
53. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de efeito de relacionamento
exemploormphp/propel/relation.php
require_once 'init.php';
$categoria = new Categoria();
$categoria->setNome('suspense');
$livro = new Livro();
$livro->setTitulo('A volta dos que não foram');
$livro->setCategoria($categoria);
$livro->save();
unset($livro);
$livro = LivroQuery::create()->filterByCategoria($categoria)-
>findOne();
echo 'Título: ' . $livro->getTitulo().'<br/>';
echo 'Categoria: ' . $livro->getCategoria()->getNome();
54. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Transações
$con = Propel::getConnection(CategoriaPeer::DATABASE_NAME);
$con->beginTransaction();
Try {
O QUE VOCÊ ESPERA QUE OCORRA
$con->commit();
} catch (Exception $e) {
O QUE OCORRE
$con->rollback();
throw $e;
}
55. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Ganchos
Class Livro extends BaseLivro
public function postSave(PropelPDO $con)
{
...
}
public function postDelete(PropelPDO $con)
{
...
}
public function updateCategoria(PropelPDO $con)
{
...
}
}
56. Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
57. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
http://www.doctrine-project.org
Mapeador
Objeto
Relacional
Camada de Abstração
de Banco de Dados
ORM DBAL
usa
►Versão 1.2.3 requer PHP 5.2.3
►Usa PDO
►Versão 2.0 usa PHP 5.3 e é...
TOTALMENTE DIFERENTE!
Pode ser instalado pelo
MongoDB
ODM
Migrations Common
58. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Neste caso, foi instalado manualmente o Doctrine
1.2.3 no Linux.
Foi criado um diretório lib/vendor/doctrine no
projeto, com links simbólicos para o diretório
Doctrine e para o arquivo Doctrine.php.
59. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Inicialização do Doctrine:
exemploormphp/doctrine/init.php
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) .
'/lib/vendor/doctrine');
require_once('Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
spl_autoload_register(array('Doctrine', 'modelsAutoload'));
$manager = Doctrine_Manager::getInstance();
$dsn = 'mysql:dbname=livrosdb;host=127.0.0.1';
$user = 'root';
$password = 'admin';
$dbh = new PDO($dsn,$user,$password);
$conn = $manager->connection($dbh,'livrosdb');
Doctrine_Core::loadModels(array('models','models/generated'));
60. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Doctrine possuía uma ferramenta de linha de
comando, com geração de código, similar ao
Propel. Essa ferramenta estava disponível na
distribuição Sandbox.
Só que a Sandbox não
está mais disponível...
Na versão 2.0, a linha de comando já vem
incluída no ORM padrão. Mas aqui não estamos
falando da versão 2.0...
61. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Mas isso não
significa que não
dê pra gerar os
modelos!
Duffy Duck by Warner Bros
62. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Crie no projeto uma pasta chamada models.
Crie na raiz do projeto um script que invoque o
método generateModelsFromDb da classe
Doctrine_Core:
require_once 'init.php';
Doctrine_Core::generateModelsFromDb('models',
array('livrosdb'),
array('generateTableClasses' => true));
exempoormphp/doctrine/gom.php
63. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
São geradas três classes
para cada tabela...
As classes com prefixo
Base contém a definição
da tabela e são herdadas
pela classe que
implementa ActiveRecord.
A classe com sufixo Table
é um Data Mapper.
64. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Para não gerar os Data Mappers, a chave
generateTableClasses do método
generateModelsFromDb deve ser configurada
para false.
Você pode
apagar os
arquivos
também, se
quiser.
Dee Dee & Dexter by Hanna Barbera
65. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Mas é preciso verificar os relacionamentos
gerados. No nosso exemplo, o Doctrine gera um
relacionamentos um-pra-muitos entre Livros e
Categorias, sendo que na verdade é um-pra-um.
class Livros extends BaseLivros
{
public function setUp()
{
parent::setUp();
$this->hasOne('Categorias', array(
'local' => 'id_categoria',
'foreign' => 'id'
)
);
}
}
66. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Também é possível criar scripts com as
definições das tabelas com o Doctrine DBAL.
Esses scripts podem ter a conexão
parametrizada, de forma a gerar tabelas para
qualquer banco de dados.
Também é possivel criar definições de tabelas no
formato YAML (Yaml Ain't Markup Language),
criar os modelos a partir delas e aí gerar as
tabelas.
DBAL
67. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de inclusão
exemploormphp/doctrine/create.php
require_once 'init.php';
$nome = (string)
$_GET['nome'];
$categoria = new Categorias();
$categoria->nome = $nome;
$categoria->save();
unset($categoria);
68. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta
exemploormphp/doctrine/recover.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
$categoriaTable = CategoriasTable::getInstance();
if (!empty($id))
$categoria = $categoriaTable->findOneById($id);
if (!empty($nome))
$categoria = $categoriaTable->findOneByNome($nome);
echo 'Nome: ' . $categoria->nome;
69. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de alteração
exemploormphp/doctrine/update.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
if (!empty($id))
$categoria = CategoriasTable::getInstance()->find($id);
if (!empty($nome))
$categoria = CategoriasTable::getInstance()->findOneByNome($nome);
$categoria->nome = 'Huguinho';
$categoria->save();
$id = $categoria->id;
unset($categoria);
$categoria = CategoriasTable::getInstance()->find($id);
echo 'Nome: ' . $categoria->nome;
70. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de exclusão
exemploormphp/doctrine/delete.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
if (!empty($id))
$categoria = CategoriasTable::getInstance()->find($id);
if (!empty($nome))
$categoria = CategoriasTable::getInstance()-
>findOneByNome($nome);
print_r($categoria);
$categoria->delete();
print_r($categoria);
O objeto ainda existe, mas não
é mais persistente. O estado pode ser
verificado com o método state().
71. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta a vários registros
exemploormphp/doctrine/listing.php
require_once 'init.php';
$livros = LivrosTable::getInstance()-
>findByDql('Categorias.nome = ?','romance');
echo 'Quantidade de livros: ' . count($livros);
foreach($livros as $livro)
{
print_r($livro);
}
72. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta SQL customizada
exemploormphp/doctrine/sqlisting.php
require_once 'init.php';
$q = Doctrine_Query::create($conn)
->select('l.id, l.titulo, c.nome')
->from('Livros l')
->innerJoin('l.Categorias c')
->where('c.nome = ?');
$livros = $q->execute(array('romance'));
echo 'Quantidade de livros: ' .
count($livros);
foreach($livros as $livro)
{
print_r($livro);
}
73. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de efeito de relacionamento
exemploormphp/doctrine/relation.php
require_once 'init.php';
$categoria = new Categorias();
$categoria->nome = 'romance';
$livro = new Livros();
$livro->titulo = 'Poeira em alto mar';
$livro->Categorias = $categoria;
$livro->save();
unset($livro);
$livro = LivrosTable::getInstance()-
>findByDql('Categorias.nome = ?','romance')->get(0);
echo 'Título: ' . $livro->titulo . '<br/>';
echo 'Categoria: ' . $livro->Categorias->nome;
74. Flávio Lisboa - PHP Conference 2010
$conn = beginTransaction();
Try {
O QUE VOCÊ ESPERA QUE OCORRA
$conn->commit();
} catch (Exception $e) {
O QUE OCORRE
$conn->rollback();
throw $e;
}
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Transações
75. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Ganchos
Class Livros extends BaseLivros
public function preSave($event)
{
...
}
public function postSave($event)
{
...
}
public function postDqlSelect($event)
{
...
}
}
76. Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
77. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
►Versão 1.10 requer PHP 5.2.4
►Usa PDO
►Versão 2.0 usará PHP 5.3 e terá ...
MUITA COISA LEGAL!
Pode ser instalado pelo
...mas por um canal não oficial Zend_Db_Adapter
Zend_Db_Profiler
Zend_Db_Select
Zend_Db_Statement
Zend_Db_Table
78. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Neste caso, foi instalado manualmente o Zend
Framework 1.10.6. Na raiz do projeto foi criado
um link simbólico para o diretório
ZendFramework-1.10.6/library/Zend.
Na raiz do projeto foi criada uma pasta models
para armazenar os modelos.
79. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
require_once 'Zend/Loader/Autoloader.php';
set_include_path(get_include_path() . PATH_SEPARATOR .
dirname(__FILE__) . '/models');
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('Zend_Config_*');
$autoloader->registerNamespace('Zend_Db_*');
$config = new Zend_Config_Ini('config.ini','database');
$conn = Zend_Db::factory($config->db->adapter,$config->db-
>params->toArray());
exemploormphp/zenddb/init.php
Inicialização do Zend_Db:
80. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
exemploormphp/zenddb/config.ini
Configuração da conexão:
[database]
db.adapter = PDO_MYSQL
db.params.username = root
db.params.password = admin
db.params.dbname = livrosdb
db.params.host = localhost
81. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Zend Framework possui um componente
chamado Zend_Tool, que é uma ferramenta de
linha de comando para geração de código.
Zend_Tool cria as classes de modelo, mas
somente quando o projeto foi criado com a
estrutura do Zend_Framework, porque as
definições são lidas e gravadas no arquivo
.zfproject.xml.
82. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Por outro lado, você não precisa
necessariamente criar a classe de modelo para
manipular o banco porque o Zend_Db provê uma
implementação genérica de Data Mapper.
Basta instanciar Zend_Db_Table passando para o
construtor o nome da tabela no banco de dados.
83. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de inclusão com Data Mapper:
exemploormphp/zenddb/createwithoutmodel.php
require_once 'init.php';
$categoria = new Zend_Db_Table('categorias');
$categoria->insert(array('nome'=>'infantil'));
unset($categoria);
84. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Mas a criação do modelo é fácil:
exemploormphp/zenddb/models/Categoria.php
class Categoria extends Zend_Db_Table_Abstract
{
protected $_name = 'categorias';
}
85. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de inclusão com modelo definido:
exemploormphp/zenddb/create.php
require_once 'init.php';
Zend_Loader::loadClass('Categoria');
$dm = new Categoria();
$categoria = $dm->createRow();
$categoria->nome = 'infantil';
$categoria->save();
unset($categoria);
86. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta
exemploormphp/zenddb/recover.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
Zend_Loader::loadClass('Categoria');
$dm = new Categoria();
if (!empty($id))
$categoria = $dm->find($id)->current();
if (!empty($nome))
$categoria = $dm->fetchRow($dm->getDefaultAdapter()->quoteInto('nome = ?',
$nome));
echo 'Nome: ' . $categoria->nome;
87. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de alteração
exemploormphp/zenddb/update.php
require_once 'init.php';
$id = (int) $_GET['id']; $nome = (string) $_GET['nome'];
Zend_Loader::loadClass('Categoria');$dm = new Categoria();
if (!empty($id))
$categoria = $dm->find($id)->current();
if (!empty($nome))
$categoria = $dm->fetchRow($dm->getDefaultAdapter()->quoteInto('nome = ?',$nome));
$categoria->nome = 'Huguinho';
$categoria->save();
$id = $categoria->id;
unset($categoria);
$categoria = $dm->find($id)->current();
echo 'Nome: ' . $categoria->nome;
88. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de exclusão
exemploormphp/zenddb/delete.php
require_once 'init.php';
$id = (int) $_GET['id'];
$nome = (string) $_GET['nome'];
Zend_Loader::loadClass('Categoria');
$dm = new Categoria();
if (!empty($id))
$categoria = $dm->find($id)->current();
if (!empty($nome))
$categoria = $dm->fetchRow($dm->getDefaultAdapter()->quoteInto('nome = ?',
$nome));
print_r($categoria->id);
$categoria->delete();
print_r($categoria->id);
O objeto ainda existe, mas seus atributos
estão vazios.
89. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Relacionamento no Modelo
exemploormphp/zenddb/models/Livro.php
class Livro extends Zend_Db_Table_Abstract
{
protected $_name = 'livros';
protected $_referenceMap = array(
'Categoria' => array(
'columns' => 'id_categoria',
'refTableClass' => 'Categoria',
'refColumns' => 'id'
));
}
90. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta a vários registros
exemploormphp/zenddb/listing.php
require_once 'init.php';
Zend_Loader::loadClass('Categoria');
$dm = new Categoria();
$categoria = $dm->fetchRow($dm->getDefaultAdapter()-
>quoteInto('nome = ?','infantil'));
$livros = $categoria->findDependentRowset('Livro');
echo 'Quantidade de livros: ' . count($livros);
foreach($livros as $livro)
{
print_r($livro);
}
91. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta SQL customizada
exemploormphp/zenddb/sqlisting.php
require_once 'init.php';
Zend_Loader::loadClass('Livro');
$dm = new Livro();
$select = $dm->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
->setIntegrityCheck(false);
$select->join('categorias','livros.id_categoria = categorias.id')
->where('categorias.nome = ?','infantil');
$livros = $dm->fetchAll($select);
echo 'Quantidade de livros: ' . count($livros);
foreach($livros as $livro)
{
print_r($livro);
}
92. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de efeito de relacionamento
exemploormphp/zenddb/relation.php
require_once 'init.php';
Zend_Loader::loadClass('Livro');Zend_Loader::loadClass('Categoria');
Zend_Loader::loadClass('LivroRow');
$dmc = new Categoria();
$categoria = $dmc->createRow();
$categoria->nome = 'tragédia';
$dml = new Livro(array('rowClass' => 'LivroRow'));
$livro = $dml->createRow();
$livro->titulo = 'Afoguei meu peixinho dourado';
$livro->setCategoria($categoria);
$livro->save(); $livro->refresh();
$id = $livro->id; unset($livro);
$livro = $dml->find($id)->current();
echo 'Título: ' . $livro->titulo . '<br/>';
echo 'Categoria: ' . $livro->findParentRow('Categoria')->nome;
93. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Atualização automática de registro relacionado
exemploormphp/zenddb/models/LivroRow.php
class LivroRow extends Zend_Db_Table_Row_Abstract
{
private $_categoria;
public function setCategoria($categoria)
{
$this->_categoria = $categoria;
}
public function save()
{
$this->_categoria->save();
$this->id_categoria = $this->_categoria->id;
parent::save();
}
}
94. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Este é um projeto GPLv2, que já faz de forma transparente o que
foi feito usando a extensão de Zend_Db_Table_Row_Abstract. Ele
vem pronto para trabalhar com MySQL, mas por herança é
possível criar adaptadores para outros bancos.
Há uma proposta em construção, para criar uma nova
implementação de ActiveRecord no Zend Framework:
http://code.google.com/p/zend-framework-orm
http://framework.zend.com/wiki/display/ZFPROP/Zend_Db_ActiveRecord
95. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Transações
$conn = Zend_Db_Table_Abstract::getDefaultAdapter();
$conn->beginTransaction();
Try {
O QUE VOCÊ ESPERA QUE OCORRA
$conn->commit();
} catch (Exception $e) {
O QUE OCORRE
$conn->rollback();
throw $e;
}
96. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Ganchos
Class LivroRow extends Zend_Db_Table_Row_Abstract
protected function _insert()
{
...
}
protected function _postInsert()
{
...
}
protected function _update()
{
...
}
}
97. Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
98. Flávio Lisboa - PHP Conference 2010
E agora, o que eu faço?
A reprodução é livre, apenas cite a fonte
@fgsl
99. Flávio Lisboa - PHP Conference 2010
Sei lá, entende?
A reprodução é livre, apenas cite a fonte
@fgsl
Patropi, interpretado por Orival Pessini
100. Flávio Lisboa - PHP Conference 2010 A reprodução é livre, apenas cite a fonte
@fgsl
Bill Karwin
Mas como com qualquer
ORM, há, inevitavelmente,
algumas consultas SQL e
operações que você não pode
fazer através da interface OO.
Nenhum ORM pode servir
como um shopping que tem
apenas uma loja.
101. Flávio Lisboa - PHP Conference 2010 A reprodução é livre, apenas cite a fonte
@fgsl
Independente de sua
escolha, saiba que
Zend Framework
trabalha com todos!
Wheelie and The Chopper Bunch (NBC,1974)
102. Flávio Lisboa - PHP Conference 2010
Coisas Realmente Importantes
A reprodução é livre, apenas cite a fonte
@fgsl
Flexibilidade
103. Flávio Lisboa - PHP Conference 2010
Coisas Realmente Importantes
A reprodução é livre, apenas cite a fonte
@fgsl
Facilidade de Manutenção
Kombi, Volkswagen
104. Flávio Lisboa - PHP Conference 2010
Obrigado!
A reprodução é livre, apenas cite a fonte
@fgsl
www.fgsl.eti.br
Little Einsteins by Walt Disney