mapeamento objeto relacional com php - php conference brasil 2010
DESCRIPTION
Apresentação feita na 5ª PHP Conference BrasilTRANSCRIPT
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
Flávio Lisboa - PHP Conference 2010
Quem sou eu
2007
2008 2009
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
►Problemas
►Soluções
►Opções:
Mapeamento Objeto Relacional
A reprodução é livre, apenas cite a fonte
@fgsl
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
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
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
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
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
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.comA reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Soluções
Mapear dados de objetos para bancos de dados relacionais
Referência:
Padrões de Arquiteturade Aplicações Corporativas
Martin Fowler,arquiteto de software
e consultor
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Momento Cultural
O que é um arquiteto de software?
A reprodução é livre, apenas cite a fonte
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
Flávio Lisboa - PHP Conference 2010
Momento Cultural
E o que é um consultor?
A reprodução é livre, apenas cite a fonte
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
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
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
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
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
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 KaneA reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Soluções
Padrão Básico
GatewayUm objeto que encapsula o acesso a um sistema
ou recurso externo
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Soluções
GatewayAPI 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
Flávio Lisboa - PHP Conference 2010
Soluções
Padrões de Mapeamento Objeto Relacional
Row Data GatewayUm objeto para cada linha retornada por uma
consultaUtilidade: trabalhar com um registro específico
Table Data GatewayUm objeto para cada tabela
Utilidade: trabalhar com um conjunto de registros
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Soluções
Padrões de Mapeamento Objeto Relacional
Active RecordUm objeto de domínio cliente sabe como interagir
com tabelas do banco de dados
Data MapperIsola os objetos do domínio do banco de dados
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Soluções
Diferenças
Active RecordO objeto de domínio sabe como incluir, alterar,
excluir e pesquisar.
Data MapperO objeto de domínio invoca um objeto que sabe
como incluir, alterar, excluir e pesquisar.
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Soluções
Preciso implementar tudo isso?
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Soluções
A reprodução é livre, apenas cite a fonte
@fgsl
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
Flávio Lisboa - PHP Conference 2010
Opções
A reprodução é livre, apenas cite a fonte
@fgsl
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
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
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
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 makebaseado em
que também pode instalar
►Versão 1.5.2 requer PHP 5.2.4►Usa PDO►É usado pelo
http://www.phing.info
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
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.
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
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
schema.xml (raiz do projeto)
<?xml version="1.0" encoding="UTF-8"?><database name="livrosdb" defaultIdMethod="native"><table name="livros" phpName="Livro"><column name="id" type="integer" required="true" primaryKey="true"autoIncrement="true" /><column name="titulo" type="varchar" size="80" required="true" /><column name="id_categoria" type="integer" required="true" /><foreign-key foreignTable="categorias"><reference local="id_categoria" foreign="id" /></foreign-key></table><table name="categorias" phpName="Categoria"><column name="id" type="integer" required="true" primaryKey="true"autoIncrement="true" /><column name="nome" type="varchar" size="80" required="true" /></table></database>
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
build.properties (raiz do projeto)
# Database driverpropel.database = mysql
# Project namepropel.project = propel
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
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
[propel-om] Processing: schema.xml[propel-om] Processing Datamodel : schema.xml[propel-om] - processing database : livrosdb[propel-om] + livros[propel-om] -> BaseLivroPeer [builder: PHP5PeerBuilder][propel-om] -> BaseLivro [builder: PHP5ObjectBuilder][propel-om] -> LivroTableMap [builder: PHP5TableMapBuilder][propel-om] -> BaseLivroQuery [builder: QueryBuilder][propel-om] -> LivroPeer [builder: PHP5ExtensionPeerBuilder][propel-om] -> Livro [builder: PHP5ExtensionObjectBuilder][propel-om] -> LivroQuery [builder: ExtensionQueryBuilder][propel-om] + categorias[propel-om] -> BaseCategoriaPeer [builder: PHP5PeerBuilder][propel-om] -> BaseCategoria [builder: PHP5ObjectBuilder][propel-om] -> CategoriaTableMap [builder: PHP5TableMapBuilder][propel-om] -> BaseCategoriaQuery [builder: QueryBuilder][propel-om] -> CategoriaPeer [builder: PHP5ExtensionPeerBuilder][propel-om] -> Categoria [builder: PHP5ExtensionObjectBuilder][propel-om] -> CategoriaQuery [builder: ExtensionQueryBuilder][propel-om] Object model generation complete - 14 files written
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
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
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
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>
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
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.php3)Carregar a configuração das conexões4)Adicionar o diretório build/classes da aplicação no include_path do PHP
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 Propelrequire_once 'Propel.php';
// Inicia a configuração de tempo de execuçãoPropel::init(BASE_PATH.APPLICATION.'/build/conf/propel-conf.php');
// Adiciona o diretório 'classes' ao include pathset_include_path(BASE_PATH.APPLICATION.'/build/classes' . PATH_SEPARATOR . get_include_path());
exemploormphp/propel/init.php
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);
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();
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de alteraçãoexemploormphp/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();
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de exclusãoexemploormphp/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 serverificado com o método isDeleted().
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);}
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta SQL customizadaexemploormphp/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);}
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de efeito de relacionamentoexemploormphp/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();
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; }
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) { ... }}
Flávio Lisboa - PHP Conference 2010
Propel
A reprodução é livre, apenas cite a fonte
@fgsl
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
MongoDBODM
Migrations Common
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.
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'));
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...
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
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
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.
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
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' ) );
}}
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
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);
Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consultaexemploormphp/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;
Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de alteraçãoexemploormphp/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;
Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de exclusãoexemploormphp/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().
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);}
Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de consulta SQL customizadaexemploormphp/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);}
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;
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
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) { ... }}
Flávio Lisboa - PHP Conference 2010
Doctrine
A reprodução é livre, apenas cite a fonte
@fgsl
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_AdapterZend_Db_ProfilerZend_Db_SelectZend_Db_StatementZend_Db_Table
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.
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:
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_MYSQLdb.params.username = rootdb.params.password = admindb.params.dbname = livrosdbdb.params.host = localhost
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.
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.
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);
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';}
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);
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;
Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de alteraçãoexemploormphp/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;
Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Exemplo de exclusãoexemploormphp/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 atributosestão vazios.
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'));}
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);}
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);}
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.phprequire_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;
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();}}
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
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; }
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() { ... }}
Flávio Lisboa - PHP Conference 2010
Zend_Db
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
E agora, o que eu faço?
A reprodução é livre, apenas cite a fonte
@fgsl
Flávio Lisboa - PHP Conference 2010
Sei lá, entende?
A reprodução é livre, apenas cite a fonte
@fgsl
Patropi, interpretado por Orival Pessini
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.
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)
Flávio Lisboa - PHP Conference 2010
Coisas Realmente Importantes
A reprodução é livre, apenas cite a fonte
@fgsl
Flexibilidade
Flávio Lisboa - PHP Conference 2010
Coisas Realmente Importantes
A reprodução é livre, apenas cite a fonte
@fgsl
Facilidade de Manutenção
Kombi, Volkswagen
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