Symfony 1.0, la guía definitiva

12.2. Eliminando elementos de la cache

Si se modifican los scripts o los datos de la aplicación, la información de la cache estará desfasada. Para evitar incoherencias y posibles errores, se pueden eliminar partes de la cache de varias formas en función de las necesidades de cada caso.

12.2.1. Borrando toda la cache

La tarea clear-cache del comando symfony se emplea para borrar la cache (la cache de HTML, de configuración y de internacionalización). Para borrar solo una parte de la cache, se pueden pasar parámetros, tal y como se muestra en el listado 12-8. Este comando solo se puede ejecutar desde el directorio raíz del proyecto.

Listado 12-8 - Borrando la cache

// Borrar toda la cache
> symfony clear-cache

// Atajo para borrar toda la cache
> symfony cc

// Borrar solo la cache de la aplicación miapp
> symfony clear-cache miapp

// Borrar solo la cache HTML de la aplicación miapp
> symfony clear-cache miapp template

// Borrar solo la cache de configuración de la aplicación miapp
> symfony clear-cache miapp config

12.2.2. Borrando partes de la cache

Cuando se modifican los datos de la base de datos, debería borrarse la cache de las acciones que tienen relación con los datos modificados. Aunque se podría borrar la cache entera, en este caso se borraría también la cache de todas las acciones que no tienen relación con los datos modificados. Por este motivo, Symfony proporciona el método remove() del objeto sfViewCacheManager. El argumento que se le pasa es una URI interna (tal y como se utilizan por ejemplo en la función link_to()) y se elimina la cache de la acción relacionada con esa URI.

Si se dispone de una acción llamada modificar en el módulo usuario, esta acción modifica el valor de los datos de los objetos Usuario. Las páginas de las acciones listado y ver de este módulo que se guardan en la cache deberían borrarse, ya que en otro caso, se mostrarían datos desfasados. Para borrar estas páginas de la cache, se utiliza el método remove() tal y como muestra el listado 12-9.

Listado 12-9 - Borrando la cache de una acción, en modules/usuario/actions/actions.class.php

public function executeModificar()
{
  // Modificar un usuario
  $id_usuario = $this->getRequestParameter('id');
  $usuario = UsuarioPeer::retrieveByPk($id_usuario);
  $this->foward404Unless($usuario);
  $usuario->setNombre($this->getRequestParameter('nombre'));
  ...
  $usuario->save();

  // Borrar la cache de las acciones relacionadas con este usuario
  $cacheManager = $this->getContext()->getViewCacheManager();
  $cacheManager->remove('usuario/listado');
  $cacheManager->remove('usuario/ver?id='.$id_usuario);
  ...
}

Eliminar de la cache los elementos parciales, los componentes y los slots de componentes es un poco más complicado. Como se les puede pasar cualquier tipo de parámetro (incluso objetos), es casi imposible identificar la versión guardada en la cache en cada caso. Como la explicación es idéntica para los 3 tipos de elementos, solo se va a explicar el proceso para los elementos parciales. Symfony identifica los elementos parciales almacenados en la cache mediante un prefijo especial (sf_cache_partial), el nombre del módulo, el nombre del elemento parcial y una clave única o hash generada a partir de todos los parámetros utilizados en la llamada a la función:

// Un elemento parcial que se llama así
<?php include_partial('usuario/mi_parcial', array('user' => $user) ?>

// Se identifica en la cache de la siguiente manera
/sf_cache_partial/usuario/_mi_parcial/sf_cache_key/bf41dd9c84d59f3574a5da244626dcc8

En teoría, es posible eliminar un elemento parcial guardado en la cache mediante el método remove() siempre que se conozca el valor de todos los parámetros utilizados en ese elemento, aunque en la práctica es casi imposible conseguirlo. Afortunadamente, si se añade un parámetro denominado sf_cache_key en la llamada del helper include_partial(), se puede definir un identificador propio para ese elemento parcial. De esta forma, y como muestra el listado 12-10, es fácil borrar un elemento parcial:

Listado 12-10 - Borrando elementos parciales de la cache

<?php include_partial('usuario/mi_parcial', array(
  'user'         => $user,
  'sf_cache_key' => $user->getId()
) ?>

// Se identifica en la cache de la siguiente forma
/sf_cache_partial/usuario/_mi_parcial/sf_cache_key/12

// Se puede borrar la cache de _mi_parcial para un usuario específico
$cacheManager->remove('@sf_cache_partial?module=usuario&action=_mi_parcial&sf_cache_key='.$user->getId());

Este método no se puede utilizar para borrar todas las versiones de un elemento parcial guardadas en la cache. Más adelante, en la sección "Borrando la cache a mano" se detalla como conseguirlo.

El método remove() también se emplea para borrar fragmentos de plantillas. El nombre que identifica a cada fragmento en la cache se compone del perfijo sf_cache_partial, el nombre del módulo, el nombre de la acción y el valor de sf_cache_key (el identificador único utilizado en la llamada al helper cache()). El listado 12-11 muestra un ejemplo.

Listado 12-11 - Borrando fragmentos de plantilla en la cache

<!-- Código guardado en la cache -->
<?php if (!cache('usuarios')): ?>
  ... // Lo que sea...
  <?php cache_save() ?>
<?php endif; ?>

// Se identifica en la cache de la siguiente forma
/sf_cache_partial/usuario/listado/sf_cache_key/usuarios

// Se puede borrar con el siguiente método
$cacheManager->remove('@sf_cache_partial?module=usuario&action=listado&sf_cache_key=usuarios');

12.2.3. Estructura del directorio de la cache

El directorio cache/ de cada aplicación tiene la siguiente estructura:

cache/                  # sf_root_cache_dir
  [nombre_aplicacion]/  # sf_base_cache_dir
    [nombre_entorno]/   # sf_cache_dir
      config/           # sf_config_cache_dir
      i18n/             # sf_i18n_cache_dir
      modules/          # sf_module_cache_dir
      template/         # sf_template_cache_dir
        [nombre_servidor]/
          all/

Las plantillas se guardan en la cache bajo el directorio [nombre_servidor] (sustituyendo los puntos por guiones bajos para mantener la compatibilidad con algunos sistemas de ficheros) y siguiendo una estructura relacionada con la URL. Por ejemplo, la plantilla de la siguiente página:

http://www.miapp.com/usuario/ver/id/12

se guarda en el siguiente directorio de la cache:

cache/miapp/prod/template/www_miapp_com/all/usuario/ver/id/12.cache

El código no debería incluir las rutas de los archivos escritas manualmente. En su lugar, se deben utilizar las constantes definidas para las rutas. Para obtener por ejemplo la ruta absoluta del directorio template/ para la aplicación y entorno actuales, se emplea sfConfig::get('sf_template_cache_dir').

Conocer la estructura de directorios es muy útil cuando se tienen que borrar manualmente partes de la cache.

12.2.4. Borrado manual de la cache

El borrado de la cache entre diferentes aplicaciones suele ser problemático. Si por ejemplo un administrador modifica los datos de la tabla usuario en la aplicación backend (la aplicación de gestión), se deberían borrar de la cache todas las acciones que dependen de ese usuario en la aplicación frontend (la aplicación pública). Como el método remove() utiliza URI internas, no se puede utilizar para borrar la cache de otras aplicaciones, ya que cada aplicación siempre se encuentra aislada de las demás y no tiene acceso a las reglas de enrutamiento del resto de aplicaciones.

La solución consiste en borrar manualmente los archivos del directorio cache/. Si la aplicación backend quiere borrar la cache de la acción usuario/ver de la aplicación frontend para el usuario cuyo id vale 12, se podría utilizar el siguiente código:

$sf_root_cache_dir = sfConfig::get('sf_root_cache_dir');
$cache_dir = $sf_root_cache_dir.'/frontend/prod/template/www_miapp_com/all';
unlink($cache_dir.'/usuario/ver/id/12.cache');

Este método de borrado no es muy convincente, ya que el comando anterior solo borra la cache del entorno actual y obliga a escribir el nombre del entorno y el nombre del servidor en la ruta del archivo. Para evitar estas molestias, se puede utilizar el método sfToolkit::clearGlob(). Este método acepta como parámetro un patrón de nombre de fichero en el que se pueden incluir comodines. El siguiente ejemplo borra de la cache los mismos archivos que el ejemplo anterior sin necesidad de especificar ni el entorno ni el nombre del servidor:

$cache_dir = $sf_root_cache_dir.'/frontend/*/template/*/all';
sfToolkit::clearGlob($cache_dir.'/usuario/ver/id/12.cache');

Este método también es muy práctico cuando se quieren borrar todas las páginas de una acción independientemente de los parámetros. Si la aplicación dispone de varios idiomas, es posible que el código del idioma aparezca en la URL. El enlace al perfil de un usuario podría tener el siguiente aspecto:

http://www.miapp.com/en/usuario/ver/id/12

Para eliminar de la cache el perfil de un usuario cuyo id vale 12 independientemente del idioma, se debe ejecutar la siguiente instrucción:

sfToolkit::clearGlob($cache_dir.'/*/usuario/ver/id/12.cache');