Zend_Controller_Action
es una clase abstracta
que puede utilizar para implementar controladores de acción (Action
Controllers) para usar con el Front Controller al crear un un sitio
basado en el patrón Modelo-Vista-Controlador (
MVC ).
Para usar Zend_Controller_Action
,
necesitará hacerla una subclase en sus clases actuales de
controladores de acción (o hacerla una subclase para crear su propia
clase base de acción de controladores). La operación más elemental
es hacerla una subclase, y crear métodos de acción que corresponden
a las diversas acciones que desee que el contralor maneje para su
sitio. El manejo del ruteo y envío de
Zend_Controller
descubrirá por sí mismo
cualquier método que termine en 'Action' en su clase, como posibles
acciones del controlador.
Por ejemplo, digamos que su clase se define como sigue:
class FooController extends Zend_Controller_Action { public function barAction() { // hacer algo } public function bazAction() { // hacer algo } }
La clase de arriba FooController (el controlador foo ) define dos acciones, bar y baz .
Se pueden lograr muchas cosas más, tales como personalizar la inicialización de acciones, las acciones a llamar por defecto no deberían especificar ninguna acción (o una acción inválida), ganchos de pre y post despacho, y una variedad de métodos ayudantes. Este capítulo sirve como panorama de la funcionalidad del controlador de acciones.
Comportamiento por Defecto
Por defecto, el front controller habilita al ayudante de acción ViewRenderer . Este ayudante toma a su cargo la inyección del objeto "view" en el contralor, así como compatibilizar automáticamente las vistas. Usted podrá desactivarlo dentro de su contralor de acción por uno de los métodos siguientes:
class FooController extends Zend_Controller_Action { public function init() { // Local a este controlador únicamente; afecta a todas las acciones // al cargarse en init: $this->_helper->viewRenderer->setNoRender(true); // Globalmente: $this->_helper->removeHelper('viewRenderer'); // También globalmente, pero tendría que ser en conjunción con la // versión local con el fin de propagarlo para este controlador: Zend_Controller_Front::getInstance() ->setParam('noViewRenderer', true); } }
initView()
,
getViewScript()
,
render()
, y
renderScript()
cada proxy al
ViewRenderer a menos que el ayudante no
esté como ayudante intermediario o no se haya establecido el
flag de noViewRenderer .
También puede simplemente desactivarse para una prestación individual ajustando el flag noRender de ViewRenderer :
class FooController extends Zend_Controller_Action { public function barAction() { // deshabilitar el autorendering para esta acción solamente: $this->_helper->viewRenderer->setNoRender(); } }
Las principales razones para desactivar ViewRenderer son si usted simplemente no necesita una objeto "view" o si no está mostrándolos via view scripts (por ejemplo, cuando se utiliza un controlador de acción para alimentar a los protocolos de un servicio web como SOAP , XML-RPC , o REST ). En muchos casos, nunca necesitará desactivar a ViewRenderer globalmente, sólo selectivamente dentro de los distintos controladores o acciones.
Si bien siempre puede anular el contolador de acción del
constructor, no lo recomendamos.
Zend_Controller_Action::__construct()
realiza algunas tareas importantes, tales como registrar los objetos
de solicitud y respuesta, así como los argumentos de cualquier
invocación personalizada pasados desde el front controller. Si debe
anular el constructor, asegúrese de llamar a
parent::__construct($request, $response,
$invokeArgs)
.
La manera más apropiada de personalizar la instanciación es
utilizar el método init()
, el cual es
llamado como la última tarea de
__construct()
. Por ejemplo, si se
quiere conectar a una base de datos en la instanciación:
class FooController extends Zend_Controller_Action { public function init() { $this->db = Zend_Db::factory('Pdo_Mysql', array( 'host' => 'myhost', 'username' => 'user', 'password' => 'XXXXXXX', 'dbname' => 'website' )); } }
Zend_Controller_Action
especifica dos métodos
que pueden ser llamados para marcar una solicitud de acción,
preDispatch()
y
postDispatch()
. Estas pueden ser
útiles de varias maneras: verificar la autenticación y
ACL s antes de ejecutar una acción (llamando
a _forward()
en
preDispatch()
, se saltará la acción),
por ejemplo, o colocando contenido generado en una plantilla general
del sitio ( postDispatch()
).
Usage of init() vs. preDispatch()
In the previous section , we introduced the
init()
method, and in this section,
the preDispatch()
method. What is the
difference between them, and what actions would you take in
each?
The init()
method is primarily
intended for extending the constructor. Typically, your
constructor should simply set object state, and not perform much
logic. This might include initializing resources used in the
controller (such as models, configuration objects, etc.), or
assigning values retrieved from the front controller, bootstrap,
or a registry.
The preDispatch()
method can also be
used to set object or environmental (e.g., view, action helper,
etc.) state, but its primary purpose is to make decisions about
whether or not the requested action should be dispatched. If
not, you should then _forward()
to
another action, or throw an exception.
Note: _forward()
actually will not
work correctly when executed from
init()
, which is a formalization
of the intentions of the two methods.
Con el objeto, se registran una serie de objetos y variables, y cada uno tiene métodos de acceso.
-
Objecto Requerimiento :
getRequest()
puede ser utilizado para recuperar el objeto solicitud utilizado para llamar a la acción. -
Objecto Respuesta :
getResponse()
puede ser utilizado para recuperar el objeto respuesta agregando la respuesta final. Algunas llamadas típicas podrían ser:$this->getResponse()->setHeader('Content-Type', 'text/xml'); $this->getResponse()->appendBody($content);
-
Argumentos de Invocación : el front controller puede empujar parámetros al router, al despachador, y al controlador de acción. Para recuperarlos, use
getInvokeArg($key)
; por otra parte, se puede traer toda la lista utilizandogetInvokeArgs()
. -
Parámetros de Requerimientos : La objeto solicitud agrega parámetros de solicitud, como cualquiera de los parámetros
_GET
o_POST
, o parámetros del usuario especificados en la información del path de la URL . Para recuperarlos, use_getParam($key)
o_getAllParams()
. También se pueden establecer parámetros de solicitud usando_setParam()
; lo que es útil cuando se reenvían a acciones adicionales.Para probar si un parámetro existe o no (muy útil para bifurcaciones lógicas), use
_hasParam($key)
.Nota
_getParam()
puede tomar opcionalmente un segundo argumento que contiene un valor por defecto a utilizar si el parámetro no está establecido o está vacío. Usándolo elimina la necesidad de llamar previamente a_hasParam()
para recuperar un valor:// Usar por defecto el valor 1 si el id no está establecido $id = $this->_getParam('id', 1); // En lugar de: if ($this->_hasParam('id') { $id = $this->_getParam('id'); } else { $id = 1; }
Integración de la Vista por Defecto via ViewRenderer
El contenido de esta sección sólo es válida cuando usted tiene explícitamente deshabilitado a ViewRenderer . De lo contrario, puede saltarse esta sección.
Zend_Controller_Action
proporciona un
mecanismo rudimentario y flexible para ver la integración. Hay dos
métodos para lograrlo, initView()
y
render()
; el anterior método
$view
carga la propiedad pública, y este
último muestra una vista en base a la acción requerida actual,
utilizando la jerarquía del directorio para determinar el path del
script.
initView()
inicializa el objeto vista.
render()
llama a
initView()
con el fin de recuperar
el objeto vista, pero puede ser iniciada en cualquier momento;
por defecto introduce información a la propiedad de
$view
con un objeto
Zend_View
, pero se puede usar
cualquier clase que implemente
Zend_View_Interface
. Si
$view
ya ha sido inicializada,
simplemente devuelve esa propiedad.
La implementación por defecto hace la siguiente hipótesis de la estructura del directorio:
applicationOrModule/ controllers/ IndexController.php views/ scripts/ index/ index.phtml helpers/ filters/
En otras palabras, los scripts de vista se supone están en el
subdirectorio /views/scripts/
, y en el
subdirectorio /views/
se supone que
contiene funcionalidades hermanas (ayudantes, filtros). Al
determinar el nombre y el path del script, el directorio
views/scripts/
será utilizado como el
path base, con directorios nombrados después que los
controladores individuales proporcionen una jerarquía a los
scripts de vista.
render()
tiene la siguiente firma:
string render(string $action = null, string $name = null, bool $noController = false);
render()
suministra un script de vista.
Si no se pasan argumentos, se supone que el script requerido es
[controller]/[action].phtml
(donde
.phtml
es el valor de la propiedad
$viewSuffix
). Pasándole un valor a
$action
suministrará esa plantilla en al
subdirectorio /[controller]/
. Para anular
el subdirectorio /[controller]/
ponga un
valor TRUE
en
$noController
. Por último, las
plantillas son suministradas en el objeto respuesta; si desea
suministrar a un determinado named
segment en el objeto respuesta, pase un valor a
$name
.
Nota
Dado que el controlador y los nombres de acción pueden
contener caracteres delimitadores como '_', '.', y '-',
render()
los normaliza a '-'
para determinar el nombre del script. Internamente, utiliza
los delimitadores de palabra y de path del despachador para
hacer esta normalización. Así, una solicitud a
/foo.bar/baz-bat
suministrará el
script foo-bar/baz-bat.phtml
. Si su
método de acción contiene camelCasing, recuerde que esto se
traducirá en palabras separadas por '-' al determinar el
nombre del archivo del script de vista.
Algunos ejemplos:
class MyController extends Zend_Controller_Action { public function fooAction() { // Suministra my/foo.phtml $this->render(); // Suministra my/bar.phtml $this->render('bar'); // Suministra baz.phtml $this->render('baz', null, true); // Suministra my/login.phtml al segmento 'form' del // objeto respuesta $this->render('login', 'form'); // Suministra site.phtml al segmento 'page' del objeto // respuesta; no usa el subdirectorio 'my/' $this->render('site', 'page', true); } public function bazBatAction() { // Suministra my/baz-bat.phtml $this->render(); } }
Además de los accesadores y de los métodos de integración de
vistas, Zend_Controller_Action
tiene varios
métodos utilitarios para realizar tareas comunes dentro de sus
métodos de acción (o de pre- y post-dispatch).
-
_forward($action, $controller = null, $module = null, array $params = null)
: realiza otra acción. Si es llamado enpreDispatch()
, la acción actualmente requerida se saltará en favor de la nueva. De lo contrario, después de procesar la acción actual, se ejecutará la acción solicitada en_forward()
. -
_redirect($url, array $options = array())
: redireccionar a otro lugar. Este método toma una URL y un conjunto de opciones. Por defecto, realiza una redirección HTTP 302.Las opciones pueden incluir uno o más de los siguientes:
-
exit: ya sea para salir inmediatamente o no. Si así lo solicita, limpiamente cerrará cualquier sesión abierta y realizará la redirección.
Puede configurar esta opción globalmente en el controlador utilizando el accesador
setRedirectExit()
. -
prependBase: ya sea anteponiendo o no la base URL registrada con el objeto solicitud a la URL provista.
Puede configurar esta opción globalmente en el controlador utilizando el accesador
setRedirectPrependBase()
. -
code: qué código HTTP utilizar en la redirección. Por defecto, se utiliza un HTTP 302; se puede utilizar cualquier código entre 301 y 306.
Puede configurar esta opción globalmente en el controlador utilizando el accesador
setRedirectCode()
.
-
Por diseño, Zend_Controller_Action
debe
ser "subclaseada" a fin de crear un controlador de acción. Como
mínimo, necesitará definir los métodos de acción que podrá llamar el
controlador.
Además de crear una funcionalidad útil para su aplicaciones web,
también puede encontrar que está repitiendo demasiado los mismos
setups o métodos utilitarios en sus diferentes controladores; si así
fuera, creando una clase base común del controlador que extienda
Zend_Controller_Action
puede resolver
esta redundacia.
Ejemplo 135. Manejando Acciones No Existentes
Si hay una solicitud a un controlador que incluye un método
de acción no definido, se invocará a
Zend_Controller_Action::__call()
.
__call()
es, por supuesto, el
método mágico de PHP para la sobrecarga del
método.
Por defecto, este método lanza un
Zend_Controller_Action_Exception
indicando que el método no se encuentró en el controlador. Si el
método requerido termina en 'Action', la suposición es que una
acción fue solicitada y no existe; tales errores resultan en una
excepción con un código 404. Todos los demás métodos resultan en
una excepción con un código 500. Esto le permite diferenciar
fácilmente entre una página no encontrada y errores de
aplicación con su manejador de errores.
Usted debe anular esta funcionalidad si desea realizar otras operaciones. Por ejemplo, si desea mostrar un mensaje de error, usted podría escribir algo como esto:
class MyController extends Zend_Controller_Action { public function __call($method, $args) { if ('Action' == substr($method, -6)) { // Si no se encontró el método de la acción, suministrar la // plantilla de error return $this->render('error'); } // todos los otros métodos lanzan una excepción throw new Exception('Se ha llamado al método "' . $method . '" que es inválido', 500); } }
Otra posibilidad es que puede querer avanzar a un controlador de página por defecto:
class MyController extends Zend_Controller_Action { public function indexAction() { $this->render(); } public function __call($method, $args) { if ('Action' == substr($method, -6)) { // Si no se encontró el método de acción, avance a la // acción index return $this->_forward('index'); } // todos los otros métodos lanzan una excepción throw new Exception('Se ha llamado al método "' . $method . '" que es inválido', 500); } }
Además de sobrecargar __call()
, cada
uno de los métodos gancho de inicialización, utilidad, accesador,
vista, y despacho mencionados anteriormente en este capítulo pueden
ser anulados a fin de personalizar sus controladores. Como ejemplo,
si está almacenando su objeto vista en un registro, quizás desee
modificar su método initView()
con código
parecido al siguiente:
abstract class My_Base_Controller extends Zend_Controller_Action { public function initView() { if (null === $this->view) { if (Zend_Registry::isRegistered('view')) { $this->view = Zend_Registry::get('view'); } else { $this->view = new Zend_View(); $this->view->setBasePath(dirname(__FILE__) . '/../views'); } } return $this->view; } }
Es de esperar, que de la información en este capítulo, usted puede ver la flexibilidad de este componente en particular y cómo puede darle forma a su aplicaciones o a las necesidades de su sitio web.