1 de setembro de 2012

Herança no Doctrine: Persistindo e recuperando objetos

Em um artigo anterior foi apresentando como a herança pode ser implementada no Doctrine. Neste artigo vamos apresentar como os elementos da herança podem ser persistidos e recuperados do Banco de Dados

Para exemplo didático vamos utilizar novamente o exemplo épico do filme Star Wars (Figura 1), onde existe uma relação de herança entre: DarthVader, Luke Skywalker e Leia Organa.


Figura 1: Exemplo didático de herança. 



As classes que representam cada um dos elementos podem ser visualizadas no post anterior


Para o conjunto de classes do exemplo vamos implementar uma classe DAO (Data Access Object) para interagir com o Banco de Dados. A seguir é apresentado o código da classe DAO:

Classe JediDAO



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php

class JediDAO {
   
    public static function add($object) {
        /**Obtendo o container contendo as operações básicas envolvendo o doctrine. */
        $doctrine_container = \Zend_Registry::get('doctrine');
        $em = $doctrine_container->getEntityManager();

        if($object->getId()){
            $object = $em->merge($object);
        }else{
            $em->persist($object);
        }
        
        $em->flush();

        return $object;
    }
    
    public static function get($id) {
        /**Obtendo o container contendo as operações básicas envolvendo o doctrine. */
        $doctrine_container = \Zend_Registry::get('doctrine');
        $em = $doctrine_container->getEntityManager();
                       
        $object = $em->getRepository('DarthVader')->find($id);

        return $object;
    } // function
    
    public static function listAll(){
        /**Obtendo o container contendo as operações básicas envolvendo o doctrine. */
        $doctrine_container = \Zend_Registry::get('doctrine');
        $em = $doctrine_container->getEntityManager();
        
        $query = $em->createQuery('select obj from DarthVader obj');
        
        $object_list = $query->getResult();
        
        return $object_list;        
    }
    
} // class

Agora vamos testar os métodos implementados na classe DAO:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?php 
        //Criando um objeto DarthVader
        $darth_1 = new  DarthVader();
        $darth_1->setAtributoAnakin(1);
        
        //Persistindo o objeto
        JediDAO::add($darth_1);
        
        // Criando um objeto Luke
        $luke_1 = new Luke();
        $luke_1->setAtributoLuke(2);
        
        JediDAO::add($luke_1);
        
        //Criando um objeto Leia
        $leia_1 = new Leia();
        $leia_1->setAtributoLeia(3);
        
        JediDAO::add($leia_1);
        
        // Recuperando o objeto de id = 2
        $jedi_2 = JediDAO::get(2);
        
        /*
          var_dump em $jedi_2 retorna: 
            object(Luke)[198]
              private 'atributo_luke' => int 2
              private 'id' (DarthVader) => int 2
              private 'atributo_anakin' (DarthVader) => null

        */
        
        //Listando todos os objetos jedi's do Banco
        $lista_jedis = JediDAO::listAll();
        
        /*
        var_dump em $lista_jedis retorna um array:

        array (size=3)
        0 => 
            object(DarthVader)[209]
              private 'id' => int 1
              private 'atributo_anakin' => int 1
        1 => 
            object(Luke)[198]
              private 'atributo_luke' => int 2
              private 'id' (DarthVader) => int 2
              private 'atributo_anakin' (DarthVader) => null
        2 => 
            object(Leia)[208]
              private 'atributo_leia' => int 3
              private 'id' (DarthVader) => int 3
              private 'atributo_anakin' (DarthVader) => null
 
        */        


1 de agosto de 2012

Projeto exemplo integrando o Zend Framework e o Doctrine

O início sempre é a parte mais complicada para alguém que está aprendendo um determinado framework, pois ele se depara com uma quantidade grande de novas informações a serem "digeridas".  



Na maioria das vezes falta um projeto básico "Hello World" para apresentar as funcionalidades básicas para o usuário. Algo semelhante ao que ocorre no aprendizado das linguagens de programação.

Em função disto, o ZeDoc foi criado para apresentar um projeto (ou template) exemplo utilizando o Zend Framework em conjunto com o Doctrine, contendo algumas funcionalidades básicas para um projeto, como por exemplo:


Informações mais detalhadas sobre o projeto (como instalar, funcionalidades implementadas) podem ser encontradas em: no site do projeto, aqui mesmo (em futuros artigos) e ali (em futuros artigos).  

25 de julho de 2012

Implementando Herança no Doctrine

Nesse artigo vamos falar um pouco sobre a implementação de Herança no Doctrine. Como exemplo didático de herança, temos a épica relação entre DarthVader,  Luke Skywalker e Leia Organa no filme Star Wars (Figura 1). Em vista disto, vamos utilizar esta relação entre os personagens para ilustrar a implementação da herança no Doctrine


Figura: "I am your father". 

A herança no Doctrine é especificada através dos atributos: 


  • @DiscriminatorColumn: utilizado para indicar qual o elemento da hierarquia (classe) a linha da tabela representa.
  • @DiscriminatorMap: utilizado para identificar quais os valores que existirão na coluna do discriminador e qual classe da hierarquia está mapeado para cada valor.
  • @InheritanceType: representa a estrutura no Banco de Dados que irá armazenar a herança. SINGLE_TABLE indicada que tanto o objeto pai quanto os objetos filhos estarão representados na mesma tabela. JOINED indica que cada classe da hierarquia terá uma tabela própria. 


Por exemplo, tendo o mapa:

@DiscriminatorMap({"father" = "DarthVader", "son" = "Luke", "daughter" = "Leia"})

temos que father representa um objeto da classe DarthVader, já son representa um elemento da classe Luke.


A seguir um exemplo de implementação da herança. São especificadas três classes: DarthVader (classe pai), Luke (classe filho) e Leia (classe filho). 


Classe DarthVader (pai)



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php

/**
 * @Entity
 * @InheritanceType("SINGLE_TABLE")
 * @Table(name="father")
 * @DiscriminatorColumn(name="discr", type="string")
 * @DiscriminatorMap({"father" = "DarthVader", "son" = "Luke", "daughter" = "Leia"})
 */
class DarthVader{
    
    /**
     * @var integer $id
     * @Column(type="integer")
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $id;
    
    public function setId($id){$this->id = $id;}
    public function getId(){return $this->id;}
    
    /**
     * 
     * @Column(type="integer")
     * 
     */
    private $atributo_anakin;    
    
    public function setAtributoAnakin($atributo){$this->atributo_anakin=$atributo;}
    public function getAtributoAnakin(){return $this->atributo_anakin;}
}


Classe Luke (filho)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php

/**
 * 
 * @Entity
 * @Table(name="son") 
 */
class Luke extends DarthVader {
    
    /**
     * 
     * @Column(type="integer")
     * 
     */
    private $atributo_luke;    
    
    public function setAtributoLuke($atributo){$this->atributo_luke=$atributo;}
    public function getAtributoLuke(){return $this->atributo_luke;}
    
}


Classe Leia (filho)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

/**
 * 
 * @Entity
 * @Table(name="daughter") 
 */
class Leia extends DarthVader {
    
    /**
     * 
     * @Column(type="integer")
     * 
     */
    private $atributo_leia;    
    
    public function setAtributoLeia($atributo){$this->atributo_leia=$atributo;}
    public function getAtributoLeia(){return $this->atributo_leia;}
    
    
}


A seguir a estrutura gerada no Banco de Dados para cada tipo de herança (InheritanceType).

JOINED


Figura: Tipo de Herança JOINED



SINGLE_TABLE



Figura: Tipo de Herança SINGLE_TABLE



Num próximo artigo vamos falar como ocorre o processo de persistência dos objetos Doctrine no Banco de Dados.

18 de julho de 2012

Adicionando Javascript nas views do Zend Framework



A inserção de código Javascript nas view do Zend Framework pode ser realizada através da utilização de dois helpers (classes) existentes: HeadScript Helper e InlineScriptHelper. Essas entidades podem ser utilizadas para adicionar diretamente o código javascript ou anexar um arquivo contendo o código javascript



HeadScript é utilizado quando se deseja referenciar o código javascript na marcação (tag) header da página. Para utilização(*) do HeadScript deve-se:

1) No Controller adicionar o endereço do arquivo no HeadScript da view.

  • Exemplo: <?php $this->view->headScript()->appendFile('/js/funcoes.js'); ?>


2) Na view imprimir o conteúdo do HeadScript:

  • Exemplo: <?php echo $this->headScript(); ?>



InlineScript é utilizado quando se deseja referenciar o código javascript na marcação (tag) body da página, ou seja, deseja-se anexar o javascript em uma determinada "posição" da página.  Para utilização(*) do InlineScript deve-se: 


1) No Controller adicionar o endereço do arquivo no InlineScript da view.

  • Exemplo: <?php $this->view->inlineScript()->appendFile('/js/funcoes.js'); ?>


2) Na view imprimir o conteúdo do InlineScript na posição desejada para o código javascript. Geralmente é recomendado imprimir o conteúdo no fim do código da view.

  • Exemplo: <?php echo $this->inlineScript(); ?>


(*) Apenas salientando que os exemplos englobam a inserção de uma referência a um arquivo .js na página. Para inserir diretamente um código javascript  verificar a função appendScript().

2 de julho de 2012

Singletons

''Se o singleton fosse um meme ele seria o Forever Alone.'' 


Forever Alone é um meme que representa o nível extremo de solidão de uma pessoa. O Singleton é um Padrão de Projeto de Software (do inglês Design Patternque restringe a instanciação de uma classe a apenas um único objeto. Como podemos observar o comportamento do Singleton é semelhante ao de nosso amigo Forever Alone, ou seja, por mais que deseje, ele não vai encontrar ninguém de seu tipo (classe) para consolá-lo na solidão e terá que chorar as pitangas sozinho.

Deixando um pouco o blablablá envolvendo Singletons, Padrões de Projetos e memes a seguir estão 2 exemplos de implementação de uma classe Singleton em PHP, sendo que apenas a primeira implementação está correta. Para cada uma das implementações são realizados alguns testes básicos para validar (ou invalidar) a implementação.  


Implementação correta: definindo um objeto estático para a classe e deixar o construtor e o método clone como privados.

1:  <?php   
2:  class ForeverAlone{  
3:       /**Instância única*/  
4:       private static $instancia = null;  
5:       /**Quantidade de chamadas ao construtor*/  
6:       private static $chamadas_construtor = 0;  
7:       /**Quantidade de chamadas ao método getInstance()*/  
8:       private static $chamadas_instancia = 0;  
9:       private function __construct(){  
10:            // construtor privado  
11:            self::$chamadas_construtor;  
12:       }  
13:       private function __clone(){  
14:            // clone privado   
15:       }  
16:       public static function getInstance(){  
17:            self::$chamadas_instancia++;  
18:            if(self::$instancia == null){  
19:                 self::$instancia = new self();  
20:            }  
21:            return self::$instancia;  
22:       }  
23:       public function getStats(){  
24:            return 'Chamadas ao Construtor: ' . self::$chamadas_construtor . "\n" .   
25:            'Chamadas ao getInstance(): ' . self::$chamadas_instancia . "\n";  
26:       }  
27:  }  



Implementação errada: deixando o construtor e o método clone como public (ou esquecendo de implementar eles).


1:  <?php   
2:  class ForeverAlone{  
3:       /**Instância única*/  
4:       private static $instancia = null;  
5:       /**Quantidade de chamadas ao construtor*/  
6:       private static $chamadas_construtor = 0;  
7:       /**Quantidade de chamadas ao método getInstance()*/  
8:       private static $chamadas_instancia = 0;  
9:       public function __construct(){  
10:            // construtor privado  
11:            self::$chamadas_construtor;  
12:       }  
13:       public function __clone(){  
14:            // clone privado   
15:       }  
16:       public static function getInstance(){  
17:            self::$chamadas_instancia++;  
18:            if(self::$instancia == null){  
19:                 self::$instancia = new self();  
20:            }  
21:            return self::$instancia;  
22:       }  
23:       public function getStats(){  
24:            return 'Chamadas ao Construtor: ' . self::$chamadas_construtor . "\n" .   
25:            'Chamadas ao getInstance(): ' . self::$chamadas_instancia . "\n";  
26:       }  
27:  }  


Testes


1:  <?php  
2:  include('ForeverAlone.php');  
3:  $objeto1 = ForeverAlone::getInstance();  
4:  // Imprimindo as estatísticas  
5:  echo $objeto1->getStats();  
6:  // Nova chamada ao getInstance  
7:  $objeto2 = ForeverAlone::getInstance();  
8:  echo $objeto2->getStats();  
9:  // Chamada ao construtor  
10:  $objeto3 = new ForeverAlone(); // Na implementação correta gera erro, pois o método é privado  
11:  echo $objeto3->getStats();  
12:  // Chamada ao clone  
13:  $objeto4 = clone $objeto1;  // Na implementação correta gera erro, pois o método é privado
14:  echo $objeto4->getStats();  
15:  ?>