Zend Layout y ActionStacks de Zend Framework
En la documentación deZend Layout no acaba de quedar muy claro como se usa y suele provocar muchas confusiones si solo hacemos una lectura vertical del manual.
Zend Layout es uno de mis objetos preferidos por la versatilidad que ofrece y una vez entiendes el proceso y como combinarlo con el resto del Framework y los placeholders obtienes una gestión muy clara de las plantillas.
Vamos a suponer el siguiente layout:
<div>
<?php echo $this->render('header.phtml') ?>
<h1><?php echo $this->placeholder('h1') ?></h1>
<?php echo $this->layout()->nav ?>
<?php echo $this->layout()->content ?>
</div>
Cada bloque de código php realiza una acción diferente.
- $this->render(’header.phtml’) se encargará de llamar al archivo header.phtml que estará ubicado en el mismo nivel que el layout.
- $this->placeholder(’h1′) nos devolverá el valor que hallamos definido en la plantilla usando $this->placeholder(’h1′)->set(’Mi h1′);
- $this->layout()->nav es un ActionStack
- $this->layout()->content nos devolverá el contenido de la plantilla
Pero ¿Que són los ActionStacks? ¿como se usan los? y ¿Para que sirven? Básicamente lo que logramos con los ActionStacks es renderizar un fragmento de código generado por una acción que no es la misma que estamos ejecutando en el momento de renderizar la página.
Todo será más fácil si usamos el MVC o Zend Application
Para hacer un ActionStack necesitaremos dos cosas: Un controlador y una llamada a este.
Lo primero será crear un controlador como cualquier otro, por ejemplo: NavegacionController con una acción menuAction. Esta acción renderizará menu.phtml pero le indicaremos en que segmento de la plantilla o layout se deberá renderizarse:
class NavegacionController extends Zend_Controller_Action{
public function menuAction(){
// renderiza menu.phtml en el segmento nav
$this->_helper->viewRenderer->setResponseSegment('nav');
}
}
Lo siguiente es hacer la llamada desde la acción principal.
class IndexController extends Zend_Controller_Action {
public function indexAction() {
$this->_helper->actionStack ('menu', 'navegacion', 'default');
}
}
Es decir, cuando llamemos a IndexAction del IndexController el se encargará de llamar a menuAction del navegaciónController para que renderize scripts/navegacion/menu.phtml en el segmento nav que hemos indicado en el layout con $this->layout()->nav.
Entonces vemos que el primer parámetro es la acción, el segundo el controlador y el tercero es opcional y se refiere al módulo que por defecto es default.
Para profundizar más con los layouts estan los Placeholder Helper pero esto se sale ya del tema y lo dejo para otro post.
Espero que os se útil.








Comentarios
Olagato dijó el 30 Septiembre de 2009 a las 6:56
Muy interesante. Está muy bien explicado y es una forma de carga de templates que desconocía.
Lo único que se me hace un poco raro es la definición de un controller para la navegación. Quizás es sólo para este ejemplo o bien es tu forma de trabajar…ahí no me meto.
No sé qué te parecerá a ti pero quizás los controladores sólo tendrían que definirse para páginas/secciones cuya url tenga sentido. Por ejemplo: el indexcontroller para la home, ofertascontroller para una sección de ofertas y así sucesívamente. Si definimos un navegacioncontroller significaría que habría una url para la navegación, cosa que quizás no tiene mucho sentido.
Una navegación es un elemento común que puede aparecer en cualquier controller de la web, como la cabecer, el footer, sidebars, etc. Para estos casos, yo meto estos templates comunes en el folder “layouts” y los cargo mediante placeholder->render() .
Quizás sea sólo una forma de organizar los proyectos y cada uno tiene la suya. La verdad es que la forma de carga que comentas en este post está muy bien y me hace dudar de mi manera actual de proceder. A ver cómo lo ves tú…
Saludos y enhorabuena por el post !
admin dijó el 30 Septiembre de 2009 a las 8:40
Hola Olagato!
¡Gracias por tu nuevo comentario!
Al principio también usaba el render() y cuando empecé a usar los ActionStacks también me pareció un poco raro hacer un controlador para la navegación, pero al momento lo encontré muy útil por varias razones. Principalmente puedo cambiar el menú en cada controlador (diferentes acciones menú) o incluso no poner menú, según si es una área privada o pública. De esta forma evito programar en la plantillas pues odio programar en las plantillas y sobre todo poner condicionales. Además así consigo un código más limpio.
De todas formas esto mismo quizás se pueda hacer con un View Helper o sencillamente hay muchos casos en que sería mejor usar diferentes layouts pero (hoy, quizás en un mes cambie de opinión) me parece más elegante esta forma usando solo un layout
Gracias nuevamente por tu comentario y ¡espero verte por aquí pronto otra vez!
Saludos
arts dijó el 30 Septiembre de 2009 a las 17:17
Hola chicos q tal… stoy comenzando con zend; y quisiera saber si asi como tu le creas un controller para el segmento de nav se pudiera hacer para cada uno de los .phtml es decir para el footer, header, etc.. seria de la misma forma????
admin dijó el 30 Septiembre de 2009 a las 21:52
Hola Arts,
Bueno eso queda a tu libre alberdio. Por lo general el footer y el header son partes más bien estáticas por lo que usaría $layout->render->(’footer.phtml’) y sí el menú de navegación es estático tampoco me complicaría a usar para ello un ActionStack. Por lo que mi respuesta de entrada es no. Como comentaba anteriormente quizás para estas cosas resulté más útil usar dos layouts uno para la zona pública y otro para la zona privada.
No obstante te cuento brevemente porque en una aplicación estoy usando el ActionStack para la navegación: Tengo un menú de navegación estático (Dashboard, Trabajos, Studios, Libros, Twitter ) y por cada uno de estos tengo una subnavegación que se renderiza en el segmento nav. Es decir la navegación principal son los controladores (o acciones índex) y las subnavegación las acciones complementarias (Nuevo, Listado, buscar, etc.)
Gracias por tu comentario y cualquier otra duda no dudes en cotinuar comentando. ¡Saludos!
olagato dijó el 1 Octubre de 2009 a las 5:20
Vale, me has convencido… usaré esta forma de carga de templates con stacks en próximos proyectos, tiene buena pinta eso de la organización y limpieza de código.
Por otro lado y en relación al manejo de templates, no sé si has visto este post:
http://blog.fedecarg.com/2009/09/20/adding-theme-support-to-your-zend-framework-application/
(su blog y twitter @fedecarg merecen la pena)
Es una bomba lo de las aplicaciones “themeables” (lo que hace wordpress), quiero implantar esto en mis proyectos de Zend framework con la idea de cambiar los estilos y diseño de la web de forma rápida y limpia.
De seguir lo que dice este post, nos obligaría a cambiar radicalmente la ubicación de los templates y quizás merezca la pena. Está siguiendo la idea de Magento: http://www.magentocommerce.com/design_guide/articles/magento-design-terminologies4#term-structural-blocks
No sé qué te parece….
Saludos.
Federico dijó el 1 Octubre de 2009 a las 9:58
Hola,
Les recomiendo este articulo, donde Ryan explica algunos de los problemas que presenta el uso de Actionstack. La verdad que no recomiendo su uso, con el tiempo aumenta la complejidad del codigo y reduce el rendimiento.
“Why the Zend Framework Actionstack is Evil”
http://bit.ly/z94Gw
Saludo
Federico dijó el 1 Octubre de 2009 a las 10:07
Me olvide de mencionar algo importante. La misma persona que introdujo este componente, Matthew, escribió en los cometarios de ese post.
Traducción:
“Ojala no hubiese escuchado a los usuarios que querían ambos, ActionStack y el action() view helper. Los dos traen problemas de rendimiento y hacen que el código sea muy difícil de depurar. Como sabran, no hay nada que estos dos permitan hacer que no se pueda hacer con un partial or view helper, incluyendo generación de menu y navegación.”
Texto original:
“I’m wishing I’d not succumbed to users who wanted both ActionStack and the action() view helper. Both introduce overhead, and both also lead to difficult to debug code. As you note, there’s almost nothing you can do with either that you could not do with a partial or a view helper — including things such as menu and navigation generation.”
admin dijó el 1 Octubre de 2009 a las 14:03
Hola Federico,
¡Muchas gracias por tu aporte! Pues habrá que tenerlo en cuenta…
Saludos y gracias otra vez
olagato dijó el 1 Octubre de 2009 a las 16:30
Hola de nuevo a todos,
Qué interesante este debate con invitados de lujo como Federico (@fedecarg, http://blog.fedecarg.com/) y el autor del blog, Backtheweb (@backtheweb)…. así da gusto.
Por lo que comenta Federico, siempre que sea posible, mejor obviar la carga de templates vía stacks o action_view_helpers.
De este modo, corregidme si me equivoco, quizás la solución más ligera para cargar cabeceras, footers u otros elementos comunes de la web sea hacer algo así en el controller (o bootstrap):
$this->view->placeholder(’cabecera’)->set($this->view->render(’cabecera.phtml’, null, true));
y luego en las vistas un:
echo $this->placeholder(’cabecera’);
No sé cómo lo veis….
Saludos !
Tweets that mention Zend Layout y ActionStacks de Zend Framework en Backtheweb -- Topsy.com dijó el 1 Octubre de 2009 a las 16:40
[...] This post was mentioned on Twitter by Olagato Olagato and Olagato Olagato. Olagato Olagato said: http://bit.ly/DJIXF [spanish] Zend Layout & ActionStacks by @backtheweb [...]
arts dijó el 1 Octubre de 2009 a las 16:55
Gracias admin!!! lo q pasa es q necesito que el footer, header sean dinamicos pero si funciona asi…!!! tengo otra duda yo tengo un layout donde hago el llamado d cada uno de los .phtml; y estaba provando haciendo el llamado con render ( render(’header.phtml’)?>) cuando hago esto debo tener cada .phtml dentro de carpeta y estas en la carpeta views/scripts, ademas debo tener los .phtml en la carpeta layout/scripts. Cuando lo hago con layout (layout()->header ?> ) debo tener solo cada .phtml dentro de carpeta y estas en la carpeta views/scripts. quisiera saber porq pasa esto??? q estoy haciendo mal??? o esto es dedido a las versiones, yo stoy usando la 1.9.3.. Saludos!!!
admin dijó el 1 Octubre de 2009 a las 22:47
Hola Arts!
Cuando haces render(’header.phtml’) ?> en un Layout el header.phtml debe estar en la misma carpeta que el layout. Pero si lo haces desde un template el header.phtml debe estar en el mismo directorio que el template.
Cuando haces “layout (layout()->header ?>” supongo que te refieres a: layout()->header ?> donde header es un segmento ¿no? En este caso dependerá de tu controlador. Es decir:
Si en cada controlador tienes un action para el header:
public function headerAction(){
$this->_helper->viewRenderer->setResponseSegment('header');
}
Entonces necesitas colocar un header.phtml en cada carpeta de vistas.
De todas formas te sugiero que tengas en cuenta lo que comenta Federico sobre el rendimiento de los ActionStaks y de como realizar estos procesos o valores también la posibilidad de hacerlo con un placeHolder como comenta Olagato pero esto personalmente aún no lo he probado (espero poder hacerlo en breve).
Personalmente no me voy a rebatir temas de rendimiento pues dichas palabras vienen de un experto en la materia y a mi me queda aún mucho por aprender. No obstante me gustaría decir unas cuantas cosas respecto del rendimiento en PHP/Zend Framework pero lo dejaré para un futuro post en el que podáis dejar vuestra opinión.
Gracias a todos por vuestros comentarios y si no he podido aclarar las dudas a Arts os pido disculpas, si me muestras con un poco más de detalle tú código tal vez pueda echarte un cable.
arts dijó el 2 Octubre de 2009 a las 14:50
Muchas gracias admin, y si; en cada controlador tengo una action para el header.!! pero lo q no entiendo es porq cuando lo hago con render teniendo los .phtml en las misma carpeta q el layout busca ademas en la carpete views/scripts, estoy m tiendo confundida..
Estoy intentando hacer lo q dijo Olagato pero no m funciona… seguire provando y cualquier cosa preguntare.!!
Saludos!!!
arts dijó el 2 Octubre de 2009 a las 14:59
Gracias admin, y si; en el controlador tengo una action para el header.. pero lo q no entiendo es porque cuando lo hago con el render el busca ademas en la carpete views/scripts teniendo los .phtml dentro de la misma carpeta donde esta el layout; esto me tiene muy confundida..
Estoy tratando de hacer lo q dijo olagato pero no m funciona; no c porq sera porq tengo un controlador para cada uno????? (aunq deberia funcionar igual) seguire probando y cualquier cosa ls aviso… Gracias!!
saludos…
Milena dijó el 2 Octubre de 2009 a las 16:54
hola que tal? Estoy estoy probando lo que han comentado y con el placeHolder me muestra del header.phtml lo que tengo estatico pero lo que tengo desde el controlador no lo muestra…
lo que estoy poniendo en el controlador del headerController es:
public function headerAction()
{
$this->_helper->viewRenderer->setResponseSegment(’header’);
$this->view->pageTitle = “Zend Layout Example”;
$this->view->bodyTitle = ‘SENCAMER’;
$this->view->bodyCopy = “SENCAMER”;
}
en el IndexController:
public function indexAction()
{
$this->view->placeholder(’header’)->set($this->view->render(’header.phtml’, null, true));
}
y en el Layout.phtml:
placeholder(’header’) ?> .
en el Header.phtml:
Fecha:
bodyTitle;
echo $this->title;
echo $this->bodyCopy; ?>
Faltara algo? porque no respondera a los echo, solo me sale es la fecha…
Gracias!!!
admin dijó el 2 Octubre de 2009 a las 23:11
Hola Milena,
estoy probando tu código y creo que la hemos liado un poco, entre actionstacks y placeholders hemos mareado la perdiz.
Por un lado te sobra el $this->_helper->viewRenderer->setResponseSegment(”header”); si lo que quieres es usar placeHolders y por otro lado fijate que entre $this->view->placeholder(’header’)->set($this->view->render(’header.phtml’, null, true)); y la función headerAction no existe conexión, es decir que no hay llamada, por eso no te imprime los valores de las variables, lo que hace es que te renderiza tal cual el views/scripts/header.phtml.
Estoy revisando este tema a fondo, espero darte una respuesta en breve.
admin dijó el 2 Octubre de 2009 a las 23:25
Hola Arts,
Creo que tu problema guarda cierto parecido con lo que le pasa a milena.
Así que he probado varios casos de donde va buscar los ficheros según se hace el render de una forma y lugar donde se pone
Si haces:
$this->view->placeholder(’header’)->set($this->view->render(’header.phtml’, null, true));
Te mostrará views/scripts/header.phtml en cambio si haces.
Pero si haces:
$this->view->placeholder(’header’)->set($this->view->render(’index/header.phtml’, null, true));
Te mostrará views/scripts/index/header.phtml
Si haces desde el layout o una plantilla:
layout()->render(’header’); ?>
Te mostrará el header.phtml que tengas en la carpeta de layouts
Si haces en el layout:
< ?php echo $this->render(’header.phtml’) ?>
Te imprimirá el header.phtml que tengas en la carpeta de layouts
Si haces en la plantilla:
< ?php echo $this->render(’header.phtml’) ?>
Te imprimirá el header.phtml que tengas en views/scripts
y finalmente si haces en el layout o la tpl
< ?php echo $this->render(’index/header.phtml’) ?>
te imprimirá el header de views/scripts/index/
De todas formas como le decía a milena estoy estudiando la formas propuesta por Olagato y por Federico.
Saludos
admin dijó el 2 Octubre de 2009 a las 23:59
Bueno he estado repasando la documentación de Zend y parece que recomiendan usar partial() solo cuando es realmente necesario por lo que proponen los ActionStacks como alternativa.
Unpartial() necesita de 3 parámetros: nombre del view script, nombre del modulo, y modelo. Creo que esto no nos sirve para lograr lo que buscamos.
Si continuamos leyendo nos dice que podemos usar action(’list’, ‘bug’) ?> donde list es la acción y bug es el controlador. De esta forma si en lugar de un controlador especifico ponemos una variable que asignamos desde el controlador podríamos llegar a la solución que buscamos.
No obstante la recomendación final es usar un view helper en lugar de action()
Bueno creo que por hoy lo dejo aquí.
Saludos y si alguien encuentra una mejor solución que no se olvide de comentar
Milena dijó el 6 Octubre de 2009 a las 15:55
Hola que tal!
Gracias por todo, resolvi mi duda anterio con layout… Ahora tengo otra duda y es que estoy intentando pasar valores que recibo en una vista a otra vista, las vistas son identicas en cuanto a los campos o tributos lo que cambia es que la primera tiene el boton que envia los valores a la otra vista…
Te muestro el codigo que tengo, y cuando hago el getValues no se trae los datos, carga el arreglo pero vacio…
en la primera vista el boton enviar tiene lo siguiente:
public function enviarAction()
{
$request = $this->getRequest();
$form = new Default_Form_Ejemplo();
if (!$form->isValid($request->getPost())) {
$variables = $form->getValues();
print_r($variables);
die();
}
$form = new Default_Form_Ejemplo2($variables);
$this->view->form = $form;
}
pero no hace nada en la segunta vista que es Ejemplo2 se quedan en blanco todas la cajas de texto
admin dijó el 6 Octubre de 2009 a las 22:10
Hola Milena
No se si te servirá, pero en lugar de $form->isValid($request->getPost() prueba con $form->isValid($_POST) Al menos es como lo estoy haciendo yo. Una vez llamado isValid() ya puedes obtener los valores del formulario.
Saludos
Milena dijó el 7 Octubre de 2009 a las 15:12
Hola Admin! Ya lo probe y sigue igual no pasa por esa condicion por ende no hace nada es como que si el formulario no fuese valido. Te muestro el codigo de lo que he hecho.
EjemploController.php (ESTE ES EL CONTROLADOR DE LA VISTA DONDE TIPEO LOS CAMPOS)
public function enviarAction()
{
$request = $this->getRequest();
$form = new Default_Form_Ejemplo();
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
$variables = $form->getParems();
}
}
$form = new Default_Form_Ejemplo2($variables);
$this->view->form = $form;
}
Ejemplo2Controller.php (ESTE ES EL CONTROLADOR DE LA SEGUNDA PANTALLA QUE TIENEN LAS MISMAS CAJAS DE TEXTO, CHECKBOX, ETC, SOLO QUE NO TIENE BOTONES Y ES QUIEN DEBE RECIBIR LOS CAMPOS Y ASIGNARLOS A CADA CAJA DE TEXTO, ETC)
?php
// application/controllers/Ejemplo2Controller.php
class Ejemplo2Controller extends Zend_Controller_Action
{
public function init()
{
$this->view->title = “Ejemplo Número II”;
}
public function indexAction()
{
$form = new Default_Form_Ejemplo2();
$this->view->title = “Ejemplo Número II”;
$this->view->form = $form;
}
public function salirAction()
{
$this->view->form = $form;
}
}
El Default_Form_Ejemplo es:
setMethod(’post’);
$this->addElement(’text’, ‘correo’, array(
‘label’ => ‘Correo Electrónico’,
‘value’ => ‘yaidem@hotmail.com’,
‘required’ => true,
‘filters’ => array(’StringTrim’),
‘validators’ => array(’EmailAddress’,)
));
$this->addElement(’textarea’,'direccion’, array(
‘label’ => ‘Dirección’,
‘value’ => ‘Tucupita’,
‘required’ => true,
‘rows’ => ‘5′,
’stringLength’ => array(0, 250)
));
$this->addElement(’checkbox’, ‘cheejemplo’, array(
‘label’ => ‘Usuario Nuevo’,
‘required’ => true,
‘checked’ => true,
‘checkboxvalue’ => array(’Natural’,'Jurídico’),
));
$this->addElement(’radio’,'radejemplo’,array(
‘label’ => ‘Tipo Usuario’,
‘required’ => true,
‘multiOptions’ => array(
‘natural’ => ‘Natural’,
‘juridico’ => ‘Jurídico’,),
));
$this->addElement(’select’,’selejemplo’,array(
‘label’ => ‘Estado’,
‘value’ => ”,
‘required’ => true,
‘autocomplete’ => false,
‘multiOptions’ => array(
’seleccione’ => ‘Seleccione’,
‘carabobo’ => ‘Carabobo’,
‘capital’ => ‘Disttrito Capital’,
‘amacuro’ => ‘Delta Amacuro’,
‘lara’ => ‘Lara’,
‘zulia’ => ‘Zulia’,),
));
$this->addElement(’image’, ‘imaejemplo’, array(
‘label’ => ‘Foto’,
));
$this->addElement(’button’, ‘enviar’, array(
‘ignore’ => true,
‘label’ => ‘Enviar’,
‘onclick’ => ‘javascript:location.href= “./ejemplo/enviar”‘,
));
$this->addElement(’reset’, ‘cancelar’, array(
‘ignore’ => true,
‘label’ => ‘Cancelar’,
));
}
}
Seguro me falta algo… que sera?
Gracias! espero que sirva de guia y puedas ayudarme!!!
Milena dijó el 7 Octubre de 2009 a las 20:13
Holaa! Pude resolver el problema, solo que de una manera que no es la que quiero, me sirve si coloco un boton desde el index.phtml y ese me llama a la primera ventana que quiero que salga y cuando introduzco los datos y le doy a enviar que tengo en el form_ejemplo.php este si me carga la segunda pantalla que es la que quiero que cargue los datos introducidos en la segunda pantalla.
Pero lo logico es que cuando cargue primera vista el boton submit del form sea el que llame a la segunda vista con los datos introducidos.
Te muestro lo que tengo en el index.phtml:
escape($this->title); ?>
form; ?>
el EjemploController.php:
view->title = “Ejemplos”;
}
public function indexAction()
{
$form = new Default_Form_Ejemplo();
$this->view->form = $form;
}
public function enviarAction()
{
$request = $this->getRequest();
$form = new Default_Form_Ejemplo();
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
Zend_Loader::loadClass(’Zend_Filter_StripTags’);
$filter = new Zend_Filter_StripTags();
$correo = trim($filter->filter($this->_request->getPost(’email’)));
$direccion = trim($filter->filter($this->_request->getPost(’direccion’)));
(AQUI ES DONDE TENDRIA QUE PASARLE LOS DATOS AL OTRO FORMULARIO)
$form = new Default_Form_Ejemplo2();
$this->view->form = $form;
}
}
$this->view->form = $form;
}
}
Milena dijó el 7 Octubre de 2009 a las 20:13
Holaa! Pude resolver el problema, solo que de una manera que no es la que quiero, me sirve si coloco un boton desde el index.phtml y ese me llama a la primera ventana que quiero que salga y cuando introduzco los datos y le doy a enviar que tengo en el form_ejemplo.php este si me carga la segunda pantalla que es la que quiero que cargue los datos introducidos en la segunda pantalla.
Pero lo logico es que cuando cargue primera vista el boton submit del form sea el que llame a la segunda vista con los datos introducidos.
Te muestro lo que tengo en el index.phtml:
escape($this->title); ?>
form; ?>
el EjemploController.php:
view->title = “Ejemplos”;
}
public function indexAction()
{
$form = new Default_Form_Ejemplo();
$this->view->form = $form;
}
public function enviarAction()
{
$request = $this->getRequest();
$form = new Default_Form_Ejemplo();
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
Zend_Loader::loadClass(’Zend_Filter_StripTags’);
$filter = new Zend_Filter_StripTags();
$correo = trim($filter->filter($this->_request->getPost(’email’)));
$direccion = trim($filter->filter($this->_request->getPost(’direccion’)));
(AQUI ES DONDE TENDRIA QUE PASARLE LOS DATOS AL OTRO FORMULARIO)
$form = new Default_Form_Ejemplo2();
$this->view->form = $form;
}
}
$this->view->form = $form;
}
}
Como seria? que me Propones que haga?
admin dijó el 7 Octubre de 2009 a las 21:08
Hola Milena,
A ver si puedo ayudarte
En primer lugar deberías cambiar el butano porsubmeti y quitar el javascript pues al hacer click no estas enviando los datos, solo esta redireccionando al navegador. Si tienes una necesidad imperiosa de hacerlo en javascript ya te contaré como hacerlo, pero no te lo recomiendo.
En tu clase formulario añade el atributo action de tu formulario:
$this->$this->setAction(’/ejemplo/enviar/’);
No esta de más añadirle un id:
$this->setAttrib(’id’, ‘frmEjemplo’);
Comentas que los 2 formularios son iguales excepto por el submit ¿no? Entonces mejor no uses dos clases de formulario. En la segunda llamada al formulario quita el submit desde el controlador $form->removeElement(’submit’); Igualmente entonces puedes usar la misma vista para los dos formularios y tampoco necesitarás estar pasando los valores de un formulario al otro.
Otra cosa más veo que haces Zend_Loader::loadClass(’Zend_Filter_StripTags’);, puedes añadir en cada elemento de tu clase formulario un filtro para tal tarea (también para el trim.
Los campos de email los construyo así:
$this->addElement('text', 'identity', array( 'label' => 'Email', 'value' => '', 'required' => true, 'filters' => array('StringTrim', 'StripTags', 'StringToLower'), 'validators' => array('EmailAddress') ));Espero que te sirva de ayuda.
Milena dijó el 7 Octubre de 2009 a las 22:17
Hola Admin!
Muchas Gracias hice lo que me dijiste y eso si me funciono!!!
Nos vemos hasta pronto!!!
arts dijó el 8 Octubre de 2009 a las 15:14
Hola admin… Tienes algun enlace de como hacer combos anidados en zend sin ajax???? porque de verdad lo poco que encontrado no me sirve…
De antemano Gracias…
Milena dijó el 8 Octubre de 2009 a las 15:15
Hola como estan? Tengo otra duda sabes estoy haciendo un radio de tipo usuario natural o juridico y se como obtener un arreglo de los valores que puede tomar el radio pero no encuentro un metodo que me permita saber cual esta chequeado, me meti en la api y no consigo como el del checkbox que es isChecked().
asi obtengo los valores del radio:
$cheNatural = $form->getElement(’radejemplo’)->getMultiOptions()->getDescription();
pero en realidad lo que deseo es saber cual esta chequeado para asi hacer aparecer unas cajas de texto y con el otro radio aparecer otras.
Gracias de antemano! Espero tu respuesta
Milena dijó el 8 Octubre de 2009 a las 15:17
Disculpa sin el getDescription(), esa era una prueba que estaba haciendo, el resto si queda igual..
arts dijó el 8 Octubre de 2009 a las 22:00
Hola admin.. con respecto a lo q l contestastes a milena “Comentas que los 2 formularios son iguales excepto por el submit ¿no? Entonces mejor no uses dos clases de formulario. En la segunda llamada al formulario quita el submit desde el controlador $form->removeElement(’submit’); Igualmente entonces puedes usar la misma vista para los dos formularios y tampoco necesitarás estar pasando los valores de un formulario al otro.” ¿¿como le envio los datos a un segundo formulario que ademas de los datos q estan en ambos tienen otros????? y quisiera q al presionar un radio m monte tanto los datos iguales como los q faltan por rellenar??? Si puedes ayudarme gracias de antemano…
Milena dijó el 9 Octubre de 2009 a las 21:22
Hola como estan??? he estado haciendo algunas prubas sobre los javascript y no encuentro la manera de llamar a las funciones que las tengo en public/javascript/. Si tengo mi formulario con Zend_Form ya que en el phtml solo tengo el echo al formulario.
Lo que estoy intentando hacer es que al seleccionar un radio me muestre unas cajas de texto y al seleccionar el otro pues me muestre otras cajas… Como podria hacer el llamado a un js si uso Zend_Form?? o hay otra manera de hacerlo???
Gracias de antemano!!!
admin dijó el 10 Octubre de 2009 a las 0:17
Hola Arts,
Perdona por responder tan tarde, ando muy liado estos dias. No he tenido tiempo de revisar bien tur problema, pero lo que me comentas es un poco complicado de hacer con el zend form.
Lo que queires hacer es algo dinámico por lo que necesiaras un poco de JavaScript.
Zend Form facilita muchas tareas en los formularios pero también limita las posibilidades.
¿Se trarta de un formulario de “dirección pedido” / “dirección facturación”? ¿O algo parececido? ¿en que cuando haces click en un checkbox,radio, o botón se copian los datos de un formulario al otro? En ese caso el proceso de copiar/mostrar el formulario con los valores lo deberás hacer con JavaScript, con Zend Framework no vas a poder. El caso de Milana es otra cosa.
admin dijó el 10 Octubre de 2009 a las 0:30
Hola nuevamente Arts,
No lo cierto es que no dispongo de un link para hacer combos anidados sin AJAX. No es una tarea demasiado complicada pero si un pelin laboriosa y no depende tanto de Zend Framework si no del algoritmo que apliques. Para situaciones de estas deberás olvidarte un poco del Zend Form
Una forma sin AJAX ni JavaScript para realizar esta tarea, vamos a suponer 2 combos, necesitras de un formulario con 2 submits, cada uno con distinto nombre (name=”") y si no me equivoco diferente value
Recuerda que si hay más campos en el formulario los deberás vover a imprimir en sus respectivos inputs para que el usuario no tenga la necesidad de volverlos a introducir.
Espero que esto te sirva de guia para empezar.
admin dijó el 10 Octubre de 2009 a las 0:53
Hola Milena,
Para hacer las llamas a los ficheros .js debeeras poner en el tu layout o tpl algo así:
headScript()->appendFile('/scripts/application.js'); ?>
Por lo general se ponen entre las etiquetas head del HTML, pero suele se mejor poner las llamadas de JavaScript justo antes de la etiqueta de cierre del body.
¿Te refieres a esto?
Milena dijó el 13 Octubre de 2009 a las 20:14
Hola admin que tal?? Lo que quiero saber en si es como hago para agregar un javascripts que me diga cual es el radio que tengo seleccionado, si estoy trabajando con Zend_Form; ya que en el phtml no tengo nada solo un echo al formulario.
Si tuviera los elementos en el html no hubiese problema pero como mi formulario es una extension de Zend_Form ese es el detalle.
Espero puedas ayudarme gracias…
Milena dijó el 14 Octubre de 2009 a las 16:38
Hola como estan??
Tengo otra duda, estaba usando PDO_Sqlite y ya lo pase a la de postgres y ya me guarda y todo chevere, el problema que tengo ahora es que estoy tratando de hacer un select y que se cargue directamente de la base de datos y lo hago asi:
$this->addElement(’select’,’selejemplo’,array(
‘label’ => ‘Estado’,
‘value’ => ”,
‘required’ => true,
‘autocomplete’ => false,
‘order’ => ‘7′,
‘decorators’ => $decorators,
‘multiOptions’ => Zend_Registry::set(’dbAdapter’,'Prueba’)->fetchPairs(’SELECT id_estado,descripcion FROM estado’),
));
me da este error:
Fatal error: Call to a member function fetchPairs() on a non-object in /var/www/SIS/application/forms/Ejemplo.php on line 100
y para el adaptador de la base de datos tengo lo siguiente:
en el aplication.ini
resources.db.adapter = “PDO_Pgsql”
resources.db.params.host = localhost
resources.db.params.username = postgres
resources.db.params.password = 123456
resources.db.params.dbname = Prueba
en el Bootstrap.php
protected function _initDB()
{
if ($this->_config->db) {
$dbAdapter = Zend_Db::factory($this->_config->db);
Zend_Db_Table::setDefaultAdapter($dbAdapter);
Zend_Registry::set(’dbAdapter’, $dbAdapter);
}
}
Sera que me hace falta algo mas?? o estare declarando algo malo?? o asi no se carga el select???
arts dijó el 14 Octubre de 2009 a las 20:21
Hola de nuevo… tengo un problemita como hago para llamar un javascripts en un button del formulario????… lo intente colocandolo en un carpeta llamda js y despues le di la ruta pero no reacciona al llamado.. si alguien m puede ayudar …
admin dijó el 14 Octubre de 2009 a las 20:39
Hola Milena
Creo que no esto no te voy poder ayudar. Pero no tengo muy claro que puedas llamar a la función
fetchParis()directamente desdeZend Registrydeberas cargarla en una variable.Saludos
admin dijó el 14 Octubre de 2009 a las 20:58
Hola Arts,
Zend Form Elementtiene un metodosetAttrib()al cual debes pasar dos parámetros: el attributo y el valor. Si lo quieres hacer desde tu clase formulario deberás hacer algo así:$this->addElement('text', 'identity', array(
'label' => 'Email',
'value' => '',
'required' => true,
'filters' => array('StringTrim', 'StripTags', 'StringToLower'),
'validators' => array('EmailAddress'),
'onclick' => "alert('test');",
));
Básicamente lo que haces es agregar el evento/attributo y su valor a la array.
Si lo que no te funciona es la llamada al fichero no se que es lo que debes estar haciendo mal…
comprueba que la llamda es correcta, usa el firebug, y mira que la llamda al ficehro no da un 404….
prueba a comprobar la ruta completa en el navegador del .js…
prueba hacer un alert en el ficehro .js …
Podrían ser mcuhas cosas… no se, por suponer podría incluso decirte que tienes mal agún parámetro en el ficehro .htaccess, pero seguro que es algo más sencillo.
admin dijó el 14 Octubre de 2009 a las 21:00
Hola Milena,
Esto es unatarea un pelin larga como para explicarla en un comentario, estoy intentando hacer algo y lo publicaré… pero no te puedo prometer que sea pronto.
Saludos
Milena dijó el 15 Octubre de 2009 a las 15:46
Ok gracias admin estaré pendiente a ver que colocas, e igual seguiré buscando a ver que consigo…
Hasta pronto
Milena dijó el 15 Octubre de 2009 a las 21:03
Hola! ya encontre la manera de traerme los valores desde la base de datos solo que ahora no se cargan en el select, ejemplo en mi Zend_Form hago la instancia del modelo obtengo los campos y se los paso al select pero no los monta, te muestro:
$table = new Default_Model_Estado();
$eje = $table->fetchAll();
$this->addElement(’select’,’selejemplo’,array(
‘label’ => ‘Estado’,
‘value’ => ”,
‘required’ => true,
‘autocomplete’ => false,
‘order’ => ‘7′,
‘decorators’ => $decorators,
‘multiOptions’ => $eje,
));
pero me manda un advertencia y ademas no muestra nada en el select o combobox.
Warning: htmlspecialchars() expects parameter 1 to be string, object given in /var/www/SIS/library/Zend/View/Abstract.php on line 850
que sera lo que pasa??? o es mas complicado como dices como me dijieste anteriormente y por eso cuando le paso la variable no muestra nada.
Gracias hasta pronto…
Milena dijó el 19 Octubre de 2009 a las 16:20
hola que tal!!!
Ya resolvi lo del select, tenia problemas con una funcion y por eso era que no se traia nada.
Gracias hasta pronto…
Milena dijó el 20 Octubre de 2009 a las 15:49
Hola que tal Admin!
Estoy haciendo un formulario de extension Zend_Form y tengo dos botones uno es un submit y el otro es un button. El submit haca la accion $this->setAction(’./ejemplo/buscar’); del form que es un buscar. (Esta accion es del controlador ejemplo)
Pero el button que es un enviar a otro formulario tiene lo siquiente: (Esta accion es del controlador ejemplo2)
‘onClick’ => ‘javascript:location.href= “./ejemplo2/otra”‘,
y monta en el url la accion (./ejemplo2/otra) como debe ser pero no hace nada monta el formulario que esta por el else que es el que se monta cuando el formulario noes valido, es como que si el form no trajeta nada de la pantalla anterior.
la accion es la siguiente:
public function otraAction()
{
$request = $this->getRequest();
$form = new Default_Form_Ejemplo();
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
$radejemplo = $form->getValue(’radejemplo’);
$correo = $form->getValue(’email’);
$direccion = $form->getValue(’direccion’);
$fecha = $form->getValue(’fecha’);
$cheejemplo = $form->getElement(’cheejemplo’)->isChecked(); //valor =1 esta chequeado
$validator = new Zend_Validate_NotEmpty();
if ((!$radejemplo==’natural’)OR(!$cheejemplo==1)OR(!$validator->isValid($correo))OR(!$validator->isValid($direccion))OR(!$validator->isValid($fecha)))
{
echo(’Verifique uno de los Campos esta en Blanco.’);
$this->_redirect(’/ejemplo’);
}else
{
$var = $_POST['radejemplo'];
if ($var == ‘natural’){
$this->view->form = $form;
$arreValores = $form->getValues();
$form = new Default_Form_Ejemplo2();
$form->removeElement(’rif’);
$form->setDefaults($arreValores);
$this->view->form = $form;
}else{
$this->view->form = $form;
$arreValores = $form->getValues();
$form = new Default_Form_Ejemplo2();
$form->removeElement(’cedula’);
$form->setDefaults($arreValores);
$this->view->form = $form;
}//else Nº 2
}//else Nº 1
}//if form
}// if getRecueste
$this->view->form = $form;
}//funcion
Sera porque son acciones de controladores distintos?? Pero si coloco la accion de (./ejemplo2/otra) en el form y el button como submit si hace todo bien y el otro submit como button y pues se daña hace lo mismo que lo anterior.
Y los dos no los puedo colocar como submit porque intentan hacer la misma accion. Uso la version 1.9.3
fernando dijó el 23 Octubre de 2009 a las 13:46
Hola, estoy haciendo una aplicacion con zend framework y quisiera hacer un menu lateral, en el cual los datos son traidos de la base de datos.
Cual es la mejor solucion para esto? ActionStack?
Me enteré que a partir de la version 1.8 existe Zend_Navigation pero todavia no lo he visto.
Si me puedes despejar esta duda te agradezco.
admin dijó el 24 Octubre de 2009 a las 18:37
Hola Fernando,
Bueno parece ser que los ActionStacks no son la mejor idea. Estoy revisando el tema con Zend Navigation pero lo veo un poco engorroso.
Lo cierto es que no puedo aconsejarte, estoy en las mismas.
arts dijó el 26 Octubre de 2009 a las 19:41
Hola admin q tal.. tengo un problemita tengo un formulario donde tengo 2 botones uno de buscar y el otro de modificar, una ves q yo busq m trae los datos y si quiero modifico el q desee(hasta los momentos), tengo 2 submit y lo hice asi:
$this->setMethod(’post’);
$this->setAction(’./formulario/validar’);
.
.
.
$this->addElement(’submit’, ‘buscar’, array(
‘ignore’ => true,
‘label’ => ‘Buscar’,
‘decorators’ => $buttonDecorators,
));
$this->addElement(’submit’, ‘modificar’, array(
‘ignore’ => true,
‘label’ => ‘Modificar’,
‘decorators’ => $buttonDecorators,
));
En el controlador esto;
public function validarAction()
{
$param= $this->_request->getPost();
$form = new Default_Form_Formulario();
if ($form->isValid($_POST)) {
$boton1 = $_POST['buscar'];
$boton2 = $_POST['modificar'];
if(!empty($boton1)) {
$id_usuario = $form->getValue(’id_usuario’);
$buscamodel = new Default_Model_Prueba();
$busca = $buscamodel->find($id_usuario);
$form->populate($busca);
$this->view->form= $form;
}
else
if (!empty ($boton2)) // boton 2
{
// $this->_forward(’accion’);
$this->_forward(’modificar’, ‘formulario’, null, $param);
}
}
else //El formulario es invalido
{
print_r(”no paso”);
}
}
public function modificarAction()
{
$param= $this->_request->getPost();
$form = new Default_Form_Formulario();
$idusuario = $form->getValue(’idusuario’);
$busqueda = new Default_Model_Prueba();
$busca = $busqueda->find($idusuario);
if (!($busca == null)) {
$busqueda->update($idusuario);
echo (’Modificado Exitosamente’);
}
}
}
El problema es q cuando busco y despues modifico al presionar el boton en la url m monta otra ves la ruta y pues el no ejecuta nada porq la ruta esta mala.. Como hago para solucinar esto????
admin dijó el 26 Octubre de 2009 a las 20:44
Hola Arts,
Una vez tienes detectado que se ha pulsado el boton de “modificar” tal vez lo que deberias hacer es una redirección:
$this->_helper->redirector($action, $controller, $module);
Eso si, entiendo que el códio que tienes en modificarAction() deberias ponerlo en el codicional del botón modificar o llamar a la funcion modificarAction desde el condicional, pero entonces no deberia ser una acción.
Lo que no tengo claro es que quieres hacer tras guardar los cambios, si mostra los datos guardados o la búsqueda.
arts dijó el 26 Octubre de 2009 a las 21:46
Voy a probar; yo necesito buscar en algun momento editar y despues guardar; son dos acciones por separado,pero en algun momento va a depender una de otra…!! si m explico???
admin dijó el 27 Octubre de 2009 a las 0:51
Hola Arts,
Hacer lo que propones no debería ser muy complicado si tienes bien claro como estructurar las acciones. Pero recuerda que un formulario solo puede llevar a una acción. Si quieres que la accion cambie dependiendo del botón deberias de programar los eventos de los botones con javascript para alterar el action del form.
Si lo haces con solo un action (personalmente prefiero esta sin javascript) entonces deberás de creater en tu controlador dos funciones una para modificar y otra para buscar, pero estas no deberían ser del tipo: modificarAction() y buscarAction(), para ello sería mejor una acción por ejemplo: procesarAction() que dependiendo de si has clicado un botón llame en el condicional a una función protegida modificar() o a la otra llamada buscar().
Una vez procesado los datos de búsqueda o de modificar los cargas en el formulario y voilà!
Imagino que lo que quieres hacer es poder buscar un registro de la bd con cualquier campo del formulario, pero ¿y si hay más de un resultado?
Por otra parte no se si tes estarás complicado, pues lo más facil y usable es seguir el método clasico de lisatdo de resultados con un botón/link indivuidual de editar el cual te lleva al formulario con los datos cargados y allí proceder con la edición.
Si luego lo que quieres es ofrecer una mejor experiencia de usuario es cuando entra en juego el javascript, pero las buenas practicas pasan primero por funcionar sin él. Entonces puedes enviar los datos por AJAX para no hacer una nueva búsqueda ni recargar la página.
En fin que todo se puede hacer, pero hay que tenero todo muy claro y saberlo hacer però Zend Framework a veces dificulta un poco estas tareas.
¿Cuanto tiempo llevas programando? ¿Y con Zend? Quizás doy por obvio algunas cosas o tal vez me puedo ahorra algunos detalles. El no saber esto creo que me lleva malas interpretaciones de lo que a veces me preguntais o os respondo.
arts dijó el 27 Octubre de 2009 a las 16:49
Ok voy a probarlo.. Pues tengo poco tiempo programando y con zend pues ahorita(Lo estoy usando por cuestiones de trabajo)… Disculpa la fastidiadera, pero como existen estos foros pues no hay una mejor parte dond preguntar… no crees!!!
violeta dijó el 29 Octubre de 2009 a las 16:26
Hola Buenos Dias…. sabes que necesito conecytarme de php a mckoi, por casualidad no sabes de un drivers que me permita comunicarme, de verdad lo necesito con urgencia.
Espero y de verdad me puedas ayudar……
admin dijó el 29 Octubre de 2009 a las 21:42
Hola Violeta,
Siento decirte que no.
YoGuuu dijó el 22 Enero de 2010 a las 18:15
Quiero agradecerte, la claridad no solo en cuanto a la redacción del código o de los artículos. Sinó a la hora de ser capaz de exponer los conceptos como digo, con una claridad que alumbra a los que estamos confundidos (por la deficiente documentación quizá). Yo veo buenas prácticas.
Ciertas cosas que he leido me han ayudado mucho a comprender. En este post concretamente aunque si bién es cierto que sería mejor hacer uso de Zend_Navigation a mi me ha hecho comprender como usar los responseSegments en el layout y ActionStack Cosa que me parece… de muchisima utilidad para manejarse.
Si necesitas ayuda de cualquier tipo, o una opinión, o para hablar de zf ya sabes mi email !!
Un saludo y Gracias !
admin dijó el 22 Enero de 2010 a las 20:45
Hola YoGuuu,
Muchas gracias por tu comentario, me han ilusionado mucho tus palabras.
Hace algunos meses que no actualizo el blog y ando bastate ocupado. Pero ahora que se avecinan cambios importantes con Zend Framework será cuestión de meterse otra vez.
Agradezco tu propuesta y tomo nota para futuros posts!
Gracias Otra vez y culaquier cosa… por aquí estamos!
YoGuuu dijó el 23 Enero de 2010 a las 22:02
De nada ! Últimamente me ha decepcionado a mi mucho la documentación de Zend Framework. Por eso me gusta tanto ver blogs como el tuyo donde hay buenos articulos en castellano sobre ZF…
Ahora estoy haciendo un proyecto base (soy novato xD), solo con un módulo “default”. Mi pensamiento es ponerle el código para que acepte un layout por modulo mediante plugin y no mediante actionHelpers como vi en otro ejemplo… y despues miraré donde tengo los ejemplos para ponerle un ACL Básico que también acepte módulos junto con la autenticación… A partir de ahí db y… uhmmmm…..
Un Saludo !!!
Daniko dijó el 25 Febrero de 2010 a las 16:51
Hola buenos días:
Tengo un formulario hecho con Zend form en donde deseo poner un campo fecha, es aca en donde tengo un problema pues deseo utilizar un datepicker pero no lo puedo configurar, hay una manera mas sencilla de hacer esto, espero que me pueda ayudar. Gracias,
Saludos