Sea cual sea el proyecto que acometamos, es muy posible que tengamos que gestionar entidades, usuarios, imágenes, videos, tengamos que clasificar contenidos, etc, y para eso vamos a utilizar algunos de los bundles de Sonata que nos proporcionan estas funcionalidades.
En concreto vamos a utilizar:
-
SonataAdminBundle: nor permite generar de forma rápida un backend para gestionar nuestras entidades
-
SonataUserBundle: integra el fantástico bundle FosUserBundle y nos proporciona características adicionales como roles y gestión de grupos.
-
SonataMediaBundle: nos ayudará en la gestión de toda la parte multimedia.
-
SonataClassificationBundle: lo utilizaremos para poder clasificar y etiquetar nuestras entidades.
Intención
Aunque puedes seguir la instalación de los diferentes bundles siguiendo la documentación de Sonata, he preferido documentarla en este post, por varias razones:
-
dejo así recogido en este documento la versión exacta con los bundles específicos que utilizaremos en un proyecto posterior.
-
evitar al lector tener que ir navegando por distintas páginas de los bundles relacionados, para poner el marcha el proyecto.
-
si vemos la instalación de los bundles por separado hay mucha información redundante, que en el artículo suprimo.
En cualquier caso, si hoy no te sientes especialmente trabajador :-) puedes bajar el proyecto ya configurado desde mi cuenta en github y simplemente seguir las instrucciones de instalación.
Actualmente existen dos ramas del proyecto AdminBundle, la más reciente etiquetada como estable es la 2.3 y es la que vamos a utilizar. La instalación la vamos a realizar en mi equipo actual con una distribución Linux Ubuntu 14.04 LTS pero debería funcionar en cualquier sistema capaz de poner en marcha un sistema LAMP.
Las versiones exactas de php y mysql que voy a utilizar son:
$ php --version PHP 5.5.11-3+deb.sury.org~precise+1 (cli) (built: Apr 23 2014 12:23:08) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies $ mysql --version mysql Ver 14.14 Distrib 5.5.37, for debian-linux-gnu (x86_64) using readline 6.2
¿Empezamos?
Instalaremos Sonata en una versión limpia de Symfony2, en concreto sobre la versión 2.3 LTS, para obtenerla ejecutamos:
composer create-project symfony/framework-standard-edition symfony2-sonata/ "2.3.*"
Para instrucciones más detalladas sobre una instalación de Symfony2 puedes consultar un post anterior
El instalador realizará preguntas sobre la configuración de la base de datos, introduce los válidos para tu sistema.
En el fichero composer.json agregamos:
// composer.json // … "sonata-project/doctrine-orm-admin-bundle": "2.3.*", "sonata-project/admin-bundle": "2.3.*", "sonata-project/easy-extends-bundle": "~2.1", "sonata-project/user-bundle": "~2.2", "sonata-project/intl-bundle": "~2.2", "sonata-project/media-bundle": "~2.2", "sonata-project/classification-bundle": "~2.2", "jms/serializer-bundle": "0.13.*" // ...
Ahora ejecutamos
cd symfony2-sonata composer update
y composer nos instalará el bundle y sus dependencias. Si no tienes instalado composer en su página oficial tienes información para hacerlo.
Una vez concluida la instalación hay que activar los bundles y establecer su configuración.
// app/AppKernel.php <?php public function registerBundles() { return array( // ... // Add your dependencies new Sonata\CoreBundle\SonataCoreBundle(), new Sonata\BlockBundle\SonataBlockBundle(), new Knp\Bundle\MenuBundle\KnpMenuBundle(), new FOS\UserBundle\FOSUserBundle(), new JMS\SerializerBundle\JMSSerializerBundle(), //... // If you haven't already, add the storage bundle // This example uses SonataDoctrineORMAdmin but // it works the same with the alternatives new Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle(), // Then add SonataAdminBundle new Sonata\AdminBundle\SonataAdminBundle(), new Sonata\EasyExtendsBundle\SonataEasyExtendsBundle(), new Sonata\UserBundle\SonataUserBundle('FOSUserBundle'), new Sonata\IntlBundle\SonataIntlBundle(), new Sonata\MediaBundle\SonataMediaBundle(), new Sonata\ClassificationBundle\SonataClassificationBundle(), // ... ); }
Ahora a por la configuración
Dentro de la carpeta app/config creamos un directorio llamado sonata y dentro de este creamos tres ficheros que contendrán la configuración de cada bundle, serán: sonata_block.yml, sonata_media.yml y sonata_classification.yml:
// app/config/sonata/sonata_admin.yml sonata_admin: title: Backend project
// app/config/sonata/sonata_block.yml sonata_block: default_contexts: [cms] blocks: # Enable the SonataAdminBundle block sonata.admin.block.admin_list: contexts: [admin]
// app/config/sonata/sonata_media.yml sonata_media: default_context: default db_driver: doctrine_orm # or doctrine_mongodb, doctrine_phpcr contexts: default: # the default context is mandatory providers: - sonata.media.provider.dailymotion - sonata.media.provider.youtube - sonata.media.provider.image - sonata.media.provider.file formats: small: { width: 100 , quality: 70} big: { width: 500 , quality: 70} cdn: server: path: /uploads/media # http://media.sonata-project.org/ filesystem: local: directory: %kernel.root_dir%/../web/uploads/media create: true providers: image: resizer: sonata.media.resizer.square
// app/config/sonata/sonata_classification.yml sonata_classification:
luego en app/config.yml importamos el contenido en app/config/config.yml
imports: // ... # Sonata conf - { resource: sonata/sonata_admin.yml } - { resource: sonata/sonata_block.yml } - { resource: sonata/sonata_media.yml } - { resource: sonata/sonata_classification.yml } // ...
En el mismo config.yml hay que agregar el tipo Json en su sección correspondiente e informar a doctrine para que maneje las entidades, le activaremos el auto_mapping para que trate las nuevas entidades de forma automática
doctrine:
// ... doctrine: dbal: // ... types: json: Sonata\Doctrine\Types\JsonType orm: auto_generate_proxy_classes: "%kernel.debug%" default_entity_manager: default entity_managers: default: auto_mapping: true // ...
Siguiendo en el mismo fichero hay agregar la configuración del bundle de gestión de usuarios, FosUserBundle:
# app/config/config.yml fos_user: db_driver: orm # can be orm or odm firewall_name: main user_class: Sonata\UserBundle\Entity\BaseUser group: group_class: Sonata\UserBundle\Entity\BaseGroup group_manager: sonata.user.orm.group_manager # If you're using doctrine orm (use sonata.user.mongodb.user_manager for mongodb) service: user_manager: sonata.user.orm.user_manager # If you're using doctrine orm (use sonata.user.mongodb.group_manager for mongodb)
Cargar rutas.
Ahora toca exponer las rutas de cada bundle, para ello debemos agregarlas al fichero de configuración correspondiente:
# app/config/routing.yml // ... admin: resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml' prefix: /admin _sonata_admin: resource: . type: sonata_admin prefix: /admin sonata_user_security: resource: "@SonataUserBundle/Resources/config/routing/sonata_security_1.xml" sonata_user_resetting: resource: "@SonataUserBundle/Resources/config/routing/sonata_resetting_1.xml" prefix: /resetting sonata_user_profile: resource: "@SonataUserBundle/Resources/config/routing/sonata_profile_1.xml" prefix: /profile sonata_user_register: resource: "@SonataUserBundle/Resources/config/routing/sonata_registration_1.xml" prefix: /register sonata_user_change_password: resource: "@SonataUserBundle/Resources/config/routing/sonata_change_password_1.xml" prefix: /profile sonata_user: resource: '@SonataUserBundle/Resources/config/routing/admin_security.xml' prefix: /admin gallery: resource: '@SonataMediaBundle/Resources/config/routing/gallery.xml' prefix: /media/gallery media: resource: '@SonataMediaBundle/Resources/config/routing/media.xml' prefix: /media
SonataAdminBundle viene con una gestión de roles propia, además hay que informar a Symfony de las nuevas reglas de control de acceso para proteger la gestión del backend, para ello hay que modificar el fichero security.yml. Así es como ha quedado mi fichero.
// app/config/security.yml security: encoders: FOS\UserBundle\Model\UserInterface: sha512 access_control: # URL of FOSUserBundle which need to be available to anonymous users - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } # Admin login page needs to be access without credential - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY } # Secured part of the site # This config requires being logged for the whole site and having the admin role for the admin part. # Change these rules to adapt them to your needs - { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] } - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY } role_hierarchy: ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN] ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] SONATA: - ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT # if you are using acl then this line must be commented providers: fos_userbundle: id: fos_user.user_manager firewalls: # Disabling the security for the web debug toolbar, the profiler and Assetic. dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false # -> custom firewall for the admin area of the URL admin: pattern: /admin(.*) context: user form_login: provider: fos_userbundle login_path: /admin/login use_forward: false check_path: /admin/login_check failure_path: null logout: path: /admin/logout anonymous: true # -> end custom configuration # default login area for standard users # This firewall is used to handle the public login area # This part is handled by the FOS User Bundle main: pattern: .* context: user form_login: provider: fos_userbundle login_path: /login use_forward: false check_path: /login_check failure_path: null logout: true anonymous: true
Extendiendo el bundle
Para poder modificar de forma adecuada el comportamiento de los bundles podemos utilizar los mecanismos que proporciona Symfony2 para poder sobreescribir controladores y configuración, puedes ver información aquí y aquí. Felizmente Sonata nos proporciona un comando que nos facilita este trabajo.
php app/console sonata:easy-extends:generate SonataUserBundle -d src php app/console sonata:easy-extends:generate SonataMediaBundle -d src php app/console sonata:easy-extends:generate SonataClassificationBundle -d src
Este comando extiende cada bundle de Sonata moviendo la configuración de las mismos en un espacio de nombres accesible bajo la carpeta src\Application, facilitando agregar nuevos campos en las entidades o modificar configuraciones.
En la configuración inicial informamos a FosUser que utilizara las clases de usuario y grupo bases de Sonata, ahora hay que actualizar estos datos para que utilice las clases recién extendidas.
Abrimos app/config/config.yml y modificamos las clases para user_clas y group_class:
// app/config/config.yml fos_user: user_class: Application\Sonata\UserBundle\Entity\User // ... group: group_class: Application\Sonata\UserBundle\Entity\Group // ...
Todavía queda activar estos nuevos bundles en el kernel:
<?php // AppKernel.php class AppKernel { public function registerbundles() { return array( // ... // SonataApplication Bundles new Application\Sonata\UserBundle\ApplicationSonataUserBundle(), new Application\Sonata\MediaBundle\ApplicationSonataMediaBundle(), new Application\Sonata\ClassificationBundle\ApplicationSonataClassificationBundle(), // ... ) } }
Como todo ha ido bien, ahora sólo queda crear y actualizar la base de datos:
Instalamos los recursos con:
app/console assets:install web --symlink app/console doctrine:database:create app/console doctrine:schema:update --dump-sql --force
Control de acceso
En pantallas anteriores modificamos el fichero security.yml para proteger el acceso al backend, pues bien ahora es necesario agregar un usuario administrador al sistema para poder autenticarnos en el mismo:
app/console fos:user:create admin --super-admin
Configurar host
Hasta aquí la configuración básica. En estos momentos sólo quedaré configurar un virtual host en apache para poder acceder y ver el proyecto en marcha.
sudo vim /etc/apache2/sites-available/030-symfony-sonata.conf
<VirtualHost *:80> ServerName local.sonatablog.es ServerAdmin adminl@mysite.com DocumentRoot "/var/www/html/test/symfony2-sonata/web" <Directory "/var/www/html/test/symfony2-sonata/web"> Options Indexes FollowSymLinks MultiViews AllowOverride None allow from all <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ app_dev.php [QSA,L] </IfModule> </Directory> </VirtualHost>
Activar el virtual host:
sudo a2ensite 030-symfony-sonata.conf
Y editar nuestro host para que resuelva:
sudo vim /etc/hosts
127.0.0.1 local.sonatablog.es
Finalizando
Si ahora accedemos a http://local.sonatablog.es/app_dev.php/admin debemos ver el dashboard de Sonata. Es hora de tomar un descanso, enviar un whatsapp a nuestros amigos y salir juntos a tomarnos un café con leche con pincho de tortilla por el trabajo bien hecho.
* Es posible que veas que las traducciones en el backend no están actuando, si es tu caso fíjate que tengas activado el servicio translator:
# app/config/config.yml framework: translator: { fallback: "%locale%" }
Creo que ha sido bastante trabajo por hoy. Si deseas estar al tanto de los próximos post sígueme en twitter recuerda también que puedes bajar el proyecto desde github.
Si eres impaciente y quieres seguri avanzando, lo siguiente sería trabajar con entidades propias y configurarlas para que se muestren en el backend, para ello puedes estudiar la documentación de SonataAdminBundle, concretamente el apartado "2.2 STEP 2: CREATE AN ADMIN CLASS".
Hasta la próxima.