terça-feira, 2 de outubro de 2012

Design Pattern Builder no PHP

Olá amigos tudo bem? Vamos "filosofar" um pouco? Vamos falar sobre o Builder um design pattern que "deriva" do Factory mas tem suas particularidades.

ANNTISiSS DE INICIAR O ARTIGO VOU DAR UM AVISO AOS NAVEGANTES:
    Não use um design pattern pq simplesmente ele é "elegante" ou então pq vc quer aprender e para isso vai jogar em código de produção para testar.
   Use os patterns quando vc REALMENTE PRECISAR, vou repetir... REALMENTE PRECISAR! Muitas vezes as pessoas tornam algo simples em algo absurdamente complexo por não saber usar ou usar os os patterns em hora errada, se vc tem dúvidas se usa ou não o pattern procure entender melhor o problema e a solução que ele propõe antes de fazer uma tremenda de uma porcaria no código. Ok? :)


Como o próprio nome já diz ele é um pattern construtor(builder), otimo para quando vc precisa criar objetos completos que atendam uma certa complexidade. No Pattern Builder um temos um diretor e um construtor trabalhando juntos para construir um objeto. O diretor controla a construção e especifica quais partes e variações entram em um objeto. O construtor sabe como montar a especificação do determinado objeto. Em resumo a intenção do padrão Construtor(Builder), é separar a construção de um objeto complexo, de modo que o mesmo processo de construção possa criar várias representações diferentes.

Veja um exemplo claro de diagrama mostrando a implementação:
O diagrama é a mesma coisa que dizer que:
A classe Builder especifica uma interface abstrata para a criação de partes de um objeto Product.
O ConcreteBuilder constrói e reúne peças do produto pela implementação da interface Builder. Ele define e mantém o controle da representação que cria e fornece uma interface para guardar o produto
A classe Director constrói o objeto complexo usando a interface do Construtor
A Product representa o objeto complexo que está sendo construído.

Veja um exemplo classico de implementação:
BUILDER
  1. <?php
  2. class Fabrica {
  3.     public function Construir($oVeiculo) {
  4.         $oVeiculo->Iniciar();
  5.         $oVeiculo->construirPortas();
  6.         $oVeiculo->construirMotor();
  7.         $oVeiculo->construirPneus();
  8.     }
  9. }
  10. abstract class ConstrutorVeiculo {
  11.     protected $Veiculo;
  12.     abstract public function Iniciar();
  13.     abstract public function construirMotor();
  14.     abstract public function construirPortas();
  15.     abstract public function construirPneus();
  16. }
  17. class Carro extends ConstrutorVeiculo {
  18.     public $Veiculo;
  19.     public function Iniciar() {
  20.         $this->Veiculo = new Veiculo('Carro');
  21.     }
  22.     public function construirPortas() {
  23.         $this->Veiculo->aPartes['Portas'] = 4;
  24.     }
  25.     public function construirMotor() {
  26.         $this->Veiculo->aPartes['Motor'] = 1;
  27.     }
  28.     public function construirPneus() {
  29.         $this->Veiculo->aPartes['Pneus'] = 4;
  30.     }
  31. }
  32. class Moto extends ConstrutorVeiculo {
  33.     public $Veiculo;
  34.     public function Iniciar() {
  35.         $this->Veiculo = new Veiculo('Moto');
  36.     }
  37.     public function construirPortas() {
  38.         $this->Veiculo->aPartes['Portas'] = 0;
  39.     }
  40.     public function construirMotor() {
  41.         $this->Veiculo->aPartes['Motor'] = 1;
  42.     }
  43.     public function construirPneus() {
  44.         $this->Veiculo->aPartes['Pneus'] = 2;
  45.     }
  46. }
  47. class Veiculo {
  48.     private $sTipo = NULL;
  49.     public $aPartes = array();
  50.     public function __construct($sTipo) {
  51.         $this->sTipo = $sTipo;
  52.     }
  53.     public function ObterInformacoes() {
  54.         printf("--------------------------\n");
  55.         printf("Veículo: %s \n", $this->sTipo);
  56.         printf("Motor:   %s \n", $this->aPartes['Motor']);
  57.         printf("Portas:  %s \n", $this->aPartes['Portas']);
  58.         printf("Pneus:   %s \n", $this->aPartes['Pneus']);
  59.     }
  60. }
  61. $Fabrica = new Fabrica;
  62. $Carro = new Carro;
  63. $Moto = new Moto;
  64. $Fabrica->Construir($Carro);
  65. $Carro->Veiculo->ObterInformacoes();
  66. $Fabrica->Construir($Moto);
  67. $Moto->Veiculo->ObterInformacoes();
  68. ?>


A explicação acima fala por si só não é? Mesmo assim qualquer dúvida... Fui

segunda-feira, 17 de setembro de 2012

Paginação com Doctrine e Zend_Framework

Olá amigos, hoje vou mostra basicamente como paginar dados usando o Zend Framework e o Doctrine, inicialmente parece algo complexo, mas vcs vão perceber que é simples.

Se vc ainda não fez uma paginação com o zend framework leia esse meu artigo sobre paginação com o ZF Paginando com Zend Framework e depois corra aqui, ou se preferir fique por aqui mesmo.

Vamos lá, vou mostrar a paginação de forma bem simples pois o grande problema de fazer um artigo sobre paginação do Zend Framework com Doctrine é que isso varia muito a arquitetura que cada um esta usando, mas nesse caso isso não vai atrapalhar pois vc vai adaptar de acordo com a sua arquitetura.

Mãos a obra

No controller....
  exemplo de consulta
  1.  public function exemploAction() {
  2.  
  3.         $request = $this->getRequest();
  4.  
  5.         if ($request->getPost()) {
  6.  
  7.             $params = $request->getPost();
  8.             $pagina = (int) $params['pag'];
  9.  
  10.             $front = \Zend_Controller_Front::getInstance();
  11.             $em = $front->getParam('bootstrap')->getResource('entityManager');
  12.             $dql = $em->createQuery("select a from Entidade_Pessoa a");
  13.  
  14.             $dados = new \DoctrineExtensions\Paginate\PaginationAdapter($dql);
  15.  
  16.             $paginator = new Zend_Paginator($dados);
  17.             // Seta a quantidade de registros por página
  18.             $paginator->setItemCountPerPage(4);
  19.             // numero de paginas que serão exibidas
  20.             $paginator->setPageRange(15);
  21.             // Seta a página atual
  22.             $paginator->setCurrentPageNumber($pagina);
  23.         }
  24.  
  25.  
  26.         $this->view->paginator = $paginator;
  27.  }

Veja que simples, usamos uma paginação aparentemente comum  do ZF não é? mas passamos para o zend_paginador a variavel $dados que contem a instância da PaginationAdapter que recebe a consulta dql e faz toda a brincadeira... esse cara esta aqui abaixo é uma classe que implementa a \Zend_Paginator_Adapter_Interface e por isso o Zend_Paginator sabe trabalhar com o objeto pois os métodos que ele usa são do nome da interface.
Lindo não é?








Veja a classe:

  ADAPTER DO DOCTRINE
  1. /**
  2.  * DoctrineExtensions Paginate
  3.  *
  4.  * LICENSE
  5.  *
  6.  * This source file is subject to the new BSD license that is bundled
  7.  * with this package in the file LICENSE. This license can also be viewed
  8.  * at http://hobodave.com/license.txt
  9.  *
  10.  * @category    DoctrineExtensions
  11.  * @package     DoctrineExtensions\Paginate
  12.  * @author      David Abdemoulaie <dave@hobodave.com>
  13.  * @copyright   Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
  14.  * @license     http://hobodave.com/license.txt New BSD License
  15.  */
  16.  
  17. namespace DoctrineExtensions\Paginate;
  18.  
  19. use Doctrine\ORM\Query;
  20.  
  21. /**
  22.  * Implements the Zend_Paginator_Adapter_Interface for use with Zend_Paginator
  23.  *
  24.  * Allows pagination of Doctrine\ORM\Query objects and DQL strings
  25.  *
  26.  * @category    DoctrineExtensions
  27.  * @package     DoctrineExtensions\Paginate
  28.  * @author      David Abdemoulaie <dave@hobodave.com>
  29.  * @copyright   Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
  30.  * @license     http://hobodave.com/license.txt New BSD License
  31.  */
  32. class PaginationAdapter implements \Zend_Paginator_Adapter_Interface {
  33.  
  34.     /**
  35.      * The SELECT query to paginate
  36.      *
  37.      * @var Query
  38.      */
  39.     protected $query = null;
  40.  
  41.     /**
  42.      * Total item count
  43.      *
  44.      * @var integer
  45.      */
  46.     protected $rowCount = null;
  47.  
  48.     /**
  49.      * Use Array Result
  50.      *
  51.      * @var boolean
  52.      */
  53.     protected $arrayResult = false;
  54.  
  55.     /**
  56.      * Constructor
  57.      *
  58.      * @param Query $query
  59.      * @param string $ns Namespace to prevent named parameter conflicts
  60.      */
  61.     public function __construct(Query $query) {
  62.  
  63.         $this->query = $query;
  64.  
  65.     }
  66.  
  67.     /**
  68.      * Set use array result flag
  69.      *
  70.      * @param boolean $flag True to use array result
  71.      */
  72.     public function useArrayResult($flag = true) {
  73.         $this->arrayResult = $flag;
  74.     }
  75.  
  76.     /**
  77.      * Sets the total row count for this paginator
  78.      *
  79.      * Can be either an integer, or a Doctrine\ORM\Query object
  80.      * which returns the count
  81.      *
  82.      * @param Query|integer $rowCount
  83.      * @return void
  84.      */
  85.     public function setRowCount($rowCount) {
  86.         if ($rowCount instanceof Query) {
  87.             $this->rowCount = $rowCount->getSingleScalarResult();
  88.         } else if (is_integer($rowCount)) {
  89.             $this->rowCount = $rowCount;
  90.         } else {
  91.             throw new \InvalidArgumentException("Invalid row count");
  92.         }
  93.     }
  94.  
  95.     /**
  96.      * Sets the namespace to be used for named parameters
  97.      *
  98.      * Parameters will be in the format 'namespace_1' ... 'namespace_N'
  99.      *
  100.      * @param string $ns
  101.      * @return void
  102.      * @author David Abdemoulaie
  103.      */
  104.     public function setNamespace($ns) {
  105.         $this->namespace = $ns;
  106.     }
  107.  
  108.     /**
  109.      * Gets the current page of items
  110.      *
  111.      * @param string $offset
  112.      * @param string $itemCountPerPage
  113.      * @return void
  114.      * @author David Abdemoulaie
  115.      */
  116.     public function getItems($offset, $itemCountPerPage) {
  117.  
  118.         $this->query->setFirstResult($offset);
  119.         $this->query->setMaxResults($itemCountPerPage);
  120.         $entities = $this->query->getResult();
  121.  
  122.         return $entities;
  123.     }
  124.  
  125.     /**
  126.      * @param Query $query
  127.      * @return int
  128.      */
  129.     public function count() {
  130.         if (is_null($this->rowCount)) {
  131.             $this->setRowCount(
  132.                     $this->createCountQuery()
  133.             );
  134.         }
  135.         return $this->rowCount;
  136.     }
  137.  
  138.     /**
  139.      * @return Query
  140.      */
  141.     protected function createCountQuery() {
  142.         return Paginate::createCountQuery($this->query);
  143.     }
  144.  
  145.     /**
  146.      * @return Query
  147.      */
  148.     protected function createLimitSubquery($offset, $itemCountPerPage) {
  149.         return Paginate::createLimitSubQuery($this->query, $offset, $itemCountPerPage);
  150.     }
  151.  
  152.     /**
  153.      * @return Query
  154.      */
  155.     protected function createWhereInQuery($ids) {
  156.         return Paginate::createWhereInQuery($this->query, $ids, $this->namespace);
  157.     }
  158.  
  159. }
Veja que nós implementamos os métodos da interface e montamos o resultado então na view é só pegar como de costume o "$this->paginator" iterar ele e mandar bala!



Dúvidas? Me avisem pois fiz esse post meio correndo... rsrs