Blog de Gonzalo

CREAR ENTIDADES EN SYMFONY 3

Despues de aprender como crear bundles en Symfony 3 ahora toca aprender a crear entidades en symfony 3. Las entidades son el modelo dentro de la arquitectura MVC, es decir, nos van a permitir guardar, actualizar y recuperar los datos de la base de datos.
En Symfony 3 las entidades usan notaciones para indicarle a la base de datos, el nombre de la tabla, las constraints, los índices, los tipos de datos etc...
Las entidades hay que guardarlas en el directorio entity del bundle que estamos desarrollando. Después de crear dicho directorio podemos empezar con un ejemplo sencillo, con dos entidades:


// src/BlogBundle/Entity/Blog.php
namespace BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(
* name="blog",
* uniqueConstraints={
* @ORM\UniqueConstraint(name="slug_idx", columns={"slug"})
* },
* indexes={
* @ORM\Index(name="category_idx", columns={"category_id"})
* })
*/
class Blog
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="blogs")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
/**
* @ORM\Column(type="string", length=150)
*/
private $slug;
/**
* @ORM\Column(type="text")
*/
private $content;
/** @ORM\Column(type="datetime") */
private $created;

Vamos a ver esta entidad:
  • Antes de la declaración de la clase hay una notación donde se espcifica el nombre de la tabla donde se guardan los datos de la entidad, los contraints y los índices de dicha tabla.
  • Antes de cada atributo de la clase vemos varias anotaciones donde se especifica , el tipo de campo, si es auto-increment, si es nulo o no y las relaciones que va a tener ese campo com otro campo de otra entidad.
Ahora voy a crear otra entidad donde se podrán ver las relaciones entre las dos entidades:

// src/BlogBundle/Entity/Category.php
namespace BlogBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="category")
*/
class Category
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/** @ORM\Column(type="datetime") */
private $created;
/** @ORM\Column(type="datetime") */
private $modified;
/** @ORM\Column(type="datetime", nullable=true) */
private $deleted = null;
/**
* @ORM\OneToMany(targetEntity="Blog", mappedBy="category")
*/
private $blogs;
public function __construct()
{
$this->blogs = new ArrayCollection();
}
}

Observando el código de las dos entidades se puede ver que en el atributo category de la entidad Blog (ManyToOne) y en el atributo blogs de la entidad Category hay otra relación (OneToMany). Ésto quiere decir que muchos posts estarán asociados a una categoría y que una categoría estará asociada a varios artículos.Importante: Observad que en la clase Cateogry se usa un array collection que es donde se guardarán los blogs asociados y si no se pone cuidado al recuperar la información de una categoría puede haber problemas de eficencia al cargar la infomación, habrá que indicar una "profundidad" a la hora de recuperar los datos.
En el ejemplo de estas dos entidades relacionadas se creará un campo en la tabla blog con el valor category_id, está indicado en la notación del atributo category, donde se guardará una categoría. Aparte se creará la tabla categorías donde se guardará el la categoría.
Pero y si se quiere asociar un post a varias categorías, entonces habrá que cambiar el tipo de relación en los campos que hemos hablado antes. Ahora se creará una tabla nueva para establacer varias relaciones de un post.
Veamos un ejemplo con las mismas entidades pero realizando un par de cambios para permitir relacionar varios posts a una categoría:

// src/BlogBundle/Entity/Blog.php
namespace BlogBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(
* name="blog",
* uniqueConstraints={
* @ORM\UniqueConstraint(name="slug_idx", columns={"slug"})
* },
* indexes={
* @ORM\Index(name="category_idx", columns={"category_id"})
* })
*/
class Blog
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToMany(targetEntity="Category", inversedBy="blogs", cascade={"persist", "remove"})
* @ORM\JoinTable(name="posts_categories")
*/
private $category;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
/**
* @ORM\Column(type="string", length=150)
*/
private $slug;
/**
* @ORM\Column(type="text")
*/
private $content;
/** @ORM\Column(type="datetime") */
private $created;
public function __construct() {
$this->categories = new ArrayCollection();
}



// src/BlogBundle/Entity/Category.php
namespace BlogBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="category")
*/
class Category
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/** @ORM\Column(type="datetime") */
private $created;
/** @ORM\Column(type="datetime") */
private $modified;
/** @ORM\Column(type="datetime", nullable=true) */
private $deleted = null;
/**
* @ORM\ManyToMany(targetEntity="Post", mappedBy="categories", cascade={"persist", "remove"})
*/
private $blogs;
public function __construct()
{
$this->blogs = new ArrayCollection();
}
}

Ahora han cambiado las entidades. Si observais la entidad Blog podréis ver que en el atributo category tiene una notación donde se establece la relación de muchos a muchos (ManyToMany) y después vereis que hay un valor que es JoinTable donde se le indica entre paréntesis el nombre de la tabla (posts_categories) donde irán los ids de los posts y de las categrías para relacionarlos. El nombre de las tablas y de los campos los podéis poner como queráis siguiendo los convenios de nombres, etc... En la entidad Cateogry también se ha establecido la relación de muchos a muchos (ManyToMany). Y en las dos entidades se usa un array para guardar las categorías, en los posts y los post, en las categorías, relacionados.
Después de definir las categorías hay que decirle a Symfony 3 que construya los setters y getters y que haga las tablas en la base de datos. En realidad esto lo realiza doctrine que es un orm que está instalado en Symfony.
Para crear getters y setters hay que lanzar el comando: php bin/console doctrine:generate:entities TuBundleBundle/Entity/NombreDeLaEntidad y para generar las tablas en base de datos: php bin/console doctrine:schema:update --force.
Si no se ha producido ningún error ya podréis usar vuestras entidades en los controladores. Para usar una entidad creada hay que referenciar el la entidad con use \bundleName\Entity\EntityName.Voy a poner un ejemplo sencillo pero si queréis saber más podéis ver más ejemplos por internet:

    /**
* @Route("/blog/create", name="blog_create")
*/
public function createAction()
{
$blog = new Blog();
//Se busca la categoria
//Si hubiese "N" categorías habría que hacer un bucle y añadirlas una por una.
$categoria= $this->getDoctrine()->getRepository('BlogBundle:Categort')->findOneById(2);
//Se asocia la categorñia al post
$blog->addCategoria($categoria);
$blog->setTitle('My first blog post');
$blog->setSlug('my-first-blog-post');
$blog->setContent('lorem ipsum...');
$blog->setCreated(date_create(date('Y-m-d H:i:s')));
$blog->setModified(date_create(date('Y-m-d H:i:s')));
$em = $this->getDoctrine()->getManager();
// Indicamos que queremos guardar este registro.
$em->persist($blog);
// Ejecuta las querys de las operaciones indicadas.
$em->flush();
return new Response('Saved new $blog entry with id '.$blog->getId());
}
/**
* @Route("/blog/read/{slug}", name="blog_read", requirements={"slug": "\S+"})
*/
public function readAction($slug)
{
$blog = $this->getDoctrine()
->getRepository('BlogBundle:Blog')
->findOneBySlug($slug);
if (!$blog) {
throw $this->createNotFoundException('No blog entry found for '.$slug);
} else {
return new Response($blog->getTitle().' '.$blog->getContent());
}
}
public function updateAction($blogId) {
$em = $this->getDoctrine()->getManager();
$blog = $em->getRepository('BlogBundle:Blog')->find($blogId);
if (!$blog) {
throw $this->createNotFoundException('No post found for id '.$blogId);
}
$blog->setTitle('Updated blog entry!');
$em->flush();
return $this->redirectToRoute('blog_list');
}

Espero que estos ejemplos os hayan servido.

Compartir en twitter