Tableless

Busca Menu

Iniciando com Symfony 2 – Parte 04

Seja o primeiro a comentar por

Anteriormente, criamos a entidade Post, vamos dar continuidade ao nosso simples projeto, criando uma entidade Author, faremos o relacionamento para que cada autor fique ligado ao post que criou.

Criando a entidade Author

Vamos criar a entidade Author, entre no terminal e digite:

 $ php app/console generate:doctrine:entity

Vamos digitar o nome da entidade como : TablelessModelBundle:Author.

 $ The Entity shortcut name: TablelessModelBundle:Author

Vamos mapeá-la usando annotation. Apenas damos enter.

 $ Configuration format (yml, xml, php, or annotation) [annotation]:

O assistente nos pergunta: Qual será o nome do nosso campo?
Digitamos “name” e damos enter.

 $ New field name (press  to stop adding fields): name

Será do tipo string.

 $ Field type [string]:

Com o tamanho de 100.

 $ Field length [255]: 100

Quando o assistente nos perguntar novamente: Qual será o novo campo? Damos enter para entrarmos no processo de finalização. E nos pergunta, se queremos criar uma classe de repositório, ele nos indica não, vamos apenas dar um enter.

 Do you want to generate an empty repository class [no]?

E para finalizar, o assistente pergunta se realmente queremos gerar a entidade. Como queremos, digitamos apenas enter.

 $ Do you confirm generation [yes]?

Nossa entidade Author está pronta.

Ao entrarmos na pasta src/Tableless/ModelBundle/Entity/ vamos encontrá-la.

Entidade Author criada

Agora devemos adicionar a annotations, @ORM\Table(name=”author”) para o nome da nossa tabela, veja na linha 10:

Veja toda a entidade Author:

 <?php 

namespace Tableless\ModelBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
 * Author 
 * 
 * @ORM\Table(name="author")
 * @ORM\Entity 
 */ 
class Author 
{ 
    /** 
     * @var integer 
     * 
     * @ORM\Column(name="id", type="integer") 
     * @ORM\Id 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
    private $id; 

    /** 
     * @var string 
     * 
     * @ORM\Column(name="name", type="string", length=100) 
     */ 
    private $name; 

    /** 
     * Get id 
     * 
     * @return integer 
     */ 
    public function getId() 
    { 
        return $this->id; 
    } 

    /** 
     * Set name 
     * 
     * @param string $name 
     * @return Author 
     */ 
    public function setName($name) 
    { 
        $this->name = $name; 
        return $this; 
    } 

    /** 
     * Get name 
     * 
     * @return string 
     */ 
    public function getName() 
    { 
        return $this->name; 
    } 
} 

Configurando o projeto

Nesse momento vamos criar uma classe abstrata com o nome Timestampable, para que não fiquemos repetindo código, pois entidade Author também receberá uma data de criação e data de atualização.

Vamos lá!

Entre na pasta src/Tableless/ModelBundle/Entity/, e vamos criar uma classe abstrata com o nome Timestampable, para que possamos mapeá lá vamos usar a classe do Doctrine Mapping e vamos dar um apelido de ORM, e fazer as annotations correspondentes.

Nesse momento, ficar explicando detalhe por detalhe levará muito tempo, e o tutorial ficará extenso, veja a classe Timestampable pronta abaixo:

 <?php 

namespace Tableless\ModelBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
 * Timestampable abstract class 
 * @ORM\MappedSuperclass 
 */ 
abstract class Timestampable 
{ 
    /** 
     * @var \DateTime 
     * 
     * @ORM\Column(name="created_at", type="datetime") 
     * @Assert\NotBlank 
     */ 
    private $createdAt; 

    /** 
     * @var \DateTime 
     * 
     * @ORM\Column(name="updated_at", type="datetime") 
     * @Assert\NotBlank 
     */ 
    private $updatedAt; 

    /** 
     * Construct 
     */ 
    public function __construct() 
    { 
        $this->createdAt = new \DateTime(); 
        $this->updatedAt = new \DateTime(); 
    } 

    /** 
     * Set createdAt 
     * 
     * @param $createdAt 
     */ 
    public function setCreatedAt($createdAt) 
    { 
        $this->createdAt = $createdAt; 
    } 

    /** 
     * Get CreatedAt 
     * 
     * @return \DateTime 
     */ 
    public function getCreatedAt() 
    { 
        return $this->createdAt; 
    } 

    /** 
     * Set UpdatedAt 
     * 
     * @param \DateTime $updatedAt 
     */ 
    public function setUpdatedAt($updatedAt) 
    { 
        $this->updatedAt = $updatedAt; 
    } 
    /** 
     * Get UpdateAt 
     * 
     * @return \DateTime 
     */ 
    public function getUpdatedAt() 
    { 
        return $this->updatedAt; 
    } 
}

Vamos estender essa classe na entidade Author, veja abaixo na linha 13:

 <?php 

namespace Tableless\ModelBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
 * Author 
 * 
 * @ORM\Table(name="author")
 * @ORM\Entity 
 */ 
class Author extends Timestampable 
{ 
…

Temos que validar os campos da entidade Author, vamos dar um use em Constraints e apelidá-la como Assert:

 use Symfony\Component\Validator\Constraints as Assert;

vamos validar o campo name com @Assert\NotBlank, veja abaixo:

 /** 
* @var string 
* 
* @ORM\Column(name="name", type="string", length=100) 
* @Assert\NotBlank 
*/ 
private $name; 

Veja a entidade Author depois da configuração:

<?php 

namespace Tableless\ModelBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
 * Author 
 * 
 * @ORM\Table(name="author")
 * @ORM\Entity 
 */ 
class Author extends Timestampable 
{  
    /** 
     * @var integer 
     * 
     * @ORM\Column(name="id", type="integer") 
     * @ORM\Id 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
    private $id; 

    /** 
     * @var string 
     * 
     * @ORM\Column(name="name", type="string", length=100) 
     * @Assert\NotBlank 
     */ 
    private $name; 


    /** 
     * Get id 
     * 
     * @return integer 
     */ 
    public function getId() 
    { 
        return $this->id; 
    } 

    /** 
     * Set name 
     * 
     * @param string $name 
     * @return Author 
     */ 
    public function setName($name) 
    { 
        $this->name = $name; 
 
        return $this; 
    } 

    /** 
     * Get name 
     * 
     * @return string 
     */ 
    public function getName() 
    { 
        return $this->name; 
    } 
} 

Configurando a entidade Post

Como criamos um classe abstrata, vamos alterar a entidade Post para que ela estenda a entidade Timestampable.

Exclua os atributos $createdAt e $updatedAt e os métodos setCreatedAt(), getCreatedAt(), setUpdatedAt(), getUpdatedAt() e o __contruct(), e vamos estender a classe Timestampable, depois de configurada, a entidade Post ficará assim:

 <?php 

namespace Tableless\ModelBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
 * Post 
 * 
 * @ORM\Table(name="post") 
 * @ORM\Entity 
 */ 
class Post extends Timestampable 
{ 
    /** 
     * @var integer 
     * 
     * @ORM\Column(name="id", type="integer") 
     * @ORM\Id 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
    private $id; 

    /** 
     * @var string 
     * 
     * @ORM\Column(name="title", type="string", length=255) 
     * @Assert\NotBlank 
     */ 
    private $title; 

    /** 
     * @var string 
     * 
     * @ORM\Column(name="content", type="text") 
     * @Assert\NotBlank 
     */ 
    private $content; 

     /** 
     * Get id 
     * 
     * @return integer 
     */ 
    public function getId() 
    { 
        return $this->id; 
    } 

    /** 
     * Set title 
     * 
     * @param string $title 
     * @return Post 
     */ 
    public function setTitle($title) 
    { 
        $this->title = $title; 

     return $this; 
    } 

    /** 
     * Get title 
     * 
     * @return string 
     */ 
    public function getTitle() 
    { 
        return $this->title; 
    } 

    /** 
     * Set content 
     * 
     * @param string $content 
     * @return Post 
     */ 
    public function setContent($content) 
    { 
        $this->content = $content; 

        return $this; 
    } 

    /** 
     * Get content 
     * 
     * @return string 
     */ 
    public function getContent() 
    { 
        return $this->content; 
    } 
} 

Atualizando o banco de dados

Geramos a entidade Author e alteramos a entidade Post, dessa forma devemos atualizar nosso banco, para que o mesmo fique configurado de acordo com as entidades.

Vamos ao terminal, e para atualizar o banco de dados vamos digitar o código:

 $ php app/console doctrine:schema:update --force

Teremos o resultado:

 Updating database schema... 
 Database schema updated successfully! "1" queries were execute

Entrando no banco de dados vamos perceber que a tabela author criada:

Tabela Author

Criando o CRUD da entidade Author

Depois da configuração das nossa entidade, vamos gerar o CRUD da entidade Author. Vamos digitar no console:

 $ php app/console generate:doctrine:crud

Digitamos TablelessModelBundle:Author:

 $ The Entity shortcut name: TablelessModelBundle:Author

O assistente nos pergunta se queremos gerar as ações de gravação, digitamos: yes.

 $ Do you want to generate the "write" actions [no]? Yes

Como vamos configurar? Vamos deixar como está, annotation, e damos enter

 $ Configuration format (yml, xml, php, or annotation) [annotation]:

Como será a rota? Vamos deixar como ele nos indica, damos enter.

 $ Routes prefix [/author]:

Vamos confirmar a geração desse CRUD dando enter.

 $ Do you confirm generation [yes]?

Prontinho nosso CRUD da entidade Author está pronto, vamos testar.

Inicie o servidor:

 $ php app/console server:run

entre na url:

http://127.0.0.1:8000/author/

Vamos criar um autor com o nome Tableless

Relacionamento com Doctrine

Vamos fazer um relacionamento no banco de dados, pois queremos que, ao criarmos um post, o mesmo esteja relacionado com o autor que o criou. Não entraremos em detalhes sobre relacionamento, caso tenha dúvidas, consulte a documentação.

Vamos configurar novamente as entidades para que o relacionamento possa acontecer.

Entre na entidade Post e acrescente o atributo $author com as seguintes annotations:

    /** 
     * @var Author 
     * 
     * @ORM\ManyToOne(targetEntity="Author", inversedBy="posts") 
     * @ORM\JoinColumn(name="author_id", referencedColumnName="id", nullable=false) 
     * @Assert\NotBlank 
     */ 
    private $author;

Entre na entidade Author e acrescente o atributo $post, com as seguintes annotations:

    /** 
     * @var ArrayCollection 
     * 
     * @ORM\OneToMany(targetEntity="Post", mappedBy="author", cascade={"remove"}) 
     */ 
    private $post;

Precisamos também dar um use na classe ArrayCollection, do Doctrine, pois um autor terá vários posts, e os posts serão buscados como array, insira o código:

 use Doctrine\Common\Collections\ArrayCollection;

Vamos criar um construtor, porém a entidade Timestampable já tem um construtor, para resolver esse problema, vamos adicionar um parent::__construct(), veja abaixo:

    /** 
     * Constructor 
     */ 
    public function __construct() 
    { 
         parent::__construct();
	
        $this->post = new ArrayCollection(); 
    }

Agora vamos gerar os métodos necessários da entidade Author, entre no console e digite:

 $ php app/console generate:doctrine:entities TablelessModelBundle:Author

Temos que gerar também para a entidade Post:

 $ php app/console generate:doctrine:entities TablelessModelBundle:Post

Entre novamente na entidade Author e acrescente o método abaixo no final da entidade:

    /** 
     * @return string 
     */ 
    public function __toString() 
    { 
        return $this->getName(); 
    }

Veja como ficou a entidade Author depois de configurarmos:

 <?php 

namespace Tableless\ModelBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 
use Doctrine\Common\Collections\ArrayCollection; 

/** 
 * Author 
 * 
 * @ORM\Table(name="author") 
 * @ORM\Entity 
 */ 
class Author extends Timestampable 
{ 
   /** 
     * @var integer 
     * 
     * @ORM\Column(name="id", type="integer") 
     * @ORM\Id 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
    private $id; 

    /** 
     * @var string 
     * 
     * @ORM\Column(name="name", type="string", length=100) 
     * @Assert\NotBlank 
     */ 
    private $name; 

    /** 
     * @var ArrayCollection 
     * 
     * @ORM\OneToMany(targetEntity="Post", mappedBy="author", cascade={"remove"}) 
     */ 
    private $post; 

    /** 
     * Constructor 
     */ 
    public function __construct() 
    { 
         parent::__construct();

        $this->post = new ArrayCollection(); 
    } 

        /** 
     * Get id 
     * 
     * @return integer 
     */ 
    public function getId() 
    { 
        return $this->id; 
    } 

    /** 
     * Set name 
     * 
     * @param string $name 
     * @return Author 
     */ 
    public function setName($name) 
    { 
        $this->name = $name; 

        return $this; 
    } 

    /** 
     * Get name 
     * 
     * @return string

    */ 
    public function getName() 
    { 
        return $this->name; 
    } 

    /** 
     * Add post 
     * 
     * @param \Tableless\ModelBundle\Entity\Post $post 
     * @return Author 
     */ 
    public function addPost(\Tableless\ModelBundle\Entity\Post $post) 
    { 
        $this->post[] = $post; 

        return $this; 
    } 

    /** 
     * Remove post 
     * 
     * @param \Tableless\ModelBundle\Entity\Post $post 
     */ 
    public function removePost(\Tableless\ModelBundle\Entity\Post $post) 
    { 
        $this->post->removeElement($post); 
    } 

    /** 
     * Get post 
     * 
     * @return \Doctrine\Common\Collections\Collection 
     */ 
    public function getPost() 
    { 
        return $this->post; 
    } 

    /** 
     * @return string 
     */ 
    public function __toString() 
    { 
        return $this->getName(); 
    } 
} 

Veja a entidade Post, após a configuração:

 <?php 

namespace Tableless\ModelBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 

/** 
 * Post 
 * 
 * @ORM\Table(name="post") 
 * @ORM\Entity 
 */ 
class Post extends Timestampable 
{ 
    /** 
     * @var integer 
     * 
     * @ORM\Column(name="id", type="integer") 
     * @ORM\Id 
     * @ORM\GeneratedValue(strategy="AUTO") 
     */ 
    private $id; 

    /** 
     * @var string 
     * 
     * @ORM\Column(name="title", type="string", length=255) 
     * @Assert\NotBlank 
     */ 
    private $title; 

    /** 
     * @var string 
     * 
     * @ORM\Column(name="content", type="text") 
     * @Assert\NotBlank 
     */ 
    private $content; 

    /** 
     * @var Author 
     * 
     * @ORM\ManyToOne(targetEntity="Author", inversedBy="posts") 
     * @ORM\JoinColumn(name="author_id", referencedColumnName="id", nullable=false) 
     * @Assert\NotBlank
    */ 
    private $author; 


    /** 
     * Get id 
     * 
     * @return integer 
     */ 
    public function getId() 
    { 
        return $this->id; 
    } 

    /** 
     * Set title 
     * 
     * @param string $title 
     * @return Post 
     */ 
    public function setTitle($title) 
    { 
        $this->title = $title; 

        return $this; 
    } 

    /** 
     * Get title 
     * 
     * @return string 
     */ 
    public function getTitle() 
    { 
        return $this->title; 
    } 

    /** 
     * Set content 
     * 
     * @param string $content 
     * @return Post 
     */ 
    public function setContent($content) 
    { 
        $this->content = $content; 

        return $this; 
    } 

    /** 
     * Get content
     * 
     * @return string 
     */ 
    public function getContent() 
    { 
        return $this->content; 
    } 

    /** 
     * Set author 
     * 
     * @param \Tableless\ModelBundle\Entity\Author $author 
     * @return Post 
     */ 
    public function setAuthor(\Tableless\ModelBundle\Entity\Author $author) 
    { 
        $this->author = $author; 

        return $this; 
    } 

    /** 
     * Get author 
     * 
     * @return \Tableless\ModelBundle\Entity\Author 
     */ 
    public function getAuthor() 
    { 
        return $this->author; 
    } 
} 

Agora vamos atualizar o banco de dados para gerar o relacionamento, para isso apague todo o conteúdo das tabelas do banco de dados, caso não o faça, ocorrerá erro,

Após apagar o conteúdo do banco, rode o comando no console:

 $ php app/console doctrine:schema:update --force

Corrigindo os formulários

Entre na classe PostType, caminho: src/Tableless/ModelBundle/Form/PostType, e acrescente a linha abaixo, no método buildForm:

 ->add('author')

Também vamos apagar as linhas:

 ->add('createdAt') 
 ->add('updatedAt') 

Pois não precisamos inserir as datas, em que o post foi criado, ou alterado, isso acontecerá automaticamente!

Depois das modificações, o método formBuilder ficará como abaixo:

    /** 
     * @param FormBuilderInterface $builder 
     * @param array $options 
     */ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
        $builder 
            ->add('title') 
            ->add('content') 
            ->add('author') 
        ; 
    }

Tudo configurado para que possamos criar nossos posts.
Para verificarmos se está tudo correto, precisamos criar primeiramente um autor, depois criamos um post, onde teremos que selecionar um autor, para o mesmo.

Veja abaixo:

autor

Lembrando que a url de autor é:

http://127.0.0.1:8000/author/

e a url de post é:

http://127.0.0.1:8000/post/

Conclusão

Vamos terminar este tutorial, pois seu conteúdo está muito extenso, no próximo, vamos fazer as configurações necessárias em nossa simples aplicação, e vamos criar um index, para mostrar nossos posts, que configuraremos com o Bootstrap, e com o template engine twig. O projeto encontra-se no GitHub!

Publicado no dia