En esta ocasión me voy a dedicar a arreglar los estropicios que hice anteriomente :D
Además, voy a añadir enlaces para eliminar los feeds (como me han solicitado) y también vamos a redirigir al usuario a la página principal después de añadir un feed (como también me han solicitado).
También añadiremos un mail al usuario que inserta el mensaje, por si no está registrado. En caso de que esté registrado, guardaremos una referencia al mismo.
Qué se explica aquí
En esta ocasión veremos cómo:
Redirigir al usuario a la página que deseemos.
Ordenación de tablas.
Expresiones regulares.
Notas previas
En la primera parte del tutorial drupal ya insistí en que sólo se debe abrir el tag de <?php, y no se debe cerrar con ?>. Dicho esto, continuamos.
Modificando la BBDD
Añadimos el campo usermail. Además, modificamos el campo “uid” para que referencie al usuario si éste hizo login.
El primer error fue la contabilización de feeds. Si miráis el tutorial Creación de un módulo Drupal (II)_, veréis la siguiente línea (función _feedback_count):
1
$query="SELECT count(id) as total from {feedback_messages} fm where fm.read != 1";
Bueno, pues está mal. Lo correcto es lo siguiente:
1
$query="select count(*) from drupal6.feedback_messages fm where isnull (fm.read) or fm.read != 1";
Como véis, comprobamos que no sea nulo, ya que en ese caso no estaba
contabilizando correctamente.
El segundo error cometido es que los set_error deben realizarse sobre un
campo. Así, en el primer tutorial, donde aparecen los set_error, están mal.
Realmente no veremos la diferencia si no la conocemos: Si lo hacemos bien, los
campos indicados se marcarán en rojo (depende del tema) indicando que el
problema se encuentra en ése campo. De esta manera, quedarían así (función
feedback_message_form_submit):
1
form_set_error('feedback',t("An error has happened. Your feedback has not been sent."));
Veremos la función completa cuando añadamos más cosas.
Y ya, como error menor, deciros que las etiquetas ‘Date’ y ‘User’ estaban cambiadas en la función feedback_admin.
Al final de este tutorial, pondré todo seguido para que podáis aclararos.
Modificando funciones
Primero vamos con lo más sencillo de todo: Queremos que cuando alguien meta un feed, que vuelva a la pantalla de inicio. Asumiré que la página de inicio es ?q=node, por lo que basta con indicarle:
1
drupal_goto('node');
A continuación, no sé si notásteis que la tabla con todos los mensajes no se ordena al pulsar las columnas. Esto nos puede venir bien para poder agrupar los mensajes no leídos, para ordenar por fecha, para agrupar los mensajes sin contenido, etc. ¡¡ Y es tan sencillo !! Basta con realizar un cambio durante la consulta, así que en feedback_admin:
1
2
3
$query="SELECT fm.id, u.name, fm.indate, fm.message FROM {feedback_messages} fm, {users} u WHERE fm.uid=u.uid";$query.=tablesort_sql($header);$queryResult=db_query($query);
Con eso le decimos a drupal que nos ordene la tabla. Ésa es una de las gracias de usar los headers en una tabla a parte, y por eso los definimos antes de realizar la consulta.
Añadiendo un mail
En las modificaciones de la base de datos, añadimos el campo usermail. Ahora vamos a usarlo. Necesitaremos que el usuario lo inserte, así que tenemos que modificar feedback_message_form:
functionfeedback_message_form(){global$user;$mail="";if($user->uid!=0)$mail=$user->mail;$form=array('feedback'=>array('#type'=>'fieldset','#title'=>t('Feedback'),'mail'=>array('#type'=>'textfield',"#title"=>"E-Mail","#default_value"=>$mail,"#description"=>"If you want any answer, please, tell me your mail. It would not be shown anywhere."),'message'=>array('#type'=>'textarea',"#description"=>"Write here your message"),'submit'=>array('#type'=>'submit','#value'=>t('Submit'),),),);return$form;}
Como veréis, esta función tiene un añadido: si el usuario ha hecho login, rellenamos el campo con el mail que puso para su usuario. Así le ahorramos trabajo. El UID del usuario no es necesario que lo metamos en el formulario, ya que podemos recuperarlo directamente de la variable global.
Las validaciones también cambian, ya que no sólo vamos a comprobar que el mensaje no esté vacío, sino que queremos hacer más cosas. Queremos que, si el usuario hizo login, entonces el campo de e-mail no es obligatorio. Si no lo hizo, entonces sí que lo es. Y el e-mail tiene que parecer un e-mail, es decir, tener su arroba y demás:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
functionfeedback_message_form_validate($form,&$form_state){global$user;$message=$form_state['values']['message'];$mail=$form_state['values']['mail'];$validmail=preg_match("/^[^0-9][A-z0-9_]+([.][A-z0-9_]+)*[@][A-z0-9_]+([.][A-z0-9_]+)*[.][A-z]{2,4}$/",$mail);if($mail==''&&$user->uid==0)form_set_error('mail',t('You are not a registered user. Please, insert your e-mail.'));if($mail!=''&&!$validmail)form_set_error('mail',t('The mail does not like an e-mail address.'));if($message=='')form_set_error('message',t('Message cannot be empty.'));return$form;}
Aquí hemos introducido la creación de una expresión regular. Explicada brevemente, estamos comprobando si encaja el mail con un patrón dado. La expresión regular es bastante compleja, así que sólo comentaré lo más básico de todo:
Lo que va entre corchetes, significa “uno de estos”. Ej: [A-z0-9_] significa que queremos una letra mayúscula o minúscula, un número o un guión bajo.
Lo que va entre corchetes pero comienza por “^”, significa “ninguno de estos”. Ej. [^0-9] significa “algo que no sea un número”.
El asterisco significa “lo anterior se puede repetir 0 o más veces”. Ej: [0-9]* significa que puede no haber nada o bien un número indeterminado de números.
El símbolo de suma significa “lo anterior se puede repetir 1 o más veces”. Ej: [0-9]+ significa que puede haber un número indeterminado de números, pero debe aparecer al menos uno.
Los paréntesis permiten agrupar cosas para aplicarle otros símbolos.
Las llaves implican la multiplicidad exacta. Ej: [A-z]{2} significa “dos letras”. [A-z]{2,4} significa “entre 2 y 4 letras”.
Habitualmente, crear una expresión regular es mucho más sencillo de lo que parece, pero modificar una que ya existe suele ser bastante complicadete :-D
functionfeedback_message_form_submit($form,&$form_state){global$user;$userid=NULL;if($user)$userid=$user->uid;$message=$form_state['values']['message'];$mail=$form_state['values']['mail'];$query="INSERT into {feedback_messages} ( uid, message, indate, usermail ) values ( %d, '%s', now(), '%s' ) ";$queryResult=db_query($query,$userid,$message,$mail);if(db_affected_rows()){drupal_set_message(t("Thank you for your feedback."));drupal_goto('node');}elseform_set_error('feedback',t("An error has happened. Your feedback has not been sent."));}
Como ya sabemos redirigir, si todo va bien, nos iremos a la página principal :-D
Ya que tenemos el mail, lo suyo es que lo veamos desde la tabla principal de feeds:
functionfeedback_admin($messageid=null){$content='';if($messageid!=null){$content.=drupal_get_form('feedback_messageadmin_form',$messageid);$content.="";}$header=array(array('data'=>t('Date'),'field'=>'indate','sort'=>'desc'),array('data'=>t('User'),'field'=>'name'),array('data'=>t('email'),'field'=>'mail'),array('data'=>t('Message'),'field'=>'message'),array('data'=>t('Read'),'field'=>'fm.read'),);$query="SELECT fm.id, u.uid as uid, u.name, fm.usermail, fm.indate, fm.message, fm.read FROM {feedback_messages} fm, {users} u WHERE fm.uid=u.uid";$query.=tablesort_sql($header);$queryResult=db_query($query);$rows=array();while($message=db_fetch_object($queryResult)){$row=array();$row['indate']=$message->indate;$row['name']=$message->uid!=0?''.$message->name.'':$message->name;$row['mail']=$message->usermail;$row['message']=$message->message;$row['read']=$message->read;$row['edit']=l(t('edit'),"feedback/adminmessages/".$message->id);$rows[]=$row;}$content.=theme_table($header,$rows);return$content;}
¡¡¡ Mucho ojo, porque a esta función aún tenemos que añadirle una línea para el borrado !!!
Además he añadido una cosa nueva. Si pulsáis sobre el nombre de uno de los usuarios, os redirigirá a la página personal del mismo.
Borrando
Ahora vamos a añadir una nueva operación: el borrado.
La forma de realizarlo va a ser similar a como está hecha la edición, con la diferencia de que vamos a cambiar el botón por uno de “eliminar”. Así que resulta fácil realizar este paso, aunque tendrá sus inconvenientes :-D
Comenzamos como siempre: permisos, menú, función principal y formularios.
No necesitamos más permisos de los que ya tenemos, así que en la función de menú (feedback_menu), añadimos lo siguiente:
functionfeedback_delete_form($form,$messageid){$query="SELECT fm.message, fm.read, fm.indate, u.name FROM {feedback_messages} fm, {users} u WHERE fm.id=%d and u.uid=fm.uid";$queryResult=db_query($query,$messageid);$message=db_fetch_object($queryResult);$form=array('feedback'=>array('#type'=>'fieldset','#title'=>t('Feedback from '.$message->name.' sended on '.$message->indate),'messageid'=>array('#type'=>'hidden',"#default_value"=>$messageid),'message'=>array('#type'=>'textarea',"#default_value"=>$message->message,"#disabled"=>TRUE),'read'=>array('#type'=>'checkbox',"#title"=>"Read","#default_value"=>$message->read,"#disabled"=>TRUE),'submit'=>array('#type'=>'submit','#value'=>t('Delete forever'),),),);return$form;}functionfeedback_delete_form_submit($form,&$form_state){$messageid=$form_state['values']['messageid'];$query="DELETE FROM {feedback_messages} where id=%d";$queryResult=db_query($query,$messageid);if(db_affected_rows()){drupal_set_message(t("Message deleted"));}drupal_goto('/feedback/adminmessages');}
Como véis, me he saltado la validación, ya que no hay nada que validar. El formulario es muy parecido al de feedback_messageadmin_form, pero con la diferencia de que el campo “read” también es de sólo lectura.
Lo que nos queda es poder llegar a este formulario. Para llegar, dijimos que usaríamos un sistema similar al del botón “edit”, así que eso mismo vamos a hacer: En la función feedback_admin, el final quedará así:
Últimamente estoy recibiendo muchas consultas sobre cómo hacer tal o cual cosa en drupal. La verdad es que no esperaba tener “tanto” éxito con los tutoriales… casi ni explico nada, sólo he desglosado un ejercicio en partes tan pequeñas que no dé miedo atacarlas.
Así que tan sólo puedo deciros una cosa: ¡¡ Muchas gracias !! ;)
Más tutoriales
Este tutorial es la continuación de una serie de tutoriales relacionados con Drupal. Podéis consultar cualquiera de ellos:
<?php/*
Copyright 2009 Miguel Ángel García Martínez
'Feedback' is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
'Feedback' is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with 'Feedback' (maybe in file "COPYING"); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/functionfeedback_schema(){$schema['feedback_messages']=array('description'=>t('Tabla para mensajes de retroalimentacion'),'fields'=>array('id'=>array('description'=>t('Identificador de mensaje'),'type'=>'serial','unsigned'=>TRUE,'not null'=>TRUE,),'uid'=>array('description'=>t('Identificador del usuario que realiza el feedback'),'type'=>'int','unsigned'=>TRUE,'not null'=>FALSE,),'message'=>array('description'=>t('Mensaje de feedback'),'type'=>'text','not null'=>TRUE,),'indate'=>array('description'=>t('Fecha en la que se crea el comentario'),'type'=>'datetime','not null'=>TRUE,),),'primary key'=>array('id'),);return$schema;}functionfeedback_update_6100(){$ret=array();db_add_field($ret,'feedback_messages','read',array('type'=>'int','size'=>'tiny'));return$ret;}functionfeedback_update_6103(){$ret=array();db_add_field($ret,'feedback_messages','usermail',array('type'=>'text'));db_change_field($ret,'feedback_messages','uid','uid',array('type'=>'int','unsigned'=>TRUE));return$ret;}functionfeedback_install(){// Create my tables.
drupal_install_schema('feedback');}functionfeedback_uninstall(){// Drop my tables.
drupal_uninstall_schema('feedback');}
<?php/*
Copyright 2009 Miguel Ángel García Martínez
'Feedback' is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
'Feedback' is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with 'Feedback' (maybe in file "COPYING"); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*//**
* Implements hook_help().
*/functionfeedback_help($path,$arg){$output='';// para construir la salida
switch(path){case'admin/help#feedback':$output.=''.t('Módulo que permite la inserción de mensajes de feedback.').'';break;}return$output;}/**
* Implements hook_perm().
*/functionfeedback_perm(){returnarray('send message','view messages');}/**
* Implementation of hook_block().
*/functionfeedback_block($op='list',$delta=0,$edit=array()){if($op=="list"){$blocks=array();$blocks[0]["info"]=t('Feedback');$blocks[1]["info"]=t('New Feedbacks');return$blocks;}elseif($op=="view"){$content='';$block=array();switch($delta){case0:$block['subject']=t('Feedback');$options=array("attributes"=>array("title"=>t("Sends a feedback message")));$link=l(t("New Feedback"),"feedback/message",$options);$content.=''.$link."";break;case1:$block['subject']=t('Feedback Messages');$options=array("attributes"=>array("title"=>t("Shows feedback messages")));$title=t("There are @total new feeds",array('@total'=>_feedback_count()));$link=l($title,"feedback/adminmessages",$options);$content.=''.$link."";break;}$block['content']=$content;return$block;}}/**
* Implementation of hook_menu().
*/functionfeedback_menu(){$items=array();$items['feedback/message']=array('title'=>'Feedback','page callback'=>'feedback_message','access arguments'=>array('send message'),'type'=>MENU_CALLBACK,);$items['feedback/adminmessages/%']=array('title'=>'Feedback admin','page callback'=>'feedback_admin','page arguments'=>array(2),'access arguments'=>array('view messages'),'type'=>MENU_CALLBACK,);$items['feedback/adminmessages']=array('title'=>'Feedback admin','page callback'=>'feedback_admin','access arguments'=>array('view messages'),'type'=>MENU_CALLBACK,);$items['feedback/delete/%']=array('title'=>'Feedback delete','page callback'=>'feedback_delete','page arguments'=>array(2),'access arguments'=>array('view messages'),'type'=>MENU_CALLBACK,);return$items;}functionfeedback_message(){$content='';$content.=drupal_get_form('feedback_message_form');return$content;}functionfeedback_message_form(){global$user;$mail="";if($user->uid!=0)$mail=$user->mail;$form=array('feedback'=>array('#type'=>'fieldset','#title'=>t('Feedback'),'mail'=>array('#type'=>'textfield',"#title"=>"E-Mail","#description"=>"If you want any answer, please, tell me your mail. It would not be shown anywhere.","#default_value"=>$mail),'message'=>array('#type'=>'textarea',"#description"=>"Write here your message"),'submit'=>array('#type'=>'submit','#value'=>t('Submit'),),),);return$form;}functionfeedback_message_form_validate($form,&$form_state){global$user;$message=$form_state['values']['message'];$mail=$form_state['values']['mail'];$validmail=preg_match("/^[^0-9][A-z0-9_]+([.][A-z0-9_]+)*[@][A-z0-9_]+([.][A-z0-9_]+)*[.][A-z]{2,4}$/",$mail);if($mail==''&&$user->uid==0)form_set_error('mail',t('You are not a registered user. Please, insert your e-mail.'));if($mail!=''&&!$validmail)form_set_error('mail',t('The mail does not like an e-mail address.'));if($message=='')form_set_error('message',t('Message cannot be empty.'));return$form;}functionfeedback_message_form_submit($form,&$form_state){global$user;$userid=NULL;if($user)$userid=$user->uid;$message=$form_state['values']['message'];$mail=$form_state['values']['mail'];$query="INSERT into {feedback_messages} ( uid, message, indate, usermail ) values ( %d, '%s', now(), '%s' ) ";$queryResult=db_query($query,$userid,$message,$mail);if(db_affected_rows()){drupal_set_message(t("Thank you for your feedback."));drupal_goto('node');}elseform_set_error('feedback',t("An error has happened. Your feedback has not been sent."));}functionfeedback_admin($messageid=null){$content='';if($messageid!=null){$content.=drupal_get_form('feedback_messageadmin_form',$messageid);$content.="";}$header=array(array('data'=>t('Date'),'field'=>'indate','sort'=>'desc'),array('data'=>t('User'),'field'=>'name'),array('data'=>t('email'),'field'=>'mail'),array('data'=>t('Message'),'field'=>'message'),array('data'=>t('Read'),'field'=>'fm.read'),);$query="SELECT fm.id, u.uid as uid, u.name, fm.usermail, fm.indate, fm.message, fm.read FROM {feedback_messages} fm, {users} u WHERE fm.uid=u.uid";$query.=tablesort_sql($header);$queryResult=db_query($query);$rows=array();while($message=db_fetch_object($queryResult)){$row=array();$row['indate']=$message->indate;$row['name']=$message->uid!=0?''.$message->name.'':$message->name;$row['mail']=$message->usermail;$row['message']=$message->message;$row['read']=$message->read;$row['edit']=l(t('edit'),"feedback/adminmessages/".$message->id);$row['delete']=l(t('delete'),"feedback/delete/".$message->id);$rows[]=$row;}$content.=theme_table($header,$rows);return$content;}/** Devuelve el número de feeds creados en la última semana
*/function_feedback_count(){$query="SELECT count(id) as total from {feedback_messages} fm where fm.read != 1 or isnull(fm.read)";$queryResult=db_query($query);$result=db_fetch_object($queryResult);return$result->total;}functionfeedback_messageadmin_form($form,$messageid){$query="SELECT fm.message, fm.read, fm.indate, u.name FROM {feedback_messages} fm, {users} u WHERE fm.id=%d and u.uid=fm.uid";$queryResult=db_query($query,$messageid);$message=db_fetch_object($queryResult);$form=array('feedback'=>array('#type'=>'fieldset','#title'=>t('Feedback from '.$message->name.' sended on '.$message->indate),'messageid'=>array('#type'=>'hidden',"#default_value"=>$messageid),'message'=>array('#type'=>'textarea',"#default_value"=>$message->message,"#disabled"=>TRUE),'read'=>array('#type'=>'checkbox',"#title"=>"Read","#default_value"=>$message->read),'submit'=>array('#type'=>'submit','#value'=>t('Submit'),),),);return$form;}functionfeedback_messageadmin_form_submit($form,&$form_state){$messageid=$form_state['values']['messageid'];$read=$form_state['values']['read'];$query="UPDATE {feedback_messages} fm set fm.read=%d where fm.id=%d";$queryResult=db_query($query,$read,$messageid);drupal_goto('/feedback/adminmessages');}functionfeedback_delete($messageid=null){$content='';$content.=drupal_get_form('feedback_delete_form',$messageid);return$content;}functionfeedback_delete_form($form,$messageid){$query="SELECT fm.message, fm.read, fm.indate, u.name FROM {feedback_messages} fm, {users} u WHERE fm.id=%d and u.uid=fm.uid";$queryResult=db_query($query,$messageid);$message=db_fetch_object($queryResult);$form=array('feedback'=>array('#type'=>'fieldset','#title'=>t('Feedback from '.$message->name.' sended on '.$message->indate),'messageid'=>array('#type'=>'hidden',"#default_value"=>$messageid),'message'=>array('#type'=>'textarea',"#default_value"=>$message->message,"#disabled"=>TRUE),'read'=>array('#type'=>'checkbox',"#title"=>"Read","#default_value"=>$message->read,"#disabled"=>TRUE),'submit'=>array('#type'=>'submit','#value'=>t('Delete forever'),),),);return$form;}functionfeedback_delete_form_submit($form,&$form_state){$messageid=$form_state['values']['messageid'];$query="DELETE FROM {feedback_messages} where id=%d";$queryResult=db_query($query,$messageid);if(db_affected_rows()){drupal_set_message(t("Message deleted"));}drupal_goto('/feedback/adminmessages');}