El IDE que utilizamos para programar es algo bastante personal pero lo cierto es que un buen entorno de desarrollo puede ayudarnos en nuestro día a día a ser más productivos y a programar con mayor rapidez. Para PHP podemos utilizar diferentes IDEs como pueden ser NetBeans, Sublime Text 2, PHPStorm, etc.
Eclipse suele ser más utilizado para lenguajes de programación tipo JAVA, pero lo cierto es que es un IDE bastante potente y se puede adaptar a cualquier lenguaje de programación gracias a la gran cantidad de plugins que hay disponibles. En este post voy a explicar como configurar Eclipse para utilizarlo cuando estemos desarrollando con Symfony2.
Evidentemente, lo primero que debemos hacer es descargarnos el IDE desde la propia web oficial de Eclipse. En este caso vamos a utilizar la versión Eclipse Classic (en este momento, versión 4.2).
Ahora vamos a descargarnos el plugin creado por Robert Gründler para ayudarnos en la programación con Symfony2. Algunas de las ventajas que obtendremos con este plugin son:
- Asistente de código para elementos específicos de Symfony2, como los servicios, rutas, entities, traducciones, bloques de Twig, etc.
- Navegación: Con un click podremos ir rapidamente a rutas, plantillas, bloques/funciones/filtros de Twig, servicios, etc.
- Soporte para anotaciones
- Soporte para Twig
Por si esto fuera poco, se incluyen plugins de terceros que nos seguirán facilitando el trabajo:
- Plugin para editar archivos Yaml.
- Asistente de código para Doctrine.
- Generador de setters/getters.
- Plugin de composer
Este plugin lo podemos encontrar en http://symfony.dubture.com/. La forma más fácil de instalarlo es desde el propio Eclipse, por lo que vamos a Help > Install new software y pulsamos sobre el botón “Add”. En name escribimos “Symfony2 Eclipse Plugin” y en location escribimos esta url: http://p2.dubture.com.
Seleccionamos todos los paquetes que aparecen y los instalamos.
Algo que también nos puede resultar de mucha ayuda es tener una consola directamente integrada en Eclipse. Esto lo podemos conseguir con el plugin Wickedshell. Para instalarlo lo haremos de la manera habitual: Help > Install new software, pulsamos el botón “Add” y como nombre de escribimos “Consola Wickedshell” y como url http://www.wickedshell.net/updatesite.
Cuando lo instalemos, tendremos una consola integrada en el propio Eclipse:
Por último y no menos importante, es cambiar la apariencia de Eclipse e instalar un theme con el que nos encontremos más a gusto programando. Para ello vamos a instalar el plugin que encontraremos en http://eclipsecolorthemes.org/ con varios themes ya disponibles para su utilización.
Lo instalamos como en pasos anteriores: Help > Install new software, pulsamos el botón “Add” y como nombre de escribimos “Eclipse Color Themes” y como url http://eclipse-color-theme.github.com/update/.
Ya solo nos queda seleccionar el theme que mejor se adapte a nosotros:
Etiquetas: composer, doctrine, eclipse, ide, php, plugin, Symfony2, twig, yaml
En las entidades de Symfony2 es sencillo relacionar un campo con otra tabla con una relación ManyToOne y que este campo solo pueda tomar un valor que esté disponible en la segunda entity. Si creamos un formulario para poder introducir nuevos registros en la base de datos, necesitamos un campo del tipo select para seleccionar uno de los datos de la segunda tabla y relacionarlos.
Deberemos modificar el formulario y añadirle un par de opciones más. En este ejemplo, vamos a relacionar un usuario con su país.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | namespace Acme\MiBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilder; class PerfilType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder->add('pais', 'entity', array( 'class' => 'AcmeMiBundle:Pais' 'label' => 'Pais', ) ); } } |
Que no se nos olvide añadir el método __toString() a la entity Pais:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace Acme\MiBundle\Entity; use Doctrine\ORM\Mapping as ORM; class Pais { [...] public function __toString() { return $this->getNombre(); } } |
Y así de sencillo, ahora en nuestra plantilla aparecerá automáticamente el campo de tipo select a la hora de seleccionar el país del usuario.
Etiquetas: AbstractType, entity, formularios, select, Symfony2
He creado dos bundles, uno llamado UserBundle y otro ProfileBundle. El bundle UserBundle es totalmente independiente y reutilizable en cualquier proyecto (contando con funcionalidades tales como registro, login, logout, recordar contraseña, confirmar usuario mediante email, etc.) con la única pega de que solamente se guardan el email y la contraseña del usuario. Hay proyectos que solo requieren estos datos y no merece la pena “ensuciarlo” con más.
El bundle ProfileBundle subsana esta limitación y otorga al usuario un perfil con su nombre, apellidos, etc. El registro se hace desde el UserBundle y, una vez logueado en la aplicación, completas tu perfil de usuario mediante el ProfileBundle.
Al terminar de completar tu perfil y pulsar el botón guardar, el usuario logueado se recarga con los nuevos datos introducidos. Al hacer esto, me aparecía el siguiente error:
You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine. |
Y en otras ocasiones también se mostraba este otro error:
Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken::serialize() must return a string or NULL |
La solución es sencilla y solo hay que fijarse en el mensaje de error. Si el usuario se va a recargar una vez ya está logueado, la entidad Usuario debe implementar la clase Serializable y definir sus métodos serialize() y unserialize().
En diferentes blogs que hablan sobre Symfony2, en los métodos serialize y unserialize hacen uso del método getUsername() lo cual puede ser un error. Lo muestro con un ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class User implements UserInterface, \Serializable { /** * @var integer $id * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string $email * * @ORM\Column(name="email", type="string", length=255, unique=true) * @Assert\Email() */ private $email; [...] function getUsername() { return $this->getEmail(); } public function serialize() { return serialize($this->getUsername()); } public function unserialize($data) { $this->email = unserialize($data); } } |
En el ejemplo anterior vemos que la propiedad $email no es la clave primaria y, aunque hayamos marcado que es única, nos seguirá apareciendo el error anterior ya que Doctrine necesita que el refresh del usuario se haga mediante su identificador único (en algún caso podría llegar a ser el email, pero no en este ejemplo).
Solamente tendremos que cambiar el código anterior por este:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class User implements UserInterface, \Serializable { /** * @var integer $id * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string $email * * @ORM\Column(name="email", type="string", length=255, unique=true) * @Assert\Email() */ private $email; [...] function getUsername() { return $this->getEmail(); } public function serialize() { return serialize($this->getId()); } public function unserialize($data) { $this->id = unserialize($data); } } |
El código anterior se puede optimizar y se podrían añadir más propiedades a los métodos serialize y unserialize (se podrían utilizar en conjunto las propiedades id, email, etc.).
Etiquetas: bundle, doctrine2, EntityUserProvider, error, serializable, serialize, Symfony2, unserialize, UserInterface
He estado desarrollando mi propio bundle para el registro de usuarios en Symfony2 y me he encontrado con el problema de querer añadir campos al formulario de registro que no he definido en el modelo. Uno de estos campos es un checkbox para aceptar los términos de uso de la aplicación. No me interesa guardar este campo en la base de datos por lo que no está definido en el modelo.
Así es como lo he hecho:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class RegisterFormType extends AbstractType { public function buildForm(FormBuilder $builder, array $options) { $builder ->add('email', 'email') ->add('password', 'repeated', array( 'type' => 'password', 'invalid_message' => 'Las dos contraseñas deben coincidir', 'options' => array('label' => 'Contraseña'), 'required' => false)) ->add("accept_tos", "checkbox", array( "property_path" => false, ) ); $builder ->addValidator(new CallbackValidator(function(FormInterface $form){ if (!$form["accept_tos"]->getData()) { $form->addError(new FormError('Debes aceptar los términos de uso')); } }) ); } } |
Como vemos, añadimos un campo checkbox con nombre “accept_tos” y le indicamos la opción “property_path” a false, por lo que no validará este campo con el modelo. Eso sí, debemos añadir un validador para este campo para asegurarnos de que el usuario acepta las condiciones de uso.
Fuente: http://www.richsage.co.uk/2011/07/20/adding-non-entity-fields-to-your-symfony2-forms/
Etiquetas: addValidator, buildForm, bundle, CallbackValidator, formularios, property_path, Symfony2
¿Cómo se puede desloguear un usuario sin tener que acceder a la ruta correspondiente del logout? Para algunas funcionalidades que queramos añadir a nuestro proyecto, es posible que necesitemos desloguear al usuario. Un ejemplo podría ser el caso de desactivar/borrar su cuenta, pero puede que haya más (todo depende de nuestra imaginación
). Vamos a ver como hacerlo con Symfony2.
$this->get("request")->getSession()->invalidate(); $this->get("security.context")->setToken(null); |
Como extra, podemos informar al usuario mediante un mensaje flash y le redirigimos a la página que queramos:
$this->get("session")->setFlash('message.success', true); return new RedirectResponse($this->generateUrl('homepage')); |
Evidentemente, la página a la que vamos a redirigir tiene que poder ser vista por usuarios anónimos (no debe necesitar autentificación).
Pd.: Ya escribí como Instalar Symfony2 desde cero
Etiquetas: logout, redirect, RedirectResponse, setFlash, Symfony2
En el grupo de Symfony2 hay una gran cantidad de preguntas entre las que, de vez en cuando, podemos encontrar un buen hilo donde se trata un tema interesante. Entre tanta “paja” (preguntas fáciles de responder solamente leyendo la documentación) es posible que pasemos por alto alguna de estas buenas preguntas junto a sus respuestas.
Voy a intentar recopilar este tipo de hilos y traducirlos al castellano, siempre dejando el enlace al hilo original del grupo de Symfony2 por si hay alguna nueva respuesta.
Para empezar, podemos encontrar como utilizar Sphinx haciendo uso de la api como un servicio en Symfony2.
1) Nos descargamos la api de Sphinx de la página oficial http://sphinxsearch.com/, colocándolo en la carpeta vendor/sphinx-client. Debemos renombrar la clase a SphinxClient.
2) Lo añadimos en el autoload.php
$loader->registerPrefixes(array( // ... 'Sphinx' => __DIR__.'/../vendor/sphinx-client', )); |
3) Añadimos Sphinx como servicio de Symfony2 en el fichero config.yml
services: search: class: SphinxClient calls: - [setArrayResult, [true]] - [setLimits, [0, 20, 1000]] |
4) Por último, podemos hacer uso del servicio desde el controlador de esta forma:
$search = $this->get('search'); $results = $search->Query($search_terms, 'myindex'); |
Evidentemente deberemos leer la documentación de Sphinx para instarlo y configurarlo correctamente. La página oficial es bastante completa en ese sentido.
Hilo original: doctrine2 and sphinx
Etiquetas: autoload, controlador, doctrine2, servicio, sphinx, Symfony2
Nos vamos acercando inevitablemente al cambio de Symfony 1.x a Symfony2 y la conclusión que he sacado de mi asistencia al evento #desymfony es que cuanto antes nos pongamos con ello, mucho mejor. Symfony2 mejora a su predecesor en numerosos aspectos y se convertirá en el framework definitivo para el desarrollo de aplicaciones web en el futuro. Si quieres saber todas las nuevas características de esta versión, te recomiendo que visites la web oficial de Symfony2: http://symfony.com/.
En este primer post procederemos a su instalación. Personalmente, me gusta programar en local (en mi propio ordenador) y una vez haya acabado con el desarrollo o quiera probarlo en un entorno de producción, hacer el deploy a un servidor real. Por ello, primero voy a explicar como configurar un servidor web en nuestro ordenador y después procederemos con la instalación de Symfony2.
La instalación la voy a hacer en un entorno Linux con la distribución Ubuntu 11.04. Adaptar los comandos según nuestra distribución (o sistema operativo).
1) Primero instalamos Apache
# apt-get install apache2 apache2.2-common apache2-utils ssl-cert apache2-mpm-prefork |
2) Instalamos y habilitamos el módulo para utilizar modrewrite
# apt-get install libapache2-mod-proxy-html |
Para habilitar el modulo en apache, ejecutamos:
# a2enmod rewrite |
3) Instalamos PHP5
# apt-get install php5 libapache2-mod-php5 php5-common php5-intl |
4) Instalamos Mysql
# apt-get install mysql-server mysql-client php5-mysql |
5) Por último instalamos phpmyadmin (opcional)
# apt-get install phpmyadmin |
Con estos sencillos pasos ya tendremos un servidor web instalado en nuestro ordenador.
Ahora continuamos con la instalación de Symfony2. Mi IDE favorito para programar es Netbeans, por lo que es el que utilizaré en este ejemplo. Si no lo hemos cambiado, nuestro workspace (donde se encuentran los proyectos a los que podemos acceder desde Netbeans) lo encontraremos en la carpeta NetBeansProjects en nuestra carpeta Home.
Procedemos a crear una nueva carpeta con el nombre de nuestro proyecto en el workspace de Netbeans:
$ mkdir $HOME/NetBeansProjects/miproyecto |
Entramos en la carpeta que acabamos de crear:
$ cd $HOME/NetBeansProjects/miproyecto |
Descargamos Symfony2 (comprueba la última versión en http://symfony.com/download):
$ wget http://symfony.com/download?v=Symfony_Standard_Vendors_2.0.0-RC4.tgz |
Y descomprimimos:
$ tar zxvf Symfony_Standard_Vendors_2.0.0-RC4.tgz |
Borramos el archivo comprimido que hemos descargado:
$ rm Symfony_Standard_Vendors_2.0.0-RC4.tgz |
Ya tenemos instalado un proyecto básico en Symfony2. Ahora vamos a configurar Apache para poder acceder desde nuestro navegador favorito.
Creamos un nuevo archivo donde irá la configuración de nuestra web:
# vi /etc/apache2/sites-available/miproyecto |
Que contendrá el siguiente contenido (cambia “jonseg” por el nombre de tu carpeta Home):
<VirtualHost *:80> ServerAdmin email@email.com DocumentRoot /home/jonseg/NetBeansProjects/miproyecto/Symfony/web ServerName miproyecto.com ServerAlias *.miproyecto.com ErrorLog /var/log/apache2/miproyecto_error.log CustomLog /var/log/apache2/miproyecto_access.log common DirectoryIndex index.php <Directory "/home/jonseg/NetBeansProjects/miproyecto/Symfony/web"> Options Indexes FollowSymLinks Order Allow,Deny Allow from all AllowOverride all <IfModule mod_php5.c> php_admin_flag engine on php_admin_flag safe_mode off php_admin_value open_basedir none </ifModule> </Directory> </VirtualHost> |
Creamos un enlace simbólico de este archivo en sites-enabled para indicar que es una web activa:
# ln -s /etc/apache2/sites-available/miproyecto /etc/apache2/sites-enabled/miproyecto |
Para que se apliquen los cambios, reiniciamos el servidor Apache:
# /etc/init.d/apache2 restart |
Por último, forzamos en el archivo /etc/hosts la ip de nuestra web, que en este caso será localhost o 127.0.0.1
# vim /etc/hosts |
Y añadimos esta línea al final del fichero:
127.0.0.1 www.miproyecto.com miproyecto.com |
Después de todo esto, ya podremos acceder a nuestro nuevo proyecto en Symfony2 desde el navegador escribiendo la url que hemos configurado.
Como primer paso, debemos comprobar si cumplimos con la configuración básica para que funcione nuestro proyecto. Lo haremos desde la siguiente url:
http://miproyecto.com/config.php
Como vemos, nos encontramos con dos problemas (podríamos tener más, deberemos resolverlos según sea necesario). En este caso el error es que las carpetas app/cache y app/logs no tienen los permisos necesarios.
Lo arreglaremos así:
chmod 777 $HOME/NetBeansProjects/miproyecto/Symfony/app/cache chmod 777 $HOME/NetBeansProjects/miproyecto/Symfony/app/logs |
Una vez arreglados los problemas, ya podemos acceder a nuestro proyecto web con Symfony2 mediante esta url:
http://miproyecto.com/app_dev.php/
En próximos artículos nos iremos adentrando poco a poco en el desarrollo de Bundles, las plantillas con Twig, etc.
Cualquier duda, en los comentarios!
Etiquetas: localhost, netbeans, php, servidor, Symfony, Symfony2