December 17th, 2008 Category: blogzf Zend Framework
40 Comments »
Zend Form
Hoy vamos a ver como armar los formularios. Para eso vamos a usar la carpeta forms dentro de nuestras vistas, ahí vamos a crear una clase para cada formulario.
Muchas ponen los formularios en el controller y algún que otro loco en el modelo, y también en los helpers, nosotros vamos a crear una clase para que resuelva nuestro problema en la carpeta forms de la vista del modulo correspondiente.
Nuestra clase va a tener un solo método init() y va a extender de Zend_Form.
El ejemplo a continuación es el de login de usuarios, con 3 elementos, usuario, password, y el botón de submit.
setName('authentication');
/**
* Creamos un elemento de tipo Text
* - Seteamos el texto que queremos que represente a este campo
* - Agregamos un filtro, que hace que cuando enviamos el
* fomrulario ponga todo el valor del campo en minuscula
* - Tambien especificamos que el campo es obligatorio.
* - Y agregamos el validador para preguntar si el campo es un campo valido
*/
$username = new Zend_Form_Element_Text('username');
$username->setLabel('Email')
->addFilter('StringToLower')
->setRequired(true)
->addValidator('NotEmpty', true);
/**
* Creamos el elemento tipo password.
* Aca vamos a generar el campo para la clave
*/
$password = new Zend_Form_Element_Password('password');
$password->setLabel('Clave')
->setRequired(true)
->addValidator('NotEmpty', true);
/**
* El boton para enviar el formulario
*/
$submit = new Zend_Form_Element_Submit('submit');
$submit->setLabel('Entrar');
/**
* Agregamos los elementos al formulario
*/
$this->addElements(array($username , $password , $submit));
}
}
Como se habrán dado cuenta nuestro archivo se va a llamar Authentication.php
Cada vez que se instancie y se imprima este objeto nos va a dibujar automaticamente nuestro formulario.
Ahora vamos a llamar a mostrar el formulario en nuestras paginas.
Vamos al controller
_request->isPost()) {
$credentials = $this->_request->getPost();
if ($form->isValid($credentials)) {
$authAdapter = new Zend_Auth_Adapter_DbTable(
Zend_Db_Table::getDefaultAdapter(),
'users','username','password', 'MD5(?) AND status="ENABLED"');
// Set the input credential values to authenticate against
$authAdapter->setIdentity($credentials['username']);
$authAdapter->setCredential($credentials['password']);
$result = Zend_Auth::getInstance()->authenticate( $authAdapter );
if ($result->isValid()) {
$this->_redirect('/admin/dashboard/');
}
$this->_flashMessenger->addError('usuario incorrecto');
$form->populate($credentials);
} else {
$this->_flashMessenger->addError('Hay datos invalidos o vacios');
$form->populate($credentials);
}
}
$this->view->form = $form;
}
}
En nuestro indexAction vemos que lo primero que se hace es instanciar la clase forms_Authentication que creamos anteriormente. Seguidamente tenemos una linea que pregunta si hay datos enviados via post, en nuestro caso esta condicion va a ser falsa porque todavia no enviamos ningun formulario. Asi que vamos a explicar lo que hacemos en caso de que no se haya enviado el formulario aun.
$this->view->form = $form;
Aca estamos pasando a la vista nuestro objeto Form. Para dibujar nuestro formulario desde el controller esto es lo unico que tenemos que hacer.
Ahora pasemos a la vista. Y veamos como queda de complejo nuestro index/index.phtml
=$this->form?>
Esto solo y nos deberia mostrar lo siguiente.
Ahora que ya tenemos nuestro formulario vamos a completar datos y enviarlo. Completamos con cualquier dato. Pero para probar vamos a completar el usuario y no la clave. Para aprender a usar los Validators.
Si hacemos esto nos deberia aparecer el formulario resaltando el problema por el cual no proceso el formulario.
Y como hicimos esto?
Muy facil, cuando creamos el formulario, no especificamos a donde queremos que envie los datos, entonces los envia a si mismo.
Esto quiere decir que enviamos un post a indexAction, ahora el condicional if ($this->_request->isPost()) nos va a dar verdadero.
Lo siguiente que preguntamos es si los datos de nuestro formulario son validos, en el caso que lo sean vamos a seguir con el logueo de usuario. En caso contrario vamos a volver a mostrar el formulario con los datos que envio el usuario, y agregano los errores correspondientes, esto lo hacemos llamando al metodo populate de Zend_Form, que solo se encarga de completar los datos que vinieron por post en el elemento correspondiente, y los errores. Lamentablemente los errores estan en ingles, y por ahora vamos a dejarlo asi. Tambien agregamos un error con el flashHelper de Zsamer.
Ahora probemos completar todos los datos, si corresponden a los de la base de datos te va a loguear, y redireccionar a tu dashboard.
Zend Auth.
Una de las cosas que mas me sorprendio cuando empeze con Zend Framework, fue la cantidad de tutoriales sobre este componente. La verdad que no tiene mucha mistica, pero el uso que le damos en blogzf es bastante basico y comun,
Primero instanciamos la clase Zend_Auth_Adapter_DbTable, y le pasamos los datos de nuestra tabla donde guardamos los datos de los usuarios, seteamos la columna donde esta el identificador, y la columna donde esta la clave (credencial).
Ya con la instancia seteamos los datos que vinieron con el formulario.
Y si Zend_Auth::getInstance()->authenticate( $authAdapter )->isValid() nos da true, estamos logueados.
Facil?, si es Zend.
Ahora necesitamos preguntar en cada modulo que lo requiera si el usuario ya esta logueado, en caso que no lo este vamos a redireccionarlo a la pantalla de login. En nuestro sistema lo vamos a hacer desde el plugin de Blogzf_Controller_Plugin_Backoffice.
$auth = Zend_Auth::getInstance();
if ( $request->module == 'admin' ) {
if( !$auth->hasIdentity() && $request->controller != 'index' ) {
header('Location: /admin/');
} elseif ( $auth->hasIdentity() && $request->controller == 'index' ) {
header('Location: /admin/dashboard/');
}
}
Con esto es suficiente.
Invitame una Cerverza
Comentar
40 Responses
La primer respuesta, es facil $form = new forms_Authentication(); esta en la linea 11 del controller.
La primera y la segunda estan relacionadas. Al yo incluir mis vistas en view, Zend ya lo toma dentro del path, asi que con solo decirle forms_Authentication(), uno de los lugares donde va a buscar el archivo es en application/blog/view/, pero tambien va a buscar en library/, y en la de los modelos ;)
application
- modules
-- Administracion
--- Controllers
--- Views
--- Models
-- FrotnEnd
--- Controllers
--- Views
--- Models
Es decir tengo un views para cada uno de los dos modulos, ahora, como utilizar el formulario? es decir, a que carpeta forms va a apuntar cuando lo instancie? pienso que si estoy dentro del controlador administracion solo puede instanciar a los forms que este dentro de su propio view, y no del view del otro modulo. Esto es asi?
Desde ya muchisimas gracias!
$this->addScriptPath('aplication/modules/administracion/views');
$this->addScriptPath('aplication/modules/FrotnEnd/views');
Gracias por tu atención, saludos.
La forma que muestro yo los formularios usan los tags predeterminados. Pero si vos queres poder establecer tus propios tags, usando los decorators. Y para los css solo con agregar los css de forma correcta ya tendria que tomarte tu estilo, tambien podes decirle a un objeto que clase, o style usar. ;)
Aca podes ver los decorators
http://framework.zend.com/manual/en/zend.form.elements.html#zend.form.elements.decorators
Mas info en la documentacion
" $this->view->setScriptPath('aplication/modules/administracion/views')" en el predistpach de mi controlador que instancia al formulario, pero me sigue diciendo el mismo error, que no encuentra la clase del formulario.
Qué hice mal?
PD: puse $this->view porque si ponia $this solamente, no podia encontrar el metodo setScriptPath
Desde ya, muchas gracias.
PATH_SEPARATOR . '..aplication/modules/administracion/views’
pero nose si es lo correcto, que opinas? de otra forma no pude hacerlo andar :-(
un abrazo.
gracias.
@Gabriel: Mira ahora que veo mi bootstrap yo lo tengo igual que vos. No me parece que sea la mejor solucion, pero todavia no le encontre nada mejor que eso, habra que investigar un poco mas. Gracias por aportar la solucion.
Un abrazo.
En primer quiero felicitarte por el blog, tienes cosas muy interesantes. Llevo unos 3-4 días mirándome un poco el Zend Framework y aunque sigo con muchas dudas... Tú blog me ha ayudado mucho.
Quería preguntarte acerca de los helpers y plugins. No se que concepto tienen respecto a Zend Framework. Por otro lado me ha quedado claro que Zend View maneja la parte visible, con respecto a que se encarga de procesar los archivos phtml. Por lo tanto todas las variables deben cargarse ya sea mediando $view -> assign(Mixed content[,mixed value]) donde $view hace una llamada previa a new Zend_View
Y bueno de momento creo que con haber pillado eso es suficiente... Pero la autentificación, es decir el checkeo de un usuario esta logueado y para según eso actuar de una forma u otra... ¿Cómo debo hacerlo? ¿Mediante algún helper, plugin o similar?
Un Saludo y muchas gracia spor tus esfuerzos.
Por un lado tenes dos tipos de Helper, los de la vista y los del controller, son para que puedas extender funcionalidades, nada del otro mundo, la forma que lo podes usar con ZF, es bastante comoda.
Con respecto al login, en este proceso yo estoy chequeando si el usuario esta logueado desde el plugin del backend.
Pero vos podes hacerlo en el predispatch de los controller que necesites autenticar.
Y lo haces de esta manera
$auth = Zend_Auth::getInstance();
if( $auth->hasIdentity() ) {
header('Location: /admin/dashboard/');
}else {
header('Location: /admin/');
}
La página no está redirigiendo adecuadamente
Firefox ha detectado que el servidor está redirigiendo la solicitud a esta dirección de una manera en la que nunca terminará.
* Este problema a veces está causado por desactivar o rechazar la recepción de cookies.
pero en mi navegador estan habilitadas las cookies
y salio el error cuando aumente estas lineas en el
predispach
if (UserModel::isLoggedIn()) {
$this->view->loggedIn = true;
$this->view->user = UserModel::getIdentity();
}else {
header('Location: /index/index/');
}
como podras ver mescle un poco de codigo del otro tuturial de blog en el capitulo 4 o 5 en logearse para dejar un comentario
por fis si podrias darme una manito te lo agradece mucho una ves mas
por fis ayudame
aqui te va mi codigo
[code]
view->baseUrl = $this->_request->getBaseUrl();
$this->user = new PersonaModel();
}
public function getForm() {
return new LoginForm ( array ('action' => '/index/login/', 'method' => 'post' ) );
}
public function preDispatch() {
if (PersonaModel::isLoggedIn()) {
$this->view->loggedIn = true;
$this->view->person = PersonaModel::getIdentity();
}
}
public function indexAction() {
$this->view->headTile = "Index Page";
$this->view->form = $this->getForm ();
}
public function loginAction() {
$form = new LoginForm();
if ($this->_request->isPost()) {
$credentials = $this->_request->getPost();
if ($form->isValid($credentials)) {
try{
$this->user->setMessage('El nombre de Usuario y Password no coinciden.', PersonaModel::NOT_IDENTITY);
$this->user->setMessage('La contraseña ingresada es incorrecta. Inténtelo de nuevo.', PersonaModel::INVALID_CREDENTIAL);
$this->user->setMessage('Los campos de Usuario y Password no pueden dejarse en blanco.', PersonaModel::INVALID_LOGIN);
$this->user->login($credentials['username'], $credentials['password']);
$this->_redirect('index/login');
} catch(Exception $e){
echo $responseLogin = $e->getMessage();
$this->_redirect('index');
}
$this->view->responseLogin = $responseLogin;
}
}
}
public function logoutAction() {
$this->user->logout();
$this->loggedIn=false;
$this->_redirect('/index');
}
}
[/code]
este es el PersonModel
[code]
"Not existent identity. A record with the supplied identity could not be found.",
self::INVALID_CREDENTIAL => "Invalid credential. Supplied credential is invalid.",
self::INVALID_USER => "Invalid User. Supplied credential is invalid",
self::INVALID_LOGIN => "Invalid Login. Fields are empty" );
/**
* @param string $messageString
* @param string $messageKey OPTIONAL
* @return UserModel
* @throws Exception
*/
public function setMessage($messageString, $messageKey = null)
{
if ($messageKey === null) {
$keys = array_keys($this->_messages);
$messageKey = current($keys);
}
if (!isset($this->_messages[$messageKey])) {
throw new Exception("No message exists for key '$messageKey'");
}
$this->_messages[$messageKey] = $messageString;
return $this;
}
/**
* @param array $messages
* @return UserModel
*/
public function setMessages(array $messages)
{
foreach ($messages as $key => $message) {
$this->setMessage($message, $key);
}
return $this;
}
public function login($nick, $password)
{
if (! empty ( $nick ) && ! empty ( $password )) {
Zend_Loader::loadClass ( 'Zend_Auth_Adapter_DbTable' );
$autAdapter = new Zend_Auth_Adapter_DbTable ( self::getAdapter () );
$autAdapter->setTableName ( 'persona' );
$autAdapter->setIdentityColumn ( 'identificador' );
$autAdapter->setCredentialColumn ( 'contrasenia' );
$autAdapter->setIdentity ( $nick );
$autAdapter->setCredential ( md5 ( $password ) );
$autAdapter->setCredentialTreatment(" AND estado='Activo'");
$auth = Zend_Auth::getInstance ();
$result = $auth->authenticate ( $autAdapter );
switch ($result->getCode ())
{
case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND :
throw new Exception ( $this->_messages [self::NOT_IDENTITY] );
break;
case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID :
throw new Exception ( $this->_messages [self::INVALID_CREDENTIAL] );
break;
case Zend_Auth_Result::SUCCESS :
if ($result->isValid ()) {
$storage = new Zend_Auth_Storage_Session();
$storage->write($autAdapter->getResultRowObject ());
// $data = $autAdapter->getResultRowObject ();
// $auth->getStorage ()->write ( $data );
} else {
throw new Exception ( $this->_messages [self::INVALID_USER] );
}
break;
default :
throw new Exception ( $this->_messages [self::INVALID_LOGIN] );
break;
}
} else {
throw new Exception ( $this->_messages [self::INVALID_LOGIN] );
}
return $this;
}
public static function logout()
{
// Zend_Auth::getInstance()->clearIdentity();
// Zend_Auth_Storage_Session::clear();
// Zend_Session::expireSessionCookie();
$storage = new Zend_Auth_Storage_Session();
$storage->clear();
return $this;
}
public static function getIdentity()
{
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
return $auth->getIdentity();
}
return null;
}
public static function isLoggedIn()
{
return Zend_Auth::getInstance()->hasIdentity();
}
}
[/code]
las lineas comentadas son las que ya cambie sin exito
plis ojala puedas ayudarme
Zend_Auth::getInstance()->clearIdentity();
Saludos.
$this->view->assign('roles',array('admin','segundo'));
despues del logeo y recupero de la siguiente manera en la vista pero no sale nada mas bien un error
foreach ($this->roles as $rol) :
echo $i++;
$this->escape($rol->name);
endforeach;
y el error es
Warning: Invalid argument supplied for foreach() in D:\MobiusWS\Quantum\application\default\views\scripts\index\Login.phtml on line 4
que puede estar fallando envio bien los datos?
tambien intente mandarlo de la siguiente manera
$this->view->roles = array('admin','segundo');
pero tampoco me llega nada
y
user:______ pass:_______ nomb:_____________
y asi
yo quise que se vieran
user:_________
pas:________
nom:________
y lo hice de la siguiente manera :
class UserForm extends Zend_Form {
public $elementDecorators = array(
'ViewHelper',
'Errors',
array(array('data' => 'HtmlTag'), array('tag' => 'td', 'class' => 'element')),
array('Label', array('tag' => 'td'),
array(array('row' => 'HtmlTag'), array('tag' => 'tr'))),
);
public $buttonDecorators = array(
'ViewHelper',
array(array('data' => 'HtmlTag'), array('tag' => 'td', 'class' => 'element')),
// array(array('label' => 'HtmlTag'), array('tag' => 'td', 'placement' => 'prepend')),
array(array('row' => 'HtmlTag'), array('tag' => 'tr')),
);
public function init()
{
$this->addElement('text', 'username', array(
'decorators' => $this->elementDecorators,
'label' => 'Username:')
);
$this->addElement('password', 'firstname', array(
'decorators' => $this->elementDecorators,
'label' => 'First Name:')
);
$this->addElement('text', 'lastname', array(
'decorators' => $this->elementDecorators,
'label' => 'Last Name:' ) );
$this->addElement('submit', 'save', array(
'decorators' => $this->buttonDecorators,
'label' => 'Save')
);
}
public function loadDefaultDecorators()
{
$this->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'table')),
'Form',
));
}
}
pero me sale todo en una linea alguna idea del porque?
gracias de antemano.
Como puedo hacer para traer los datos del action de validacion, al action del form (en caso de que los datos no sean correctos),
se puede hacer con populate?
Los datos del formualrio lso tenes en $form->getValue('elemento');
y para popular todo haces $form->populate($form->getValues());
Saludos.
Warning: Zend_Loader::include_once(Zend/Controller.php) [zend-loader.include-once]: failed to open stream: No such file or directory in /var/www/proyecto/library/Zend/Loader.php on line 83
Warning: Zend_Loader::include_once() [function.include]: Failed opening 'Zend/Controller.php' for inclusion (include_path='.:library/:application/models/:.:/var/www/Proyectos/library') in /var/www/proyecto/library/Zend/Loader.php on line 83
Fatal error: Uncaught exception 'Zend_Exception' with message 'File "Zend/Controller.php" does not exist or class "Zend_Controller" was not found in the file' in /var/www/proyecto/library/Zend/Loader.php:88 Stack trace: #0 /var/www/proyecto/index.php(22): Zend_Loader::loadClass('Zend_Controller') #1 {main} thrown in /var/www/proyecto/library/Zend/Loader.php on line 88
Seguramente en tus controllers pusiste que extienda de Zend_Contoller cuando en realidad tiene que extender de Zend_Controller_Action.
Saludos, y contame si soluciono esto tu problema
Si queres mandame por mail el source de tu codigo y lo miro.
pablofmorales [at] gmail com
Es decir tengo 3 botones de tipo submit, el form tengo la accion de una funcion que tengo en el controlador que me valida que boton toque y hace hacer la funcion que le corresponde pero el problema esta en que cuando le doy a otro submit la url cambia pero sigue mostrando la accion del form y por eso no ejecuta como debe ser cada metodo..
public function seleccionAction()
{
$request = $this->getRequest();
$form = new Default_Form_Ejemplo();
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
$boton1 = $_POST['buscar'];
$boton2 = $_POST['modificar'];
$boton3 = $_POST['eliminar'];
if(!empty($boton1)) {
// $this->_forward('/buscar');
$this->_forward('/buscar', null, null, $request->getPost());
} else {
if(!empty($boton2)){
$this->_forward('/modificar', null, null, $request->getPost());
// $this->_forward('/modificar');
}else{
$this->_forward('/eliminar', null, null, $request->getPost());
// $this->_forward('/eliminar');
}
}
}
}
$this->view->form = $form;
}
Este es la funcion que me valida que boton piso.
cuando piso el buscar la url es la siguiente http://localhost/SISLunes26/public/buscar/seleccion
despues que midifico lo que estan en las cajas y toco modificar hace esto http://localhost/SISLunes26/public/buscar/buscar/seleccion
la idea es que salga http://localhost/SISLunes26/public/buscar/modificar para que ejecute la otra accion.
Que sera lo que falta??? tengo algo malo????
$form->getValue( 'nombredelparametro');
No te conviene usar empty en este caso. Ya que empty puede ser "", 0, false, NULL esto hace que siempre pase por el primero.
Fijate que valor te trae el POST, para saber como validarlo mejor
por ejemplo podes hacer
Zend_Debug::dump( $this->getRequest()->getParams() );
Para saber cual es el valor exacto y poder compararlo con ese valor
veras tengo un formulario en el cual tengo cajas de texto un sibmin y un radiobutton con 2 opciones, perfecto hasta aqui,
el problema nace en que cuando seleciono una opcion del radiobutton quiero que muestre una caja de texto y si selecciono la otra ya no la muestre, no se como hacer esto si en alguno de tus Articulos tocaras este tipo de temas con una posible solucion te lo agradeceria
Acordate que dentro de Zend Form podes decirle que tenga un style de css, y podes decirle display:block; para que no se muestre
Saludos.





- Con que linea estas instanciando el objeto del formulario en el controller? no logro distinguir donde esta el "new objeto",
- Como te quedaria la primera linea de la clase del formulario, asi?
class Authenciador.php extends Zend_Form.
- otra cosita, como configuras el Zend para informarle, que la carpeta forms de las vistas, tambien va a tener clases?
desde ya
Muchas gracias.