Módulo LosBase

Hoje vou falar um pouco sobre meu primeiro módulo ZF2: LosBase.

Comecei meu primeiro projeto com ZF2 quando ainda estava no beta2 e, como acredito que a melhor forma de aprender é colocando a mão na massa, comecei a aprender o ZF2 fazendo este módulo e estudando os poucos que estavam sendo feitos.

Vou falar sobre as principais funcionalidades do módulo e darei alguns exemplos. Chamo de LosBase pois é uma base para outros módulos e todos meus projetos.

Atualmente o módulo está na sua versão 2.5.x, onde fiz uma faxina, melhorei o código, e acrescentei várias coisas.

Instalação

Para instalar, basta acrescentar no seu composer.json:

e fazer o composer update.

Criação automática de módulo

Para não criar um módulo no seu projeto manualmente, existe a ferramenta da zend framework chamada zftool para criar projetos, módulos, etc. O módulo LosBase disponibiliza também um comando para criar um módulo com tudo o que é necessário para um CRUD simples:

Para usar este comando, você já precisa ter o LosBase instalado no seu projeto. Ele automaticamente já cria:

  • Estrutura de diretórios para o novo módulo
  • config/module.config.php
  • Rotas para o crud
  • Arquivos do autoload
  • Module.php
  • Controller (usando AbstractCrudController abaixo)
  • Entity (Usando Entity\AbstractEntity abaixo)
  • Serviço (Usando Service\AbstractEntity abaixo)
  • Arquivos da view (list.phtml, add.phtml, edit.phtml e delete.phtml)
  • Nova entrada no application.config.php para seu novo módulo

Depois de criado, basta entrar na entidade, adicionar os campos que quiser e nas views, em especial no list.phtml, para montar a tabela como quiser.

Atenção! Os arquivos de view estão estilizados para o bootstrap 3 e usando alguns view helpers do LosUi, então se você não quiser usar o LosUi, altere o necessário nas views.

Controller\AbstractCrudController

Na maioria dos meus projetos uso o doctrine e em todo projeto tenho as entidades e pelo menos alguns CRUDs simples, então resolvi criar as classes abstratas para ganhar tempo (afinal nós desenvolvedores somos preguiçosos por natureza rss) e principalmente evitar erros.

Quando preciso de um crud simples (listar, inserir, alterar e excluir) de uma entidade, meu controller fica assim:

Pronto! Já tenho um controller que lista os clientes cadastrados e já paginados, cria a form para inserir a trata os dados vindos da form, salva no banco, edita e exclui.

Se quisermos evitar que existam 2 clientes com o mesmo nome, podemos alterar o controller:

Automaticamente o controller vai checar se já existe um cliente com o nome informado antes de inserir, usando o LosBase\Validator\NoEntityExists.

Durante a alteração, ele checa se você tentar alterar o nome para o mesmo de um cliente já cadastrado usando o LosBase\Validator\NoOtherEntityExists, pois se usarmos apenas o NoEntityExists, você não conseguirá alterar nenhum cliente pois o nome dele já existe e é ele mesmo.

Para que o controller funcione, é necessário que crie 2 classes:

Uma classe de serviço, responsável pelas operações de persistência dos dados no banco de dados.

A nossa entidade em si.

Existem outras opções no controller que podem ser usadas:

Entity\AbstractEntity

Normalmente, todas as minhas entidades possuem um id no banco de dados, data de criação e alteração. Então criei esta classe abstrata e minhas entidades a usam.

Se por algum motivo não quiser usar esta classe (por exemplo usa “extends” em outra), pode usar os mesmos campos apenas usando as traits:

  • LosBase\Entity\Db\Field\Id
  • LosBase\Entity\Db\Field\Created
  • LosBase\Entity\Db\Field\Updated

DBAL\Types\BrPriceType

Com frequência, precisamos usar preço nos sistemas, mas o formato que usamos para números (1.234,56) é diferente do padrão do banco dados (1234.56), então sempre acabamos fazendo conversões antes de salvar no banco e após ler dele.

Este tipo automatiza este processo. Basta definir a propriedade da entidade com este tipo que automaticamente ele converte nossos números para o formato do banco de dados e vice-versa:

Por padrão, ele usa precisão de 9 e 2 decimais mas, caso precise, basta passar novos valores como de costume no ORM:

Apesar do nome, você pode usar este tipo para qualquer tipo numérico.

DBAL\Types\BrDateTimeType e UtcDateTimeType

Falando em data, um grande problema quando se trabalha com datas em projetos não regionais (usamos em mais de uma zona datetime) ou em servidores no exterior, é como armazenar corretamente as datas no banco de dados de forma consistente.

O BrDateTimeType automaticamente converte a data para UTC antes de salvar no banco de dados e converte de volta para “America/Sao_Paulo” (não, não sou paulista, sou carioca rss) quando é lido do banco. Isso já facilita muito o trabalho.

O UtcDateTime faz a mesma coisa, mas retorna em UTC.

Para usar, basta definir no annotation do Doctrine da entidade:

Não precisa alterar nenhum configuração, o módulo já faz isso para você.

Entity\EntityManagerAwareTrait

Com frequência crio serviços ou controllers que usam o EntityManager do Doctrine e esta trait já me traz o necessário, com o setter e getter:

 ORM\Tools\Pagination\Paginator

Criei este paginator para disponibilizar a quantidade total dos registros para losPaginator do módulo LosUi.

Service\AbstractEntity

Mais uma classe visando agilizar o desenvolvimento. Todo controller de crud precisa salvar os dados no banco (inserir, alterar e excluir) e costumo separar estas operações num serviço da entidade ao invés de fazer direto no controller.

Esta classe abstrata já valida a form, salva a entidade com os dados submetidos, atualiza o campo updated se estiver disponível, etc. Também tem um método para excluir a entidade. São usados automaticamente pelo AbstractCrudController.

Resumindo, é um módulo que facilita em muito o desenvolvimento do projeto e ajuda a evitar erros de copy/paste onde muitas vezes se esquece de trocar uma variável, namespace, etc e que já traz várias classes úteis para o doctrine.

Até a próxima!

Leandro Silva

 

PHP developer since 1997, loves movies, music and dogs.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

*