Como manejar fechas en Zend Framework con Zend Form y Zend Validate
Publicado en PHP el por
Validar una fecha en un formulario usando los módulos Zend Form y Zend Validate no tiene ningún misterio tan solo deberemos agregar la clase Zend_Validate_Date a la opción valdators de nuestro elemento tipo text del fomulario, algo así:
$form->addElement('text', 'date', array(
'label' => 'date',
'validators' => array('date')
));
El problema lo encontramos cuando queremos usar un determinado formato de fecha y lo queremos almacenar en la base de datos. Este tipo de tareas son las que un programador siempre recopila en una función y se las guarda en su librería para facilitarse la tareas repetitivas en sus proyectos. En cierto modo estas tareas ya las hacen o deberían hacer los frameworks (pues los frameworks son al final una recopliación de funciones y clases para facilitarnos el trabajo).
En el Zend Framework no existe por ahora una forma muy clara de como automatizar este proceso si usamos el módulo Zend Application pero con un par de apaños y sin usar ningún plugin o helper veamos como lo podemos solucionar con lo que nos ofrece el framework
Primeros, vamos a suponer que estamos creando una aplicación con la misma estructura que se usa en el Quick Start del Zend Framework. Entonces ¿Que neceistamos?
-
- Un objeto de formulario Zend_Form
- Un modelo de datos Zend_DB_Table y un mapeador
- internacionalizar la aplicación con Zend_Locale
¿Por dónde empezamos?
Lo primero que haremos será que nuestro formulario valide las fechas con el formato que a nosotros nos interesa dd/mm/yyyy (es decir el más común en la lengua hispánica). Para ello en nuestra objeto formulario que extiende el Zend_Form debe existir un elemento tipo texto para introducir la fecha:
$this->addElement('text', 'fecha', array(
'label' => 'fecha',
'required' => true,
'filters' => array('StringTrim', 'StripTags'),
'validators' => array('date')
));
Lo que estamos haciendo es que solo las fechas serán validas pero no estamos indicando en que formato. Aquí es cuando entra en juego Zend Locale por lo que añdiremos en nuestro bootstrap la siguiente función:
protected function _initLocale(){
$locale = new Zend_Locale();
$locale->setLocale('es_ES');
Zend_Registry::set('Zend_Locale', $locale); // la registramos para su futuro uso en el resto de la aplicación
}
Una vez la fecha es valida la hemos de guardar en la base de datos con el formato tipico de yyyy-mm-dd. Nos situamos en la función Save de nuestro mapper y añadiremos al principio la conversión de tipo de fecha con Zend_date:
public function save(Default_Model_Mitabla $tabla){
// Creamos un objeto Zend_Date y como parámetro la fecha que recibimos
$fecha = new Zend_Date($tabla->getFecha());
$data = array(
'nombre' => $tabla->getNombre(),
'startDate' => $startDate->getIso() // retornamos la fecha en formato ISO 8601
);
if (null === ($id = $tabla->getId()) || $tabla->getID() == 0) {
unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id));
}
}
Finalmente solo nos queda una cosa, recuperar las fechas de la base de datos en el formato que deseamos, por lo que modificaremos la función Find del mapper:
public function find($id, Default_Model_Mitabla $tabla){
$result = $this->getDbTable()->find($id);
if (0 == count($result)) {
return;
}
$row = $result->current();
$fecha = new Zend_Date($row->fecha, Zend_Date::ISO_8601);
$job->setId($row->id)
->setNombre($row->nombre)
->setStartDate(str_replace('00:00:00', '', $fecha->getDate()));
}
Nuevamente lo que hacemos es crear un objeto Zend Date pasando como primer argumento la fecha que recibimos de la base de datos y como segundo el formato en que la recibimos. Luego con getDate() devolvemos la fecha en el formato esperado tal como hemos indicado con Zend_Locale. Notad que he añadido un str_replace pues como se trata de un campo de tipo Date y no Datetime no me interesa que me retorne la hora.
De esta forma, en principio, nos será fácil mantener una aplicación en diferentes idiomas y las fechas se mostraran en el formato propio del idioma indicado, prueba a cambiar el argumento locale del objeto >Zend Locale y todo debería funcionar correctamente.
Espero que os sea útil y se veis algún error o sabéis la forma de hacerlo mucho más fácil espero vuestros comentarios.
12 Comentarios
caro dijó el 22 septiembre de 2009 a las 16:05
Muy bueno este material.. necesito ayuda como hago formularios asignandoles funciones a cada boton.. como por ejemplo guardar, eliminar y modificar.. si alguien tiene algun ejemplo o m puede ayudar c lo agradeceria…
admin dijó el 22 septiembre de 2009 a las 16:40
¡Gracias!
Respondiendo a tu pregunta: Primero deberás crear en tu controler las acciones necesarias por ejemplo: public function actionEliminar(){} y hacer las llamadas necesarias al modelo para eliminar. En este caso solo necesitarás un link tipo : {controller}/{accion}/id/$idFila donde id es el parámetro GET y $idFila será el valor del id. Bueno esto es solo el principio, en unos días publicaré un post explicando detalladamente que hacer para cada botón que necesitas.
Saludos
caro dijó el 7 octubre de 2009 a las 14:54
Gracias admin!!
Tengo un problemita a ver si me puedes ayudar, tengo una vista donde lleno unos datos basicos despues tengo una accion q m envia los datos al mismo formulario pero no m lo valida… no se porque te envio n accion para q le eches un vistaso y m ayudes si puedes
public function pasarAction()
{
$form = new Default_Form_Formulario();
$parametros= $this->_request->getPost();
print_r ($parametros);
if ($form->isValid($_POST))
{
$form->populate($parametros);
$this->view->form= $form;
echo “paso”;
}
$this->view->form = $form;
}
al imprimir lo q tiene parametros m muestra Array (); creo q no estoy haciendo bien el paso de parametros.. Cual es mi erro????? De antemano gracias..
admin dijó el 7 octubre de 2009 a las 23:45
Hola Caro
He probado tú código y no consigo reproducir tu error, pero vayamos por pasos:
Según la documentación setDefaults() y populate() hacen exactamente lo mismo. Fijate que la array devuelta por estas funciones las Keys coinciden con los elementos de tus formularios y que los valores de estas sean los que tu has introducido.
Si te muestra array() esta claro que lo que significa es que la array esta vacía. Por lo que no se están recibiendo los datos.
Asegurate que estas enviando los datos correctamente esto lo puedes comprobar mirando (Como el comentaba a Milena):
Sí has puesto el method como post en el formulario. Si no lo has echo es estarán enviando por get
o Si estas enviando los datos con javascript:locación.href en un botón y no con un sumbmit
También puedes probar de hacer un print_r de $_POST. Si no te devuelve datos, es que no los estas enviando correctamente. Si pruebas a imprimir $_GET y te devuelve los datos es por que no has especificado el tipo de envío como post en el action del formulario es decir method=”post” por lo que deberás añadir en tu clase de formulario $this->setMethod(‘post’);.
Si esto no resuelve tu problema te cuento como lo hago normalmente.
Uso la misma acción para mostrar el formulario vacío y procesar los datos (para editar los datos lo suelo hacer en otra acción). Te lo transcribo a ver si te da alguna pista:
public function newAction(){
$form = new Default_Form_Job();
if ($this->getRequest()->isPost()) {
$request = $this->getRequest();
if ($form->isValid($request->getPost())) {
$model = new Default_Model_Jobs($form->getValues());
$model->save();
/*
Si queremos redirigir a listado
(faltaría pasar algún parámetro para mostrar algún mensaje de “guardado”
*/
//return $this->_helper->redirector(‘index’);
}
} else {
// Si los datos han de ser inicializados desde una tabla:
// (generalmente uso una acción para editar y otra para crear,
// pero a modo de ejemplo lo pongo aquí)
$jobID = $this->_getParam(‘id’, 0);
$model = new Default_Model_Jobs();
$job = $model->find($jobID);
//Iniciamos el formulario con una array que
//contiene los datos de la tabla
$form->setDefaults($job->toArray());
}
$this->view->form = $form;
}
De esta forma procesamos los datos:
Instanciamos el formulario
Comprobamos si se han enviado los datos por post
Obtenemos los datos
Validamos los datos
Instanciamos el modelo
Guardamos los datos en el modelo/tabla
Si queremos redirigir al listado usamos el helper
Entonces si no se han recibido parámetros se carga el formulario vacío o con los datos inicializados según si hacemos o no el bloque del else.
Si los hemos recibido pero no son validos cargamos el formulario con los nuevos datos y los errores.
Lo importante aquí es la parte del isValid() que es el que se encarga de de obtener los datos del formulario con getValues() y procesarlos.
Espero que te sirva de ayuda.
arts dijó el 12 noviembre de 2009 a las 21:45
Hola, muy bueno el material pero m dejo una duda quien es startDate… ????
arts dijó el 13 noviembre de 2009 a las 14:56
Hola, tengo un problemita…Estoy usando esto para las fechas pero no c quien es setStartDate() , y al colocarlo m da error.. si m puedes ayudar t lo agradeceria..
admin dijó el 13 noviembre de 2009 a las 20:10
Hola Arts,
startDatees el nombre del campo de mi modelo de datos. Tu debes usar tus propios campos.Milena dijó el 26 noviembre de 2009 a las 15:10
Hola que tal a todos!!!
Estoy probando el codigo que dices para la fecha y no me hace nada guarda pero a la hora de mostrar la fecha sigue en el formato yyyy/mm/dd.
en el mapper tengo lo siguiente:
public function save(Default_Model_Modificar $ejemplo2)
{
$fecha = new Zend_Date($tabla->getFecha());
$data = array(
‘email’ => $ejemplo2->getEmail(),
‘cedula’ => $ejemplo2->getCedula(),
‘rif’ => $ejemplo2->getRif(),
‘direccion’ => $ejemplo2->getDireccion(),
‘id_estado’ => $ejemplo2->getId_estado(),
‘fecha’ => $startDate->getIso(),
//’fecha’ => $ejemplo2->getFecha(),
‘id_usuario’ => $ejemplo2->getId_usuario(),
);
if (null === ($id_eje = $ejemplo2->getId_eje())) {
unset($data['id_eje']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array(‘id_eje = ?’ => $id_eje));
}
}
public function fetchAll()
{
$resultSet = $this->getDbTable()->fetchAll();
$entries = array();
$fecha = new Zend_Date($row->fecha, Zend_Date::ISO_8601);
foreach ($resultSet as $row) {
$entry = new Default_Model_Ejemplo2();
$entry->setId_eje($row->id_eje)
->setEmail($row->email)
->setCedula($row->cedula)
->setRif($row->rif)
->setDireccion($row->direccion)
->setId_estado($row->id_estado)
->setFecha(str_replace(’00:00:00′, ”, $fecha->getDate()))
//->setStarDate(str_replace(’00:00:00′, ”, $fecha->getDate()))
//->setFecha($row->fecha)
->setId_usuario($row->id_usuario)
->setMapper($this);
$entries[] = $entry;
}
en el Bootstrap tengo lo mismo:
protected function _initLocale()
{
$locale = new Zend_Locale();
$locale->setLocale(‘es_ES’);
Zend_Registry::set(‘Zend_Locale’, $locale); // la registramos para su futuro uso en el resto de la aplicación
}
el setStarDate supongo que es el que esta en el modelo y en el mio se llama setFecha por eso lo demas esta en comentario… Que sera que me falta o que tengo malo y por eso no me trae la fecha en el formato dd/mm/yyy.
Gracias, espero puedas ayudarme
admin dijó el 26 noviembre de 2009 a las 23:19
Hola,
mmm… prueba a poner esto:
date_default_timezone_set('Europe/Vienna');Donde Europe/Vienna ha de ser tu timezone
Milena dijó el 30 noviembre de 2009 a las 20:32
Hola, gracias por responder…
Lo probe en el Bootstrap y me da un error, lo que hice es que eso se lo pase a una variable y al Zend_Registry le pase esa variable, pero al momento de hacer la busqueda de un error localidad…
no es alli donde va???? o es en el Mapper…
Gracias de antemano
Milena dijó el 30 noviembre de 2009 a las 20:49
Hola…
Listo ya lo resolvi el detalle ahora es que me sale en el formato de fecha dd/mm/yyyy en una lista donde tengo todos los registros de la base de datos el problema esta en que cuendo selecciono uno de ellos para modificar y se carga en la vista con las cajas de texto el campo fecha sigue apareciendo en yyyy/mm/dd.
Por que sera esto, la vista donde se muestran los valores es http://localhost/SIS/public/modificar
y una vez que hago click para modificar es http://localhost/SIS/public/modificar/modificar/id_eje/4
No se supone que esta en el mismo lado????
Alexis dijó el 1 abril de 2010 a las 8:21
Me ha gustado mucho el articulo, llevaba mucho tiempo detras del asuntillo de validar fechas y al ver esta solución tan sencilla no me lo podía creer.
Muchas gracias y saludos