SensioLabs
SYMFONY
BUENAS PRÁCTICAS
Javier Eguiluz
Symfony
Barcelona
gracias a
Marc Morera
@mmoreram
gracias a
Elcodi
Symfony components based
e-commerce platform
gracias a
Introducción
13
OCTUBRE
Las buenas prácticas oficiales
Conjunto de técnicas que
puedes utilizar para desarrollar
aplicaciones Symfony como
recomie...
symfony.com/best-practices
LIBROSWEB
FABIEN POTENCIER
RYAN WEAVER
JAVIER EGUILUZ
BUENAS
PRÁCTICAS
PARA APLICACIONES
SYMFON...
¿Por qué?
Las buenas prácticas oficiosas
complican mucho el desarrollo
de aplicaciones y no siguen la
filosofía pragmática...
Definición de “Best Practice”
A well defined procedure
that is known to produce
near-optimum results.
Definición de “Pragmatic”
Concerned with making
decisions and actions that
are useful in practice, not
just theory.
Las buenas prácticas Symfony
Las buenas prácticas Symfony
• Reflejan las ideas de su creador.
Las buenas prácticas Symfony
• Reflejan las ideas de su creador.
• Son opcionales.
Las buenas prácticas Symfony
• Reflejan las ideas de su creador.
• Son opcionales.
• Symfony no cambiará para
obligarte a ...
Usa las buenas prácticas …
Usa las buenas prácticas …
• En proyectos pequeños y medianos.
Usa las buenas prácticas …
• En proyectos pequeños y medianos.
• En proyectos web estándar.
Usa las buenas prácticas …
• En proyectos pequeños y medianos.
• En proyectos web estándar.
• Si eres nuevo/a en Symfony.
No uses las buenas prácticas …
No uses las buenas prácticas …
• En bundles compartidos (públicos o
privados).
No uses las buenas prácticas …
• En bundles compartidos (públicos o
privados).
• En aplicaciones muy complejas o con
arqui...
No uses las buenas prácticas …
• En bundles compartidos (públicos o
privados).
• En aplicaciones muy complejas o con
arqui...
Aplicaciones vs
bundles
Estructura de una aplicación web
proyecto/
!" app/
# !" config/
# $" Resources/
# $" views/
!" src/
!" vendor/
$" web/
!" ...
Estructura de una aplicación web
configuración
proyecto/
!" app/
# !" config/
# $" Resources/
# $" views/
!" src/
!" vendo...
Estructura de una aplicación web
configuración
plantillas
proyecto/
!" app/
# !" config/
# $" Resources/
# $" views/
!" sr...
Estructura de una aplicación web
configuración
plantillas
tu código
proyecto/
!" app/
# !" config/
# $" Resources/
# $" vi...
Estructura de una aplicación web
configuración
plantillas
tu código
dependencias
proyecto/
!" app/
# !" config/
# $" Resou...
Estructura de una aplicación web
configuración
plantillas
tu código
dependencias
assets
proyecto/
!" app/
# !" config/
# $...
¿Cómo crear un sistema de plugins?
¿Cómo crear un sistema de plugins?
• Deben funcionar de manera
autónoma.
¿Cómo crear un sistema de plugins?
• Deben funcionar de manera
autónoma.
• Pueden definir su propia
configuración.
¿Cómo crear un sistema de plugins?
• Deben funcionar de manera
autónoma.
• Pueden definir su propia
configuración.
• Puede...
Estructura de un plugin
plugin/
!" DependencyInjection/
# $" Configuration.php
!" Resources/
# !" config/
# !" public/
# #...
Estructura de un plugin
configuración
plugin/
!" DependencyInjection/
# $" Configuration.php
!" Resources/
# !" config/
# ...
Estructura de un plugin
configuración
assets
plugin/
!" DependencyInjection/
# $" Configuration.php
!" Resources/
# !" con...
Estructura de un plugin
configuración
plantillas
assets
plugin/
!" DependencyInjection/
# $" Configuration.php
!" Resource...
Estructura de un plugin
configuración
plantillas
tu código
assets
plugin/
!" DependencyInjection/
# $" Configuration.php
!...
proyecto/
!" app/
# !" config/
# $" Resources/
# $" views/
!" src/
!" vendor/
$" web/
!" css/
$" js/
Aplicaciones vs plugi...
Los bundles son mini-aplicaciones
Configuración Plantillas
Código!
fuente
Assets
Contenedor
servicios
Kernel
Caché!
y logs
...
proyecto/
!" app/
# !" config/
# $" Resources/
# $" views/
!" src/
#
#
#
#
#
#
!" vendor/
$" web/
!" css/
$" js/
Los bundl...
proyecto/
!" app/
# !" config/
# $" Resources/
# $" views/
!" src/
#
#
#
#
#
#
!" vendor/
$" web/
!" css/
$" js/
Los bundl...
proyecto/
!" app/
# !" config/
# $" Resources/
# $" views/
!" src/
#
#
#
#
#
#
!" vendor/
$" web/
!" css/
$" js/
Los bundl...
Una verdad incómoda
Es muy probable que los
bundles de tus aplicaciones
no sean bundles, sólo
directorios que molestan.
Buenas prácticas en
la práctica
Organizando el
proyecto
Seguridad
Anotaciones
Simplificaciones
Organizando el
proyecto
Seguridad
Anotaciones
Simplificaciones
Crea un solo
bundle llamado
AppBundle
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Controller/
# # $" DefaultController.php
# !" PaymentBundle/
# # $"...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Controller/
# # $" DefaultController.php
# !" PaymentBundle/
# # $"...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Controller/
# # $" DefaultController.php
# !" PaymentBundle/
# # $"...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Controller/
# # $" DefaultController.php
# !" PaymentBundle/
# # $"...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Controller/
# # $" DefaultController.php
# !" PaymentBundle/
# # $"...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Controller/
# # $" DefaultController.php
# !" PaymentBundle/
# # $"...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Controller/
# # $" DefaultController.php
# !" PaymentBundle/
# # $"...
Configuración del enrutamiento
# app/config/routing.yml
app:
resource: @AppBundle/Controller/
type: annotation
No añadas un
vendor en los
bundles que no
compartas
No añadas un vendor a los bundles privados
AcmeNetworksAcmeWebsiteMarketingBundle
!
AcmeNetworksAcmeWebsiteMarketingBundle...
No añadas un vendor a los bundles privados
AcmeNetworksAcmeWebsiteMarketingBundle
!
AcmeNetworksAcmeWebsiteMarketingBundle...
Guarda todas
tus plantillas
en app/
Esta buena práctica es
la que produce un
mayor impacto positivo
AVISO IMPORTANTE
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Resources/
# # $" views/
# # $" Default/
# # !" index.html.twig
# #...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Resources/
# # $" views/
# # $" Default/
# # !" index.html.twig
# #...
aplicacion/
!" app/
!" src/
# !" ContactBundle/
# # $" Resources/
# # $" views/
# # $" Default/
# # !" index.html.twig
# #...
Centralizar las plantillas
Centralizar las plantillas
Cambia la vida
a tus diseñadores/as
Centralizar las plantillas
Cambia la vida
a tus diseñadores/as
Simplifica
mucho tu código
Nueva organización de plantillas
aplicacion/
$" app/Resources/views/
!" contact/
# !" index.html.twig
# $" show.html.twig
...
La nueva notación de las plantillas
$this->render('AcmeDemoBunde:Default:index.html.twig');
$this->render('default/index.h...
La nueva notación de las plantillas
{% extends '::layout.html.twig' %}
{% extends 'layout.html.twig' %}
!
{{ include('Acme...
Los problemas de la notación tradicional
AcmeDemoBundle:Default:subdir/index.html.twig
Los problemas de la notación tradicional
• Requiere explicársela a cada diseñador/programador.
AcmeDemoBundle:Default:subd...
Los problemas de la notación tradicional
• Requiere explicársela a cada diseñador/programador.
• Tiene excepciones (alguna...
Los problemas de la notación tradicional
• Requiere explicársela a cada diseñador/programador.
• Tiene excepciones (alguna...
Guarda todos
tus assets en
web/
Centralizar los assets (CSS, JavaScript)
• Tiene las mismas ventajas que centralizar
las plantillas.
Organizando los assets web
proyecto/
!" app/
!" src/
!" vendor/
$" web/
!" css/
# !" bootstrap.min.css
# $" app.css
$" js/...
Organizando los assets web
proyecto/
!" app/
!" src/
!" vendor/
$" web/
!" css/
# !" bootstrap.min.css
# $" app.css
$" js/...
En resumen
• Si utilizas mal los bundles, estás repitiendo
la estructura de la aplicación sin necesidad
• Si no vas a comp...
Organizando el
proyecto
Seguridad
Anotaciones
Simplificaciones
Escala de sensibilidad
para programadores
Escala de sensibilidad
para programadores
Política
Religión
Fútbol
Estándar de código
Editor de código
Anotaciones
Anotaciones PHP
use AppBundleEntityPost;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
!
class CommentController...
Anotaciones PHP
use AppBundleEntityPost;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
!
class CommentController...
Anotaciones PHP
use AppBundleEntityPost;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
!
class CommentController...
Anotaciones PHP
/** @Route(...) */Anotación
Comentario /* @Route(...) */
Utiliza @Route,
@Security y
@Cache
Enrutamiento tradicional
# app/config/routing.yml
_admin_post:
resource: '@AcmeAdminBundle/Resources/config/routing/post.y...
Enrutamiento con anotaciones
namespace AppBundleControllerAdmin;
!
use SymfonyBundleFrameworkBundleControllerController;
u...
No utilices la
anotación
@Template
La anotación @Template es mágica
/** @Template() */
public function indexAction()
{
// ...
return array('posts' => $posts)...
Utiliza los
ParamConverter
cuando sea
sencillo
Los ParamConvertes en la práctica
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use AppBundleEntityPost;
!
class...
Un controlador Symfony de ejemplo
namespace AppBundleController;
!
use AppBundleEntityPost;
use SymfonyBundleFrameworkBund...
Nuestro consejo
DESACOPLA ACOPLA
la
lógica de negocio
los
controladores
Los atajos de los controladores
$this->forward();
$this->redirect();
$this->redirectToRoute();
$this->getUser();
$this->ge...
Organizando el
proyecto
Seguridad
Anotaciones
Simplificaciones
Utiliza bcrypt
para codificar
las contraseñas
Combina varios
sistemas de
autorización
Restricciones poco granulares
# app/config/security.yml
security:
encoders:
# ...
!
providers:
# ...
!
firewalls:
# ...
!
...
Restricciones sencillas y comunes
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBu...
Restricciones sencillas y comunes
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SensioBundleFrameworkExtraBu...
Restricciones sencillas y comunes
use AppBundleEntityPost;
use SensioBundleFrameworkExtraBundleConfigurationRoute;
use Sen...
Restricciones sencillas y comunes
// src/AppBundle/Entity/Post.php
// ...
!
class Post
{
// ...
!
public function isAuthor...
Restricciones sencillas y comunes
use AppBundleEntityPost;
use SensioBundleFrameworkExtraBundleConfigurationSecurity;
!
/*...
Restricciones avanzadas (voters)
namespace AppBundleSecurity;
!
use SymfonyComponentSecurityCoreAuthorizationVoterAbstract...
Organizando el
proyecto
Seguridad
Anotaciones
Simplificaciones
Nombres de servicios en apps Symfony
// Servicios Symfony
$this->get('doctrine')
$this->get('logger')
$this->get('session'...
Nombres de servicios propios
$this->get('slugger')
$this->get('parser')
$this->get('markdown_parser')
$this->get('stats_ag...
No definas parámetros para las clases
# app/config/services.yml
parameters:
slugger.class: AppBundleUtilsSlugger
!
service...
No definas parámetros para las clases
# app/config/services.yml
parameters:
slugger.class: AppBundleUtilsSlugger
!
service...
No definas parámetros que no cambian
# app/config/config.yml
parameters:
homepage.num_items: 10
!
// src/AppBundle/Entity/...
No definas parámetros que no cambian
# app/config/config.yml
parameters:
homepage.num_items: 10
!
// src/AppBundle/Entity/...
No añadas botones en los formularios
class PostType extends AbstractType {
public function buildForm($builder, $options) {...
No añadas botones en los formularios
class PostType extends AbstractType {
public function buildForm($builder, $options) {...
No utilices form_start y form_end
<form method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
!
<input type="sub...
No generes las URLs en los tests
public function testBlogArchives()
{
$client = self::createClient();
$url = $client->getC...
No generes las URLs en los tests
public function testBlogArchives()
{
$client = self::createClient();
$url = $client->getC...
Configuración
proyecto/app/config/
!" config.yml
!" parameters.yml
$" parameters.yml.dist
Configuración
no cambia de un ordenador a otro
proyecto/app/config/
!" config.yml
!" parameters.yml
$" parameters.yml.dist
Configuración
no cambia de un ordenador a otro
cambia de un ordenador a otro
no se sube al repositorio
proyecto/app/config...
Configuración
no cambia de un ordenador a otro
cambia de un ordenador a otro
no se sube al repositorio
este sí se sube al ...
No utilices una configuración semántica
public function getConfigTreeBuilder() {
$treeBuilder = new TreeBuilder();
$rootNo...
Conclusiones
Conjunto de técnicas que
puedes utilizar para desarrollar
aplicaciones Symfony como
recomiendan sus creadores.
Todo es opcional y no es
necesario utilizar todas las
buenas prácticas a la vez.
Estas buenas prácticas no
sirven en algunos proyectos
y escenarios concretos.
Aunque no las sigas, te
pueden servir para crear tus
propias buenas prácticas.
Nadie conoce tu trabajo y tus
circunstancias como tu. Por eso
las mejores buenas prácticas
son tus buenas prácticas.
Muchas gracias.
¿Preguntas, comentarios?
SensioLabs
Próxima SlideShare
Cargando en…5
×

Las buenas prácticas oficiales para aplicaciones Symfony

2.392 visualizaciones

Publicado el

La primera versión del framework Symfony2 se publicó hace más de tres años. Durante este tiempo, la comunidad de programadores Symfony ha originado una serie de buenas prácticas oficiosas que han sido adoptadas por la mayoría de aplicaciones.
Lamentablemente muchas de estas prácticas tienen poco que ver con la visión original de los creadores de Symfony y complican en exceso el desarrollo de las aplicaciones.
En esta sesión se presentarán muchas de las buenas prácticas oficiales recomendadas por Fabien Potencier, creador de Symfony. Sorpréndete con una visión totalmente renovada y pragmática del desarrollo de aplicaciones Symfony profesionales.

Publicado en: Tecnología
0 comentarios
9 recomendaciones
Estadísticas
Notas
  • Sé el primero en comentar

Sin descargas
Visualizaciones
Visualizaciones totales
2.392
En SlideShare
0
De insertados
0
Número de insertados
19
Acciones
Compartido
0
Descargas
41
Comentarios
0
Recomendaciones
9
Insertados 0
No insertados

No hay notas en la diapositiva.

Las buenas prácticas oficiales para aplicaciones Symfony

  1. 1. SensioLabs SYMFONY BUENAS PRÁCTICAS Javier Eguiluz
  2. 2. Symfony Barcelona gracias a
  3. 3. Marc Morera @mmoreram gracias a
  4. 4. Elcodi Symfony components based e-commerce platform gracias a
  5. 5. Introducción
  6. 6. 13 OCTUBRE
  7. 7. Las buenas prácticas oficiales Conjunto de técnicas que puedes utilizar para desarrollar aplicaciones Symfony como recomiendan sus creadores.
  8. 8. symfony.com/best-practices LIBROSWEB FABIEN POTENCIER RYAN WEAVER JAVIER EGUILUZ BUENAS PRÁCTICAS PARA APLICACIONES SYMFONY bit.ly/buenas-practicas-symfony 50 páginas 57 páginas
  9. 9. ¿Por qué? Las buenas prácticas oficiosas complican mucho el desarrollo de aplicaciones y no siguen la filosofía pragmática de los creadores de Symfony.
  10. 10. Definición de “Best Practice” A well defined procedure that is known to produce near-optimum results.
  11. 11. Definición de “Pragmatic” Concerned with making decisions and actions that are useful in practice, not just theory.
  12. 12. Las buenas prácticas Symfony
  13. 13. Las buenas prácticas Symfony • Reflejan las ideas de su creador.
  14. 14. Las buenas prácticas Symfony • Reflejan las ideas de su creador. • Son opcionales.
  15. 15. Las buenas prácticas Symfony • Reflejan las ideas de su creador. • Son opcionales. • Symfony no cambiará para obligarte a usarlas.
  16. 16. Usa las buenas prácticas …
  17. 17. Usa las buenas prácticas … • En proyectos pequeños y medianos.
  18. 18. Usa las buenas prácticas … • En proyectos pequeños y medianos. • En proyectos web estándar.
  19. 19. Usa las buenas prácticas … • En proyectos pequeños y medianos. • En proyectos web estándar. • Si eres nuevo/a en Symfony.
  20. 20. No uses las buenas prácticas …
  21. 21. No uses las buenas prácticas … • En bundles compartidos (públicos o privados).
  22. 22. No uses las buenas prácticas … • En bundles compartidos (públicos o privados). • En aplicaciones muy complejas o con arquitecturas muy especiales.
  23. 23. No uses las buenas prácticas … • En bundles compartidos (públicos o privados). • En aplicaciones muy complejas o con arquitecturas muy especiales. • Si tienes tus propias buenas prácticas.
  24. 24. Aplicaciones vs bundles
  25. 25. Estructura de una aplicación web proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ !" vendor/ $" web/ !" css/ $" js/
  26. 26. Estructura de una aplicación web configuración proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ !" vendor/ $" web/ !" css/ $" js/
  27. 27. Estructura de una aplicación web configuración plantillas proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ !" vendor/ $" web/ !" css/ $" js/
  28. 28. Estructura de una aplicación web configuración plantillas tu código proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ !" vendor/ $" web/ !" css/ $" js/
  29. 29. Estructura de una aplicación web configuración plantillas tu código dependencias proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ !" vendor/ $" web/ !" css/ $" js/
  30. 30. Estructura de una aplicación web configuración plantillas tu código dependencias assets proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ !" vendor/ $" web/ !" css/ $" js/
  31. 31. ¿Cómo crear un sistema de plugins?
  32. 32. ¿Cómo crear un sistema de plugins? • Deben funcionar de manera autónoma.
  33. 33. ¿Cómo crear un sistema de plugins? • Deben funcionar de manera autónoma. • Pueden definir su propia configuración.
  34. 34. ¿Cómo crear un sistema de plugins? • Deben funcionar de manera autónoma. • Pueden definir su propia configuración. • Pueden incluir plantillas y assets.
  35. 35. Estructura de un plugin plugin/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  36. 36. Estructura de un plugin configuración plugin/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  37. 37. Estructura de un plugin configuración assets plugin/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  38. 38. Estructura de un plugin configuración plantillas assets plugin/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  39. 39. Estructura de un plugin configuración plantillas tu código assets plugin/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  40. 40. proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ !" vendor/ $" web/ !" css/ $" js/ Aplicaciones vs plugins/bundles bundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  41. 41. Los bundles son mini-aplicaciones Configuración Plantillas Código! fuente Assets Contenedor servicios Kernel Caché! y logs Aplicación ✔ ✔ ✔ ✔ ✔ ✔ ✔ Bundle ✔ ✔ ✔ ✔ ✔ ✘ ✘
  42. 42. proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ # # # # # # !" vendor/ $" web/ !" css/ $" js/ Los bundles en aplicaciones privadas AcmeUserBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeProductBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeOfferBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeInvoiceBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  43. 43. proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ # # # # # # !" vendor/ $" web/ !" css/ $" js/ Los bundles en aplicaciones privadas AcmeUserBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeProductBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeOfferBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeInvoiceBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  44. 44. proyecto/ !" app/ # !" config/ # $" Resources/ # $" views/ !" src/ # # # # # # !" vendor/ $" web/ !" css/ $" js/ Los bundles en aplicaciones privadas AcmeUserBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeProductBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeOfferBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ... AcmeInvoiceBundle/ !" DependencyInjection/ # $" Configuration.php !" Resources/ # !" config/ # !" public/ # # !" css/ # # $" js/ # $" views/ $" ...
  45. 45. Una verdad incómoda Es muy probable que los bundles de tus aplicaciones no sean bundles, sólo directorios que molestan.
  46. 46. Buenas prácticas en la práctica
  47. 47. Organizando el proyecto Seguridad Anotaciones Simplificaciones
  48. 48. Organizando el proyecto Seguridad Anotaciones Simplificaciones
  49. 49. Crea un solo bundle llamado AppBundle
  50. 50. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Controller/ # # $" DefaultController.php # !" PaymentBundle/ # # $" Controller/ # # $" DefaultController.php # !" ProductBundle/ # # $" Controller/ # # $" DefaultController.php # $" UserBundle/ # $" Controller/ # $" DefaultController.php !" vendor/ $" web/ aplicacion/ !" app/ !" src/ # $" AppBundle/ # $" Controller/ # !" ContactController.php # !" PaymentController.php # !" ProductController.php # $" UserController.php !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales
  51. 51. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Controller/ # # $" DefaultController.php # !" PaymentBundle/ # # $" Controller/ # # $" DefaultController.php # !" ProductBundle/ # # $" Controller/ # # $" DefaultController.php # $" UserBundle/ # $" Controller/ # $" DefaultController.php !" vendor/ $" web/ aplicacion/ !" app/ !" src/ # $" AppBundle/ # $" Controller/ # !" ContactController.php # !" PaymentController.php # !" ProductController.php # $" UserController.php !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales 8directorios 4archivos
  52. 52. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Controller/ # # $" DefaultController.php # !" PaymentBundle/ # # $" Controller/ # # $" DefaultController.php # !" ProductBundle/ # # $" Controller/ # # $" DefaultController.php # $" UserBundle/ # $" Controller/ # $" DefaultController.php !" vendor/ $" web/ aplicacion/ !" app/ !" src/ # $" AppBundle/ # $" Controller/ # !" ContactController.php # !" PaymentController.php # !" ProductController.php # $" UserController.php !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales 8directorios 4archivos 2directorios 4archivos
  53. 53. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Controller/ # # $" DefaultController.php # !" PaymentBundle/ # # $" Controller/ # # $" DefaultController.php # !" ProductBundle/ # # $" Controller/ # # $" DefaultController.php # $" UserBundle/ # $" Controller/ # $" DefaultController.php !" vendor/ $" web/ aplicacion/ !" app/ !" src/ # $" AppBundle/ # $" Controller/ # !" ContactController.php # !" PaymentController.php # !" ProductController.php # $" UserController.php !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales
  54. 54. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Controller/ # # $" DefaultController.php # !" PaymentBundle/ # # $" Controller/ # # $" DefaultController.php # !" ProductBundle/ # # $" Controller/ # # $" DefaultController.php # $" UserBundle/ # $" Controller/ | !" GroupController.php | !" ProfileController.php | !" RegistrationController.php | !" ResettingController.php | $" SecurityController.php !" vendor/ $" web/ aplicacion/ !" app/ !" src/ # $" AppBundle/ # $" Controller/ # !" ContactController.php # !" PaymentController.php # !" ProductController.php # $" User/ | !" GroupController.php | !" ProfileController.php | !" RegistrationController.php | !" ResettingController.php | $" SecurityController.php !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales
  55. 55. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Controller/ # # $" DefaultController.php # !" PaymentBundle/ # # $" Controller/ # # $" DefaultController.php # !" ProductBundle/ # # $" Controller/ # # $" DefaultController.php # $" UserBundle/ # $" Controller/ | !" GroupController.php | !" ProfileController.php | !" RegistrationController.php | !" ResettingController.php | $" SecurityController.php !" vendor/ $" web/ aplicacion/ !" app/ !" src/ # $" AppBundle/ # $" Controller/ # !" ContactController.php # !" PaymentController.php # !" ProductController.php # $" User/ | !" GroupController.php | !" ProfileController.php | !" RegistrationController.php | !" ResettingController.php | $" SecurityController.php !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales 8directorios 8archivos
  56. 56. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Controller/ # # $" DefaultController.php # !" PaymentBundle/ # # $" Controller/ # # $" DefaultController.php # !" ProductBundle/ # # $" Controller/ # # $" DefaultController.php # $" UserBundle/ # $" Controller/ | !" GroupController.php | !" ProfileController.php | !" RegistrationController.php | !" ResettingController.php | $" SecurityController.php !" vendor/ $" web/ aplicacion/ !" app/ !" src/ # $" AppBundle/ # $" Controller/ # !" ContactController.php # !" PaymentController.php # !" ProductController.php # $" User/ | !" GroupController.php | !" ProfileController.php | !" RegistrationController.php | !" ResettingController.php | $" SecurityController.php !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales 8directorios 8archivos 3directorios 8archivos
  57. 57. Configuración del enrutamiento # app/config/routing.yml app: resource: @AppBundle/Controller/ type: annotation
  58. 58. No añadas un vendor en los bundles que no compartas
  59. 59. No añadas un vendor a los bundles privados AcmeNetworksAcmeWebsiteMarketingBundle ! AcmeNetworksAcmeWebsiteMarketingBundle:Default:index.html.twig ! {{ render(controller( 'AcmeNetworksAcmeWebsiteMarketingBundle:Default:latestNews' )) }}
  60. 60. No añadas un vendor a los bundles privados AcmeNetworksAcmeWebsiteMarketingBundle ! AcmeNetworksAcmeWebsiteMarketingBundle:Default:index.html.twig ! {{ render(controller( 'AcmeNetworksAcmeWebsiteMarketingBundle:Default:latestNews' )) }} Esto lo he visto con mis propios ojos
  61. 61. Guarda todas tus plantillas en app/
  62. 62. Esta buena práctica es la que produce un mayor impacto positivo AVISO IMPORTANTE
  63. 63. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Resources/ # # $" views/ # # $" Default/ # # !" index.html.twig # # $" show.html.twig # . . . # $" ProductBundle/ # $" Resources/ # $" views/ # $" Default/ # !" index.html.twig # !" category.html.twig # $" show.html.twig !" vendor/ $" web/ your-application/ !" app/ # $" Resources/ # $" views/ # !" contact/ # # !" index.html.twig # # $" show.html.twig # . . . # $" product/ # !" index.html.twig # !" category.html.twig # $" show.html.twig !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales
  64. 64. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Resources/ # # $" views/ # # $" Default/ # # !" index.html.twig # # $" show.html.twig # . . . # $" ProductBundle/ # $" Resources/ # $" views/ # $" Default/ # !" index.html.twig # !" category.html.twig # $" show.html.twig !" vendor/ $" web/ your-application/ !" app/ # $" Resources/ # $" views/ # !" contact/ # # !" index.html.twig # # $" show.html.twig # . . . # $" product/ # !" index.html.twig # !" category.html.twig # $" show.html.twig !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales 8directorios 5archivos
  65. 65. aplicacion/ !" app/ !" src/ # !" ContactBundle/ # # $" Resources/ # # $" views/ # # $" Default/ # # !" index.html.twig # # $" show.html.twig # . . . # $" ProductBundle/ # $" Resources/ # $" views/ # $" Default/ # !" index.html.twig # !" category.html.twig # $" show.html.twig !" vendor/ $" web/ your-application/ !" app/ # $" Resources/ # $" views/ # !" contact/ # # !" index.html.twig # # $" show.html.twig # . . . # $" product/ # !" index.html.twig # !" category.html.twig # $" show.html.twig !" vendor/ $" web/ Aplicaciones Symfony tradicionales Buenas Prácticas oficiales 8directorios 5archivos 4directorios 5archivos
  66. 66. Centralizar las plantillas
  67. 67. Centralizar las plantillas Cambia la vida a tus diseñadores/as
  68. 68. Centralizar las plantillas Cambia la vida a tus diseñadores/as Simplifica mucho tu código
  69. 69. Nueva organización de plantillas aplicacion/ $" app/Resources/views/ !" contact/ # !" index.html.twig # $" show.html.twig . . . ! $" product/ !" index.html.twig !" category.html.twig $" show.html.twig
  70. 70. La nueva notación de las plantillas $this->render('AcmeDemoBunde:Default:index.html.twig'); $this->render('default/index.html.twig'); ! $this->render('AcmeDemoBundle::index.html.twig'); $this->render('index.html.twig');
  71. 71. La nueva notación de las plantillas {% extends '::layout.html.twig' %} {% extends 'layout.html.twig' %} ! {{ include('AcmeDemoBundle:Default:subdir/index.html.twig') }} {{ include('default/subdir/index.html.twig') }} ! {{ include('AcmeDemoBundle:Default/subdir:index.html.twig') }} {{ include('default/subdir/index.html.twig') }}
  72. 72. Los problemas de la notación tradicional AcmeDemoBundle:Default:subdir/index.html.twig
  73. 73. Los problemas de la notación tradicional • Requiere explicársela a cada diseñador/programador. AcmeDemoBundle:Default:subdir/index.html.twig
  74. 74. Los problemas de la notación tradicional • Requiere explicársela a cada diseñador/programador. • Tiene excepciones (alguna de sus partes puede estar vacía) e inconsistencias (subdirectorios). AcmeDemoBundle:Default:subdir/index.html.twig
  75. 75. Los problemas de la notación tradicional • Requiere explicársela a cada diseñador/programador. • Tiene excepciones (alguna de sus partes puede estar vacía) e inconsistencias (subdirectorios). • No es inmediato saber dónde está la plantilla (debes traducir la notación a un directorio). AcmeDemoBundle:Default:subdir/index.html.twig
  76. 76. Guarda todos tus assets en web/
  77. 77. Centralizar los assets (CSS, JavaScript) • Tiene las mismas ventajas que centralizar las plantillas.
  78. 78. Organizando los assets web proyecto/ !" app/ !" src/ !" vendor/ $" web/ !" css/ # !" bootstrap.min.css # $" app.css $" js/ !" jquery.min.js $" app.js
  79. 79. Organizando los assets web proyecto/ !" app/ !" src/ !" vendor/ $" web/ !" css/ # !" bootstrap.min.css # $" app.css $" js/ !" jquery.min.js $" app.js proyecto/ !" app/ # $" Resources/ # $" assets/ # !" scss/ # # !" bootstrap/ # # $" app.scss # $" js/ !" src/ !" vendor/ $" web/ !" css/app.css $" js/app.js
  80. 80. En resumen • Si utilizas mal los bundles, estás repitiendo la estructura de la aplicación sin necesidad • Si no vas a compartir tus bundles, utiliza los directorios de la aplicación (app/ Resources/ y web/). • El número de archivos se mantiene, los directorios y la complejidad se reducen.
  81. 81. Organizando el proyecto Seguridad Anotaciones Simplificaciones
  82. 82. Escala de sensibilidad para programadores
  83. 83. Escala de sensibilidad para programadores Política Religión Fútbol Estándar de código Editor de código Anotaciones
  84. 84. Anotaciones PHP use AppBundleEntityPost; use SensioBundleFrameworkExtraBundleConfigurationRoute; ! class CommentController extends Controller { /** * @Route("/edit/{id}", name = "post_edit") */ public function editAction(Post $post) { ... } ! /* * @Route("/edit/{id}", name = "post_edit") */ public function editAction(Post $post) { ... } }
  85. 85. Anotaciones PHP use AppBundleEntityPost; use SensioBundleFrameworkExtraBundleConfigurationRoute; ! class CommentController extends Controller { /** * @Route("/edit/{id}", name = "post_edit") */ public function editAction(Post $post) { ... } ! /* * @Route("/edit/{id}", name = "post_edit") */ public function editAction(Post $post) { ... } } Anotación
  86. 86. Anotaciones PHP use AppBundleEntityPost; use SensioBundleFrameworkExtraBundleConfigurationRoute; ! class CommentController extends Controller { /** * @Route("/edit/{id}", name = "post_edit") */ public function editAction(Post $post) { ... } ! /* * @Route("/edit/{id}", name = "post_edit") */ public function editAction(Post $post) { ... } } Anotación Comentario
  87. 87. Anotaciones PHP /** @Route(...) */Anotación Comentario /* @Route(...) */
  88. 88. Utiliza @Route, @Security y @Cache
  89. 89. Enrutamiento tradicional # app/config/routing.yml _admin_post: resource: '@AcmeAdminBundle/Resources/config/routing/post.yml' prefix: '/admin/post' ! # src/Acme/AdminBundle/Resources/config/routing/post.yml admin_post_show: pattern: '/{id}' defaults: { _controller: 'AcmeAdminBundle:Post:show' } ! ! namespace AcmeAdminBundleController; ! class PostController { public function showAction($id) { ... } }
  90. 90. Enrutamiento con anotaciones namespace AppBundleControllerAdmin; ! use SymfonyBundleFrameworkBundleControllerController; use SensioBundleFrameworkExtraBundleConfigurationRoute; ! /** * @Route("/admin/post") */ class PostController extends Controller { /** * @Route("/{id}", name="admin_post_show") */ public function showAction($id) { ... } }
  91. 91. No utilices la anotación @Template
  92. 92. La anotación @Template es mágica /** @Template() */ public function indexAction() { // ... return array('posts' => $posts); } ! ! public function indexAction() { // ... return $this->render('blog/index.html.twig', array( 'posts' => $posts )); }
  93. 93. Utiliza los ParamConverter cuando sea sencillo
  94. 94. Los ParamConvertes en la práctica use SensioBundleFrameworkExtraBundleConfigurationRoute; use AppBundleEntityPost; ! class CommentController extends Controller { /** * @Route("/edit/{id}", name = "post_edit") */ public function editAction(Post $post) { } } use SensioBundleFrameworkExtraBundleConfigurationRoute; ! ! class CommentController extends Controller { /** * @Route("/edit/{id}", name = "post_edit") */ public function editAction($id) { $em = $this->getDoctrine()->getManager(); $post = $em->getRepository('AppBundle:Post')->find($id); ! if (!$post) { throw $this->createNotFoundException(); } } }
  95. 95. Un controlador Symfony de ejemplo namespace AppBundleController; ! use AppBundleEntityPost; use SymfonyBundleFrameworkBundleControllerController; use SensioBundleFrameworkExtraBundleConfigurationRoute; ! class BlogController extends Controller { /** * @Route("/edit/{id}", name="post_edit") */ public function editAction(Post $post) { return $this->render('blog/edit.html.twig', array( 'post' => $post )); } }
  96. 96. Nuestro consejo DESACOPLA ACOPLA la lógica de negocio los controladores
  97. 97. Los atajos de los controladores $this->forward(); $this->redirect(); $this->redirectToRoute(); $this->getUser(); $this->getDoctrine(); $this->generateUrl(); $this->createNotFoundException(); $this->createAccessDeniedException()
  98. 98. Organizando el proyecto Seguridad Anotaciones Simplificaciones
  99. 99. Utiliza bcrypt para codificar las contraseñas
  100. 100. Combina varios sistemas de autorización
  101. 101. Restricciones poco granulares # app/config/security.yml security: encoders: # ... ! providers: # ... ! firewalls: # ... ! access_control: - { path: ^/admin, roles: ROLE_ADMIN }
  102. 102. Restricciones sencillas y comunes use SensioBundleFrameworkExtraBundleConfigurationRoute; use SensioBundleFrameworkExtraBundleConfigurationSecurity; ! /** * @Route("/new", name="admin_post_new") * @Security("has_role('ROLE_ADMIN')") */ public function newAction() { // ... }
  103. 103. Restricciones sencillas y comunes use SensioBundleFrameworkExtraBundleConfigurationRoute; use SensioBundleFrameworkExtraBundleConfigurationSecurity; ! /** * @Route("/new", name="admin_post_new") */ public function newAction() { if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) { throw $this->createAccessDeniedException(); } ! ! // ... }
  104. 104. Restricciones sencillas y comunes use AppBundleEntityPost; use SensioBundleFrameworkExtraBundleConfigurationRoute; use SensioBundleFrameworkExtraBundleConfigurationSecurity; ! /** * @Route("/{id}/edit", name="admin_post_edit") * @Security("user.getEmail() == post.getAuthorEmail()") */ public function editAction(Post $post) { // ... }
  105. 105. Restricciones sencillas y comunes // src/AppBundle/Entity/Post.php // ... ! class Post { // ... ! public function isAuthor(User $user = null) { return $user && $user->getEmail() == $this->getAuthorEmail(); } }
  106. 106. Restricciones sencillas y comunes use AppBundleEntityPost; use SensioBundleFrameworkExtraBundleConfigurationSecurity; ! /** * @Route("/{id}/edit", name="admin_post_edit") * @Security("post.isAuthor(user)") */ public function editAction(Post $post) { // ... } ! ! {% if post.isAuthor(app.user) %} <a href=""> ... </a> {% endif %}
  107. 107. Restricciones avanzadas (voters) namespace AppBundleSecurity; ! use SymfonyComponentSecurityCoreAuthorizationVoterAbstractVoter; use SymfonyComponentSecurityCoreUserUserInterface; ! class PostVoter extends AbstractVoter { protected function getSupportedAttributes() { return array('create', 'edit'); } ! protected function getSupportedClasses() { return array('AppBundleEntityPost'); } ! protected function isGranted($attribute, $post, $user = null) { // ... } }
  108. 108. Organizando el proyecto Seguridad Anotaciones Simplificaciones
  109. 109. Nombres de servicios en apps Symfony // Servicios Symfony $this->get('doctrine') $this->get('logger') $this->get('session') $this->get('validator') ! // Servicios de terceros $this->get('imagine.filter.loader.thumbnail') $this->get('knp_menu.renderer_provider') $this->get('sonata.admin.form.filter.type.datetime_range')
  110. 110. Nombres de servicios propios $this->get('slugger') $this->get('parser') $this->get('markdown_parser') $this->get('stats_aggregator') ! // Aceptable también $this->get('app.slugger') $this->get('app.parser') $this->get('app.markdown_parser') $this->get('app.stats_aggregator')
  111. 111. No definas parámetros para las clases # app/config/services.yml parameters: slugger.class: AppBundleUtilsSlugger ! services: slugger: class: "%slugger.class%"
  112. 112. No definas parámetros para las clases # app/config/services.yml parameters: slugger.class: AppBundleUtilsSlugger ! services: slugger: class: "%slugger.class%" Innecesario y poco útil en la práctica
  113. 113. No definas parámetros que no cambian # app/config/config.yml parameters: homepage.num_items: 10 ! // src/AppBundle/Entity/Post.php class Post { const NUM_ITEMS = 10; ! // ... }
  114. 114. No definas parámetros que no cambian # app/config/config.yml parameters: homepage.num_items: 10 ! // src/AppBundle/Entity/Post.php class Post { const NUM_ITEMS = 10; ! // ... } Este valor seguramente no cambia nunca
  115. 115. No añadas botones en los formularios class PostType extends AbstractType { public function buildForm($builder, $options) { $builder // ... ->add('save', 'submit', array('label' => 'Create Post')) ; } ! // ... }
  116. 116. No añadas botones en los formularios class PostType extends AbstractType { public function buildForm($builder, $options) { $builder // ... ->add('save', 'submit', array('label' => 'Create Post')) ; } ! // ... } Te dificulta reutilizar los formularios
  117. 117. No utilices form_start y form_end <form method="post" {{ form_enctype(form) }}> {{ form_widget(form) }} ! <input type="submit" value="Create" class="btn btn-default pull-right" /> </form>
  118. 118. No generes las URLs en los tests public function testBlogArchives() { $client = self::createClient(); $url = $client->getContainer()->get('router')->generate('blog_archives'); $client->request('GET', $url); // ... } ! ! public function testBlogArchives() { $client = self::createClient(); $client->request('GET', '/blog/archives/'); // ... }
  119. 119. No generes las URLs en los tests public function testBlogArchives() { $client = self::createClient(); $url = $client->getContainer()->get('router')->generate('blog_archives'); $client->request('GET', $url); // ... } ! ! public function testBlogArchives() { $client = self::createClient(); $client->request('GET', '/blog/archives/'); // ... } Si rompes la URL no te enteras
  120. 120. Configuración proyecto/app/config/ !" config.yml !" parameters.yml $" parameters.yml.dist
  121. 121. Configuración no cambia de un ordenador a otro proyecto/app/config/ !" config.yml !" parameters.yml $" parameters.yml.dist
  122. 122. Configuración no cambia de un ordenador a otro cambia de un ordenador a otro no se sube al repositorio proyecto/app/config/ !" config.yml !" parameters.yml $" parameters.yml.dist
  123. 123. Configuración no cambia de un ordenador a otro cambia de un ordenador a otro no se sube al repositorio este sí se sube al repositorio proyecto/app/config/ !" config.yml !" parameters.yml $" parameters.yml.dist
  124. 124. No utilices una configuración semántica public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('framework'); ! $rootNode ->children() ->scalarNode('secret')->end() ->scalarNode('http_method_override') ->info("Set true to enable support for ...”) ->defaultTrue() ->end() ->arrayNode('trusted_proxies') ->beforeNormalization() ->ifTrue(function ($v) { return !is_array($v) && null !== $v; }) ->then(function ($v) { return is_bool($v) ? array() : preg_split('/s*,s*/', $v); }) ->end() ->prototype('scalar') ->validate() ->ifTrue(function ($v) { if (empty($v)) { return false; } ! if (false !== strpos($v, '/')) { Sólo es útil en configuraciones muy complejas
  125. 125. Conclusiones
  126. 126. Conjunto de técnicas que puedes utilizar para desarrollar aplicaciones Symfony como recomiendan sus creadores.
  127. 127. Todo es opcional y no es necesario utilizar todas las buenas prácticas a la vez.
  128. 128. Estas buenas prácticas no sirven en algunos proyectos y escenarios concretos.
  129. 129. Aunque no las sigas, te pueden servir para crear tus propias buenas prácticas.
  130. 130. Nadie conoce tu trabajo y tus circunstancias como tu. Por eso las mejores buenas prácticas son tus buenas prácticas.
  131. 131. Muchas gracias.
  132. 132. ¿Preguntas, comentarios?
  133. 133. SensioLabs

×