Symfony es un framework PHP que recientemente ha cumplido los 500 Millones de descargas y es conocido por su gran ecosistema de componentes. También es la base de proyectos como drupal, magento y prestashop(en sus fases iniciales al port hacia symfony) entre otros. Cuenta con una comunidad muy activa, y su creador está entre los miembros del PHP-FIG, es por ello que desde acceseo os queremos mostrar en este articulo una serie de buenas prácticas y consejos para mejorar vuestro código en Symfony.
Una de las principales características, conjuntamente con el sistema de componentes, es la calidad de su documentación, así como un amplio repertorio de test que le proporcionan una gran aceptación por parte de la comunidad y una base muy sólida para empezar cualquier proyecto sin importar su magnitud.
Vamos a citar en primer lugar algunos tips and tricks, y acto seguido, algunas buenas prácticas, extraídas directamente desde la propia sección.
Trucos y consejos para optimizar Symfony
Tabla de contenidos
ToggleExisten multitud de plataformas que hacen uso de las variables de entorno para almacenar los credenciales de las aplicaciones. Recientemente, symfony (en su versión 3.3) ha publicado un componente llamado Dotenv, el cual nos permite parsear archivos .env. En nuestra aplicación, podemos añadir las variables como parámetros:
// app/AppKernel.php public function registerContainerConfiguration(LoaderInterface $loader) { $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); try { (new Dotenv\Dotenv(__DIR__.'/../'))->load(); $envParameters = $this->getEnvParameters(); $loader->load(function($container) use($envParameters) { $container->getParameterBag()->add($envParameters); }); } catch (Dotenv\Exception\InvalidPathException $e) { // don't do much at the moment, possibly the env variables are set differently (e.g. AWS) }
En su versión 3.2 de symfony, se integró el uso de la función env, encargada de obtener el valor de la variable de entorno desde la configuración en yaml con el siguiente formato:
# app/config/config.yml doctrine: dbal: # ... password: "%env(DB_PASSWORD)%"
En la versión 2.6 fue añadido LockHandler, y en su versión mas reciente, la 3.3, han anunciado el componente llamado Lock component, el cual nos permite bloquear el acceso a los recursos a través de diversos métodos, tales como flock de php, PHP Semaphore extension, Redis y Memcache.
Yaml, human friendly data serialization standard, mantenido por Clark C. Evans, es un standard que tiene por objetivo la serialización de la información de forma descriptiva. En los últimos años ha ganado popularidad, debido a la facilidad de parseado frente a alternativas como XML. Herramientas como Docker, también lo usan para expresar sus archivos de configuración. Symfony cuenta con un componente llamado YAML Parser. Desde la versión 3.3, ahora se nos permite crear etiquetas personalizadas.
$yaml = "!my_tag { foo: bar }"; $config = Yaml::parse($yaml, Yaml::PARSE_CUSTOM_TAGS); $tag = $config->getTag(); // $tag = 'my_tag' $value = $config->getValue(); // $value = array('foo' => 'bar')
Lo podemos usar para añadir funcionalidades específicas para la configuración de nuestro bundle, por ejemplo.
Como última novedad, han incorporado la carga de archivos locales con patrones globales. Ahora podemos hacer lo siguiente:
const CONFIG_EXTS = '.{php,xml,yaml,yml}'; // ... protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) { $confDir = dirname($this->getRootDir()).'/etc'; $loader->import($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob'); $loader->import($confDir.'/packages/'.$this->getEnvironment().'/**/*'.self::CONFIG_EXTS, 'glob'); $loader->import($confDir.'/container'.self::CONFIG_EXTS, 'glob'); }
Existe una característica del componente Config no muy conocida, que nos permite hacer override de los archivos que hemos cargado:
# app/config/config.yml imports: - { resource: 'parameters.yml' } - { resource: '/etc/sites/mysite.com/parameters.yml', ignore_errors: true }
De esta forma, podemos tener en el servidor de producción un archivo con los parámetros correspondientes. Sin embargo, en local, como no existe dicho archivo y le hemos indicado que no lance excepción seguirá el flujo habitual de la aplicación.
Por lo que a conexión con capa de persistencia de datos se refiere, symfony usa Doctrine, un ORM (Object Relational Mapper). Los bundles con los que viene symfony, por regla general, vienen con una gran cantidad de configuración por defecto que nosotros podemos modificar según nuestras necesidades. Por lo que respecta al naming de las tablas, resulta común que la estrategia varíe según los requisitos del proyecto. Para tal propósito, podemos forzar la estrategia de naming con una configuración, para evitar la redundancia de escribir el parámetro en cada valor de la entidad en caso de pretender modificar el comportamiento habitual:
#app/config/config.yml config: doctrine: dbal: # ... orm: # ... entity_managers: default: naming_strategy: doctrine.orm.naming_strategy.underscore
También podremos hacer nuestras propias estrategias de naming haciendo uso de la clase: Doctrine\ORM\Mapping\NamingStrategy según indican en su documentación.
En lo referente a su motor de plantillas, twig, hay interesantes mejoras que podemos utilizar.
Disponemos de la posibilidad de evaluar si existe un bloque, a través de la siguiente sintaxis:
{%if 'block_name' is block%} Esto es un bloque {% endif %}
Cuando creamos nuestros propios filtros, y necesitamos proporcionarle un número arbitrario de parámetros de entrada, podemos usar la opción is_variadic
$filter = new Twig_Filter('thumbnail', function ($file, array $options = array()) { // ... }, array('is_variadic' => true));
Para finalizar, podemos usar lo que llaman, named arguments. Nos confían una mayor legibilidad en el código:
{{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}
En cuanto a los logs, symfony cuenta con su propio componente, que nos ayuda identificar los estados por los cuales pasa nuestra aplicación. Es un gran desconocido,
pero cuenta con muchas funcionalidades que nos pueden ayudar identificar problemáticas futuras.
Podemos crear canales personalizados, de forma muy sencilla:
# app/config/config.yml monolog: channels: ['foo', 'bar']
Ahora symfony ya permite pasar el canal de log a través de un argumento:
#app/config/config.yml services: some_service: class: Namespace\Some\Service arguments: ["@monolog.logger.alert"]
Podemos crear formatters personalizados desde la configuración, sin necesidad de implementar una clase de formateo:
#config.yml services: app.log.formatter: class: Monolog\Formatter\LineFormatter public: false arguments: - '%%level_name%% [%%datetime%%] [%%channel%%] %%message%%\n' #mensaje a escribir en el archivo de log - 'H:i:s' #formato - false #ignorar \n en los logs
Configurando donde queremos usar dicho formato:
#app/config/config.yml monolog: handlers: main: formatter: app.log.formatter
Gestión de correos en entorno de desarrollo
Cuando se trata de correos, son una parte básica de cualquier aplicación, sobretodo si la aplicación tiene usuarios y deseamos verificar el correo de registro, por ejemplo. En entornos de desarrollo, es importante que los emails, sigan el flujo habitual. Así como la posibilidad de poder visualizarlos. Nosotros lidiamos con este problema con una herramienta llamada Mailhog, el cual cuenta con repositorio en github. Podemos ir a la sección releases de la documentación para encontrar la última versión compilada de la misma. Está dotado con un servidor de stmp y un panel web para visualizar todos los correos salientes de la aplicación. Es una gran opción que no necesita de instalar daemons en el caso de linux, tan sólo ejecución en el momento en que necesitemos de la funcionalidad.
En symfony tenemos una guía para organizar los entornos con diferentes archivos de configuración de manera jerárquica en función de los directorios como se muestra en la documentación. Esto nos puede servir para cargar diferentes configuraciones, como por ejemplo en este caso, que nos interesa cambiar los datos del servidor smtp para poder evaluar la aplicación al completo.
Buenas prácticas en Symfony
Por último vamos a citar algunas de las buenas prácticas a modo de resumen, que nos proporcionan desde la sección de best practices.
- Define toda la configuración de la infraestructura en el archivo parameters.
- Define todos los parámetros en parameters.yml.dist. Ten en cuenta que composer evalua este archivo para regenerar el parameters.yml.
- Define la configuración de la aplicación en config.yml.
- Usa constantes para definir la configuración.
- El naming de los parámetros debería ser lo mas corto posible.
Organizar la lógica de negocio:
- Usa nombres lo mas cortos posibles para los servicios del bundle.
- Escribe la configuración de los servicios en archivos YAML
- Como hemos comentado anteriormente, mueve los datos sensibles fuera de la aplicación con variables de entorno.
- Los controladores deben extender siempre del controlador base de FrameworkBundle.
- No uses la anotación @Template.
- Usa ParamConverters para obtener la entidad en el controlador.
- Por norma general, como indican en la documentación, los controladores deberían seguir la regla 5-10-20. 5 líneas variables o menos, 10 acciones o menos y 20 líneas o menos
Como conclusión final, symfony tiene una curva de aprendizaje en sus inicios algo elevada, pero cuando se domina el framework en sus aspectos más básicos nos puede ayudar con un ágil desarrollo con poco esfuerzo y una gran calidad del código, siguiendo unas normas básicas de buenas prácticas.
4 comentarios en “Buenas prácticas y consejos para mejorar tu código en Symfony”
Hola Jordi, estoy empezando con Symfony y tengo una duda respecto a lo que comentas de tener el código de los controladores lo más reducido posible.
Cuando el código tiene que ver con entidades, entiendo que todos los métodos tienen que ir al repositorio correspondiente, pero cuando no es el caso, ¿cual sería el sitio correcto o la estructura correcta para dejar el código y no ponerlo en los actions de los controladores?
Muchas gracias.
Buenas tardes Sergio,
como bien sabrás hay diversas soluciones por las que puedes optar en función de la problemática. A lo que hago mención aquí, es a extraer la lógica perteneciente a los controladores, para evitar la duplicidad del código. Por norma general, siempre que copies código es una mala práctica. Hay diversas soluciones que te animo a buscar, no sin pasar por alto la documentación de symfony, que es de gran calidad.
Saludos.
Lastimosamente muchas recomendaciones del post ya están obsoletas, da mucha rabia realizar búsquedas sobre Symfony y ver que el 100% del material encontrado, solo puede valer un 50%, y aún es más peor ver que la información encontrada parece estar bien comentada y explicada pero sin valor. Me estoy dando cuenta que cada vez parece tener menos sentido realizar trabajos explicativos sobre el funcionamiento sobre el framework, seguramente muchos que se han tomado el tiempo en realizar estos apuntes deberán sentir mucho disgusto.
Hola Matias,
gracias por tu comentario. Hay aspectos que han cambiado en forma, pero en el fondo hacen referencia a lo mismo. Además, la gran mayoría de cambios, han dado una mayor estabilidad y flexibilidad al framework. Te aconsejamos que leas la documentación oficial, que a grandes rasgos, fomenta las mismas buenas prácticas ;).