Aprende Symfony2 (Parte 2): Aplicación vacía

1 de octubre de 2014

Este es el segundo artículo de la serie para aprender a programar con el framework Symfony. En el primer artículo empezamos creando nuestro proyecto vacío con los siguientes archivos:

.
├── composer.json
├── composer.lock
└── .gitignore

Al ejecutar el comando composer install se debería crear el directorio vendor/, que hemos ignorado en Git. Si lo necesitas, echa un vistazo al repositorio de código público en el que estamos desarrollando la aplicación. Veamos cómo crear una aplicación Symfony2 vacía.

El controlador frontal

Empecemos por el principio: vamos a crear un archivo que actuará como controlador frontal. En otras palabras, este archivo será el único punto de entrada a nuestra aplicación y decidirá qué página mostrar.

Creemos su directorio:

$ mkdir web

Después, crea un archivo llamado app.php con el siguiente contenido:

<?php
// web/app.php

use Symfony\Component\HttpFoundation\Request;

require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/../app/AppKernel.php';

$kernel = new AppKernel('prod', false);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Primero incluímos el autoloader o cargador automático de clases de Composer, que se encarga de incluir todos los archivos necesarios en la aplicación.

Después creamos una instancia de nuestro kernel, en el entorno de producción y con las herramientas de debug o depuración deshabilitadas. Esta clase actúa como un servidor web: recibe una petición HTTP y devuelve una respuesta HTTP.

Request::createFromGlobals() crea un objecto PHP que representa a la petición HTTP. El objeto se rellena con la información contenida originalmente en las variables superglobales de PHP ($_GET, $_POST, etc).

Después el kernel se hace cargo de la petición. Para no entrar en muchos detalles, diremos que lo que hace es encontrar el controlador asociado a la URL solicitada. Es responsabilidad del controlador frontal devolver un objeto (de tipo Symfony\Component\HttpFoundation\Response) que represente a la respuesta HTTP.

El método $response->send() simplemente llama a la función header() de PHP, e imprime una cadena de texto que será el contenido de la respuesta (normalmente HTML, JSON o lo que tú quieras).

Finalmente, el método $kernel->terminate() ejecuta cualquier tarea asociada al evento kernel.terminate. Esto te permite responder al usuario tan rápido como sea posible y después de enviar la respuesta, seguir ejecutando tareas y código, como por ejemplo enviar emails.

NOTA El concepto de los eventos Symfony no se trata en este artículo por ser demasiado avanzado, pero nos parecía conveniente al menos mencionarlos.

Creando el kernel de la aplicación

El componente HttpKernel nos da la clase Kernel, de la que extenderemos para crear el núcleo o kernel de nuestra propia aplicación.

Comienza creando el siguiente directorio:

$ mkdir app

Y después crea el archivo del AppKernel con el siguiente contenido:

<?php
// app/AppKernel.php
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        return array(
            new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
        );
    }

    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        $loader->load(__DIR__.'/config/config.yml');
    }
}

Esta clase carga la configuración del proyecto. También es aquí donde registrarás los bundles del proyecto. Hablaremos más sobre bundles en el próximo artículo. Por ahora lo único que necesitas saber es que son una especie de plugins.

El kernel tiene la responsabilidad de buscar todos los bundles registrados para obtener su configuración.

El bundle FrameworkBundle define algunos servicios que te permiten elegir qué activar desde la configuración.

NOTA Los servicios son objetos que tienen una única responsabilidad.Ofrecen exactamente lo que prometen: un servicio. Aprenderemos más sobre ellos en uno de los próximos artículos.

Para que el kernel funcione correctamente, debemos crear un archivo de configuración.

Primero crea el directorio config:

$ mkdir app/config

Y después, crea el archivo config.yml con el siguiente contenido:

# app/config/config.yml
framework:
    secret: "El valor de esta opción debe ser una cadena aleatoria."

El parámetro secret se usa como semilla para generar cadenas aleatorias (por ejemplo tokens CSRF para proteger a los formularios de las aplicaciones web).

Ahora que tenemos la estructura de nuestra aplicación, hagamos un commit al repositorio:

$ git add -A
$ git commit -m 'Creada la estructura básica de la aplicación'

Logs y caché

Para completar la aplicación, crea también los directorios logs y cache:

$ mkdir app/{cache,logs}
$ touch app/{cache,logs}/.gitkeep

Git no permite subir al repositorio directorios vacíos. Por eso tenemos que crear los archivos .gitkeep. Dado que los archivos en estos directorios no deben subirse al repositorio de código, los ignoraremos:

$ echo '/app/cache/*' >> .gitignore
$ echo '/app/logs/*' >> .gitignore
$ git add -A
$ git add -f app/cache/.gitkeep
$ git add -f app/logs/.gitkeep
$ git commit -m 'Directorios temporales creados'

Configuración de Apache

Para que tu sitio sea accesible, necesitarás configurar tu servidor web. El proceso está muy bien explicado en la documentación, así que esta es la pinta que tiene un virtual host de Apache para Symfony:

<VirtualHost *:80>
    ServerName knight.local

    DocumentRoot /home/loic.chardonnet/Projects/gnugat/knight/web

    ErrorLog "/home/loic.chardonnet/Projects/gnugat/knight/app/logs/apache_errors.log"
    CustomLog "/home/loic.chardonnet/Projects/gnugat/knight/app/logs/apache_accesses.log" common

    <Directory /home/loic.chardonnet/Projects/gnugat/knight/web>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        allow from all

        <IfModule mod_rewrite.c>
            RewriteEngine On
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteRule ^(.*)$ /app.php [QSA,L]
        </IfModule>
    </Directory>
</VirtualHost>

Si te encuentras con problemas de permisos (como no poder escribir en cache/ y logs/), puede que quieras cambiar las variables de entorno APACHE_RUN_USER y APACHE_RUN_GROUP, presentes en /etc/apache2/envvars, por tu propio usuario y su grupo.

Conclusión

Una aplicación Symfony2 sigue este patrón: un controlador frontal asocia una URL a un controlador, que recoge una petición HTTP y devuelve una respuesta HTTP.

El siguiente artículo va sobre bundles, así que permanece atento.

Sobre el autor

Este artículo fue publicado originalmente por Loïc Chardonnet y ha sido traducido con permiso por Manuel Gómez.

Artículos de la serie Aprende Symfony