En este artículo vamos a aprender los fundamentos básicos para usar el editor. Aprenderemos a implementarlo en nuestro script primario, y algunos aspectos básicos de la configuración, necesarios por otra parte, y que nos acompañarán ya en todos los artículos de esta serie.
En realidad, lo que vamos a ver no es nada dífícil. Sin embargo, al principio puede parecer un poco laborioso. No te asustes. Verás como ese aparente aumento de trabajo ahora nos va a ahorrar cientos de horas más adelante, en los proyectos que llevemos a cabo con el editor. Vamos, que sí, que este complemento está genial, pero oye, algo sí tendremos que currar. Este es el momento de aprender los puntos mínimos que serán comunes a cualquier proyecto.
LO QUE NECESITAMOS
Vamos a empezar con un ejercicio sencillo, basado en la primera base de datos que usamos de personal de una multinacional. En esta base de datos tenemos una tabla, con los datos de ciudades y cargos en la misma tabla que el personal, sin tablas relacionadas… Todo muy simple y minimalista, del mismo modo que hicimos cuando empezamos con DataTables. La base de datos en SQL te la dejo para descargar en este enlace. Hala. Píllala y móntala en tu localhost, con PHPMyAdmin, o la herramienta que uses.
LO QUE VAMOS A HACER
En este primer ejercicio práctico vamos a agregar unas funcionalidades muy básicas de edición de los registros de nuestra tabla, así cómo adición de nuevos registros, y eliminación de los existentes. Tras el análisis, veremos que, a pesar de las funcionalidades implementadas, el trabajo en sí adolece de ciertas carencias. No obstante, nos permitirá sentar las bases para mejorarlo en posteriores artículos, a fin de ir aprendiendo los mejores recursos del editor.
En este ejercicio vamos a usar tres scripts (en lugar de los dos que veníamos usando en los artículos de DataTables). El primario cumple la misma función que siempre. Es el que incluye todo lo demás, y renderiza la página con los resultados. Uno de los scripts secudarios es lo mismo que ya conocemos: lee los datos de la tabla y los vuelca al script principal. El tercer script contiene las funcionalidades de creación, edición y eliminación de registros. Si cargamos el script primario de este artículo en el navegador veremos algo similar a lo siguiente:
Cómo ves, la tabla tiene algunas novedades. En la parte superior izquierda vemos tres botones para crear un nuevo registro, editar uno o más ya existentes o eliminar alguno(s). Los botones de edición y eliminación aparecen desactivados hasta que seleccionemos, al menos, un registro. En la parte inferior izquierda vemos una leyenda que nos informa de que en este momento no hay registros seleccionados. Por cierto. Aquí empezamos a ver la utilidad de la selección de registros que vimos en el artículo XII de la serie de DataTables.
EL SCRIPT PRINCIPAL
El script principal de este ejercicio se llama articulo_editor_02.php
y su listado es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Uso de DataTables</title> <!-- El CSS de DataTables --> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jszip-2.5.0/pdfmake-0.1.18/dt-1.10.12/af-2.1.2/b-1.2.2/b-colvis-1.2.2/b-flash-1.2.2/b-html5-1.2.2/b-print-1.2.2/cr-1.3.2/fc-3.2.2/fh-3.1.2/kt-2.1.3/r-2.1.0/rr-1.1.2/sc-1.4.2/se-1.2.0/datatables.min.css"/> <!-- El CSS de Bootstrap --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <!-- El editor --> <link rel="stylesheet" type="text/css" href="editor/css/editor.dataTables.css"> </head> <body> <br> <div class="container"> <div class="row"> <div class="col-sm-12"> <table id="tabla_de_personal" class="table display nowrap table-striped table-bordered"> <thead> <tr> <th>NOMBRE</th> <th>APELLIDO</th> <th>CARGO</th> <th>CIUDAD</th> <th>INGRESO</th> <th>SALARIO</th> </tr> </thead> <tbody> </tbody> </table> </div> </div> </div> <!-- jQuery --> <script language="javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <!-- El JavaScript de DataTables --> <script language="javascript" type="text/javascript" src="https://cdn.datatables.net/v/dt/jszip-2.5.0/pdfmake-0.1.18/dt-1.10.12/af-2.1.2/b-1.2.2/b-colvis-1.2.2/b-flash-1.2.2/b-html5-1.2.2/b-print-1.2.2/cr-1.3.2/fc-3.2.2/fh-3.1.2/kt-2.1.3/r-2.1.0/rr-1.1.2/sc-1.4.2/se-1.2.0/datatables.min.js"></script> <!-- El JavaScript de BootStrap --> <script language="javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <!-- El editor --> <script type="text/javascript" src="editor/js/dataTables.editor.js"></script> <!-- El código JavaScript --> <script language="javascript"> var objetoEditor = new $.fn.dataTable.Editor({ ajax: 'crud_editor_02.php', table: '#tabla_de_personal', idSrc: 'id', i18n: { create: { button: "Nuevo", title: "Crear nuevo registro", submit: "Grabar" }, edit: { button: "Editar", title: "Editar registro", submit: "Actualizar" }, remove: { button: "Borrar", title: "Borrar registro", submit: "Borrar", confirm: { _: "¿Está seguro de eliminar estos %d registros?", 1: "¿Está seguro de eliminar este registro?" } }, multi: { title: "Múltiples valores", info: "Los registros seleccionados contienen diversos valores para este campo. Para editar este campo con el mismo valor en los registros seleccionados, pulsa aquí. En caso conterario, los registros mantendrán sus valores individuales en este campo.", restore: "Restaurar los valores múltiples", noMulti: "Esta entrada puede ser modificada individualmente, pero no como parte de un grupo." } }, fields: [ {label: 'Nombre:', name: 'nombre'}, {label: 'Apellido:', name: 'apellido'}, {label: 'Cargo:', name: 'cargo'}, {label: 'Ciudad:', name: 'ciudad'}, {label: 'F. Ingreso:', name: 'fecha_de_ingreso'}, {label: 'Salario anual:', name: 'salario_bruto_anual'}, ] }); var objetoDataTables_personal = $('#tabla_de_personal').DataTable({ "language": { select: { rows: { _: "%d registros seleccionados", 0: "No se han seleccionado registros", 1: "1 registro seleccionado" } }, "emptyTable": "No hay datos disponibles en la tabla.", "info": "Del _START_ al _END_ de _TOTAL_ ", "infoEmpty": "Mostrando 0 registros de un total de 0.", "infoFiltered": "(filtrados de un total de _MAX_ registros)", "infoPostFix": "(actualizados)", "lengthMenu": "Mostrar _MENU_ registros", "loadingRecords": "Cargando...", "processing": "Procesando...", "search": "Buscar:", "searchPlaceholder": "Dato para buscar", "zeroRecords": "No se han encontrado coincidencias.", "paginate": { "first": "Primera", "last": "Última", "next": "Siguiente", "previous": "Anterior" }, "aria": { "sortAscending": "Ordenación ascendente", "sortDescending": "Ordenación descendente" } }, "lengthMenu": [[5, 10, 20, 25, 50, -1], [5, 10, 20, 25, 50, "Todos"]], "iDisplayLength": 10, "bServerSide": true, "sAjaxSource": "datos_externos_editor_02.php", "columns" : [ {"data": 'nombre'}, {"data": 'apellido'}, {"data": 'cargo'}, {"data": 'ciudad'}, {"data": 'fecha_de_ingreso'}, {"data": 'salario_bruto_anual'} ], select: true, dom: 'Bfrtipl', buttons: [ {extend: 'create', editor: objetoEditor}, {extend: 'edit', editor: objetoEditor}, {extend: 'remove', editor: objetoEditor} ] }); $('label').addClass('form-inline'); $('select, input[type="search"]').addClass('form-control input-sm'); </script> </body> </html> |
En las líneas resaltadas vemos las novedades del script principal. Vamos a irlas comentando para irnos familiarizando con la incorporación y uso del editor.
En las líneas 13
y 45
vemos como se incluyen, respectivamente, el CSS y el JavaScript del editor. Como puedes ver, y tal cómo te comentaba en el artículo anterior, no se hace por CDN, sino, directamente, desde un directorio en nuestro servidor de desarrollo (o de producción, cuando llegue el caso).
<link rel="stylesheet" type="text/css" href="editor/css/editor.dataTables.css">
y
<script type="text/javascript" src="editor/js/dataTables.editor.js"></script>
EL OBJETO EDITOR
En las líneas de la 49
a la 88
vemos que definimos un objeto específico para el editor. En esta página tenemos, por tanto, dos objetos para poder operar. El objeto DataTables, que ya conocemos (en seguida comentaremos las novedades que trae) y el objeto específico para el editor. Siempre que vayamos a usar el complemento editor de DataTables deberemos crear este objeto, y configurarlo, en cada caso, según las necesidades.
Dentro del mismo vemos, en este primer ejercicio, las opciones de configuración más básicas.
En la línea 48
vemos como establecemos el nombre (y la ruta, si fuera el caso) del script secundario que se encargará de efectuar las inserciones de nuevos registros, o editar y eliminar los existentes, cuando pulsemos los correspondientes botones del editor (los que vemos en la parte superior izquierda de la tabla de HTML):
ajax: 'crud_editor_02.php',
En la línea 49
vemos la forma en que le decimos al editor la tabla HTML a la que queremos asociar el objeto que estamos creando. En tu página podría haber más de una tabla (ya vimos un ejemplo con dos tablas en uno de los artículos de DataTables). Además, aún en el caso de tener una sola tabla, sigue siendo necesario asociar el objeto editor a dicha tabla. Lo hacemos así:
table: '#tabla_de_personal',
El identificativo que le ponemos es, cómo ves, el atributo id
de la correspondiente tabla HTML.
En la línea 50
vemos el uso de la opción idSrc
. Se emplea para indicarle al editor el nombre del campo, en la tabla MySQL sobre la que vamos a trabajar, que contiene la clave primaria. Esto es fundamental para que luego se puedan hacer operaciones de edición y eliminación. Si bien para las más simples podríaos prescindir de este dato, ya que, como veremos, no lo vamos a usar ahora, para otras más complejas si lo necesitaremos, así que mejor aprendemos, desde ya, a usarlo:
idSrc: 'id',
Entre las líneas 53
y 79
vemos la opción i18n
. Como sabes (y, si aún no lo sabes, te lo cuento yo ahora) i18n
es una nomenclatura para archivos o matrices de textos en diferentes idiomas, para que los contenidos puedan internacionalizarse; es lo que se llama un númeronimo (toma palabreja) normalizado para referirse a archivos u otros medios para internacionalizar el software. La naturaleza y los protocolos de i18n
exceden el objetivo de este artículo. Puedes leer más sobre este tema en pulsando aquí. De todos modos, que sepas que esta opción es, como puedes ver, a su vez, un grupo de opciones con textos (en este caso en español) para los botones de crear un nuevo registro, editar o eliminar registros existentes. A la vista de las referencias a botones empleadas se ve que parte es para cada botón.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
i18n: { create: { button: "Nuevo", title: "Crear nuevo registro", submit: "Grabar" }, edit: { button: "Editar", title: "Editar registro", submit: "Actualizar" }, remove: { button: "Borrar", title: "Borrar registro", submit: "Borrar", confirm: { _: "¿Está seguro de eliminar estos %d registros?", 1: "¿Está seguro de eliminar este registro?" } }, multi: { title: "Múltiples valores", info: "Los registros seleccionados contienen diversos valores para este campo. Para editar este campo con el mismo valor en los registros seleccionados, pulsa aquí. En caso conterario, los registros mantendrán sus valores individuales en este campo.", restore: "Restaurar los valores múltiples", noMulti: "Esta entrada puede ser modificada individualmente, pero no como parte de un grupo." } }, |
Hay un par de puntos a los que quiero prestar especial atención. Dentro de la definición de los textos para el botón de eliminación de registros hay una opción llamada confirm
, que se refiere al mensaje de confirmación que deberemos responder para hacer efectiva la eliminación de los registros seleccionados. Como ves en las líneas 19
y 20
, el mensaje es diferente, según haya un registro seleccionado o cualquier otra cantidad (más de uno). Fíjate en la peculiar forma de establecer esto.
Otro punto sobre el que quiero llamar tu atención es la opción multi
. Son los mensajes que se mostrarán en el formulario de edición si hay varios registros seleccionados. Esta es una situación un tanto particular. Si seleccionamos vartios registros y pulsamos el botón de edición, se nos abrirá un formulario con los campos de la ficha, de modo que si rellenamos un valor (por ejemplo la ciudad) y dejamos los demás datos sin rellenar, al pulsar el botón de actualizar la ciudad que hayamos tecleado se asignará a todos los registros seleccionados, manteniéndose intactos los demás datos. Esto se lo explicamos al usuario mediante unos mensajes definidos en esta opción. No te preocupes si todo esto ahora te suena un poco confuso. Cuando pruebes el ejercicio en tu navegador irás viendo los mensajes y comprobarás cuales te aparecen en cada caso.
La última opción que vamos a definir en el objeto del editor en este ejercicio es fields
, entre las líneas 80
y 87
. Se emplea para indicarle a nuestro editor cuales son los campos que deben aparecer en los formularios de edición y nuevo registro, las etiquetas (label
) que tendrán, y los nombres de los campos. Observa que hemos hecho coincidir los nombres de los campos con los que hemos definido en el objeto DataTables (líneas de la 126
a la 131
). Esto no es estrictamente imprescindible, pero ayuda mucho a efectos de organizarnos.
Ya dentro del objeto DataTables, en las líneas 92
a 98
, vemos definidos los mensajes que aparecen en la parte inferior izquierda de la tabla HTML, para indicar el número de registros seleccionados, o si no hay ninguno. La forma de definir los textos coincide con la que hemos usado en la opción i18n.remove.confirm
del objeto del editor.
En la línea 133
, la opción select
, con el valor true
, es lo que permite que se selecciones o deseleccionen registros haciendo clic sobre ellos. Las selecciones múltiples se pueden hacer con las teclas Shift
y Ctrl
. Si lo recuerdas, ya hablamos de esto en el artículo XIII de la serie de DataTables.
En las líneas 134
a 139
establecemos los botones que vamos a necesitar (en este caso los de nuevo registro, edición y eliminación), y los relacionamos con objetoEditor
. La opción dom
puede parecer un poco críptica, con el valor que recibe. Las letras que forman ese valor establecen que botones podemos llegar a usar en nuestra tabla. En posteriores artículos profundizaremos más sobre el tema. Por ahora, simplemente, la ponemos así, porque si no, los botones no aprecerán. mención especial merece la clave l
, al final del valor asignado a esta opción. Esta nos permite que, aún usando el editor, aparezca el combo selector del número de registros que queremos ver. Si no, no aparecería. Al haber puesto la l
al final de la opción dom
, este selector queda debajo de la tabla. Como ves, la opción buttons
define cada uno de los botones de forma individual. También sobre esto profundizaremos más adelante. De momento, lo aceptamos como dogma de fé. Sí, ya se, no es la mejor manera de entender las cosas, pero a veces es necesario ir poco a poco.
Ahora haz un pequeño alto en la lectura de este artículo, y prueba el funcionamiento. Graba el script primario, y los dos secundarios que ves más adelante, en tu directorio datatables
, dentro de localhost
, y prueba a añadir nuevos miembros del personal a la plantilla, o editar y eliminar algunos, seleccionándolos previamente. Ten en cuenta que, cuando añadas un nuevo miembro, es posible que no lo veas aparecer, y pienses que no se ha grabado. En ese caso, usa los botones de paginación que parecen en la parte inferior derecha de la tabla HTML, porque, si no lo ves, es que, por ordenación, ha quedado en otra página. Por ejemplo, si tienes tu tabla ordenada por nombres y estás en la primera página, verás los nombres que empiezan por las primeras letras del alfabeto. Si el nombre del nuevo miembro empieza por una letra “más alta” tendrás que despazarte a otras páginas para verlo.
LOS SCRIPTS SECUNDARIOS
Cómo hemos comentado, este ejercicio tiene dos scripts secundarios. Uno de ellos corresponde al objeto DataTables, y se llama datos_externos_editor_02.php
. Su listado es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
<?php // Establecemos la codificacion para las llamadas y respuestas HTTP mb_internal_encoding ('UTF-8'); /* CREAMOS LA CONEXION A LA BASE DE DATOS, O BIEN LA IMPORTAMOS DESDE UN ARCHIVO EXTERNO DE CONFIGURACION. */ $conexion = new PDO('mysql:host=localhost;dbname=datatables;charset=UTF8', 'root', ''); $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); /* RECUPERAMOS TODOS LOS PARAMETROS DE $_GET. LOS QUE NO APAREZCAN EN LA CONSULTA RECIBIRAN UN VALOR PREDETERMINADO. ESTOS DATOS SON LOS QUE SE RECIBEN CADA VEZ QUE EL PLUGIN DATATABLES LLAMA A ESTE SCRIPT. */ $datosDeLlamada = $_GET; /* SE INDICA(N) LA(S) TABLA(S) QUE SE VA(N) A USAR EN LA CONSULTA. */ $tablasDeBBDD = array( 'personal' ); /* SE DEFINE LA LISTA DE COLUMNAS QUE SE DEVOLVERON PARA SER MOSTRADAS EN LA TABLA HTML. LOS NOMBRES DE ESTAS COLUMNAS DEBEN COINCIDIR CON LOS DE LAS COLUMNAS DE LA(S) TABLA(S) AFECTADA(S) POR LA CONSULTA. */ $columnasParaRetorno = array( $tablasDeBBDD[0].'.nombre', $tablasDeBBDD[0].'.apellido', $tablasDeBBDD[0].'.cargo', $tablasDeBBDD[0].'.ciudad', $tablasDeBBDD[0].'.fecha_de_ingreso', $tablasDeBBDD[0].'.salario_bruto_anual', $tablasDeBBDD[0].'.id' ); $numeroDeColumnas = count($columnasParaRetorno); //////////////////////////////////////////////// REGLAS DE FILTRADO //////////////////////////// /* PREPARAMOS EL FILTRADO POR COLUMNAS PARA LA CAJA DE BUSQUEDA */ $reglasDeFiltradoDeUsuario = array (); if (isset($datosDeLlamada['sSearch']) && $datosDeLlamada['sSearch'] != "") { for($i = 0; $i < $numeroDeColumnas; $i++) { if (isset ($datosDeLlamada['bSearchable_'.$i]) && $datosDeLlamada['bSearchable_'.$i] == 'true') { $reglasDeFiltradoDeUsuario[] = $columnasParaRetorno[$i]." LIKE '%".addslashes($datosDeLlamada['sSearch'])."%'"; } } } if (!empty($reglasDeFiltradoDeUsuario)){ $reglasDeFiltradoDeUsuario = ' ('.implode(" OR ", $reglasDeFiltradoDeUsuario).') '; } else { $reglasDeFiltradoDeUsuario = ''; } /* PREPARAMOS LAS REGLAS DE FILTRADO DE RELACIONES ENTRE TABLAS. ESTAS SE PROGRAMAN AQUI A MANO, PORQUE PUEDEN EXISTIR O NO, DEPENDIENDO DE QUE SE USE UNA TABLA O MAS DE UNA. */ $reglasDeFiltradoDeRelaciones = ''; /* SE COMPONE TODA LA REGLA DE FILTRADO. EN ESTE CASO INCLUYE LAS CLAÚSULAS DE BÚSQUEDA, Y LAS RELACIONES ENTRE TABLAS. SIGUE SIENDO UN EJEMPLO SIMPLE, PERO MÁS ELABORADO QUE EL ANTERIOR. MÁS ADELANTE VEREMOS OTROS USOS. LO IMPORTANTE AQUI ES QUE, ADEMÁS DE LAS CLAUSULAS DE BÚSQUEDA (VARIABLE $reglasDeFiltradoDeUsuario, QUE PUEDEN EXISTIR O NO) TAMBIÉN HAY UNA CLAÚSULA DE RELACIONES ENTRE LAS TABLAS. SI HAY MÁS DE UNA TABLA SIEMPRE HABRÁ UNA CLAÚSULA DE RELACIONES ($reglasDeFiltradoDeRelaciones). LAS IMPLEMENTAMOS COMO UNA MATRIZ PARA PODER COMPROBAR LAS QUE EXISTEN Y LAS QUE NO, Y LUEGO LAS UNIMOS CON EL OPERADOR AND, SI HAY MÁS DE UNA CLAÚSULA DE FILTRADO. */ $reglasDeFiltrado = array(); if ($reglasDeFiltradoDeUsuario > '') $reglasDeFiltrado[] = $reglasDeFiltradoDeUsuario; if ($reglasDeFiltradoDeRelaciones > '') $reglasDeFiltrado[] = $reglasDeFiltradoDeRelaciones; $reglasDeFiltrado = implode(" AND ", $reglasDeFiltrado); //////////////////////////////////////////// FIN DE REGLAS DE FILTRADO /////////////////////////// /////////////////////////// REGLAS DE ORDENACION //////////////////////// /* SE COMPONE LA REGLA DE ORDENACION. */ $reglasDeOrdenacion = array (); if (isset($datosDeLlamada['iSortCol_0'] )) { $columnasDeOrdenacion = intval($datosDeLlamada['iSortingCols']); for($i = 0; $i < $columnasDeOrdenacion; $i ++) { if ($datosDeLlamada['bSortable_'.intval($datosDeLlamada['iSortCol_'.$i])] == 'true') { $reglasDeOrdenacion[] = $columnasParaRetorno[intval($datosDeLlamada['iSortCol_'.$i])].($datosDeLlamada['sSortDir_'.$i] === 'asc'?' asc':' desc'); } } } if (!empty($reglasDeOrdenacion)) { $reglasDeOrdenacion = " ORDER BY ".implode(", ", $reglasDeOrdenacion); } else { $reglasDeOrdenacion = ""; } /* SE COMPONE LA REGLA DE LIMITACION DE REGISTROS. */ $reglaDeLimitacion = ";"; if ($datosDeLlamada['iDisplayLength'] != "-1") $reglaDeLimitacion = ' LIMIT '.$datosDeLlamada['iDisplayStart'].', '.$datosDeLlamada['iDisplayLength'].';'; /////////////////////////////////////// FIN DE REGLAS DE ORDENACION //////////////////// /* SE PREPARA LA CONSULTA DE RECUPERACION DEL DATASET SOLICITADO. */ $consulta = "SELECT ".implode(', ', $columnasParaRetorno)." "; $consulta .= "FROM ".implode(', ', $tablasDeBBDD)." "; $consulta .= "WHERE 1 "; if ($reglasDeFiltrado > "") $consulta .= "AND (".$reglasDeFiltrado.") "; $consulta .= $reglasDeOrdenacion; $consulta .= $reglaDeLimitacion; $hacerConsulta = $conexion->prepare($consulta); $hacerConsulta->execute(); $DataSet = $hacerConsulta->fetchAll(PDO::FETCH_ASSOC); $hacerConsulta->closeCursor(); /* SI ES NECESARIO ADAPTAR ALGUN DATO PARA PRESENTACION, SE ADAPTA AQUI. SI ES NECESARIOS AGREGAR ENLACES, REFERENCIAS A IMAGENES, O CUALQUIER OTRA COSA, SE INCLUYE EN ESTA SECCION. EN ESTE CASO, LO ÚNICO QUE VAMOS A HACER ES DARLE FORMATO AL SALARIO ANUAL. */ foreach ($DataSet as $keyDL=>$DL){ $DataSet[$keyDL]['fecha_de_ingreso'] = date("d-m-Y", strtotime($DL['fecha_de_ingreso'])); $DataSet[$keyDL]['salario_bruto_anual'] = number_format($DL['salario_bruto_anual'], 2, ",", ".").' €'; } /* CALCULO DE DATOS INFORMATIVOS DE REGISTROS. */ $numeroDeRegistrosDelDataSet = count($DataSet); /* CALCULO DEL TOTAL DE REGISTROS QUE CUMPLEN LAS REGLAS DE FILTRADO SIN ORDENACION NI LIMITACION. */ $consulta = "SELECT COUNT(".$columnasParaRetorno[0].") "; $consulta .= "FROM ".implode(', ', $tablasDeBBDD)." "; $consulta .= "WHERE 1 "; if ($reglasDeFiltrado > "") $consulta .= "AND (".$reglasDeFiltrado.") "; $hacerConsulta = $conexion->prepare($consulta); $hacerConsulta->execute(); $totalDeRegistrosConFiltrado = $hacerConsulta->fetch(PDO::FETCH_NUM)[0]; $hacerConsulta->closeCursor(); /* TOTAL DE REGISTROS DE LA TABLA PRIMARIA (O UNICA, SI SOLO HAY UNA). */ $consulta = "SELECT COUNT(".$columnasParaRetorno[0].") "; $consulta .= "FROM ".$tablasDeBBDD[0].";"; $hacerConsulta = $conexion->prepare($consulta); $hacerConsulta->execute(); $totalDeRegistrosEnBruto = $hacerConsulta->fetch(PDO::FETCH_NUM)[0]; $hacerConsulta->closeCursor(); // SE PREPARA UNA MATRIZ CON TODOS LOS DATOS NECESARIOS PARA LA SALIDA. $matrizDeSalida = array( "sEcho" => intval($datosDeLlamada['sEcho']), "iTotalRecords" => strval($totalDeRegistrosEnBruto), "iTotalDisplayRecords" => strval($totalDeRegistrosConFiltrado), "aaData" => array () ); foreach ($DataSet as $DL){ $registro = array(); foreach ($DL as $keyDato=>$dato) $registro[$keyDato] = $dato; $matrizDeSalida['aaData'][] = $registro; unset($registro); } $salidaDeDataSet = json_encode ($matrizDeSalida, JSON_HEX_QUOT); /* SE DEVUELVE LA SALIDA */ echo $salidaDeDataSet; ?> |
En este script no hay ninguna novedad. Su listado coincide con el script secundario que vimos en el artículo XIII de la serie de DataTables. Sólo te he puesto el código para que veas que no hay novedades aquí y para que lo tengas a mano para copiarlo en tu localhost.
El script secundario que nos interesa ahora es crud_editor_02.php
, que es el invocado desde el objeto del editor para ocuparse de añadir nuevos registros, o editar o eliminar. Su listado es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
<?php // Establecemos la codificacion para las llamadas y respuestas HTTP mb_internal_encoding ('UTF-8'); /* CREAMOS LA CONEXION A LA BASE DE DATOS, O BIEN LA IMPORTAMOS DESDE UN ARCHIVO EXTERNO DE CONFIGURACION. */ $conexion = new PDO('mysql:host=localhost;dbname=datatables;charset=UTF8', 'root', ''); $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); /* RECUPERAMOS TODOS LOS PARAMETROS DE $_POST. LOS QUE NO APAREZCAN EN LA CONSULTA RECIBIRAN UN VALOR PREDETERMINADO. ESTOS DATOS SON LOS QUE SE RECIBEN CADA VEZ QUE EL PLUGIN DATATABLES LLAMA A ESTE SCRIPT. */ $datosDeLlamada = $_POST; /* SE INDICA(N) LA(S) TABLA(S) QUE SE VA(N) A USAR EN LA CONSULTA. */ $tablasDeBBDD = array( 'personal' ); /* SE DEFINE LA LISTA DE COLUMNAS QUE SE DEVOLVERON PARA SER MOSTRADAS EN LA TABLA HTML. LOS NOMBRES DE ESTAS COLUMNAS DEBEN COINCIDIR CON LOS DE LAS COLUMNAS DE LA(S) TABLA(S) AFECTADA(S) POR LA CONSULTA. */ $columnasDeDatos = array( $tablasDeBBDD[0].'.nombre', $tablasDeBBDD[0].'.apellido', $tablasDeBBDD[0].'.cargo', $tablasDeBBDD[0].'.ciudad', $tablasDeBBDD[0].'.fecha_de_ingreso', $tablasDeBBDD[0].'.salario_bruto_anual', $tablasDeBBDD[0].'.id' ); /* Se determina qué es lo que se va a hacer. Esto viene por POST en la variable "action". Puede ser remove, edit o create. En cada caso se llevara a cabo la acción elegida, sobre los registros que estuvieran seleccionados. Además, se prepara la respuesta adecuada para devolver al script primario. */ $data = array(); switch ($datosDeLlamada["action"]){ case "remove": foreach ($datosDeLlamada["data"] as $keyReg=>$registro){ $consulta = "DELETE FROM ".$tablasDeBBDD[0]." "; $consulta .= "WHERE ".$columnasDeDatos[6]."='".$keyReg."';"; $conexion->query($consulta); } break; case "edit": foreach ($datosDeLlamada["data"] as $keyReg=>$registro){ $consulta = "UPDATE ".$tablasDeBBDD[0]." SET "; $consulta .= $columnasDeDatos[0]."='".$registro["nombre"]."', "; $consulta .= $columnasDeDatos[1]."='".$registro["apellido"]."', "; $consulta .= $columnasDeDatos[2]."='".$registro["cargo"]."', "; $consulta .= $columnasDeDatos[3]."='".$registro["ciudad"]."', "; $consulta .= $columnasDeDatos[4]."='".date("Y-m-d", strtotime($registro["fecha_de_ingreso"]))."', "; $consulta .= $columnasDeDatos[5]."='".$registro["salario_bruto_anual"]."' "; $consulta .= "WHERE ".$columnasDeDatos[6]."='".$keyReg."';"; $conexion->query($consulta); $elemento = array("id"=>$keyReg); foreach ($registro as $keyItem=>$item) $elemento[$keyItem] = $item; $data[] = $elemento; } break; case "create": $consulta = "INSERT INTO ".$tablasDeBBDD[0]." ("; $consulta .= $columnasDeDatos[0].", "; // nombre $consulta .= $columnasDeDatos[1].", "; // apellido $consulta .= $columnasDeDatos[2].", "; // cargo $consulta .= $columnasDeDatos[3].", "; // ciudad $consulta .= $columnasDeDatos[4].", "; // fecha_de_ingreso $consulta .= $columnasDeDatos[5].""; // salario_bruto_anual $consulta .= ") VALUES ("; $consulta .= "'".$datosDeLlamada["data"][0]["nombre"]."', "; // nombre $consulta .= "'".$datosDeLlamada["data"][0]["apellido"]."', "; // apellido $consulta .= "'".$datosDeLlamada["data"][0]["cargo"]."', "; // cargo $consulta .= "'".$datosDeLlamada["data"][0]["ciudad"]."', "; // ciudad $consulta .= "'".date("Y-m-d", strtotime($datosDeLlamada["data"][0]["fecha_de_ingreso"]))."', "; // fecha_de_ingreso $consulta .= "'".$datosDeLlamada["data"][0]["salario_bruto_anual"]."'"; // salario_bruto_anual $consulta .= ");"; $conexion->query($consulta); $elemento = array("id"=>$conexion->lastInsertId()); foreach ($datosDeLlamada["data"][0] as $keyItem=>$item) $elemento[$keyItem] = $item; $data[] = $elemento; break; } $datosParaDevolver = array("data"=>$data); $resultado = json_encode($datosParaDevolver); echo $resultado; ?> |
En primer lugar, este script, cuando es invocado, recibe datos de los registros con los que vamos a trabajar por POST, en lugar de GET, como hace el objeto DataTables. Esto es lógico. Cuando pulsas, por ejemplo, el botón de añadir un nuevo registro, se te abre un formulario con todos los campos en blanco. Los rellenas y pulsas el botón de grabar. En este formulario puede haber muchos campos o, incluso, como ya veremos en artículos posteriores, campos de tipo fichero. Todo ese paquete de información debe ser pasado por POST. Cuando pulsas el botón de edición, la situación es similar. Cuando pulsas el botón de eliminación, en realidad sólo vamos a necesitar que pasen los id de los registros a eliminar, pero el editor pasa todos los datos, así que también pasan por POST. En la línea 13
del script ves como los recuperamos.
La forma en que llegan los datos a este script secundario es cómo una matriz. El primer elemento tiene la clave action
, y el valor create
, edit
o remove
, según la operación que estemos haciendo. El segundo elemento tiene la clave data
y es, a su vez, una matriz con los datos de todos los registros afectados, a razón de un elemento de esta matriz por registro, siendo la clave de dicho elemento el id del registro. Por ejemplo, en caso de eliminación de dos registros, la matriz que llega por post tendrá un aspecto similar al siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
array(2) { ["action"]=>string(6) "remove" ["data"]=>array(2) { [3]=>array(7) { ["nombre"]=>string(6) "Ashton" ["apellido"]=>string(3) "Cox" ["cargo"]=>string(23) "Junior Technical Author" ["ciudad"]=>string(13) "San Francisco" ["fecha_de_ingreso"]=>string(10) "12-01-2009" ["salario_bruto_anual"]=>string(13) "86.000,00 €" ["id"]=>string(1) "3" } [5]=>array(7) { ["nombre"]=>string(4) "Airi" ["apellido"]=>string(5) "Satou" ["cargo"]=>string(10) "Accountant" ["ciudad"]=>string(5) "Tokyo" ["fecha_de_ingreso"]=>string(10) "28-11-2008" ["salario_bruto_anual"]=>string(14) "162.700,00 €" ["id"]=>string(1) "5" } } } |
En el supesto de editar dos registros de dos personas, de las que digamos que queremos conservar todos sus datos, excepto la ciudad, ya que ambos los trasladamos a Brisbane, la matriz enviada a este script tendría un aspecto así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
array(2) { ["action"]=>string(4) "edit" ["data"]=>array(2) { [3]=>array(6) { ["nombre"]=>string(6) "Ashton" ["apellido"]=>string(3) "Cox" ["cargo"]=>string(23) "Junior Technical Author" ["ciudad"]=>string(8) "Brisbane" ["fecha_de_ingreso"]=>string(10) "12-01-2009" ["salario_bruto_anual"]=>string(13) "86.000,00 €" } [5]=> array(6) { ["nombre"]=>string(4) "Airi" ["apellido"]=>string(5) "Satou" ["cargo"]=>string(10) "Accountant" ["ciudad"]=>["fecha_de_ingreso"]=>string(10) "28-11-2008" ["salario_bruto_anual"]=>string(14) "162.700,00 €" } } } |
Y ahora supongamos que agregamos un nuevo miembro de personal. La matriz rtecibida podría ser similar a la que aparece a continuación:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
array(2) { ["action"]=>string(6) "create" ["data"]=>array(1) { [0]=>array(6) { ["nombre"]=>string(5) "John" ["apellido"]=>string(5) "Foster" ["cargo"]=>string(6) "Security Officer" ["ciudad"]=>string(11) "New York" ["fecha_de_ingreso"]=>string(10) "10-02-1969" ["salario_bruto_anual"]=>string(9) "75000" } } } |
Además, este script debe devolver, por ajax, un objeto JSON que indique cómo quedan los datos, para que el objeto editor pueda renderizar los cambios en tiempo real en la tabla HTML. Así, en caso de una eliminación, se devolverá un obeto JSON similar al siguiente:
1 2 3 |
{ "data": [] } |
Cómo ves, se trata de un objeto JSON sin contenido. Como es una eliminación, el objeto editor en el script primarip debe reemplazar el registro o registros que se hubieran seleccionado por, exactamente, eso: nada, un conjunto de datos vacío.
Si se trata de una edición como la que hemos visto en el ejemplo de más arriba, donde mudábamos a dos personas a Brisbane, el objeto JSON devuelto al editor tendría un aspecto cómo el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
{ "data": [ { "id": "3", "nombre": "Ashton", "apellido": "Cox", "cargo": "Junior Technical Author", "ciudad": "Brisbane", "fecha_de_ingreso": "12-01-2009", "salario_bruto_anual": "86000" }, { "id": "5", "nombre": "Airi", "apellido": "Satou", "cargo": "Accountant", "ciudad": "Brisbane", "fecha_de_ingreso": "28-11-2008", "salario_bruto_anual": "162700" } ] } |
Por último, en el caso de un nuevo registro, el objeto JSON devuelto tendrá un aspecto parecido al que ves a continuación.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "data": [ { "id": "58", "nombre": "John", "apellido": "Foster", "cargo": "Security Officer", "ciudad": "New York", "fecha_de_ingreso": "10-02-1969", "salario_bruto_anual": "75000" } ] } |
Al recibir estos datos en el formato JSON correcto, el editor puede, cómo hemos comentado, actualizar la tabla HTML en tiempo real.
Sin embargo, este nuevo script no sólo debe recibir los datos por POST y generar el JSON a devolver. Además, en el camino, debe efectuar la correspondiente consulta de creación, edición o eliminación. Si ves el código con detalle, podrás identificar los procesos que lleva a cabo el script.
En el próximo artículo seguiremos profundizando en las capacidades del editor de DataTables. Los scripts y la base de datos de esste artículo te los puedes descargar en este enlace.
Pingback: El editor de DataTables (III) – El desván de Jose