CRUD Producto Symfony

Entidad Producto:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ProductoRepository")
 */
class Producto
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $nombre;

    /**
     * @ORM\Column(type="integer")
     */
    private $precio;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $stock;

    
    public function getId(): ?int
    {
        return $this->id;
    }

    public function getNombre(): ?string
    {
        return $this->nombre;
    }

    public function setNombre(string $nombre): self
    {
        $this->nombre = $nombre;

        return $this;
    }

    public function getPrecio(): ?int
    {
        return $this->precio;
    }

    public function setPrecio(int $precio): self
    {
        $this->precio = $precio;

        return $this;
    }

    public function getStock(): ?int
    {
        return $this->stock;
    }

    public function setStock(?int $stock): self
    {
        $this->stock = $stock;

        return $this;
    }
}

Controlador:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use App\Entity\Producto;

class ProductoController extends AbstractController {

    /**
     * @Route("/producto", name="producto")
     */
    public function index() {
        /*
          $entityManager = $this->getDoctrine()->getManager();

          for ($i = 1; $i <= 10; $i++) {
          $producto = new Producto();
          $producto->setNombre('Producto '.$i);
          $producto->setPrecio($i);

          // Guardamos el producto
          $entityManager->persist($producto);
          }
          // Actualizamos los datos en la BD
          $entityManager->flush();
         */
        /*
          //Producto es un objeto del tipo Producto Entity
          //Con sus propiedades y métodos (concretamente los get y set de las columnas)
          $producto = $this->getDoctrine()
          ->getRepository(Producto::class)
          ->find($id);
          $producto->setNombre('Nuevo nombre cool para mi producto ¡Mola!');
          $entityManager = $this->getDoctrine()->getManager();
          $entityManager->remove($producto);
          $entityManager->flush();

          $producto = $this->getDoctrine()
          ->getRepository(Producto::class)
          ->findOneBy(['nombre'=>'Producto 5']);


         * 
         */
        $productos = $this->getDoctrine()
                ->getRepository(Producto::class)
                ->findAll();
        $salida = [];
        foreach ($productos as $producto) {
            $salida[] = [$producto->getId(),
                $producto->getNombre(),
                $producto->getPrecio()];
        }
        return $this->render('producto/index.html.twig', [
                    'productos' => $salida]);
    }

    /**
     * @Route("/producto/nuevo", name="nuevo")
     */
    public function nuevo() {
        $request = Request::createFromGlobals();
        $nombre = $request->request->get('nombre');
        $precio = $request->request->get('precio');
        $stock = $request->request->get('stock');
        $id = '';
        if (!empty($nombre) && !empty($precio)) {
            //Añadir el producto
            $producto = new Producto();
            $producto->setNombre($nombre);
            $producto->setPrecio($precio);
            if (empty($stock)) {
                $stock = 0;
            }
            $producto->setStock($stock);
            $entityManager = $this->getDoctrine()->getManager();
            // Guardamos el producto
            $entityManager->persist($producto);

            // Actualizamos los datos en la BD
            $entityManager->flush();
            $id = $producto->getId();
        }
        return $this->render('producto/nuevo.html.twig', ['id' => $id]);
    }

    /**
     * @Route("/producto/eliminar/{id}", name="eliminar")
     */
    public function eliminar(Producto $producto) {

        $nombre = $producto->getNombre();

        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->remove($producto);
        $entityManager->flush();

        return $this->render('producto/eliminar.html.twig', ['nombre' => $nombre]);
    }

    /**
     * @Route("/producto/editar/{id}", name="editar")
     */
    public function editar(Producto $producto) {

        $request = Request::createFromGlobals();
        $nombre = $request->request->get('nombre');
        $precio = $request->request->get('precio');
        $stock = $request->request->get('stock');
        if (!empty($nombre) && !empty($precio)) {
            $producto->setNombre($nombre);
            $producto->setPrecio($precio);
            if (empty($stock)){$stock=0;}
            $producto->setStock($stock);
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->flush();
        }
        return $this->render('producto/editar.html.twig', [
                    'nombre' => $producto->getNombre(),
                    'precio' => $producto->getPrecio(),
                    'stock' => $producto->getStock(),
        ]);
    }

}

Plantillas:

index:

{% extends 'base.html.twig' %}

{% block title %}{% endblock %}

{% block body %}
    <div class="container">
        <h1>Productos</h1>
        <a href="/producto/nuevo" class="btn btn-success">Nuevo producto</a>
        <table class="table">
            <tr><td>Id</td><td>Nombre</td><td>Precio</td><td>Acciones</td></tr>
            {% for producto in productos %}
                <tr><td>{{producto[0]}}</td><td>{{producto[1]}}</td><td>{{producto[2]}}</td>
                    <td><a href="/producto/editar/{{producto[0]}}" class="btn btn-info">Editar</a> 
                        <a href="/producto/eliminar/{{producto[0]}}" class="btn btn-danger">Eliminar</a></td></tr> 
                {% endfor %}
        </table>
    </div>
{% endblock %}

nuevo

{% extends 'base.html.twig' %}

{% block title %}{% endblock %}

{% block body %}
    <div class="container">
        <h1>Nuevo Producto</h1>
        {% if id %}
            <div class="alert alert-success alert-dismissible">
                <a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
                <strong>Correcto</strong> Se ha insertado con éxito el producto con id {{id}}.
            </div>
        {% endif %}

        <form method="post">
            <div class="form-group">
                Nombre: <input  class="form-control" type="text" name="nombre"></div>
            <div class="form-group">
                Precio: <input  class="form-control" type="text" name="precio"></div>
            <div class="form-group">
                Stock: <input  class="form-control" type="text" name="stock"></div>
            <input type="submit" class="btn btn-info">
        </form>
    </div>
{% endblock %}

editar:

{% extends 'base.html.twig' %}

{% block title %}{% endblock %}

{% block body %}
    <div class="container">
        <h1>Editar Producto</h1>
      

        <form method="post">
            <div class="form-group">
                Nombre: <input  class="form-control" type="text" value="{{nombre}}" name="nombre"></div>
            <div class="form-group">
                Precio: <input  class="form-control" type="text" value="{{precio}}" name="precio"></div>
            <div class="form-group">
                Stock: <input  class="form-control" type="text" value="{{stock}}" name="stock"></div>
            <input type="submit" class="btn btn-info">
        </form>
            <a href="/producto">Volver al listado</a>
    </div>
{% endblock %}

eliminar:

{% extends 'base.html.twig' %}

{% block title %}{% endblock %}

{% block body %}
    <div class="container">
        <h1>Eliminar Producto</h1>
        <p>Has eliminado el producto <b>{{nombre}}</b></p>
        <a href="/producto">Volver al listado</a>
    </div>
{% endblock %}

Entidades y bases de datos

En el archivo de configuración tenemos que poner la ruta a nuestra base de datos:

.env

DATABASE_URL=mysql://root:@127.0.0.1:3306/symfony

Para crear una entidad usamos lo siguiente:

php bin/console make:entity

Nos preguntará el nombre de la entidad y los campos ¡Ojo! que el id ya lo crea él.

Cuando ya hayamos creado todas las entidades que necesitamos tenemos que hacer una migración:

php bin/console make:migration

Esto nos crea un archivo Migration dentro de src/MIgrations con el sql que se tendría que ejecutar. Todavía no se ha mandado a la base de datos, se podría revisar. Para ejecutarlo tenemos que hacer lo siguiente:

php bin/console doctrine:migrations:migrate

Ojo, que esto nos afecta a la base de datos y nos podemos cargar cosas.

Aquí el mapeo de tipos: https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#doctrine-mapping-types

Para crear una entidad en la base de datos. Primero la usamos:

use App\Entity\Producto;

Y después hacemos lo siguiente:

$entityManager = $this->getDoctrine()->getManager();

$product = new Producto();
$product->setNombre(‘Keyboard’);
$product->setPrecio(1999);

// Guardamos el producto
$entityManager->persist($product);

// Actualizamos los datos en la BD
$entityManager->flush();

Para buscar un producto por id:

$product = $this->getDoctrine()
->getRepository(Producto::class)
->find($id);

Buscar un elemento:

$product = $this->getDoctrine()
->getRepository(Producto::class)
->findOneBy([‘nombre’ => ‘Keyboard’]);

Otras opciones:
$product = $this->getDoctrine()
->getRepository(Producto::class)
->findBy(
[‘name’ => ‘Keyboard’],
[‘price’ => ‘ASC’]
);

// Todos
$product = $this->getDoctrine()
->getRepository(Producto::class)->findAll();

https://symfony.com/doc/current/doctrine.html

Como hacer ingeniería inversa, obtener las entidades de una base de datos ya existente.

https://symfony.com/doc/current/doctrine/reverse_engineering.html

Plantillas con twig

Symfony usa como plantillas la librería externa twig.

Dispone de una serie de elementos que nos permiten hacer algo de programación pero toda orientada al diseño. Así, tenemos bucles o estructuras de control, filtros que podemos aplicar a las variables, pero no disponemos de las funciones de php.

Para imprimir una variable usamos {{ … }}

Para una etiqueta de programación usamos {% … %}

Para un comentario usamos {# … #}

Algunos ejemplos:

{% if users %}
    <ul>
        {% for user in users %}
            <li>{{ user.username|e }}</li>
        {% endfor %}
    </ul>
{% endif %}
{% if temperature > 18 and temperature < 27 %}
    <p>It's a nice day for a walk in the park.</p>
{% endif %}
{% for i in 0..10 %}
    * {{ i }}
{% endfor %}

Rutas en symfony

Hay muchas maneras de indicar las rutas en symfony, pero la más cómoda es usar annotations como hemos hecho en el ejemplo anterior:


 /**
* @Route("/hola/saludo")
*/

También podemos recuperar parámetros:


class HolaController
{
/**
* @Route("/hola/saludo/{nombre}")
*/
public function saludo($nombre)
{
$texto="Hola $nombre que tal";

return new Response(
'&lt;html&gt;&lt;body&gt;&lt;h1&gt; '.$texto.'&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;'
);
}
}

En nombre podemos usar un valor por defecto:

<strong>public function saludo($nombre='')[/php</strong>]

Y podemos usar expresiones regulares para indicar que queremos un tipo concreto de parámetro:

</pre>
class HolaController
{
/**
* @Route("/hola/saludo/{numero<\d+>}")
*/
public function saludos($numero=1)
{
$texto="<h1>Hola que tal</h1>";
$res="";
for($i=0;$i<$numero;$i++){
$res.=$texto;
}
return new Response(
'<html><body>'.$res.'</body></html>'
);
}
/**
* @Route("/hola/saludo/{nombre}")
*/
public function saludo($nombre='')
{
$texto="Hola $nombre que tal";

return new Response(
'<html><body><h1> '.$texto.'</h1></body></html>'
);
}

}
<pre>

Primera página en symfony

Como vimos en el ejemplo de MVC desde cero, necesitamos una ruta y un controlador. Lo haremos todo junto.

Dentro de src\controller creamos una página llamada HolaController:


<?php
// src/Controller/HolaController.php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class HolaController
{
/**
* @Route("/hola/saludo")
*/
public function saludo()
{
$texto="Hola que tal";

return new Response(
'<html><body><h1> '.$texto.'</h1></body></html>'
);
}
}

 

Si ahora vamos a la siguiente dirección, deberíamos ver el saludo:

http://localhost:8000/hola/saludo

Otra manera de crear un controlador es desde la consola:

 php bin/console make:controller adios

Esto nos crea lo siguiente:


<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class AdiosController extends AbstractController
{
/**
* @Route("/adios", name="adios")
*/
public function index()
{
return $this->render('adios/index.html.twig', [
'controller_name' => 'AdiosController',
]);
}
}

Instalar Symfony

Primero, instalar composer:

https://getcomposer.org/download/

Comprobar que tenemos php 7.1 o superior. Si no es así, debemos instalarla. La podemos instalar en otra carpeta.

Nos colocamos en htdocs, abrimos la consola y escribimos lo siguiente:

composer create-project symfony/website-skeleton mi_symfony

Para ejecutar nuestro symfony debemos hacer lo siguiente:

 cd mi_symfony
 php bin/console server:run

Y lo podremos ver en localhost:8000