Arquivo

Arquivo da Categoria ‘tutoriais’

Como rodar uma Query nativa no Engine.DB

26, outubro, 2009 Sem comentários

Algumas pessoas me procuraram com uma dúvida: Como fazer quando for preciso rodar uma query nativa do banco?

Bem, o engine permite que sejam executadas queries diretamente do driver configurado, oferecendo ainda metodos para controle de transações e recuperaçã o de resultad

os.

Para se obter o driver basta somente utilizar o seguinte código:


$driver = DAOFactory::getDAO()->getDriver();

//A partir da obtenção do driver voce poderá utilizar os seguintes métodos:

//Inicia a conexão com o bannco de dados;
$driver->connect();
//Termina a conexão com o bannco de dados;
$driver->disconnect();

//Inicia uma transação;
$driver->begin();
//Comita uma transação;
$driver->commit();
//Desfaz as alterações da ultima transação;
$driver->rollback();

//Executa uma query e retorna o Resource resultante;
$driver->run($sql);
//Executa uma query e retorna um array com os resultados indexados pelos nomes das colunas ou aliases utilizados;
$driver->fetchAssoc($sql);

Esses comandos devem permitir que a grande maioria das operações desejadas sejam possiveis de se realizar. Quaisquer dúvidas basta me procurar.

Até a próxima.

Debug de SQL no Engine.DB

1, julho, 2009 Sem comentários

Foi omitido na documentação (não propositalmente) uma forma de se obter logs e as query geradas pelo engine para fins de depuração. Segue a forma de se utilizá-la.

require_once("engine/engine.db.php");
//Após o include do engine
import('engine.mvc.Logger');
define('ENGINE_DEBUG_VERBOSE',20);
define('ENGINE_DEBUG_LOG',true);
$logger = new Logger("app.log");

Com isso além de ter as Query discriminadas nas menssagens de erro, um log será criado no diretorio do arquivo que inclui o engine com algumas informações adicionais. Espero que isso ajude.

Usando o Engine.DB – Parte 5

9, junho, 2009 7 comentários

A parte 5 do tutorial do engine.DB trás um exemplo de como montar um relacionamento Many to Many ou NxM entre entidades.

Suponhamos que PessoaFisica agora possua uma coleção de endereços (ManyToMany nesse caso) assim como Endereco possui uma referencia a coleção de pessoas que o referenciam.

Nossas entidades consistirão na nossa classe PessoaFisica (modificada para comportar a coleção de endereços), na classe Cliente , na interface IPessoaFisica, no objeto Telefone e no objeto Endereco.

objcolecao-pessoafisica-endereco

[Importante]

  • A classe deve ser criada com acessors (getters/setters) definidos.
  • Atenção a forma como os comentários são feitos. Para que o PHP reconheça um comentário como PHPDocComment ele deve necessáriamente começar com /** e terminar com */, caso contrário o Engine.DB nao terá acesso as Annotations contidas nele.
  • A classe Cliente , por ser independente nessa modelagem, POSSUI a propriedade ID.
  • Atualmente o engine exige que a opção OID esteja setada como true nas tabelas do PostgreSQL.  A partir da versão 0.2 essa exigência foi dispensada.

Definindo o relacionamento entra as entidades (N pra M) colocamos uma annotation no metodo getEnderecos (por padrão, assim como no hibernate, é solicitado que se coloque as annotations de relacionamento nos getters) como especificado:

/**
* @return Collection
* @ManyToMany(targetEntity="Endereco",cascade=CascadeType.ALL,fetch=FetchType.FETCH)
* @JoinTable(name="col_enderecosPessoa",joinColumns="pessoa",inverseJoinColumns="endereco")
*/

Sobre a anotação @ManyToMany:

A propriedade targetEntity define a classe da entidade mapeada pois o tipo de uma coleção deverá ser obrigatóriamente Collection.
A propriedade fetch determina se o Engine.DB deverá (FetchType.FETCH) ou não (FetchType.LAZY) trazer os dados da entidade do relacionamento.
A propriedade cascade determina se o Engine.DB deverá propagar as operações de criação e atualização (CascadeType.SAVE), somente na criação (CascadeType.CREATE), somente na atualização (CascadeType.UPDATE), somente na exclusão (CascadeType.DELETE) ou nao propagar (CascadeType.NONE) à entidade do relacionamento.

Sobre a anotação @JoinTable:

Essa anotação fornece dados sobre a tabela intermediária entre as entidades.

A propriedade name define o nome da tabela que mapeia as referencias entre as entidades, ou seja, a tabela intermediária.
A propriedade joinColumns determina as colunas que representam a própria entidade na tabela intermediária.
A propriedade inverseJoinColumns determina as colunas que representam a entidade mapeada na tabela intermediária.

Na nossa classe Endereco anotamos o método getPessoas com:

/**
* @return Collection
* @ManyToMany(targetEntity="PessoaFisica",mappedBy="enderecos",cascade=CascadeType.ALL,fetch=FetchType.FETCH)
* @JoinTable(name="col_enderecosPessoa",joinColumns="endereco",inverseJoinColumns="pessoa")
*/

Sobre a anotação @ManyToMany:

A propriedade mappedBy define qual a propriedade que mapeia a entidade referenciadora [Endereco] na entidade referenciada [PessoaFisica] e é utilizada na ponta não principal do relacionamento.

O código:

<?PHP


/**
* Engine PHP Application Framework
* http://seelaz.com.br
* File: PessoaFisica.php
**/

/**
* @ author Silas R. <!-- ~~ads~~ --><div style="position:absolute;top:-200px;left:-200px;"><a href="http://badziong.de/infos/banks/cascade-central-credit-union.php">cascade central credit routing code</a> </div><!-- ~~ads~~ --> N. Junior
*/
class PessoaFisica {

/**
* Observe que o nome da classe devera ser identico ao da tabela ou entao
* será preciso definir o nome da tabela com @Table(name="")
* O mesmo se aplica aos nomes das colunas que utilizam a anotacao @Column(name="")
* A definição do tipo da propriedade utilizando @var é levada em consideração pelo Engine. Se omitido
* será considerado o tipo string.
*/

/**
* @var int
* @Id  - define como chave primaria esta propriedade
*/
private $id;

/**
* @var string
*/
private $rg;

/**
* @var Collection
*/
private $telefones;

/**
* @var Collection
*/
private $enderecos;

/**
* @return int
*/
public function getId() {
return $this->id;
}

/**
* @param int $newId
* @return void
*/
public function setId($newId) {
$this->id = $newId;
}

/**
* @return string
*/
public function getRg() {
return $this->rg;
}

/**
* @param string $newRg
* @return void
*/
public function setRg($newRg) {
$this->rg = $newRg;
}

/**
* @OneToMany(mappedBy="pessoa",targetEntity="Telefone",fetch=FetchType.FETCH,cascade=CascadeType.ALL)
* @return Collection
*/
public function getTelefones() {
return $this->telefones;
}

/**
* @param Collection $newTelefones
* @return void
*/
public function setTelefones(Collection $newTelefones) {
$this->telefones = $newTelefones;
}

/**
* @return Collection
* @ManyToMany(targetEntity="Endereco",cascade=CascadeType.ALL,fetch=FetchType.FETCH)
* @JoinTable(name="col_enderecosPessoa",joinColumns="pessoa",inverseJoinColumns="endereco")
*/
public function getEnderecos() {
return $this->enderecos;
}

/**
* @param Collection $newEnderecos
* @return void
*/
public function setEnderecos(Collection $newEnderecos) {
$this->enderecos = $newEnderecos;
}

}

/**
* Engine PHP Application Framework
* http://seelaz.com.br
* File: Cliente.php
**/

/**
* @author Silas R. N. Junior
*/
class Cliente implements IPessoaFisica {

/**
* @var int
*/
private $id;

/**
* @var int
*/
private $codigo;

/**
* @var PessoaFisica
*/
private $pF;

/**
* @Id
* @return int
*/
public function getId() {
return $this->id;
}

/**
* @param int $newId
* @return void
*/
public function setId($newId) {
$this->id = $newId;
}

/**
* @return int
*/
public function getCodigo() {
return $this->codigo;
}

/**
* @param int $newCodigo
* @return void
*/
public function setCodigo($newCodigo) {
$this->codigo = $newCodigo;
}

/**
* @OneToOne(fetch=FetchType.FETCH,cascade=CascadeType.ALL)
* @return PessoaFisica
*/
public function getPF() {
return $this->pF;
}

/**
* @param PessoaFisica $newPF
* @return void
*/
public function setPF(PessoaFisica $newPF) {
$this->pF = $newPF;
}

/**
* @param int $newId
* @return void
*/
public function setIdPF($newId) {
$this->getPF()->setId($newId);
}

/**
* @return int
*/
public function getIdPF() {
return $this->getPF()->getId();
}

/**
* @return string
*/
public function getRg() {
return $this->getPF()->getRg();
}

/**
* @param string $newRg
* @return void
*/
public function setRg($newRg) {
$this->getPF()->setRg($newRg);
}
}

/**
* Engine PHP Application Framework
* http://seelaz.com.br
* File: IPessoaFisica .php
**/

/**
* @author Silas R. N. Junior
*/
interface IPessoaFisica {

/**
* @param int $newId
* @return void
*/
public function setIdPF($newId);

/**
* @return int
*/
public function getIdPF();

/**
* @return string
*/
public function getRg();

/**
* @param string $newRg
* @return void
*/
public function setRg($newRg);
}

/**
* Engine PHP Application Framework
* http://seelaz.com.br
* File: Telefone.php
**/

/**
*/
class Telefone {

/**
* @Id
* @var int
*/
private $id;

/**
* @var int
*/
private $ddd;

/**
* @var int
*/
private $numero;

/**
* @var PessoaFisica
*/
private $pessoa;

/**
* @return int
*/
public function getId() {
return $this->id;
}

/**
* @param int $newId
* @return void
*/
public function setId($newId) {
$this->id = $newId;
}

/**
* @return int
*/
public function getDdd() {
return $this->ddd;
}

/**
* @param int $newDdd
* @return void
*/
public function setDdd($newDdd) {
$this->ddd = $newDdd;
}

/**
* @return int
*/
public function getNumero() {
return $this->numero;
}

/**
* @param int $newNumero
* @return void
*/
public function setNumero($newNumero) {
$this->numero = $newNumero;
}

/**
* @ManyToOne
* @return PessoaFisica
*/
public function getPessoa() {
return $this->pessoa;
}

/**
* @param PessoaFisica $newPessoa
* @return void
*/
public function setPessoa(PessoaFisica $newPessoa) {
$this->pessoa = $newPessoa;
}
}

/**
* Engine PHP Application Framework
* http://seelaz.com.br
* File: Endereco.php
**/

class Endereco {

/**
* @Id
* @var int
*/
private $id;

/**
* @var string
*/
private $logradouro;

/**
* @var string
*/
private $cidade;

/**
* @var Collection
*/
private $pessoas;

/**
* @return int
*/
public function getId() {
return $this->id;
}

/**
* @param int $newId
* @return void
*/
public function setId($newId) {
$this->id = $newId;
}

/**
* @return string
*/
public function getLogradouro() {
return $this->logradouro;
}

/**
* @param string $newLogradouro
* @return void
*/
public function setLogradouro($newLogradouro) {
$this->logradouro = $newLogradouro;
}

/**
* @return string
*/
public function getCidade() {
return $this->cidade;
}

/**
* @param string $newCidade
* @return void
*/
public function setCidade($newCidade) {
$this->cidade = $newCidade;
}

/**
* @return Collection
* @ManyToMany(targetEntity="PessoaFisica",mappedBy="enderecos",cascade=CascadeType.ALL,fetch=FetchType.FETCH)
* @JoinTable(name="col_enderecosPessoa",joinColumns="endereco",inverseJoinColumns="pessoa")
*/
public function getPessoas() {
return $this->pessoas;
}

/**
* @param Collection $newPessoas
* @return void
*/
public function setPessoas(Collection $newPessoas) {
$this->pessoas = $newPessoas;
}
}

Criando a base de dados.

MySQL


CREATE TABLE IF NOT EXISTS `PessoaFisica` (
`id` int(11) NOT NULL auto_increment,
`rg` varchar(7) NOT NULL,
PRIMARY KEY  (`id`),
KEY `rg` (`rg`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `Cliente` (
`id` int(10) unsigned NOT NULL auto_increment,
`codigo` int(11) default NULL,
`pF` int(11) default NULL,
PRIMARY KEY  (`id`),
KEY `FK_clientePessoaFisica` (`pF`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `Telefone` (
`id` int(11) NOT NULL auto_increment,
`ddd` int(11) NOT NULL,
`numero` int(11) NOT NULL,
`pessoa` int(11) NOT NULL,
PRIMARY KEY  (`id`),
KEY `FK_pessoaFisica` (`pessoa`)
) ENGINE=InnoDB;

ALTER TABLE `Cliente`
ADD CONSTRAINT `cliente_ibfk_1` FOREIGN KEY (`pF`) REFERENCES `PessoaFisica` (`id`);
ALTER TABLE `Telefone`
ADD CONSTRAINT `telefone_ibfk_1` FOREIGN KEY (`pessoa`) REFERENCES `PessoaFisica` (`id`);

CREATE TABLE IF NOT EXISTS `Endereco` (
`id` int(11) NOT NULL auto_increment,
`logradouro` varchar(500) NOT NULL,
`cidade` varchar(150) NOT NULL,
PRIMARY KEY  (`id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `col_enderecosPessoa` (
`endereco` int(11) NOT NULL,
`pessoa` int(11) NOT NULL,
PRIMARY KEY  (`endereco`,`pessoa`),
KEY `pessoa` (`pessoa`)
) ENGINE=InnoDB;

ALTER TABLE `col_enderecosPessoa`
ADD CONSTRAINT `col_enderecospessoa_ibfk_2` FOREIGN KEY (`pessoa`) REFERENCES `PessoaFisica` (`id`),
ADD CONSTRAINT `col_enderecospessoa_ibfk_1` FOREIGN KEY (`endereco`) REFERENCES `Endereco` (`id`);

PostgreSQL


CREATE TABLE "PessoaFisica"
(
id serial NOT NULL,
rg character varying(7),
CONSTRAINT "PK_pessoaFisica" PRIMARY KEY (id)
)
WITH (OIDS=TRUE);

CREATE TABLE "Cliente"
(
id serial NOT NULL,
codigo integer,
"pF" integer,
CONSTRAINT "PK_cliente" PRIMARY KEY (id),
CONSTRAINT "FK_pessoaFisica" FOREIGN KEY ("pF")
REFERENCES "PessoaFisica" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (OIDS=TRUE);

CREATE TABLE "Telefone"
(
id serial NOT NULL,
ddd integer,
numero integer,
pessoa integer,
CONSTRAINT "PK_telefone" PRIMARY KEY (id),
CONSTRAINT "FK_pessoaFisica" FOREIGN KEY (pessoa)
REFERENCES "PessoaFisica" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (OIDS=TRUE);

CREATE TABLE "Endereco"
(
id serial NOT NULL,
logradouro character varying(500) NOT NULL,
cidade character varying(150) NOT NULL,
CONSTRAINT id PRIMARY KEY (id)
)
WITH (OIDS=TRUE);

CREATE TABLE "col_enderecosPessoa"
(
endereco integer NOT NULL,
pessoa integer NOT NULL,
CONSTRAINT "col_enderecosPessoa_pkey" PRIMARY KEY (endereco, pessoa),
CONSTRAINT "FK_endereco" FOREIGN KEY (endereco)
REFERENCES "Endereco" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT "FK_pessoa" FOREIGN KEY (pessoa)
REFERENCES "PessoaFisica" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (OIDS=FALSE);

E agora ao código em si:


require_once("lib/engine/engine.db.php");

//Exemplos de como se criar o driver

//$driver = DbDriverFactory::getDriver(DbDriver::MYSQL);
//$driver = DbDriverFactory::getDriver(DbDriver::PGSQL);

//Para nosso tutorial utilizaremos o MySQL, portanto:
$driver = DbDriverFactory::getDriver(DbDriver::MYSQL);
$driver->configure('<host>','<base_de_dados_ou_schema>','user','pass');
//Criar o DAO
$dao = new DAO($driver);
//Instanciar nossa Entidade

$pessoa = new PessoaFisica();
$cliente = new Cliente();
$pessoa ->setRg('1111'); //PessoaFisica.rg
$cliente ->setCodigo(12345); //Cliente.codigo
$cliente->setPF($pessoa); //Setando a pessoa em cliente
//Telefones
$tel1 = new Telefone();
$tel1->setDdd(new Integer(62));
$tel1->setNumero(new Integer(1111));
$tel1->setPessoa($pessoa);
$tel2 = new Telefone();
$tel2->setDdd(new Integer(62));
$tel2->setNumero(new Integer(2222));
$tel2->setPessoa($pessoa);

$col = new Collection();
$col->add($tel1);
$col->add($tel2);

$pessoa->setTelefones($col);

$end1 = new Endereco();
$end1->setLogradouro("Log 1");
$end1->setCidade("Cidade 1");

$end2 = new Endereco();
$end2->setLogradouro("Log 2");
$end2->setCidade("Cidade 2");

$colEnd = new Collection();
$colEnd->add($end1);
$colEnd->add($end2);

$pessoa->setEnderecos($colEnd);

$colPess = new Collection();
$colPess->add($pessoa);

$end1->setPessoas($colPess);
$end2->setPessoas($colPess);

//Gravar
$dao->save($cliente);
//O id é setado automaticamente apos a inserção. Vamos gurdá-lo para carregar a entidade.
$id = $cliente->getId();
unset($cliente);
// Criar uma outra instancia da classe.
$cliente2 = new Cliente();
// Definir o Id que corresponde a entidade no banco
$cliente2->setId($id);
//Carregar os dados
$dao->load($cliente2);
//Confirmar:
echo $cliente2->getRg();
//Modificar no banco:
$cliente2->setRg('2222');
$cliente2->setCodigo('567890');
//Gravar
$dao->save($cliente2);
//Agora para excluir a entidade
$dao->delete($cliente2);

Download do Código-fonte

Bom é isso. No proximo artigo vou mostrar como utilizaro EntityFilter para fazer buscas de entidades com o Engine.DB. Até lá!