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

https://netbeans.org/

https://www.apachefriends.org/pt_br/index.html