CRUD básico con Symfony. Esta presentación es una continuación de lo contado en la II Symfony Zaragoza. Explica un ejemplo sencillo de un CRUD para mostrar como realizar modelos, controladores, vistas, formularios, etc.
3. Crear el proyecto Symfony 2
composer create-project symfony/framework-standard-edition <directorio> 2.4.*
Ejemplo en Windows
C:> composer create-project symfony/framework-standard-edition
"D:ProyectosCupon" 2.4.*
Ejemplo en Linux y Mac OS X
$ composer create-project symfony/framework-standard-edition "/prueba" 2.4.*
4. *Importante - Permisos
Un problema común al instalar Symfony2 es que los directorios
app/cache y app/logs deben tener permiso de escritura, tanto para el
servidor web cómo para el usuario de la consola de comandos.
Podeis ver como hacerlo en el apartado ‘3.1.2. Instalando y
configurando’ de
http://librosweb.es/symfony_2_4/capitulo_3/instalando_una_distribucio
n_de_symfony2.html
5. *Importante - Entornos
Si revisas el directorio web/, encontrarás dos archivos PHP: app.php y
app_dev.php. Estos archivos son controladores frontales: todas las
peticiones a la aplicación se hacen a través de ellos. Pero, ¿por qué
tenemos dos controladores frontales si hemos definido sólo una
aplicación?
Muy sencillo, ambos archivos apuntan a la misma aplicación pero para
distintos entornos.
Y un entorno symfony es un conjunto único de ajustes de
configuración. El framework Symfony incluye tres de ellos: dev, test, y
prod.
Producción: www.symfony-demo.local/app.php
Desarrollo: www.symfony-demo.local/app_dev.php
6. Comprobar la instalación
Antes de empezar a programar tu aplicación debes asegurarte de que tu
ordenador cumple con los requisitos para que Symfony2 funcione bien.
$ php app/check.php
El script check.php muestra por consola una lista de requisitos obligatorios
(Mandatory requirements) y otra lista de requisitos deseables (Optional
checks) para ejecutar Symfony2. No sigas adelante si incumples alguno de los
requisitos obligatorio
7. Estructura de directorios
app
Contiene los archivos de configuración, la caché, los logs y los recursos
globales.
app/config/
Guarda todos los archivos de configuración de la aplicación.
app/cache/
Contiene todos los archivos generados por las numerosas cachés de
Symfony2 (clases, enrutamiento, plantillas, entidades, validación, etc.). Junto
con el directorio app/logs/ es el único en el que Symfony2 debe tener
permisos de escritura.
8. Estructura de directorios
app/logs/
Contiene los archivos de log generados por la aplicación en cualquier entorno
de ejecución (desarrollo, producción, tests, etc.). Junto con el directorio
app/cache/ es el único en el que Symfony2 debe tener permisos de escritura.
app/Resources/
Almacena los recursos que se utilizan globalmente en el proyecto (como por
ejemplo el layout de las plantillas) o recursos muy especiales que no encajan
en ningún otro sitio (como por ejemplo una librería Java para comprimir
archivos CSS y JavaScript)
9. Estructura de directorios
src/
Guarda todo el código fuente propio del proyecto. Aquí es donde creas los
bundles de tu aplicación.
vendor/
Contiene todo el código fuente de Symfony2 y de todas las librerías externas.
web/
El único directorio público del proyecto. Contiene los archivos web (CSS,
JavaScript e imágenes) y los controladores frontales de la aplicación (app.php
y app_dev.php)
11. YAML
YAML es un lenguaje muy sencillo que permite describir los datos como en
XML, pero con una sintaxis mucho más sencilla. YAML es un formato
especialmente útil para describir datos que pueden ser transformados en
arrays simples y asociativos.
$casa = array(
'familia' => array('apellido' => 'García', 'padres' => array('Antonio',
'María'), 'hijos' => array('Jose', 'Manuel', 'Carmen')),
'direccion' => array( 'numero' => 34, 'calle' => 'Gran Vía',
'ciudad' => 'Cualquiera', 'codigopostal' => '12345' )
);
13. Doctrine
Doctrine es un mapeador de objetos-relacional (ORM) escrito en PHP que
proporciona una capa de persistencia para objetos PHP. Es una capa de
abstracción que se sitúa justo encima de un SGBD.
14. TWIG
Twig es un motor y lenguaje de plantillas para PHP muy rápido y eficiente.
Symfony2 recomienda utilizar Twig para crear todas las plantillas de la
aplicación. No obstante, si lo prefieres puedes seguir escribiendo las plantillas
con código PHP normal y corriente.
La sintaxis de Twig se ha diseñado para que las plantillas sean concisas y muy
fáciles de leer y de escribir.
Esto en Twig:
{% if usuario is defined %}
Hola {{ usuario.nombre }} hoy es {{ 'now' | date('d/m/Y') }}
{% endif %}
16. Aplicando la filosofía de Symfony
Antes de empezar a programar la aplicación, es necesario adaptar todas las
funcionalidades y wireframes a la filosofía de trabajo de Symfony2. Planificar
bien el proyecto según la forma de pensar de Symfony2 te asegura que
podrás desarrollarlo lo más eficientemente posible.
El orden recomendado para aplicar la filosofía de
Symfony consiste en definir primero las entidades,
después los bundles y por último el enrutamiento.
17. Nuestro caso
Entidades
Solo una, Prueba (name, surname, email, phone)
Bundles
Solo uno, Prueba
Enrutamiento
/
/new/
/view/{id}
/edit/{id}
/delete/{id}
18. Creando el bundle
Dentro de un bundle puedes utilizar cualquier estructura de directorios, pero
Symfony2 espera que utilices una estructura muy específica para simplificar
su trabajo.
Para ayudarte, Symfony tiene el siguiente comando:
$ php app/console generate:bundle
Este comando te hará una serie de preguntas:
- Bundle namespace: SymfonyZgz/PruebaBundle
- Bundle name: PruebaBundle
- Target directory: <Enter> (para elegir el valor por defecto)
- Configuration format: yml
19. Creando el bundle
- Do you want to generate the whole directory structure?Respuesta
recomendada: no
- Confirm automatic update of your Kernel?, contesta yes para que el bundle
se active en la aplicación después de generarlo
- Confirm automatic update of the Routing?, contesta también yes para que
el archivo de enrutamiento del bundle se cargue automáticamente desde el
archivo de enrutamiento general de la aplicación.
20. Creando la entidad
Para ayudarte, Symfony tiene el siguiente comando:
$ php app/console doctrine:generate:entity
The Entity shortcut name: PruebaBundle:Prueba
Configuration format (yml, xml, php, or annotation) [annotation]: <Enter>
// Vamos creando los campos
New field name (press <return> to stop adding fields): nombre
Field type [string]: <Enter>
Field length [255]: <Enter>
21. La base de datos
# app/config/parameters.yml
parameters:
database_driver: pdo_mysql
database_host: 127.0.0.1
database_port: null
database_name: prueba
database_user: root
database_password: mipass
// Creando la base de datos
php app/console doctrine:database:create
// Creando la estructura
php app/console doctrine:schema:create
// Actualizando la estructura
php app/console doctrine:schema:update --force
23. Nuestro controlador
# src/SymfonyZgz/PruebaBundle/Controller/PruebaController.php
use SymfonyZgzPruebaBundleEntityPrueba;
use SymfonyZgzPruebaBundleFormPruebaType;
class PruebaController extends Controller
{
public function indexAction(){...}
public function newAction(){...}
public function viewAction(){...}
public function editAction(){...}
public function deleteAction(){...}
}
24. indexAction
public function indexAction(){
$results = $this->getDoctrine()->getRepository('PruebaBundle:Prueba’)->findAll();
return $this->render('PruebaBundle:Prueba:list.html.twig', array('results' => $results));
}
29. Nuestro formulario
namespace SymfonyZgzPruebaBundleFormType;
use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;
class PruebaType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){...}
public function setDefaultOptions(OptionsResolverInterface $resolver){..}
public function getName(){..}
}
31. Nuestro formulario-tipos de campo
Campos de texto
● text
● textarea
● email
● integer
● money
● number
● password
● percent
● search
● url
Campos de selección
● choice
● entity
● country
● language
● locale
● timezone
Campos de fecha y hora
● date
● datetime
● time
● birthday
● Otros campos
● checkbox
● file
● radio
Campos para grupos
● collection
● repeated
● Campos ocultos
● hidden
● csrf
● Campos base
● field
● form
32. Nuestro formulario - dataClass
Cada formulario debe conocer el nombre de la clase asociada al objeto manejado por el
formulario. Por lo general, esta información se deduce automáticamente en función del objeto
que se pasa como segundo argumento del método ‘createForm’, aunque es recomendable
indicarlo:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'SymfonyZgzPruebaBundleEntityPrueba'
));
}
33. Nuestro formulario - getName
Simplemente devuelve un identificador único para este tipo de formulario.
public function getName()
{
return ‘prueba’;
}
34. Nuestro formulario - Validaciones
El método $form->isValid() en realidad es un atajo que pregunta al objeto $prueba si tiene datos
válidos o no.
Validación en archivo yml
# SymfonyZgz/PruebaBundle/Resources/config/validation.yml
SymfonyZgzPruebaBundleEntityPrueba:
properties:
name:
- NotBlank: ~
surname:
- NotBlank: ~
35. Nuestro formulario - Validaciones
Validación con anotaciones:
use SymfonyComponentValidatorConstraints as Assert;
class Prueba
{
/**
* @AssertNotBlank()
*/
public $name;
/**
* @AssertNotBlank()
*/
protected $surname;
}
36. Las vistas
Se crean en la carpeta:
src/SymfonyZgz/PruebaBundle/Resources/views/<nombre_controller>
En nuesto caso:
src/SymfonyZgz/PruebaBundle/Resources/views/Prueba
index.html.twig
edit.html.twig
view.html.twig
Si en lugar de utilizar Twig, quisiésemos utitilizar PHP, bastaría con
cambiar la extensión de la vista:
index.html.php
edit.html.php
…
40. Las vistas - Formularios
form_start(form), muestra la etiqueta <form> de apertura del formulario.
form_errors(form), muestra los errores globales del formulario (los errores específicos se muestran al lado
de cada campo de formulario erróneo).
form_row(form.name), muestra el título, los errores (si los hay) y las etiquetas HTML necesarias para
mostrar el campo indicado (por ejemplo, dueDate). Por defecto todos estos elementos se agrupan dentro
de una etiqueta <div>.
form_end(form), muesta la etiqueta </form> de cierre del formulario y todos los campos de formulario que
no se han mostrado todavía. Por lo general es buena idea utilizar este helper en la parte inferior de cada
formulario (por si te has olvidado de mostrar algún campo o para no tener que mostrar uno a uno los
campos ocultos del formulario). Este helper también es muy útil para mostrar automáticamente el campo
oculto relacionado con la protección CSRF.
Si quisiésemos tener más control a la hora de pintar los campos, podríamos utilizar
en lugar de form_row:
{{ form_label(form.name) }}
{{ form_errors(form.mane) }}
{{ form_widget(form.name, { 'attr': {'class': 'mi_class'} }) }}
41. Las vistas - Un poco más
Uso de funciones:
{{ prueba.descripcion | striptags }}
{{ prueba.name | upper }}
Todos los filtros de Symfony2 se pueden encadenar para aplicarlos en cascada
{{ prueba.descripcion | striptags | upper }}
Fechas:
{{ prueba.fecha | date('d/m/Y') }}
Asignar un valor a las variables que no existen o están vacías.
{{ descripcion | default('Presentación de Symfony Zgz') }}
Twig por defecto escapa los caracteres hml. Para no aplicar el mecanismo de
escape en una determinada variable
{{ producto.descripcion | raw }}
42. Las vistas - Un poco más
Declarar variables:
{% set variable = valor %}
Arrays:
{% set miArray = [4, 8, 18] %}
Estructuras de control
{% for articulo in articulos %}
{# ... #}
{% endfor %}
{% if articulos is divisibleby(5) %}
{# ... #}
{% endif %}
44. Las vistas - Herencia
{% extends 'base.html.twig' %}
{% block titulo %}Aquí pondríamos el título{% endblock %}
{% block contenido %}
Y aquí el contenido
{% endblock %}
Reutilizando el contenido de los bloques:
{% block contenido %}
<h1>{{ block('titulo') }}</h1>
Y aquí el contenido
{% endblock %}
48. Si esto se repite en
las mayoría de proyectos
¿no hay un comando?
49. Generar CRUD por consola
Todo el tiempo dedicado a realizar este CRUD podríamos haber ejecutado
este comando y habernos ido de cañas :)
php app/console generate:doctrine:crud --entity=PruebaBundle:Prueba
--format=yml --with-write