Estas en: Home > symfony

Entradas etiquetadas con symfony

Symfony: El controlador (I)

0

Continuo dándole caña a Symfony. Ahora toca el controlador.

¿Qué hace el controlador? Pues lo siguiente:

  • El controlador frontal es el único punto de entrada a la aplicación. Carga la configuración y determina la acción a ejecutarse.
  • Las acciones contienen la lógica de la aplicación. Verifican la integridad de las peticiones y preparan los datos requeridos por la capa de presentación.
  • Los objetos request, response y session dan acceso a los parámetros de la petición, las cabeceras de las respuestas y a los datos persistentes del usuario. Se utilizan muy a menudo en la capa del controlador.
  • Los filtros son trozos de código ejecutados para cada petición, antes o después de una acción. Por ejemplo, los filtros de seguridad y validación son comúnmente utilizados en aplicaciones web. Puedes extender el framework creando tus propios filtros.

EL CONTROLADOR FRONTAL

http://localhost/index.php/mimodulo/miAccion

La URL de arriba es un ejemplo de que tarea realiza el controlador frontal. En este caso nuestro controlador frontal es el archivo index.php que se encargará de ejecutar miAccion de mimodulo y generar la página que mostrará al usuario.

EL TRABAJO DEL CONTROLADOR EN DETALLE

Estas son las tareas que ejecuta el controlador antes de que se muestre la página al usuario:

  1. Carga la clase de configuración del proyecto y las librerías de Symfony.
  2. Crea la configuración de la aplicación y el contexto de Symfony.
  3. Carga e inicializa las clases del núcleo del framework.
  4. Carga la configuración.
  5. Decodifica la URL de la petición para determinar la acción a ejecutar y los parámetros de la petición.
  6. Si la acción no existe, redireccionará a la acción del error 404.
  7. Activa los filtros (por ejemplo, si la petición necesita autenticación).
  8. Ejecuta los filtros, primera pasada.
  9. Ejecuta la acción y produce la vista.
  10. Ejecuta los filtros, segunda pasada.
  11. Muestra la respuesta.

index.php, EL CONTROLADOR FRONTAL POR DEFECTO

Este archivo se encuentra en la carpeta /web del proyecto y contiene el siguiente código:

[codesyntax lang=»php»]

<?php    

  require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');

  $configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
  sfContext::createInstance($configuration)-&gt;dispatch();

[/codesyntax]

Lo que hace es simple, carga el archivo de la clase de configuración, llama a la clase y despacha la petición usando el método dispatch() de la clase sfContext.

Podemos crear otros controladores frontales simplemente copiando el archivo y modificando el segundo parámetro del método getApplicationConfiguration().

Para ello copiaremos el código del archivo index.php a frontend_staging.php y sustituiremos el segundo parámetro del método getApplicationConfiguration() que en vez de ser prod (de producción), será staging. Utilizaremos este controlador para que el cliente pueda probar la aplicación antes de ponerla en producción.

Una vez hecho esto modificaremos el archivo app.yml en la carpeta /config de la aplicación (en este caso sería /frontend/config) como sigue:

[codesyntax lang=»php»]

staging:
  mail:
    webmaster: falso@misitio.com
    contacto: falso@misitio.com
all:
  mail:
    webmaster: webmaster@misitio.com
    contacto: contacto@mysite.com

[/codesyntax]

Ahora solo tienes que escribir la siguiente URL para ver como se comporta el nuevo controlador frontal:

http://localhost/frontend_staging.php/mimodulo/index

LAS ACCIONES

[codesyntax lang=»php»]

<?php

class mimoduloActions extends sfActions
 {
   public function executeIndex()
   {
     // ...
   }
 }

[/codesyntax]

Las acciones son métodos de una clase que hereda de sfActions y se encuentran agrupadas por módulos. Esta clase se encuentra en el archivo actions.class.php en la carpeta /actions del módulo.

Para añadir más acciones sólo es necesario añadir más métodos execute al objeto sfActions:

[codesyntax lang=»php»]

<?php

class mimoduloActions extends sfActions
{
  public function executeIndex()
  {
    // ...
  }

  public function executeListar()
  {
    // ...
  }
}

[/codesyntax]

Y para ver en el navegador estas acciones sólo habría que escribir:

Para executeIndex() -> http://localhost/frontend_dev.php/mimodulo/index
Para executeListar() -> http://localhost/frontend_dev.php/mimodulo/listar

 

SEPARANDO LAS ACCIONES EN ARCHIVOS DIFERENTES

Para crear acciones de un mismo módulo en archivos diferentes se debe crear una clase que extienda sfAction (en vez de sfActions que utilizabamos anteriormente), en un archivo llamado nombreAccionAction.class.php y el nombre del método en cada archivo será, simplemente, execute.

[codesyntax lang=»php» title=»Archivo de una sola acción, en frontend/modules/mimodulo/actions/indexAction.class.php»]

<?php

class indexAction extends sfAction
{
  public function execute($peticion)
  {
    // ...
  }
}

[/codesyntax]

[codesyntax lang=»php» title=»Archivo de una sola acción, en frontend/modules/mimodulo/actions/listAction.class.php»]

<?php

class listarAction extends sfAction
{
  public function execute($peticion)
  {
    // ...
  }
}

[/codesyntax]

 

OBTENIENDO INFORMACIÓN DE LAS ACCIONES

sfActions proporciona acceso a sfContext::createInstance() a través de getContext() que devuelve un objeto que guarda una referencia de todos los objetos del núcleo de symfony relacionados con la petición dada:

[codesyntax lang=»php» title=»Métodos comunes de sfActions»]

<?php

class mimoduloActions extends sfActions
{
  public function executeIndex($peticion)
  {
    // Obteniendo parametros de la petición
    $password      = $peticion->getParameter('password');

    // Obteniendo información del controlador
    $nombreModulo  = $this->getModuleName();
    $nombreAccion  = $this->getActionName();

    // Obteniendo objetos del núcleo del framework
    $sesionUsuario = $this->getUser();
    $respuesta     = $this->getResponse();
    $controlador   = $this->getController();
    $contexto      = $this->getContext();

    // Creando variables de la acción para pasar información a la plantilla
    $this->setVar('parametro', 'valor');
    $this->parametro = 'valor';           // Versión corta.
  }
}

[/codesyntax]

  • sfController: El objeto controlador (->getController())
  • sfRequest: El objeto de la petición (->getRequest())
  • sfResponse: El objeto de la respuesta (->getResponse())
  • sfUser: El objeto de la sesión del usuario (->getUser())
  • sfDatabaseConnection: La conexión a la base de datos (->getDatabaseConnection())
  • sfLogger: El objeto para los logs (->getLogger())
  • sfI18N: El objeto de internacionalización (->getI18N())

Se puede llamar al método sfContext::getInstance() desde cualquier parte del código.

 

TERMINACIÓN DE LAS ACCIONES

Normalmente cuando finalizamos un método o función y queremos devolver algún dato utilizamos la palabra return seguida de alguna variable u objeto. En Symfony es más o menos igual, me explico:

Symfony, una vez a procesado la acción, enviará los datos a la plantilla para que el usuario pueda visualizarlo. Por defecto, Symfony siempre utiliza return sfView::SUCCESS para buscar la plantilla que debe mostrar los datos:

[codesyntax lang=»php» title=»Acciones que llaman a las plantillas indexSuccess.php y listarSuccess.php»]

<?php

public function executeIndex()
{
  return sfView::SUCCESS;
}

public function executeListar()
{
}

[/codesyntax]

Al ser sfView::SUCCESS la vista por defecto, si no se indica en la acción, Symfony buscará una plantilla llamada nombreacciónSuccess.php.

En el caso de que quisieramos mostrar al usuario otra plantilla en caso de error haríamos lo siguiente:

[codesyntax lang=»php»]

<?php

return sfView::ERROR;

[/codesyntax]

Esto buscará una plantilla llamada nombreacciónError.php. Si queremos mostrar una vista personalizada:

[codesyntax lang=»php»]

<?php

return 'MiResultado';

[/codesyntax]

En ete caso, Symfony buscará una plantilla llamada nombreacciónMiResultado.php (ojo a las mayusculas ya que Symfony es case sensitive)

Si no se quiere utilizar ninguna vista:

[codesyntax lang=»php»]

<?php

return sfView::NONE;

[/codesyntax]

En el caso de que la acción vaya a ser utilizada por Ajax, podemos devolver los datos sin necesidad de pasar por la vista con el método renderText():

[codesyntax lang=»php»]

<?php

public function executeIndex()
{
  $this->getResponse()->setContent("<html><body>¡Hola Mundo!</body></html>");

  return sfView::NONE;
}

// Es equivalente a
public function executeIndex()
{
  return $this->renderText("<html><body>¡Hola Mundo!</body></html>");
}

[/codesyntax]

En algunos casos se necesita enviar sólo las cabeceras de la petición, como en el caso de J-SON:

[codesyntax lang=»php»]

<?php

public function executeActualizar()
{
  $salida = '<"titulo","Mi carta sencilla"],["nombre","Sr. Pérez">';
  $this->getResponse()->setHttpHeader("X-JSON", '('.$salida.')');

  return sfView::HEADER_ONLY;
}

[/codesyntax]

Si se quiere utilizar una plantilla específica, se debe prescindir de la sentencia return y utilizar el método setTemplate():

[codesyntax lang=»php»]

<?php

$this->setTemplate('miPlantillaPersonalizada');

[/codesyntax]

 

SALTANDO A OTRA ACCIÓN

Hay dos formas de saltar a otra acción:

[codesyntax lang=»php»]

<?php

//Si la acción debe continuar en otro módulo
$this->forward('otroModulo', 'index');

//Si la acción debe redireccionar a otro módulo o una web externa
$this->redirect('otroModulo/index');
$this->redirect('http://www.google.com/');

[/codesyntax]

En el caso de que quisieramos redireccionar para mostrar un error 404:

[codesyntax lang=»php»]

<?php

public function executeVer($peticion)
{
  $articulo = ArticuloPeer::retrieveByPK($peticion->getParameter('id'));
  if (!$articulo)
  {
    $this->forward404();
  }
}

[/codesyntax]

Si estás buscando la acción y la plantilla del error 404, las puedes encontrar en el directorio $sf_symfony_lib_dir/controller/default/. Se puede personalizar esta página agregado un módulo default a la aplicación, sobrescribiendo el del framework, y definiendo una acción error404 y una plantilla error404Success dentro del nuevo módulo. Otro método alternativo es el de establecer las constantes error_404_module y error_404_action en el archivo settings.yml para utilizar una acción existente.

La clase sfActions tiene algunos métodos más, llamados forwardIf(), forwardUnless(), forward404If(), forward404Unless(), redirectIf() y redirectUnless(). Estos métodos simplemente requieren un parámetro que representa la condición cuyo resultado se emplea para ejecutar el método. El método se ejecuta si el resultado de la condición es true y el método es de tipo xxxIf() o si el resultado de la condición es false y el método es de tipo xxxUnless():

[codesyntax lang=»php»]

<?php

// Esta acción es equivalente a la mostrada en el Listado 6-11
public function executeVer($peticion)
{
  $articulo = ArticuloPeer::retrieveByPK($peticion->getParameter('id'));
  $this->forward404If(!$articulo);
}

// Esta acción también es equivalente
public function executeVer()
{
  $articulo = ArticuloPeer::retrieveByPK($peticion->getParameter('id'));
  $this->forward404Unless($articulo);
}

[/codesyntax]

 

REPITIENDO CÓDIGO PARA VARIAS ACCIONES DE UN MÓDULO

Si por alguna razón nuestras acciones siempre van a ejecutar el mismo código al inicio o al final del método, podemos evitar duplicar código creando los métodos postExecute() y preExecute(), pero además podemos añadir al archivo de la acción (con sfAction) o acciones (con sfActions) nuestros propios métodos siempre que no empiecen con execute y no sean métodos públicos (utilizando para ello las sentencias protected o private).

[codesyntax lang=»php»]

<?php

class mimoduloActions extends sfActions
{
  public function preExecute()
  {
    // El código insertado aquí se ejecuta al principio de cada llamada a una acción
    // ...
  }

  public function executeIndex($peticion)
  {
    // ...
  }

  public function executeListar($peticion)
  {
    // ...
    $this->miPropioMetodo();  // Se puede acceder a cualquier método de la clase acción
  }

  public function postExecute()
  {
    // El código insertado aquí se ejecuta al final de cada llamada a la acción
    ...
  }

  protected function miPropioMetodo()
  {
    // Se pueden crear métodos propios, siempre que su nombre no comience por "execute"
    // En ese case, es mejor declarar los métodos como protected o private
    // ...
  }
}

[/codesyntax]

Symfony: La vista (IV), mecanismo de escape

0

Este capítulo del libro me está resultando de lo más pesado, principalmente porque no hay mucho con lo que practicar, ya que la mayoría de la información es teoría basada en donde ubicar cada cosa en cada caso. Aunque las posibilidades que ofrece Symfony a medida que te adentras en él, son enormes.

Para acabar con la vista solo queda ver el mecanismo de escape que utiliza Symfony. Empezemos:

Este apartado del libro comienza así:

Cuando se insertan datos generados dinámicamente en una plantilla, se debe asegurar la integridad de los datos. Por ejemplo, si se utilizan datos obtenidos mediante formularios que pueden rellenar usuarios anónimos, existe un gran riesgo de que los contenidos puedan incluir scripts y otros elementos maliciosos que se encargan de realizar ataques de tipo XSS (cross-site scripting). Por tanto, se debe aplicar un mecanismo de escape a todos los datos mostrados, de forma que ninguna etiqueta HTML pueda ser peligrosa.

ACTIVANDO EL MECANISMO DE ESCAPE

Fácil. El mecanismo de escape se activa en el archivo config/settings.yml de la aplicación utilizando para ello dos parámentros:

  • scaping_strategy: Define la forma en la que las variables están disponibles en la vista.
  • scaping_method: Indica la función que se aplica a los datos.

all:
.settings:
escaping_strategy: both
escaping_method: ESC_ENTITIES

Esto de aquí arriba es lo único que tendrás que escribir para activar el mecanismo de escape. Ahora mismo, nuestra aplicación estaría utilizando el método htmlentities() de PHP para escapar los caracteres de html. Más adelante veremos más valores que pueden tener estos parámentros.

Por ejemplo, si tenemos en nuestra acción esta variable:

$this->prueba = ‘<script>alert(document.cookie)</script>’;

Al tener el mecanismo de escape activado, al mostrarla en la plantilla nos dará el siguiente resultado:

echo $prueba;
=> &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt;

Si se activa el mecanismo de escape, desde cualquier plantilla se puede acceder a una nueva variable llamada $sf_data. Se trata de un objeto contenedor que hace referencia a todas las variables que se han modificado mediante el sistema de escape. De esta forma, también es posible mostrar el contenido de la variable prueba de la siguiente manera:

echo $sf_data->get(‘prueba’);
=> &gt;&lt;script&gt;alert(document.cookie)&lt;/script&gt;

Con esta clase también podemos acceder a los datos de la variable en crudo, es decir, antes de que sus caracteres fuesen escapados:

echo $sf_data->getRaw(‘prueba’);
=> <script>alert(document.cookie)</script>

OPCIONES PARA scaping_strategy

  • backward compatible mode (o modo retrocompatible): el contenido de las variables no se modifica, pero el contenedor $sf_data almacena una versión modificada de cada variable. De esta forma, los datos de las variables se obtienen en crudo, a menos que se obtenga la versión modificada del objeto $sf_data. Se trata del valor por defecto de la opción, aunque se trata del modo que permite los ataques de tipo XSS.
  • both: a todas las variables se les aplica el mecanismo de escape. Los valores también están disponibles en el contenedor $sf_data. Se trata del valor recomendado, ya que solamente se está expuesto al riesgo si se utilizan de forma explícita los datos originales. En ocasiones, se deben utilizar los valores originales, por ejemplo para incluir código HTML de forma que se interprete en el navegador y no se muestre el código HTML. Si una aplicación se encuentra medio desarrollada y se cambia la estrategia del mecanismo de escape a este valor, algunas funcionalidades pueden dejar de funcionar como se espera. Lo mejor es seleccionar esta opción desde el principio.
  • on: los valores solamente están disponibles en el contenedor $sf_data. Se trata del método más seguro y más rapido de manejar el mecanismo de escape, ya que cada vez que se quiere mostrar el contenido de una variable, se debe elegir el método get() para los datos modificados o el método getRaw() para el contenido original. De esta forma, siempre se recuerda la posibilidad de que los datos de la variable sean corruptos.
  • off: deshabilita el mecanismo de escape. Las plantillas no pueden hacer uso del contenedor $sf_data. Si nunca se va a necesitar el sistema de escape, es mejor utilizar esta opción y no la opción por defecto bc, ya que la aplicación se ejecuta más rápidamente.

OPCIONES PARA scaping_method

  • ESC_RAW: no modifica el valor original.
  • ESC_ENTITIES: aplica la función htmlentities() de PHP al valor que se le pasa y utiliza la opción ENT_QUOTES para el estilo de las comillas.
  • ESC_JS: modifica un valor que corresponde a una cadena de JavaScript que va a ser utilizada como HTML. Se trata de una opción muy útil para escapar valores cuando se emplea JavaScript para modificar de forma dinámica el contenido HTML de la página.
  • ESC_JS_NO_ENTITIES: modifica un valor que va a ser utilizado en una cadena de JavaScript pero no le añade las entidades HTML correspondientes. Se trata de una opción muy útil para los valores que se van a mostrar en los cuadros de diálogo (por ejemplo para una variable llamada miCadena en la instrucción javascript:alert(miCadena);).

APLICANDO EL MECANISMO DE ESCAPE A ARRAYS Y OBJETOS

// Definición de la clase
class miClase
{
public function pruebaCaracterEspecial($valor = »)
{
return ‘<‘.$valor.’>’;
}
}

// En la acción
$this->array_prueba = array(‘&’, ‘<‘, ‘>’);
$this->array_de_arrays = array(array(‘&’));
$this->objeto_prueba = new miClase();

// En la plantilla
<?php foreach($array_prueba as $valor): ?>
<?php echo $valor ?>
<?php endforeach; ?>
=> &amp; &lt; &gt;
<?php echo $array_de_arrays[0][0] ?>
=> &amp;
<?php echo $objeto_prueba->pruebaCaracterEspecial(‘&’) ?>
=> &lt;&amp;&gt;

Los métodos de los objetos a los que se aplica el mecanismo de escape aceptan un parámetro adicional:

<?php echo $objeto_prueba->pruebaCaracterEspecial(‘&’) ?>
=> &lt;&amp;&gt;
// Las siguientes 3 líneas producen el mismo resultado
<?php echo $objeto_prueba->pruebaCaracterEspecial(‘&’, ESC_RAW) ?>
<?php echo $sf_data->getRaw(‘objeto_prueba’)->pruebaCaracterEspecial(‘&’) ?>
<?php echo $sf_data->get(‘objeto_prueba’, ESC_RAW)->pruebaCaracterEspecial(‘&’) ?>
=> <&>

Las variables de Symfony también se modifican al activar el mecanismo de escape. Por tanto, las variables $sf_user, $sf_request, $sf_param y $sf_context siguen funcionando, pero sus métodos devuelven sus datos modificados, a no ser que se utilice la opción ESC_RAW como último argumento de las llamadas a los métodos.

Symfony: La vista (III), configuración de la vista

0

La vista en Symfony está dividida en dos partas:

  • Las plantillas (fragmentos de código): donde se recoge el resultado de la acción.
  • El resto: etiquetas meta, título de la página, archivos js y css, acciones que necesitan un layout personalizado (ventanas emergentes, publi) y las acciones que no necesitan layout alguno como las acciones para ajax.

Para modificar todo lo del segundo punto, que en general, podríamos considerar las cabeceras de la página, Symfony utiliza dos formas: a través del archivo de configuración view.yml o a través del objeto sfResponse para poder modificar las cabeceras de forma dinámica desde las acciones.

Si un mismo parámetro de configuración se establece mediante el objeto sfResponse y mediante el archivo view.yml, tiene preferencia el valor establecido mediante el objeto sfResponse.

EL ARCHIVO view.yml

editSuccess:
metas:
title: Edita tu perfil

editError:
metas:
title: Error en la edición del perfil

all:
stylesheets: [mi_estilo]
metas:
title: Mi sitio web

Esto anterior es la configuración de la vista de un módulo. Por defecto el archivo no existe y tendrías que crearlo y guardarlo dentro de la carpeta del módulo así: mimodulo/config/view.yml. Como puedes ver hay tres apartados:

  • editSuccess: Esta configuración se utilizará cuando la acción edit devuelva una respuesta igual a sfView::SUCCESS (o no devuelve nada, ya que es el valor devuelto por defecto).
  • editError: Esta configuración se utilizará cuando la acción edit devulva una respuesta igual a sfView::ERROR.
  • all: Esta es la configuración por defecto del módulo.

Para que veas la configuración en cascada de una aplicación en Symfony mira esto:

  • En apps/miaplicacion/modules/mimodulo/config/view.yml, las definiciones de cada vista solo se aplican a una vista y además sus valores tienen preferencia sobre las opciones generales del módulo.
  • En apps/miaplicacion/modules/mimodulo/config/view.yml, las definiciones bajo all: se aplican a todas las acciones del módulo y tienen preferencia sobre las definiciones de la aplicación.
  • En apps/miaplicacion/config/view.yml, las definiciones bajo default: se aplican a todos los módulos y todas las acciones de la aplicación.

Supongo que te estarás preguntando dónde se definen las cabeceras de la página, pues bien, estás se defienen en el archivo view.yml de la aplicación.

default:
http_metas:
content-type: text/html
metas:
title: symfony project
robots: index, follow
description: symfony project
keywords: symfony, project
language: en
stylesheets: [main]
javascripts: [ ]

has_layout: on
layout: layout

Más adelante explico las distintas opciones de la configuración de la vista. Antes veamos la segunda forma de configurar la vista.

EL OBJETO sfResponse

Aunque el objeto sfResponse pertenece a la vista, se puede acceder a él a través de la acción mediante el método getResponse. Algunos métodos que se utilizan habitualmente:

class mimoduloActions extends sfActions
{
public function executeIndex()
{
$respuesta = $this->getResponse();

// Cabeceras HTTP
$respuesta->setContentType(‘text/xml’);
$respuesta->setHttpHeader(‘Content-Language’, ‘en’);
$respuesta->setStatusCode(403);
$respuesta->addVaryHttpHeader(‘Accept-Language’);
$respuesta->addCacheControlHttpHeader(‘no-cache’);

// Cookies
$respuesta->setCookie($nombre, $contenido, $expiracion, $ruta, $dominio);

// Atributos Meta y cabecera de la página
$respuesta->addMeta(‘robots’, ‘NONE’);
$respuesta->addMeta(‘keywords’, ‘palabra1 palabra2’);
$respuesta->setTitle(‘Mi Página de Ejemplo’);
$respuesta->addStyleSheet(‘mi_archivo_css’);
$respuesta->addJavaScript(‘mi_archivo_javascript’); } }

Los métodos setter mostrados anteriormente que permiten dar un valor a la propiedad, también disponen de un método getter que devuelven el valor de la propiedad.

OPCIONES DE CONFIGURACIÓN DE LA VISTA

Copypasteo la introducción de esta sección del libro de Symfony:

Puede que hayas observador que existen 2 tipos diferentes de opciones para la configuración de la vista:

  • Las opciones que tienen un único valor (el valor es una cadena de texto en el archivo view.yml y el objeto respuesta utiliza un método set para ellas)
  • Las opciones que tienen múltiples valores (el archivo view.yml utiliza arrays para almacenar los valores y el objeto respuesta utiliza métodos de tipo add)

Hay que tener en cuenta por tanto que la configuración en cascada va sobrescribiendo los valores de las opciones de un solo valor y va añadiendo valores a las opciones que permiten valores múltiples. Este comportamiento se entiende mejor a medida que se avanza en este capítulo.

ETIQUETAS META

Las etiquetas <meta> se pueden definir dentro de las claves http_metas: y metas: en el archivo view.yml, o utilizando los métodos addHttpMeta() y addMeta() del objeto sfResponse dentro de la acción:

http_metas:
cache-control: public
metas:
description: Página sobre economía en Francia
keywords: economía, Francia

$this->getResponse()->addHttpMeta(‘cache-control’, ‘public’);
$this->getResponse()->addMeta(‘description’, ‘Página sobre economía en Francia’);
$this->getResponse()->addMeta(‘keywords’, ‘economía, Francia’);

Para las etiquetas <meta>, se puede añadir al método addHttpMeta() (y también a setHttpHeader()) un tercer parámetro con un valor de false para que añadan el valor indicado al valor que ya existía y así no lo reemplacen.

$this->getResponse()->addHttpMeta(‘accept-language’, ‘en’);
$this->getResponse()->addHttpMeta(‘accept-language’, ‘fr’, false);
echo $this->getResponse()->getHttpHeader(‘accept-language’);
=> ‘en, fr’

Para añadir las etiquetas <meta> en la página que se envía al usuario, se deben utilizar los helpers include_http_metas() e include_metas() dentro de la sección <head>.

EL TÍTULO DE LA PÁGINA

indexSuccess:
metas:
title: Los tres cerditos

$this->getResponse()->setTitle(sprintf(‘Los %d cerditos’, $numero));

El título de la página se puede incluir en el layout a través del método include_metas(), a través de include_title() o ambos, ya que es totalmente válido tener una etiqueta <meta name=»title»> o una etiqueta <title>.

INCLUIR ARCHIVOS

indexSuccess:
stylesheets: [miestilo1, miestilo2]
javascripts: [miscript]

$this->getResponse()->addStylesheet(‘miestilo1’);
$this->getResponse()->addStylesheet(‘miestilo2’);
$this->getResponse()->addJavascript(‘miscript’);

La extensión de los archivos no es necesario ponerla, a no ser que tengan una extensión diferente a la habitual (.css para archivos de estilos, .js para archivos javascript).

La inclusión de los archivos en la cabecera de la página es automática, no se necesita ningún método para añadirlos.

Recuerda que se sigue aplicando la configuración en cascada, por tanto los archivos que añadas a view.yml de la aplicación se mostrarán en todas las páginas de la aplicación.

view.yml de la aplicación:

default:
stylesheets: [principal]

view.yml del módulo:

indexSuccess:
stylesheets: [especial]

all:
stylesheets: [otra]

Si no se quiere incluir un archivo definido en alguno de los niveles de configuración superiores, se puede añadir un signo – delante del nombre del archivo en la configuración de más bajo nivel.

Ejemplo de archivo view.yml en el módulo y que evita incluir algunos de los archivos incluidos desde el nivel de configuración de la aplicación:

indexSuccess:
stylesheets: [-principal, especial]

all:
stylesheets: [otra]

Para eliminar todas las hojas de estilos o todos los archivos de JavaScript, se puede utilizar la siguiente sintaxis:

indexSuccess:
stylesheets: [-*]
javascripts: [-*]

Se puede ser todavía más preciso al incluir los archivos, ya que se puede utilizar un parámetro adicional para indicar la posición en la que se debe incluir el archivo (sólo se puede indicar la posición primera o la última):

# En el archivo view.yml
indexSuccess:
stylesheets: [especial: { position: first }]

// En la acción
$this->getResponse()->addStylesheet(‘especial’, ‘first’);

Para modificar el atributo media de la hoja de estilos incluida, se pueden modificar las opciones por defecto de Symfony:

indexSuccess:
stylesheets: [principal, impresora: { media: print }]

$this->getResponse()->addStylesheet(‘impresora’, », array(‘media’ => ‘print’));

Html devuelto por Symfony:

$this->getResponse()->addStylesheet(‘impresora’, », array(‘media’ => ‘print’));

CONFIGURACIÓN DEL LAYOUT

Normalmente Symfony, por defecto, utilizará la plantilla guardada en la carpeta /templates de la aplicación llamada layout.php, pero podemos indicarle cualquier otro layout:

indexSuccess:
layout: mi_layout

$this->setLayout(‘mi_layout’);

Si no se necesita ningún layout, se puede eliminar:

indexSuccess:
has_layout: false

$this->setLayout(false);

Symfony: La vista (II), ayudantes

0

Los ayudantes o helpers son funciones PHP que permiten agilizar ciertas tareas repetitivas, devuelven código HTML y se utilizan en las plantillas Por ejemplo:

<?php echo input_tag(‘nick’) ?> => <input type=»text» name=»nick» id=»nick» value=»» />

La función input_tag(nombre, valor) genera el código para crear un campo de texto de un formulario con sus atributos básicos (aunque se pueden añadir otros atributos como tercer parámetro en la función). Algunos helpers disponen de cierta inteligencia:

<?php echo auto_link_text(‘Por favor, visita nuestro sitio web www.ejemplo.com’) ?> => Por favor, visita nuestro sitio web <a href=»http://www.ejemplo.com»>www.ejemplo.com</a>

Los helpers deben ser declarados, ya que al ser funciones y no clases no se cargan directamente. Para declarar un helper se hace uso de la función use_helper(‘nombre_del_helper1’, ‘nombre_del_helper2’):

Esta plantilla utiliza un grupo de helpers específicos <?php use_helper(‘Text’) ?> … <h1>Descripción</h1> <p><?php echo auto_link_text($descripcion) ?></p>

Si se quieren añadir más helpers hay que seperarlos con comas. Los helpers pueden ser cargados automáticamente utilizando el archivo de configuración settings.yml. De los siete helpers existentes en Symfony, cuatro (Helper, Tag, Url y Asset) no se pueden eliminar del archivo de configuración, pero los otros tres (Partial, Cache, Form) sí.

Los siete helpers:

  • Helper: se necesita para incluir otros helpers (de hecho, la función use_helper() también es un helper
  • Tag: helper básico para etiquetas y que utilizan casi todos los helpers
  • Url: helpers para la gestión de enlaces y URL
  • Asset: helpers que añaden elementos a la sección <head> del código HTML y que proporcionan enlaces sencillos a elementos externos (imágenes, archivos JavaScript, hojas de estilo, etc.)
  • Partial: helpers que permiten incluir trozos de plantillas
  • Cache: manipulación de los trozos de código que se han añadido a la cache
  • Form: helpers para los formularios

Los helpers más habituales:

/ Grupo Helper
<?php use_helper(‘NombreHelper’) ?>
<?php use_helper(‘NombreHelper1’, ‘NombreHelper2’, ‘NombreHelper3’) ?>

// Grupo Tag
<?php echo tag(‘input’, array(‘name’ => ‘parametro’, ‘type’ => ‘text’)) ?>
<?php echo tag(‘input’, ‘name=parametro type=text’) ?> // Sintaxis alternativa para las opciones
=> <input name=»parametro» type=»text» />
<?php echo content_tag(‘textarea’, ‘contenido de prueba’, ‘name=parametro’) ?>
=> <textarea name=»parametro»>contenido de prueba</textarea>

// Grupo Url
<?php echo link_to(‘Pínchame’, ‘mimodulo/miaccion’) ?>
=> <a href=»/ruta/a/miaccion»>Pínchame</a> // Depende del sistema de enrutamiento

// Grupo Asset
<?php echo image_tag(‘miimagen’, ‘alt=imagen size=200×100’) ?>
=> <img src=»/images/miimagen.png» alt=»imagen» width=»200″ height=»100″/>
<?php echo javascript_include_tag(‘miscript’) ?>
=> <script language=»JavaScript» type=»text/javascript» src=»/js/miscript.js»></script>
<?php echo stylesheet_tag(‘estilo’) ?>
=> <link href=»/stylesheets/estilo.css» media=»screen» rel=»stylesheet» type=»text/css» />

Por último, existe una manera de acceder a los helpers desde otro punto de la aplicación que no sea una plantilla, mediante la función sfLoader::loadHelpers($helpers).

Symfony: La vista (I), fragmentos de código

0

Debido a que la parte de Symfony que explicaré hoy es bastante densa no podré resumir en un solo post todo el capítulo referente a la Vista, por tanto este será el primero de una serie de post sobre la Vista en Symfony que se explica en el manual de Symfony.

La vista

Como ya he comentado en anteriores post, Symfony sigue el sistema de Modelo-Vista-Controlador (MVC) para que la realización de nuestros proyectos estén mucho mejor estructurados y sean más fáciles de comprender por otros programadores.

Symfony para crear las vistas o implementar el diseño que hemos creado a nuestro proyecto, utiliza plantillas, esto son trozos de código html que se unen para formar la página que ha pedido el usuario.

En Symfony todo el diseño se divide de la siguiente manera:

  • Layout: Es la parte del diseño que se mostrará en todas las páginas (cabeceras, pie, menú, etc).
  • Elementos parciales: Si el fragmento contiene poca lógica.
  • Componentes: Si el fragmento tiene mucha lógica o debe acceder a la base de datos.
  • Slots: Si el fragmento va a sustituir a una parte del layout y se mostrará una parte por defecto.

En el libro lo explican bastante bien como se dividen las plantillas, los fragmentos de código que se pueden utilizar, cómo pasar variables desde la acción a los fragmentos de código, y algún detalle más que viene bien conocer. Os dejo el link a los Fragmentos de código.

Normalmente cuando trabajamos con plantillas en nuestros proyectos PHP, utilizamos la instrucción include() y en Symfony podríamos añadir a nuestro código algo como lo siguiente:

<?php include(sfConfig::get(‘sf_app_template_dir’).’/miFragmento.php’) ?>

Pero esta forma de añadir fragmentos de código no es muy limpia y, además, la caché de Symfony no reconoce la instrucción include() con lo que ese fragmento no podría ser cacheado. Aquí es donde entran en juego los fragmentos de código que he comentado anteriormente.

ELEMENTOS PARCIALES

Observa un periódico digital, su portada concretamente, verás que las noticias estan encajadas como en recuadros imaginarios y que cada noticia sigue un patrón: un titular y un pequeño avance de la noticia. Eso es un elemento parcial. Podemos poner ese elemento parcial en cualquier parte de ese periódico digital, ya que siempre será importante que el usuario pueda acceder a otras noticias con un pequeño avance.

Symfony sigue esta misma lógica para los elementos parciales. Estos, al igual que las plantillas, se ubican en la carpeta «templates/» del proyecto y son accesibles desde el módulo en el que se encuentre el archivo, desde otro módulo o desde la carpeta raíz de las plantillas «templates/«. Los elementos parciales se diferencian de las plantillas por llevar un guión bajo al principio del nombre del archivo ( _elementoparcial.php). Veamos como llamar a los elementos parciales desde distintas ubicaciones:

// Incluir el elemento parcial de miaplicacion/modules/mimodulo/templates/_miparcial1.php
// Como la plantilla y el elemento parcial están en el mismo módulo,
// se puede omitir el nombre del módulo
<?php include_partial(‘miparcial1’) ?>

// Incluir el elemento parcial de miaplicacion/modules/otromodulo/templates/_miparcial2.php
// En este caso es obligatorio indicar el nombre del módulo
<?php include_partial(‘otromodulo/miparcial2’) ?>

// Incluir el elemento parcial de miaplicacion/templates/_miparcial3.php
// Se considera que es parte del módulo ‘global’
<?php include_partial(‘global/miparcial3’) ?>

PASANDO VARIABLES AL ELEMENTO PARCIAL

Primero definimos la variable en la acción del módulo llamado mimodulo (mimodulo/actions/actions.class.php)

class mimoduloActions extends sfActions
{
public function executeIndex()
{
$this->total = 100;
}
}

En la plantilla llamamos al elemento parcial con la función include_partial() y le pasamos la variable en mimodulo/templates/indexSuccess.php.

<p>¡Hola Mundo!</p>
<?php include_partial(‘miparcial’, array(‘mitotal’ => $total)
) ?>

De esta manera podremos usar la variable en el elemento parcial en mimodulo/templates/_miparcial.php.

<p>Total: <?php echo $mitotal ?></p>

COMPONENTES

Los componentes son como los módulos, pero más rápidos. Siguen la misma lógica que los módulos y tienen una estructura de archivos parecida. Para nombrar un componente se utiliza la palabra execute seguido del nombre del componente, por ejemplo:

La clase de los componentes, en modules/news/actions/components.class.php

<?php

class newsComponents extends sfComponents
{
public function executeHeadlines()
{
$c = new Criteria();
$c->addDescendingOrderByColumn(NewsPeer::PUBLISHED_AT);
$c->setLimit(5);
$this->news = NewsPeer::doSelect($c);
}
}

La parte visual de los componentes se crea utilizando los elementos parciales. Para nombrarlos se usa lo mismo que para los componentes solo que sustituyendo la palabra execute por un guión bajo.

El elemento parcial, en modules/news/templates/_headlines.php

<div>
<h1>Últimas noticias</h1>
<ul>
<?php foreach($news as $headline): ?>
<li>
<?php echo $headline->getPublishedAt() ?>
<?php echo link_to($headline->getTitle(),’news/show?id=’.$headline->getId()) ?>
</li>
<?php endforeach ?>
</ul>
</div>

Cada vez que se quiera añadir el componente a una plantilla, sólo será necesario escribir el siguiente código:

<?php include_component(‘news’, ‘headlines’) ?>

Paso de parámetros a un componente y su plantilla:

// Llamada al componente
<?php include_component(‘news’, ‘headlines’, array(‘parametro’ => ‘valor’)) ?>

// Dentro del componente
echo $this->parametro;
=> ‘valor’

// Dentro del elemento parcial _headlines.php
echo $parametro;
=> ‘valor’

SLOTS

Aquí debería hablaros de los slots que simplemente son una especie de elemento parcial configurable, y para explicároslo solo se me ocurre hacer un copy&paste del libro, así que os dejo el link (al final de la página) y espero que os ayude.

Instalar PEAR desde WAMP + Bonus track: instalar Symfony desde PEAR

0

Hace tiempo que quería crear un post explicando con instalar PEAR en wamp, y además, desde hace unos meses, crear otro explicación como instalar Symfony desde PEAR. y hoy navegando un poco por la red, he encontrado dos fabulosos tutoriales que explica a la perfección estos dos temas. Así que, sin más preambulos, os dejo los links a estos dos geniales post:

Instalando PEAR en windows

Instalando symfony en windows

Symfony: Archivos de configuración

0

Bueno, sigo dandole caña a Symfony a través del manual en español, y después de practicar un poco con los conocimientos que he adquirido últimamente, puedo haceros un resumen de lo que os vais a encontrar.

(más…)

Pasar un proyecto symfony de un servidor a otro (a capón xD)

6

Sí, soy un poco bestia para algunas cosas jejeje; en este caso tuve que pasar el proyecto con el que estaba trabajando en el portatil al ordenador de sobremesa. En el portatil tengo instalada una versión de WAMP y en el sobremesa AppServ así que cuando pasé la carpeta del proyecto con un copy&paste y fui a ejecutarlo al navegador, obviamente no funcionaba, exactamente daba este error:

Warning: sfAutoload::require(C:/wamp/www/sf_sandbox/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/database/sfDoctrineDatabase.class.php) [sfautoload.require]: failed to open stream: No such file or directory in F:\AppServ\www\sf_sandbox\lib\vendor\symfony\lib\autoload\sfAutoload.class.php on line 188

Fatal error: sfAutoload::require() [function.require]: Failed opening required ‘C:/wamp/www/sf_sandbox/lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/database/sfDoctrineDatabase.class.php’ (include_path=’.;F:\AppServ\php5\pear’) in F:\AppServ\www\sf_sandbox\lib\vendor\symfony\lib\autoload\sfAutoload.class.php on line 188

(más…)

Mi primer ¡Hola Mundo! con Symfony

12

Ayer os mostré mi pequeña odisea para instalar Symfony en WAMP o al menos el SandBox, hoy toca empezar a programar.

Sigo con el libro en español de symfony.es. En el capítulo cuarto la cosa se empieza a poner interesante, voy a empezar a enrear con Symfony jejejeje.

(más…)

Instalar Symfony + WAMP

26

Una de las cosas más entretenidas de un programador (al menos para mí), es la de reciclarse cada poco tiempo para no quedarse estancado. Yo estoy en este proceso y después de varios días intentando instalar Symfony junto con WAMP al fin lo he conseguido (Sí, me ha costado un huevo, ¡que pasa! xD); para que otros desarrolladores no tengan que dedicarse a buscar información sobre como instalar Symfony junto a WAMP voy a explicar como realizarlo, los fallos que me ha dado, como solucionarlos, etc. Vamos allá.

(más…)

Ir arriba