Symfony es el framework full-stack de desarrollo PHP más activo en la comunidad. Llamado full-stack porque abarca tanto el frontend como el backend. Es un framework, que simple y llanamente, ha ido recopilando las mejores técnicas de desarrollo de software de muchos frameworks y lenguajes. Y ha englobado todas éstas técnicas en un sólo framework.
Esto hace que la curva de aprendizaje inicial sea muy pronunciada. Es un framework complicado para que un principiante empieze a desarrollar aplicaciones web. Pero una vez alcanzada la cumbre inicial, proporciona una productividad impresionante al desarrollador. Con muy pocas líneas de código fuente se crean gran cantidad de acciones. Las modificaciones son muy rápidas, y los resultados son de la máxima calidad y robustez.
La seguridad, una de las máximas prioridades.
Enrutamiento, excelente mapeado de los datos de las peticiones.
Diseño modelo-vista-controlador (MVC).
Generación dinámica de formularios.
Creación de objetos/modelos de datos automatizado.
Guardado, listado, editado y borrado de objetos de datos simplificado.
Independización de la base de datos con ORM.
Generación de vistas usando Twig.
Internacionalización.
Tests te integración unitarios y funcionales, puenteando hacia PHPUnit.
Simulador de navegador.
Crawler del DOM.
Herramienta visual de desarrollo y depuración.
Generador de CRUDs.
Interfaz de consola, para línea de comandos.
Cacheado.
Y un largo etcétera..
100% integrado con el gran Composer, el gestor de dependencias que ha revolucionado el trabajo en PHP. Gracias a esto, su instalación, mantenimiento, actualización y adición de nuevas funcionalidades es realmente sencillo. Todo esto no es más que la punta del iceberg. Symfony es la apuesta segura. Destapa el porqué, poco a poco, tantos proyectos web se están reconstruyendo completa o parcialmente mediante Symfony:
phpBB, Drupal, Prestashop, Joomla, Magento, API Platform, eZ Platform, Thelia, Sylius, Dailymotion, OroCRM, Yahoo! Answers..
Las nubes por definición son sistemas informáticos que crecen o decrecen según la necesidad. Son conjuntos de servidores/servicios que se adaptan a la demanda. Con todo esto, llegamos a una de las cosas más interesantes de AWS, el auto-escalado o la tolerancia a fallos, además de la personalización de los servidores. Podemos controlar la carga de los servidores que haya. Además automatizar el arranque y parada a ciertas horas de algunos de los servidores. O podemos duplicar los sistemas para evitar los ‘single point of failure como una casa’.
En OpsWorks tenemos herramientas muy interesantes relacionadas con esto. Algo rústicas, quizá clásicas dirían algunos. Pero gracias a ello, sin límites en la flexibilidad para configurar. Y si lo llevamos al extremo, este mismo sistema nos puede servir para automatizar la creación de nuestros servidores con herramientas como Chef y Kitchen. Todo esto y mucho más es lo que se puede hacer con el clásico OpsWorks.
Primero tendremos que ver qué son las AMIs. Cómo crear una manualmente o automáticamente. Y finalmente veremos cómo se usan, para hacernos una buena idea de qué podemos hacer en OpsWorks, y si es o no lo que necesitamos. Quizá es interesante ir a Docker con el EC2 Container Service o a CloudFormation, pero esto son otros temas..
No voy a entrar al detalle de cómo hacer cada cosa, no terminaría nunca. Así que si buscas una guía general para enfrentar después cada detalle poco a poco, este es tu post.
Este es un pequeño HOWTO para tener de referencia.
Si tienes una relación entre dos entidades de la forma ManyToMany, una de ellas tendrá inversedBy y la otra mappedBy. Con un ejemplo se ve más claro.
Suponiendo que has generado las acciones CRUD con el comando siguiente:
$ php app/console doctrine:generate:crud
Supongamos que tenemos usuarios y negocios relacionados así, en una relación muchos a muchos. En la entidad Business tenemos: /** * @ORMManyToMany(targetEntity=»User», * inversedBy=»users», cascade={«persist»}) */ private $users;
Y en la entidad User tenemos:
/** * @ORMManyToMany(targetEntity=»Business», * mappedBy=»users», cascade={«persist»}) * @ORMJoinColumn(onDelete=»SET NULL») */ private $businesses; Ahora el editar los usuarios tenemos en el formulariode edición de un usuario lo siguiente:
->add(‘businesses’, ‘entity’, array( ‘by_reference’ => false, //.. )) La entidad inversedBy, que en este caso es Business, guardará correctamente los Users referenciados al editarlos. Pero al contrario con la entidad Users, tiene los Business mapeados, lo que hará que no guarde automáticamente las referencias.
Hay que añadir lo que he puesto en negrita en los códigos anteriores y en la entidad User lo siguiente para permitir que añada y borre los Business correctamente.
/** * Add businesses. * * @param AppBundleEntityBusiness $businesses * * @return User */ public function addBusiness(AppBundleEntityBusiness $business) { $this->businesses[] = $business; $business->addUser($this);
return $this; }
/** * Remove businesses. * * @param AppBundleEntityBusiness $businesses */ public function removeBusiness(AppBundleEntityBusiness $business) { $this->businesses->removeElement($business); $business->removeUser($this); }
Con ésto ya debe de funcionar. Si estamos editando un Business y añadimos o borramos Users lo hará correctamente, y de la forma inversa, si estamos editando un User, también añadirá o borrará Business.
Brutal el proyecto que están desarrollando en Sylius. Navegando y navegando por proyectos para hacer tiendas online. Viendo las principales opciones del mercado: Magento, Prestashop y WordPress con WooCommerce. Me planteaba la opción de cómo sería desarrollar una tienda completa en Symfony. Integrar pasarelas de pago, métodos de envío, ordenando todo los productos por categorías, valores, atributos de los productos.. es un trabajazo. Pero por otro lado no quería prescindir de la flexibilidad y agilidad que nos da un buen framework PHP, en este caso el gran Symfony.
Aterrizaje
Todas estas búsquedas me llevaron a encontrar Sylius. Lo que hasta ahora es el proyecto de tienda online basado en Symfony que me ha parecido más interesante. A fecha en que escribo está en fase de desarrollo aunque hay quien ya lo está utilizando.
Se trata de un proyecto Open Source, licenciado bajo la MIT license. Esto nos permite usar Sylius para cualquier proyecto, libremente sin coste de compra ninguno. Lo único que no se pude hacer es decir que Sylius lo hemos hecho nosotros, como es lógico. Se puede adaptar, modificar, ampliar, etc.. Cualquier cosa se puede hacer porque lo que tenemos entre manos es un proyecto Symfony.
Diferenciación
La principal diferenciación es que para modificarlo no tienes que leerte una ingente cantidad de documentación. Cuando estás desarrollando algo para algún CMS como WordPress, Magento, Joomla.. debes tener siempre a mano su documentación. Acabas especializándote y luego no te puedes salir de dicha plataforma. Por otro lado, el que mucho abarca poco aprieta, no te puedes espcializar mucho en un CMS en concreto. Si lo haces, que luego no te saquen de ahí porque cuando te llevan a otro CMS es otro mundo.
Al ser una plataforma 100% en Symfony, todo sigue el esquema general. Las plantillas están donde deben de estar, igual los controladores, las entidades de las bases de datos. La estructura de directorios es la misma que la de cualquier proyecto Symfony. Las nuevas librerías se añaden igual que cualquier proyecto Symfony. Todo está en su sitio. Esto agiliza mucho la adaptación y ampliación de funcionalidades. No necesitas sumergirte en un mar de documentación específica del CMS en cuestión.
Características
Por su propia naturaleza, se trata de un programa muy potente, rápido, flexible, adaptable y escalable a más no poder. Es como si se tratara de un desarrollo de una tienda 100% artesanal, pero donde estará casi todo listo para usar.
Esta siendo traducido a varios idiomas, con zona frontal, zona de administración. Tendremos productos, el clásico carro de la compra, productos organizados por categorías y atributos, formas de pago, métodos de envío, gestión de mensajes de clientes, páginas estáticas, además de muchas otras configuraciones. Incluso se prevee la inclusión de una API para interconectar el sistema Sylius con otros sistemas.
Resumiendo
¡Toda una joya de la informática! A mi me parece un gran proyecto. Que está siendo organizado empresarialmente desde Lakion.com. Una empresa que preveo que ofrecerá todo tipo de servicios alrededor del proyecto. De igual forma que hacen la mayoría de proyectos Open Source.
Resumiendo, tenemos un gran proyecto. Pretende revolucionar el mundo de los CMS de tiendas online. Está siendo una revolución en el mundo de la programación a medida. Y seguro que lo va a ser también en el mundo de los CMSs cuando alcance su madurez para que cualquier no-programador lo use.
Puede ser algo trivial, pero es el punto de partida para iniciar la internacionalización de una web. Me refiero a la llegada del usuario, recogida del código de idioma y región del navegador, se comprueban los idiomas disponibles y posteriormente se le redirige a la página de su idioma correspondiente.
Es mucho más sencillo que lo que puede parecer a priori, pero claro está, hay que tener claras un par de cosas que si no después se complica.
El usuario llega a la web
En este punto, tenemos un usuario que llega a la web. Ahora es el momento de elegir el idioma en que le vamos a mostrar la página web al usuario. Que podemos hacerlo de dos formas diferentes: eligiendo el idioma por defecto o con el idioma que nos sugiera el navegador.
Vamos a empezar con un ejemplo de controlador que recibe la visita inicial del usuario:
<?php namespace FrontBundleController;
use SymfonyBundleFrameworkBundleControllerController; use SensioBundleFrameworkExtraBundleConfigurationRoute; use SensioBundleFrameworkExtraBundleConfigurationTemplate; use SymfonyComponentHttpFoundationRequest; /* * Controlador de ejemplo para empezar a traducir una web. * Sólo tiene las dos rutas necesarias para empezar la navegación traducida * Se necesita de la entidad Idioma para tener los idiomas disponibles. */ class DefaultController extends Controller { /** * Esta ruta es la página de inicio. Simplemente recibe al visitante * busca entre los idiomas publicados y le redirige a la ruta siguiente * poniendo el código del idioma en la URL. * * @Route («/», name=»iniciototal») */ public function inicioTotalAction(Request $request) { $manager = $this->getDoctrine()->getManager();
// Creamos el array de idiomas disponibles que se obtienen de la // entidad Backbundle:Idioma, aquí lo que hacemos es recuperar de la // BD los idiomas publicados guardando en un array los códigos de idioma. $idiomas = $manager->getRepository(‘BackBundle:Idioma’)->findBy(array( ‘publicado’ => true )); $idiomasarray = array(); foreach ($idiomas as $idioma) { $idiomasarray[] = $idioma->getCodigo(); }
// Consulta los lenguajes preferidos del navegador, comprueba // los que tenemos disponibles disponibles devolviendo el primero // que tenemos disponible de los preferidos por el navegador. $codigoLocale = $request->getPreferredLanguage($idiomasarray);
// Redirigimos la visita a la ruta de abajo poniéndole el código // del idioma. return $this->redirect($this->generateUrl(‘inicio’, array( ‘_locale’ => $codigoLocale ))); } /** * En esta ruta ya tenemos un código de idioma establecido, * podemos hacer a partir de aquí todo. El resto de rutas de la aplicación * deben tener la ruta de la forma «/{_locale}/resto/de/la/ruta» * para continuar navegando en el idioma actual. * * @Route («/{_locale}/», name=»inicio») * @Template */ public function inicioAction($_locale) { $manager = $this->getDoctrine()->getManager(); // Aquí tenemos ya el código de idioma en la variable especial $_locale // con esto ya podemos consultar la BD con el idioma que tenemos en curso // mostrándole al usuario todo traducido o lo que sea que necesitemos hacer.
return array(); } }
A partir de aquí ya tendremos la visita con el idioma. La variable _locale es una variable especial. Se puede consultar en las plantillas Twig poniendo en la plantilla:
{{ app.request.locale }}
La variable _locale es especial porque se establece a partir del momento en que la establecemos nosotros. Se nos puede ocurrir obtener el _locale de la aplicación con la instrucción siguiente en el controlador:
$this->getRequest()->getLocale();
Si hacemos esto en el controlador, en la ruta «iniciototal», no obtendremos el _locale del navegador, si no que obtendremos el _locale puesto en el fichero de parámetros de configuración parameters.yml. A mi me ha pasado y lleva a confusión. Podemos usar ésta última instrucción y tendremos el código de idioma actual si lo hemos establecido recibiendo el _locale en la ruta poniendo siempre al principio del resto de las rutas el _locale. Como indico en el comentario del código, usando rutas de la forma «/{_locale}/resto/de/la/ruta». Es decir, tendremos que recibir la variable {_locale} en todas las rutas para poder usar en el controlador:
$this->getRequest()->getLocale();
.. y que nos devuelva correctamente el idioma. Si lo que queremos es ver el _locale que nos pide el navegador podemos ejecutar lo siguiente:
Cada vez viene siendo más sencillo programar con Symfony. Con la última versión 2.7 LTS leo que tenemos un sencillo programa de línea de comando que nos hace aún más rápido el comenzar un nuevo proyecto.
Simplemente ejecutando lo que se ve en la imagen te creará la estructura básica de un nuevo proyecto con la última versión del framework listo para empezar a crear los bundles, las entidades, CRUDs, o lo que necesitemos.
No hay más que ejecutar desde el directorio donde lo queramos lo siguiente:
Me despido recomendando una vez más a todos los programadores web a seguir aprendiendo frameworks. Seamos productivos utilizándolos, en mi caso ha sido una buena inversión de tiempo. Y ahora que miro atrás en cómo se hacen los desarrollos web sin frameworks, o con frameworks.. Veo cada día más claro que con tanto CMS el futuro de los desarrolladores web está en utilizar frameworks. Ahí lo dejo 😉