ContextSwitch con AjaxContext
El ayudante de acción
ContextSwitch
está
destinado a facilitar el regreso de respuestas de diferentes formatos de
solicitud. El
helper
AjaxContext
es una
versión especializada de
ContextSwitch
que
facilita el regreso de respuestas a XmlHttpRequests.
Para habilitar alguno, usted debe proporcionar indicios en su
controlador de qué acciones
pueden responder a que contextos. Si una
solicitud entrante indica un contexto válido para la
acción determinada,
entonces el ayudante:
Deshabilita los esquemas, si están habilitados.
Establecer un sufijo de vista alternativo, requiriendo de
manera efectiva un script
de vista separado para el contexto.
Envía las cabeceras de respuesta apropiadas para el contexto
deseado.
Opcionalmente, llama a llamadas de retorno especifícas para
configurar el contexto
y/o realizar post-procesamiento.
Como ejemplo, tomemos el siguiente controlador:
_forward('list');
}
/**
* Lista nuevos items
*/
public function listAction()
{
}
/**
* Vista del nuevo item
*/
public function viewAction()
{
}
}
]]>
Digamos que queremos que
listAction()
también esté disponible en un formato
XML
. En lugar
de crear una acción diferente, podemos indicarle que puede devolver una
respuesta
XML
:
_helper->getHelper('contextSwitch');
$contextSwitch->addActionContext('list', 'xml')
->initContext();
}
// ...
}
]]>
Esto es lo que hará:
Establecer la cabecera de respuesta 'Content-Type' a
'
text/xml
'.
Cambiar el sufijo de vista de '
xml.phtml
' (o, si usa un
sufifo de vista alternativo, 'xml.[su sufijo]').
Ahora, necesitará crear un nuevo script de vista,
news/list.xml.phtml
', que creará y mostrará a
XML
.
Para determinar si una solicitud debe iniciar un cambio de contexto,
el ayudante comprueba
si hay un token en el objeto solicitud. Por
defecto, busca el parámetro 'format', aunque esto
puede ser configurado.
Esto significa que, en muchos casos, para provocar un cambio de
contexto, puede agregar un parámetro 'format' a su solicitud:
Via parámetro
URL
:
/news/list/format/xml
(recordar que
el valor por defecto del esquema de ruteo permite pares
arbitrarios de
clave/valor tras la acción).
Via parámetro
GET
:
/news/list?format=xml
ContextSwitch
le permite especificar contextos
arbitrarios, incluso qué sufijo cambiará (si hay alguno),
cualquier
cabecera de respuesta que deba ser enviada, y callbacks arbitrarios para
la
inicialización y posterior procesamiento.
Contextos Disponibles por Defecto
Por defecto, dos contextos están a disposición del ayudante
ContextSwitch
:
JSON
y
XML
.
JSON
. El contexto
JSON
establece la cabecera de
respuesta 'Content-Type' a '
application/json
', y el sufijo
del script de vista a '
json.phtml
'.
Sin embargo, por defecto, no es necesario un script de
vista. Simplemente
serializará todas las variables de la
vista, y emitirá la respuesta
JSON
inmediatamente.
Este comportamiento puede ser desactivado apagando la
serialización automática de
JSON
:
_helper->contextSwitch()->setAutoJsonSerialization(false);
]]>
XML
. El contexto
XML
establece la cabecera de respuesta 'Content-Type' a
'
text/xml
', y el sufijo del script de
vista a '
xml.phtml
'.
Necesitará crear un script de vista nuevo para el contexto.
Creando Contextos Personalizados
A veces, los contextos por defecto no son suficientes. Por
ejemplo, puede que desee
devolver
YAML
, o
PHP
serializado, un
RSS
o
ATOM
feed, etc.
ContextSwitch
le permite hacerlo.
La forma más fácil para añadir un nuevo contexto es a través del
método
addContext()
. Este método tiene dos
argumentos, el nombre del contexto, y un array de especificación.
La
especificación debería incluir uno o más de los siguientes:
suffix
: el sufijo a anteponer al
sufijo de la vista por defecto tal como está
registrado en
ViewRenderer.
headers
: un array de pares
cabecera/valor que desea enviar como parte de la respuesta.
callbacks
: un array que contiene una
o más de las claves 'init' o 'post', apuntando a
callbacks
PHP
válidos que pueden utilizarse
para inicializar el contexto y posterior
procesamiento.
La inicialización de callbacks ocurre cuando el contexto
es detectado por
ContextSwitch
.
Usted puede usarlo para ejecutar una lógica arbitraria. Por
ejemplo, el contexto
JSON
utiliza un
callback para desactivar a ViewRenderer cuando está activada
la
serialización auto-JSON.
El post procesamiento ocurre durante la rutina de la
acción
postDispatch()
, y puede ser
utilizada para ejecutar una lógica arbitraria. Como ejemplo,
el
contexto
JSON
utiliza un callback para
determinar si la serialización auto-JSON está activada;
si
así fuera, serializa las variables de la vista a
JSON
y envía la respuesta, pero si
no, re-habilita a ViewRenderer.
Hay una variedad de métodos para interactuar con contextos:
addContext($context, array $spec)
:
agrega un nuevo contexto. Lanza una excepción si el contexto
ya existe.
setContext($context, array $spec)
:
añade un nuevo contexto o sobrescribirá un contexto
existente. Usa la misma
especificación que
addContext()
.
addContexts(array $contexts)
: añade
muchos contextos de una vez. El array
$contexts
debería ser un array
de pares contexto/especificación. Si alguno de los contextos
ya existe, arrojará una excepción.
setContexts(array $contexts)
: añade
nuevos contextos y sobreescribe los existentes. Usa la misma
especificación que
addContexts()
.
hasContext($context)
: devuelve
TRUE
si el contexto existe,
FALSE
de lo contrario.
getContext($context)
: recupera un
único contexto por su nombre. Devuelve un array siguiendo la
especificación usada en
addContext()
.
getContexts()
: recupera todos los
contextos. Devuelve un array de pares
contexto/especificación.
removeContext($context)
: elimina un
único contexto por su nombre. Devuelve
TRUE
si tiene éxito,
FALSE
si el
contexto no fue encontrado.
clearContexts()
: elimina todos los
contextos.
Estableciendo los Contextos por Acción
Hay dos mecanismos para establecer contextos disponibles. Puede
crear manualmente los
arrays en su controlador, o utilizar varios
métodos en
ContextSwitch
para ensamblarlos.
El método principal para añadir relaciones acción/contexto es
addActionContext()
. Se esperan dos
argumentos, la acción a la que el contexto se añade, y el nombre de
un
contexto o un array de contextos. Como ejemplo, considere la
siguiente clase controlador:
Supongamos que queremos añadir un contexto
XML
a la acción 'list', y contextos
XML
y
JSON
a la acción 'comments'. Podríamos
hacerlo en el método
init()
:
_helper->contextSwitch()
->addActionContext('list', 'xml')
->addActionContext('comments', array('xml', 'json'))
->initContext();
}
}
]]>
Alternativamente, puede simplemente definir la propiedad del
array
$context
:
array('xml'),
'comments' => array('xml', 'json')
);
public function init()
{
$this->_helper->contextSwitch()->initContext();
}
}
]]>
El anterior es el menos sobrecargado, pero también está expuesto
a posibles errores.
Los siguientes métodos pueden ser utilizados para construir los
mapeos del contexto:
addActionContext($action,
$context)
: marca uno o más contextos como
disponibles para una acción. Si ya existen los
mapeos,
simplemente se añade a esos mapeos.
$context
puede ser un único
contexto, o un array de contextos.
Un valor de
TRUE
para el
contexto marcará todos los contextos como disponibles para
la acción.
Un valor vacío de $contexto desactivará todos los
contextos para la acción
determinada.
setActionContext($action,
$context)
: marca uno o más contextos como
disponibles para una acción. Si el mapeo ya
existe, se
reemplaza con los especificados.
$context
puede ser un único
contexto, o un array de contextos.
addActionContexts(array $contexts)
:
agrega varios pares acción/contexto de una vez.
$contexts
debe ser un array
asociativo de pares acción/contexto. Le pasa la petición a
addActionContext()
, lo que
significa que si los emparejamientos ya existen, se añade a
ellos.
setActionContexts(array $contexts)
:
actúa como
addActionContexts()
,
pero sobreescribe pares de acción/contexto existentes.
hasActionContext($action,
$context)
: determina si una acción particular
tiene un contexto determinado.
getActionContexts($action = null)
:
devuelve o todos los contextos para una acción determinada,
o todos los pares de
acción/contexto.
removeActionContext($action,
$context)
: elimina uno o más contextos de
una acción determinada.
$context
puede ser un único contexto o un array de contextos.
clearActionContexts($action =
null)
: elimina todos los contextos de una
acción determinada, o de todas las acciones
con contextos.
Inicializando Conmutación de Contextos (Context
Switching)
Para inicializar la conmutación de contexto, necesita llamar a
initContext()
en su controlador de
acción:
_helper->contextSwitch()->initContext();
}
}
]]>
En algunos casos, puede querer forzar el contexto utilizado; por
ejemplo, puede que sólo
quiera permitir el contexto XML si la
conmutación de contexto está activada. Puede
hacerlo pasando el
contexto a
initContext()
:
initContext('xml');
]]>
Funcionalidad Adicional
Se pueden utilizar una variedad de métodos para alterar el
comportamiento del ayudante
ContextSwitch
.
Estos incluyen:
setAutoJsonSerialization($flag)
:
Por defecto, los contextos
JSON
serializarán cualquier variable de vista a notación
JSON
y lo devolverán como una
respuesta. Si usted desea crear su propia respuesta,
debe
deshabilitar esta opción; esto debe hacerse antes de llamar
a
initContext()
.
setAutoJsonSerialization(false);
$contextSwitch->initContext();
]]>
Puede recuperar el valor del flag con
getAutoJsonSerialization()
.
setSuffix($context, $suffix,
$prependViewRendererSuffix)
: Con este
método, puede especificar un sufijo diferente para
utilizarlo en un
contexto determinado. El tercer argumento
es utilizado para indicar si anteponer
o no el actual sufijo
de ViewRenderer con el nuevo sufijo; este flag está
activado
por defecto.
Pasando un valor vacío para el sufijo hará que sólo el
sufijo ViewRenderer será
utilizado.
addHeader($context, $header,
$content)
: Añadir una cabecera de respuesta
para un determinado contexto.
$header
es el nombre de la
cabecera, y
$content
es el valor a
pasar por esa cabecera.
Cada contexto pueden tener múltiples cabeceras;
addHeader()
agrega cabeceras
adicionales al stack de cabecera del contexto.
Si el
$header
especificado ya
existe para el contexto, arrojará una excepción.
setHeader($context, $header,
$content)
:
setHeader()
actúa igual que
addHeader()
, excepto que le
permite sobreescribir cabeceras del contexto actual.
addHeaders($context, array
$headers)
: Añade varias cabeceras de una
vez a un determinado contexto. Delega a
addHeader()
, así que si la
cabecera ya existe, arrojará una excepción.
$headers
es un array de pares
cabecera/contexto.
setHeaders($context, array
$headers.)
: como
addHeaders()
, excepto que lo
delegua a
setHeader()
,
permitiéndole sobreescribir las cabeceras existentes.
getHeader($context, $header)
:
recuperar el valor de una cabecera para un determinado
contexto. Retorna null si
no existe.
removeHeader($context, $header)
:
eliminar una única cabecera para un determinado contexto.
clearHeaders($context, $header)
:
eliminar todas las cabeceras para un determinado contexto.
setCallback($context, $trigger,
$callback)
: establecer un callback en un
determinado disparador para poner en marcha un
determinado
contexto. Los disparadores pueden ser 'init' o 'post'
(indicando que
se llamará a un callback para cada contexto
de inicialización o postDispatch).
$callback
debe ser un callback
válido de
PHP
.
setCallbacks($context, array
$callbacks)
: establece varios callbacks
para un determinado contexto.
$callbacks
deben ser pares de
diparadores/callbacks. En realidad, la mayor cantidad de
callbacks que pueden ser registrados son dos, uno para la
inicialización y otro
para el procesamiento posterior.
getCallback($context, $trigger)
:
recuperar un callback para un determinado disparador en un
contexto dado.
getCallbacks($context)
: recupera
todos los callbacks para un determinado contexto. Devuelve
un array de
pares disparor/callback.
removeCallback($context, $trigger)
:
elimina un callback para un determinado disparador y
contexto.
clearCallbacks($context)
: elimina
todos los callbacks para un determinado contexto.
setContextParam($name)
: establece
el parámetro de petición para comprobar si un conmutador de
contexto
ha sido solicitado. El valor por defecto es
'format', pero este accededor puede
ser utilizado para
establecer un valor alternativo.
getContextParam()
puede ser
utilizado para recuperar el valor actual.
setAutoDisableLayout($flag)
: Por
defecto, los esquemas están deshabilitados cuando sucede una
conmutación de
contexto; esto es porque normalmente los
esquemas sólo serán utilizados para
devolver respuestas
normales, y no tienen sentido en otros contextos. Sin
embargo, si desea usar esquemas (tal vez puede tener un
diseño para el nuevo
contexto), puede cambiar este
comportamiento pasando un valor falso a
setAutoDisableLayout()
. Usted
debería hacer esto
antes
de llamar a
initContext()
.
Para conseguir el valor de este flag, utilice el
accededor
getAutoDisableLayout()
.
getCurrentContext()
Puede ser
utilizado para determinar qué contexto fue detectado, si hay
alguno.
Este retorna null si no hubo conmutación de
contexto, o si
initContext()
fue
llamado antes de ser invocado.
Funcionalidad de AjaxContext
El ayudante
AjaxContext
extiende
ContextSwitch
, así que toda de la
funcionalidad listada para
ContextSwitch
está disponible. Hay algunas diferencias fundamentales, sin embargo.
En primer lugar, el controlador de acción utiliza una propiedad
diferente para determinar
contextos,
$ajaxable
. Esto es, que puede tener
diferentes contextos utilizados para
AJAX
versus
peticiones normales
HTTP
. Los diversos métodos
*ActionContext*()
de
AjaxContext
le escribirán a esta
propiedad.
En segundo lugar, sólo se disparará si se produjo un
XmlHttpRequest, según lo determinado
por la solicitud del método del
objeto
isXmlHttpRequest()
. Así, si se pasa
el parámetro de contexto ('format') en la solicitud, pero la
solicitud
no fue hecha como un XmlHttpRequest, no se disparará
ninguna conmutación de contexto.
En tercer lugar,
AjaxContext
agrega un
contexto adicional,
HTML
. En este contexto, se establece el sufijo a
'
ajax.phtml
' para diferenciar el contexto de una solicitud normal.
No se devuelven cabeceras
adicionales.
Permitiendo a las Acciones Responder a Requerimientos
Ajax
En el siguiente ejemplo, estamos permitiendo requerimientos a
las acciones 'view',
'form', y 'process' para responder a
peticiones
AJAX
. En los dos primeros casos,
'view' y 'form', devolveremos fragmentos (snippets) de
HTML
con
los cuales actualizaremos la página; y en el último,
devolveremos
JSON
.
_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('view', 'html')
->addActionContext('form', 'html')
->addActionContext('process', 'json')
->initContext();
}
public function viewAction()
{
// Tirar para ver un único comentario.
// Cuando se detecta AjaxContext, utiliza el script de vista
// comment/view.ajax.phtml.
}
public function formAction()
{
// Mostrar el form "add new comment".
// Cuando se detecta AjaxContext, utiliza el script de vista
// comment/form.ajax.phtml.
}
public function processAction()
{
// Procesar un nuevo comentario
// Devolver los resultados como JSON; simplemente asignar los
// resultados como variables de la vista, y se devolverán como JSON.
}
}
]]>
En el lado del cliente, su biblioteca
AJAX
simplemente pedirá los parámetros finales '
/comment/view
',
'
/comment/form
', y '
/comment/process
', y pasar el parámetro
'format': '
/comment/view/format/html
',
'
/comment/form/format/html
', '
/comment/process/format/json
'. (O
puede pasar el parámetro via string de consulta: ejemplo
"?format=json").
Asumiendo que su biblioteca pasa la cabecera
'X-Requested-With:XmlHttpRequest'
entonces estas acciones
devolverán la respuesta en el formato apropiado.