Criando um CRUD com Zend Framework 2 e Doctrine 2
Veja nesse artigo como criar um projeto CRUD utilizando dois dos principais frameworks utilizados atualmente: Zend e Doctrine.
Neste artigo veremos como criar um projeto CRUD utilizando dois dos principais frameworks utilizados atualmente: Zend Framework e Doctrine. Mas antes de iniciar o processo de construção do projeto, vamos definir quais as ferramentas utilizadas para o projeto, além do servidor utilizado para o projeto, que será o XAMPP e a IDE escolhida é o NETBEANS.
Primeiramente devemos entrar no site do Zend Framework e realizar o download do mesmo, além do exemplo Skeleton, que está disponível no próprio site. O Skeleton é um projeto inicial que utiliza o Zend Framework como base. Baixe o Skeleton da através do link http://framework.zend.com/downloads/skeleton-app.
Após o download, adicione no servidor e rode o projeto, assim, logo vê-se que já existe uma estrutura básica, conhecida como Application, que conta com um projeto simples do Zend, ao qual a partir deste iniciaremos a construção dos demais.
Veja na Figura 1 de como o projeto deve estar caso a instalação do skeleton tenha sido feita corretamente.
Figura 1. Projeto inicial do Zend Framework 2
Com o projeto configurado corretamente, iniciamos o projeto de modificação para a inclusão do Doctrine. Primeiro, abra o arquivo composer.json da raiz do projeto e altere este arquivo adicionando a dependência do Doctrine2, como mostra a Listagem 1 e execute o composer para atualizar as libs do seu projeto.
Listagem 1. Arquivo composer.json completo do projeto.
{
"name": "zendframework/skeleton-application",
"description": "Skeleton Application for ZF2",
"license": "BSD-3-Clause",
"keywords": [
"framework",
"zf2"
],
"homepage": "http://framework.zend.com/",
"require": {
"php": ">=5.3.3",
"zendframework/zendframework": "2.3.*",
"doctrine/doctrine-orm-module" : "0.*"
}
}
Após as libs atualizadas iremos iniciar a configuração do projeto para aceitar o Doctrine 2, para isto, abra o arquivo application.config.php, conforme a Figura 2, e adicione quais os módulos serão carregados pelo projeto.
Figura 2. Caminho para chegar ate o arquivo application.config.php
Neste arquivo adicione as linhas DoctrineModule e DoctrineORMModule, conforme mostra a Listagem 2. Além disso, é necessário criar dentro da pasta data as pastas DoctrineORMModule e DoctrineORMModule/Proxy.
Listagem 2. Arquivo application.config.php com a alteração do modulo
'modules' => array(
'Application',
'DoctrineModule',
'DoctrineORMModule'
),
Após adicionar os módulos e criar as pastas necessárias para o funcionamento do Doctrine, vamos iniciar a construção do projeto e, para isto, altere o arquivo responsável por mostrar a primeira página do nosso projeto. Todos os arquivos de tela (layout) ficam armazenados dentro da pasta Application/view.
Abra o arquivo Application/view/application/index/index.phtml e crie a página inicial da aplicação. No arquivo índex.phtml iremos criar um simples formulário, conforme mostra a Listagem 3, para inserir funcionários no projeto.
Listagem 3 – Formulário php para adicionar funcionario
<h3>Adicionar Funcionário</h3>
<form method="post">
Informe o nome do funcionário..:
<br>
<input type="text" name="nome">
<br><br>
Informe o cpf do funcionário..:
<br>
<input type="text" name="cpf">
<br><br>
Informe o salário do funcionário..:
<br>
<input type="text" name="salario">
<br><br>
<input type="submit" value="Adicionar">
</form>
<br><br>
<?php echo $this->resp; ?>
A linha $this->resp será utilizada posteriormente para enviar mensagens do controle para as nossas páginas, mas neste momento ela não vai imprimir nenhum valor. Se executar o nosso projeto já podemos observar o mesmo sendo construído, conforme a Figura 3.
Figura 3. Página inicial do sistema
Após o usuário preencher os dados deste formulário e clicar no botão Adicionar, o Zend Framework irá chamar a mesma URL, visto que não adicionamos nenhuma action para o nosso form. Com isso, a classe IndexController.php será chamada novamente e seu método actionIndex() carregado mais uma vez. É justamente neste método onde temos que preparar a gravação no banco de dados.
Vá ate o arquivo Application/src/Application/Controller/IndexController.php e modifique o mesmo conforme a Listagem 4.
Listagem 4. Código do IndexController.php recebendo os dados do formulário
public function indexAction()
{
$request = $this->getRequest();
$result = array();
if($request->isPost())
{
$nome = $request->getPost("nome");
$cpf = $request->getPost("cpf");
$salario = $request->getPost("salario");
$result["resp"] = $nome. ", enviado corretamente!";
}
return new ViewModel($result);
}
Após a criação do método indexAction(), o projeto já está recebendo os dados dos três campos do formulário: nome, CPF e salário, e retornando para a index.phtml através da variável $result[“resp”] e a mensagem $nome enviada corretamente.
Neste momento vamos criar a classe de entidade responsável pela ligação dos dados do formulário com o banco de dados, para isso, crie uma pasta Model dentro de Application/src/Application e uma classe Funcionario.php dentro da pasta Model.
A classe Funcionario.php irá conter os atributos do formulário, o encapsulamento com set e get destes atributos e um mapeamento do doctrine referenciando a tabela funcionário do banco de dados. Veja na Listagem 5 como é a classe Funcionario.php
Listagem 5 – Classe Funcionario.php com o mapeamento do Doctrine 2.
<?php
namespace Application\Model;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Funcionario {
/**
* @ORM\Id
* @ORM\GeneratedValue("AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=50)
*/
private $nome;
/**
* @ORM\Column(type="string", length=15)
*/
private $cpf;
/**
* @ORM\Column(type="decimal")
*/
private $salario;
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getNome() {
return $this->nome;
}
public function setNome($nome) {
$this->nome = $nome;
}
public function getCpf() {
return $this->cpf;
}
public function setCpf($cpf) {
$this->cpf = $cpf;
}
public function getSalario() {
return $this->salario;
}
public function setSalario($salario) {
$this->salario = $salario;
}
}
Podemos ver já o mapeamento do doctrine para cada um dos atributos e podemos observar a utilização do Doctrine\ORM\Mapping, pois o mesmo é utilizado para carregar as classes de mapeamento do Doctrine.
O elemento Id é utilizado para definir a chave primária da classe e o elemento GeneratedValue é adicionado para definir o tipo de value para este campo, no caso campo auto incremento, e por fim, o atributo Column define o tipo do campo, a quantidade de caracteres, entre outros parâmetros referentes a coluna.
Com a classe Funcionario devidamente mapeada, vamos criar o banco de dados conforme a Listagem 6.
Listagem 6. Código para a criação da tabela no banco de dados
create database devmedia_site;
use devmedia_site;
create table funcionario(
id int auto_increment primary key,
nome varchar(50),
cpf varchar(15),
salario double
);
Vamos realizar a configuração do doctrine para o projeto agora: primeiro vamos criar um arquivo dentro da pasta config/autoload chamado de doctrine_orm.local.php, que é responsável pela configuração com o banco de dados e nele que iremos adicionar os valores para usuário, senha e nome do banco de dados utilizado, conforme a Listagem 7.
Listagem 7. Arquivo de configuração com o banco de dados pelo doctrine.
<?php
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
'params' => array(
'host' => 'localhost',
'port' => '3306',
'user' => 'root',
'password' => '',
'dbname' => 'devmedia_site',
)
)
)
),
);
Conforme a listagem acima, podemos ver os parâmetros para o caminho do banco de dados, a porta utilizada, usuário, senha e nome do banco de dados. Altere este arquivo conforme a configuração desejada. Depois desta vamos à configuração do módulo, pois é necessário definir parâmetros do doctrine. Para isso, vá até o arquivo Application/config/module.config.php e adicione os valores da Listagem 8.
Listagem 8. Configuração do doctrine para o modulo.
'doctrine' => array(
'driver' => array(
// defines an annotation driver with two paths, and names it `my_annotation_driver`
'my_annotation_driver' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(
__DIR__ . "/src/Application/Model"
),
),
// default metadata driver, aggregates all other drivers into a single one.
// Override `orm_default` only if you know what you're doing
'orm_default' => array(
'drivers' => array(
// register `my_annotation_driver` for any entity under namespace `My\Namespace`
'Application\Model' => 'my_annotation_driver'
)
)
)
)
Podemos ver que foi configurado o driver utilizado pelo projeto, a referência do path onde estão localizadas as classes mapeadas pelo doctrine conforme a linha 'paths' => array( __DIR__ . "/src/Application/Model"), que define para o doctrine procurar na pasta Model as classes que possuem anotação. Logo abaixo vemos a configuração do namespace utilizado nas classes de Model, conforme a linha 'Application\Model' => 'my_annotation_driver'.
Após esta configuração realizada corretamente, o próximo passo é executar o processo para iniciar o CRUD. Então, volte até a classe IndexController onde vamos terminar a gravação de dados que havia iniciado no método indexAction(), e crie uma instância da classe Funcionario, adicione os dados do formulário para este objeto, chame o serviço do Doctrine e realize a gravação dos dados, conforme a Listagem 9.
Listagem 9. Método indexAction() finalizado com a operação de gravar dados corretamente.
public function indexAction()
{
$request = $this->getRequest();
$result = array();
if($request->isPost())
{
try{
$nome = $request->getPost("nome");
$cpf = $request->getPost("cpf");
$salario = $request->getPost("salario");
$funcionario = new \Application\Model\Funcionario();
$funcionario->setNome($nome);
$funcionario->setCpf($cpf);
$funcionario->setSalario($salario);
$em = $this->getServiceLocator()->get("Doctrine\ORM\EntityManager");
$em->persist($funcionario);
$em->flush();
$result["resp"] = $nome. ", enviado corretamente!";
} catch (Exception $e){
}
}
return new ViewModel($result);
}
Conforme visto na listagem acima, após receber os dados do formulário e adicionar no objeto $funcionario, para utilizar o Doctrine basta chamar o serviço do Doctrine com $this->getServiceLocator()->get("Doctrine\ORM\EntityManager"), e depois dele já iniciado, utilize o método $em->persist($funcionario).
Este método faz com que o Doctrine olhe a classe Funcionario.php e conforme o que foi mapeado na classe, grava os dados nos campos e tabela correspondentes. Por fim, é necessário chamar o método $em->flush() que faz o commit das operações anteriores.
Após a finalização do cadastrar funcionário, vamos criar um link para a página de lista de funcionários. Adicione um link, conforme a Listagem 10, no arquivo index.phtml com referência para o controller listarAction() da mesma classe, IndexController que será criado posteriormente.
Listagem 10. Link adicionado na pagina index.phtml
<a href="<?php echo $this->url('application/default',
array('controller' => 'index', 'action' => 'listar')); ?>">Listar Funcionario</a>
Crie um método listarAction() dentro da classe Application/src/Application/Controller/IndexController.php com a função de realizar a busca dos dados da tabela funcionário. Esta será uma busca simples, com um select de todos os dados da tabela funcionário. Para isto, basta chamar o serviço do Doctrine e utilizar o método findAll(), conforme a Listagem 11.
Listagem 11. Método listarAction() carregando os dados com doctrine do banco de dados
public function listarAction()
{
$em = $this->getServiceLocator()->get("Doctrine\ORM\EntityManager");
$lista = $em->getRepository("Application\Model\Funcionario")->findAll();
return new ViewModel(array('lista' => $lista));
}
Repare que o método listarAction() faz a consulta dos dados referente ao Repositório de Funcionário e seu resultado é enviado para uma variável lista no retorno do método. Agora deve-se criar um arquivo listar.phtml e mostrar a variável lista que possui os dados dos funcionários. O arquivo listar.phtml deve ser criado dentro do caminho Application/view/application/índex/listar.phtml, como mostra a Listagem 12.
Listagem 12. Página listar.phtml com a tabela dos dados do banco.
<h3>Listar Funcionário</h3>
<table>
<tr>
<th>NOME</th>
<th>CPF</th>
<th>SALÁRIO</th>
<th>EDITAR</th>
<th>EXCLUIR</th>
</tr>
<?php foreach ($this->lista as $f): ?>
<tr>
<td><?php echo $f->getNome(); ?></td>
<td><?php echo $f->getCpf(); ?></td>
<td><?php echo $f->getSalario(); ?></td>
<td>Editar</td>
<td>Excluir</td>
</tr>
<?php endforeach; ?>
</table>
<a href="<?php echo $this->url('home'); ?>">Voltar</a>
Vamos criar uma tabela e mostrar os dados provenientes do método listarAction(), a listagem dos dados acontece através de um foreach simples da variável lista do controle. Para cada iteração realizada no foreach, o Zend cria um novo objeto $f referente a classe Funcionario e para imprimir os atributos de Funcionário é necessário utilizar os métodos get().
Para continuar com o projeto é necessário criar um nova rota que permita o envio de id (código) dos funcionários, para isto basta irmos no arquivo Application/config/module.config.php e adicionar a nova rota conforme mostra a Figura 4e a Listagem 13.
Figura 4.Parte do arquivo module.config.php com a nova rota
Listagem 13.Nova rota criada para o editar e o excluir
'rota2' => array(
'type' => 'Segment',
'options' => array(
'route' => '/application/flag/[:action]/[:id][/]',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
),
),
),
Podemos ver a criação de uma rota do tipo Segment, que permite dados cariados na URL. A mesma será executada sempre que na URL/application/flag/aparecer, uma action e um valor para o id. Com isso podemos ir no arquivo listar.phtml e adicionar as rotas para os links de editar e excluir, conforme a Listagem 14.
Listagem 14.Link para editar e excluir os dados
<td>
<a href="<?php echo $this->url('rota2', array(
'action' => 'editar', 'id' => $f->getId()
)); ?>">
Editar</a></td>
<td>
<a href="<?php echo $this->url('rota2', array(
'action' => 'excluir', 'id' => $f->getId()
)); ?>">
Excluir</a></td>
Repare que após o comando $this->url() definimos o valor rota2 que havia sido criada anteriormente e apenas alteramos o valor do action e do id. Agora devemos criar o método editarAction() e excluirAction() dentro do controller IndexController, e o método excluirAction() será redirecionado para a Listagem 15. Já o método editarAction() terá uma página para realizar a edição dos dados.
Listagem 15.Método para editar e excluir o funcionário
public function excluirAction()
{
$id = $this->params()->fromRoute("id", 0);
$em = $this->getServiceLocator()->get("Doctrine\ORM\EntityManager");
$funcionario = $em->find("Application\Model\Funcionario", $id);
$em->remove($funcionario);
$em->flush();
return $this->redirect()->toRoute('application/default',
array('controller' => 'index', 'action' => 'listar'));
}
public function editarAction()
{
$id = $this->params()->fromRoute("id", 0);
$em = $this->getServiceLocator()->get("Doctrine\ORM\EntityManager");
$funcionario = $em->find("Application\Model\Funcionario", $id);
return new ViewModel(array('f' => $funcionario));
}
Conforme a listagem acima, vemos que através de $this->params()->fromRoute("id", 0) buscamos o id que foi adicionado na URL, e com este valor vamos no banco através do doctrine e buscamos o Funcionário correspondente com $em->find("Application\Model\Funcionario", $id).
Com o funcionário conhecido pelo seu id, no método excluir basta chamar a função remove() do doctrine para deletar este registro no banco de dados e redirecionar para a listagem novamente. Já no exemplo do editar iremos retornar o funcionário encontrado para o arquivo editar.phtml que deve ser criado em Application/view/application/índex/editar.phtml.
O arquivo editar.phtml deve ser criado igual a index.phtml, mas sua diferença é pelo fato dos inputs possuírem value para o valor do funcionário devolvido pelo método editarAction(). Veja na Listagem 16 como deve ser o formulário editar.
Listagem 16.Formulário para editar o funcionário
<h3>Editar Funcionário</h3>
<form method="post">
Informe o nome do funcionário..:
<br>
<input type="text" name="nome" value="<?php echo $this->f->getNome(); ?>">
<br><br>
Informe o cpf do funcionário..:
<br>
<input type="text" name="cpf" value="<?php echo $this->f->getCpf(); ?>">
<br><br>
Informe o salário do funcionário..:
<br>
<input type="text" name="salario" value="<?php echo $this->f->getSalario(); ?>">
<br><br>
<input type="submit" value="Editar">
</form>
<br><br>
<a href="<?php echo $this->url('application/default',
array('controller' => 'index', 'action' => 'listar')); ?>">Listar Funcionario</a>
Após alterar os dados do formulário e clicar no botão EDITAR, o Zend chamará novamente o método editarAction(), porém os dados do formulário serão enviados, com estes valores podemos alterar o valor inicial adicionado no banco de dados, conforme a Listagem 17.
Listagem 17.Método editarAction() concluído.
public function editarAction()
{
$id = $this->params()->fromRoute("id", 0);
$em = $this->getServiceLocator()->get("Doctrine\ORM\EntityManager");
$funcionario = $em->find("Application\Model\Funcionario", $id);
$request = $this->getRequest();
if($request->isPost())
{
try{
$nome = $request->getPost("nome");
$cpf = $request->getPost("cpf");
$salario = $request->getPost("salario");
$funcionario->setNome($nome);
$funcionario->setCpf($cpf);
$funcionario->setSalario($salario);
$em = $this->getServiceLocator()->get("Doctrine\ORM\EntityManager");
$em->merge($funcionario);
$em->flush();
} catch (Exception $e){
}
return $this->redirect()->toRoute('application/default',
array('controller' => 'index', 'action' => 'listar'));
}
return new ViewModel(array('f' => $funcionario));
}
Conforme a listagem acima, iremos receber os dados do formulário e basta chamar o método merge() do doctrine que os dados são modificados na tabela funcionário.
Com isto finalizamos nosso artigo sobre criação de um projeto utilizando Zend Framework 2 e Doctrine 2. Eespero que possa ter ajudado a todos vocês, obrigado a todos e bons estudos.
Links
Artigos relacionados
-
DevCast
-
DevCast
-
DevCast
-
DevCast
-
DevCast