scieee AI-readable full text Open interactive document viewer

Diseño y desarrollo de una aplicación web para gestión de bases de datos en el COPCV

Calabuig Mondéjar, Isidro

Full text

PROYECTO FINAL DE CARRERA EN COLABORACIÓN CON EL COL.LEGI OFICIAL COL.LEGI OFICIAL COL.LEGI OFICIAL COL.LEGI OFICIAL DE PSICO DE PSICODE PSICO DE PSICOLEGS DE LA COMUNITAT LEGS DE LA COMUNITAT LEGS DE LA COMUNITAT LEGS DE LA COMUNITAT VALENCIANA VALENCIANAVALENCIANA VALENCIANA Autor: Isidro Calabuig Mondejar Director de proyecto: Manuel Agustí Melchor Titulación: Ingeniero técnico en Informática de Sistemas 1 ÍNDICE • Presentación. • Introducción. • Parte 1: Aplicación en C# para la realización del Dvd de Informació Psicològica. • Parte 2: Aplicación en PHP y MySQL para el registro de votantes para las elecciones celebradas en el Col.legi. • Parte 3: Aplicación en PHP y MySQL para la gestión de la base de datos de JUNTAS que reside en el servidor del Col.legi. • Parte 4: CSS. • Parte 5: Ampliaciones futuras. • Parte 6: Conclusiones. • Parte 7: Índice de figuras. • Parte 8: Bibliografía. 2 PRESENTACIÓN Aquí me dispongo a presentar mi proyecto de final de carrera de ITIS. Se me presentó la oportunidad de trabajar en el Col.legi Oficial de Psicòlegs de la Comunitat Valenciana y después de revisar las condiciones decidí aceptar la propuesta ya que la consideré beneficiosa: • Tenía la posibilidad de aprender un lenguaje nuevo como PHP y su integración con otras herramientas. • Me familiarizaría con el diseño de páginas Web, que era un mundo que me atraía bastante. • A parte de aprender PHP, aprendería a desenvolverme en distintos campos de la informática, ya que debería hacer frente a posibles problemas derivados del servidor, impresoras, cuentas de correo…y resolver consultas de los colegiados. • Tendría la posibilidad de hacer el proyecto de final de carrera. Para esto último necesitaba un director de proyecto y decidí proponérselo a Manolo Agustí, que conocía de la asignatura de Sistemas Operativos 2, y que había colaborado anteriormente en un proyecto realizado también en el Colegio. Aceptó la propuesta y ha colaborado aportando soluciones e información y guiándome en la redacción de la memoria. Agradezco su ayuda y comprensión en la realización de todo el proceso. 3 INTRODUCCIÓN El Colegio facilita a los estudiantes en prácticas la realización de su proyecto de final de carrera. Para ello hay una lista de tareas pendientes a realizar por el departamento de informática y el estudiante, en acuerdo con su tutor, deciden cuál de ellas se convertirá en su proyecto. Así que el trabajo del estudiante no cae en saco roto, ya que las aplicaciones que realice servirán para mejorar el funcionamiento del Colegio. El proyecto está dividido en partes. Dado que en el Colegio me encontraba trabajando, mi estancia allí no se limitó a la realización del proyecto. Como parte de mi aprendizaje del lenguaje PHP y MySQL, colaboré en distintas tareas que eran necesarias para el Colegio, y le propuse a Manolo incluir algunas de las aplicaciones que consideraba interesante contar y de esa forma completar mi memoria. La primera parte que vamos a incluir en la memoria es una aplicación que realizamos en C Sharp(C#) o C sostenido. C# es un lenguaje de programación orientado a objetos. Su sintaxis básica deriva de C/C++ y utiliza el modelo de objetos de la plataforma .NET el cual es similar al de Java y fue diseñado para combinar el control a bajo nivel de lenguajes como C y la velocidad de programación de lenguajes como Visual Basic. Esta aplicación consiste en un menú donde se pueden visualizar en formato .pdf una colección de revistas que ha publicado en Colegio en su historia. La segunda parte es una aplicación en PHP y MySQL. Dado que se iban a celebrar unas elecciones a la Junta en el Colegio se precisaba una forma rápida de conteo de los votos, de manera que se pudiera diferenciar los validos de los no validos en el momento de su registro. Por ello nos encargaron esta tarea y pensamos que estas dos herramientas serían las más adecuadas para llevarla a cabo. MySQL es un sistema de gestión de base de datos relacional, multihilo y multiusuario con más de seis millones de instalaciones. Está desarrollado en su mayor parte en ANSI C. Por su parte PHP es un lenguaje de programación usado frecuentemente para la creación de contenido para sitios web con los cuales se puede programar las páginas html y los códigos de fuente. Se trata de un lenguaje interpretado usado para la creación de aplicaciones para servidores, o creación de contenido dinámico para sitios web. La tercera parte de la memoria es la referente al proyecto en sí. En el Colegio las bases de datos se gestionan mediante Microsoft Access y este sistema, a lo largo del tiempo, ha ralentizado su administración por las continuas modificaciones que han sufrido estas bases. Por ello, poco a poco, se quiere migrar este sistema a MySQL, dada su facilidad y fiabilidad a la hora de llevar a cabo estos cambios. Mi proyecto consiste en hacer todo esto con la base de datos de Juntas del Colegio, que contiene unas tablas y formularios relacionados entre si. Ahora pasaremos a ver con más detalle todos estos puntos. 4 PARTE 1: APLICACIÓN EN C# PARA LA REALIZACIÓN DEL DVD DE INFORMACIÓ PSICOLÒGICA Uno de los trabajos previos en los que colaboré antes de empezar a realizar el proyecto fue la revista de Informació Psicològica. Esta revista se editó con motivo del 25 aniversario de la creación de la revista. En consecuencia se pensó en hacer un recopilatorio de todas las revistas y mandarlas a los colegiados en un CD. Las revistas se visualizarían en formato PDF y en el CD incluiría una aplicación que permitiera hacer una búsqueda por campos y así facilitar la localización de la revista deseada. Para este trabajo se pensó en utilizar el lenguaje C Sharp (C#) puesto que de los lenguajes que se adaptaban para hacer la aplicación era el que más conocíamos puesto que habíamos cursado la asignatura de Ingeniería del Software recientemente. La aplicación que utilizamos para programar la aplicación fue el Sharp Develop 2.0, puesto que era una versión gratuita de compilador de C# y no tenia incompatibilidades con las distintas versiones del compilador del Microsoft Visual Studio. El primer paso fue crear el proyecto y decidir la estructura de la ventana principal. Puesto que el programa facilita la creación de las ventanas gracias a una herramienta gráfica, nos situamos en la parte de diseño para situar los botones y las pestañas y modelar la estructura de las diferentes ventanas. Una vez hecho esto el SharpDevelop crea el código correspondiente al “dibujo”, asignando los tipos a las variables necesarias de manera que se puedan reutilizar posteriormente. El aspecto inicial de nuestra aplicación es como vemos en la figura 1: Fig1. Aspecto inicial de la aplicación de la revista En ella podemos ver la pestaña donde posteriormente se visualizaran todas las revistas, la pestaña correspondiente a la búsqueda de la cual antes hablábamos, un menú de Archivo, donde hay un submenú para salir de la aplicación y un menú de ayuda en el que hay un “Acerca de” donde se incluyen los nombres de los colaboradores que ayudaron a realizar las distintas revistas y un submenú de ayuda donde se explican los requisitos necesarios para poder ejecutar la aplicación. Pestaña “Ver Todas” Una vez diseñado el “contenedor”, pasamos a mostrar las miniaturas de las portadas de las revistas en la pantalla principal para poder acceder a sus PDF en un clic. Para ello creamos una función ‘CargarTodos()’ que accediera a la base de datos donde teníamos las revistas y las mostrara en la pantalla principal. Esto se consiguió con una consulta que quedaría como sigue: "SELECT * FROM revistas ORDER BY numero_revista" , además así tendríamos ordenadas las revistas por su número de publicación. Para crear los botones que contendrían las miniaturas de las revistas, realizamos un while, y para cada registro de la base de datos, crearíamos un botón con su imagen correspondiente. Una captura de pantalla del aspecto que tiene lo explicado la podemos ver en la figura 2: Fig2. Menú de revistas 6 Para facilitar la identificación de cada revista se nos ocurrió añadir un objeto de tipo ToolTip, que muestra un mensaje al dejar el cursor del ratón sobre un objeto determinado. En nuestro caso hicimos que si situábamos el cursor sobre una miniatura determinada, mostrar el número de la revista. Esto también se puede ver en la captura, en este caso el mensaje muestra que es la revista “Informació PsicològicaNúmero 67”. El siguiente paso era hacer posible que al pulsar una miniatura se mostrara el su PDF correspondiente. Para ello creamos una función Ejecutar y se la asignamos a cada botón. Esta función accede a la carpeta donde están almacenadas las revistas en el CD; nosotros le indicamos la ruta y al pulsar la miniatura muestra el PDF. Pestaña “Búsqueda” Como dijimos antes, incluimos en la aplicación una opción para buscar por los campos de esta pestaña. Estos campos son titulo, autor, palabras clave y staff(Junta Rectora, Direcció…). La estructura de esta pantalla es el que vemos en la figura 3: Fig3. Pantalla de búsqueda Se nos dijo que priorizáramos la búsqueda por este último campo sobre la búsqueda por los demás campos, por lo tanto hicimos una primera consulta para buscar por el ‘staff’, que es el nombre que recibió el campo en cuestión en la base de datos. Las líneas de código en cuestión son: 7 if (staff.Text!="") { "SELECT DISTINCT r.numero_revista, r.fecha_revista FROM revistas r INNER JOIN staff s ON r.numero_revista=s.numero_revista WHERE s.nombre LIKE LCase('%"+staff.Text+"%')" La consulta en caso de que el campo de ‘staff’ esté vacio es la siguiente: cmd.CommandText="SELECT articulos.numero_revista, articulos.titulo_articulo,articulos.autores_articulo, articulos.seccion,articulos.palabras_clave,revistas.fecha_revista, articulos.pagina FROM articulos,revistas WHERE articulos.numero_revista=revistas.numero_revista"; if (titulo.Text!="") cmd.CommandText+=" AND titulo_articulo LIKE LCase('%"+titulo.Text+"%')"; if (autor.Text!="") cmd.CommandText+=" AND autores_articulo LIKE LCase('%"+autor.Text+"%')"; if (palabras.Text!="") cmd.CommandText+=" AND palabras_clave LIKE LCase('%"+palabras.Text+"%')"; cmd.CommandText+=" ORDER BY articulos.numero_revista ASC, titulo_articulo ASC"; , donde uno por uno cada campo se comprueba si esta vacío y si no se le añade a la consulta su ‘AND’ correspondiente. El resto de código es el mismo para ambos casos, se realiza un while para recorrer los registros a buscar y mientras haya mostrará todas las revistas encontradas en forma de una lista, donde además para cada una se incluirán 3 botones: uno para ver la revista, otro para ver el índice de dicha revista y otro para información adicional. A modo de ejemplo mostramos una captura donde hemos buscado las revistas que contienen en su título la palabra esquizofrenia. El resultado es el que vemos en la figura 4: 8 Fig4. Resultado de la búsqueda Si la búsqueda no encuentra ningún resultado, un mensaje avisa de esta circunstancia, dejando la parte de la ventana donde salen los resultados en blanco. PROBLEMAS ENCONTRADOS Después de realizar varias pruebas de la aplicación, nos dimos cuenta que si se introducía como parámetro a buscar una cadena de caracteres inferior a 3 el coste de obtener los resultados era muy grande, llegando a desesperar. Por lo tanto decidimos incluir, con el consentimiento del Colegio, la condición de que la cadena a introducir en la búsqueda superara siempre los 2 caracteres. La mejora en el funcionamiento de la aplicación fue notable y el resultado contentó a todo el mundo. Posteriormente se realizó el envío de los CDs a todos los colegiados, teniendo unas opiniones muy favorables sobre la aplicación. Esta aplicación podría ampliar sus prestaciones añadiendo más código, sin embargo con el lenguaje C# esto es costoso. Dado el caso se podría aprovechar la aplicación para publicar próximas recopilaciones de revistas, y no habría que empezar de cero. Se podría, por ejemplo, ampliar el número de revistas a visualizar situando un botón más en las coordenadas correspondientes y añadiendo las imágenes de las revistas en la carpeta donde están las demás. También se podrían insertar campos para la búsqueda, añadiéndolos al SELECT de la consulta y a la pestaña donde están los demás campos. Como conclusión decir que esta aplicación fue probada en Windows 2000 y Windows XP y no tuvimos ningún tipo de problema en ejecutarla. 9 <script type='text/javascript'> Calendar.setup({ inputField : 'fecha', // id del campo de texto ifFormat : '%d/%m/%Y', // formato de la fecha que se escriba en el campo de texto button : 'fechaini' // el id del botn que lanzar el calendario }); </script> </td> Ahora vamos con las capturas de pantalla en la figura 6 para mostrar como se pasaran a ver en el navegador estas líneas de código: Fig6. Registrar voto Esta es la página inicial y al mostrar el colegiado se pueden ver dos mensajes, uno que indica si el colegiado esta en el censo y otro que muestra si el colegiado esta dado de alta. La pagina para buscar el colegiado por su nombre y apellidos la podemos ver en la figura 7: 16 Fig7. Buscar colegiado Una vez está el colegiado seleccionado, el botón ‘Añadir’ es el que permite agregar al colegiado para que conste que ha votado y el botón ‘Elegir listado’ llama a la función ‘elegir_listado()’ que nos muestra un formulario que nos permite elegir entre varias opciones según lo que deseemos, Fig8. Elegir listado 17 Este formulario esta dividido en 4 tablas: Seleccione opción, Provincia, Fechas y Observaciones. En él hemos introducido nuevos elementos. Los elementos de tipo ‘radio’, que son excluyentes entre si, permiten seleccionar entre una de las listas de cada tabla y la tabla de Fechas permite seleccionar un intervalo de tiempo a la hora de ver el listado. La estructura del listado que se mostrará será el siguiente: Fig9. Ver listado Aquí omitimos datos referentes a los colegiados, pero capturamos la tabla donde se irán mostrando los datos de los votantes en filas. En la columna de Duplicado aparecerá una ‘X’ si el colegiado ha votado mas de una vez y en la de Censo aparecerá un ‘NO’ si el colegiado no esta en censo, en caso contrario no aparecerá nada. La columna de provincia indica donde se ha realizado el voto, y la de fecha de registro la fecha cuando se registró dicho voto. Por último la columna de observaciones registraría posibles incidencias de las cuales se tuviera que tener constancia (sobres mal sellados, fuera de plazo…..). PROBLEMAS ENCONTRADOS Aunque la aplicación no se usó finalmente para el recuento de votantes ya que lo anularon (algo que ya nos habían advertido que podía pasar), sirvió para reforzar mis conocimientos de PHP y MySQL, además de comprobar lo que es realizar un trabajo “contrarreloj” y de bastante importancia. Podemos decir que el mayor problema en esta parte fue que había que ir modificando la aplicación con cierta frecuencia para satisfacer los requisitos del Colegio. 18 PARTE 3: APLICACIÓN EN PHP Y MYSQL PARA LA GESTIÓN DE LA BASE DE DATOS DE JUNTAS QUE RESIDE EN EL SERVIDOR DEL COLEGIO Además de realizar estas 2 aplicaciones previas a la realización del proyecto, colaboré en otras tareas de carácter, sino menores, si de menos repercusión o que no eran tan urgentes, dado que la aplicación de las revistas y la de los votos tenían un plazo límite por el transcurso mismo de los acontecimientos. Dicho esto, voy a pasar a explicar la parte central de la memoria, que es la realización del proyecto. La propuesta presentada fue: DISEÑO Y DESARROLLO DE UNA APLICACIÓN WEB PARA GESTIÓN DE BASE DE DATOS EN COPCV. Descripción El Colegio necesita rediseñar la base de datos de Juntas, ya que la aplicación esta hecha en MS/Access y no cumple los requerimientos necesarios que en un principio habían sido establecidos. Además, hay módulos sin terminar y esto dificulta su mantenimiento. Esta base de datos está en el servidor central en Valencia, y es usada además en las sedes de Castellón y Alicante. La base de datos que está relacionada en el proceso de mejora incluye módulos para gestionar Juntas, Expedientes, Agenda, Entrevistas, Entidades y Correspondencia (de entrada y salida): -La base de datos de Juntas gestiona las reuniones de la Junta de Gobierno donde se toman decisiones que posteriormente serán llevadas a cabo por los administrativos. -La base de datos de Expedientes está encargada de almacenar toda la documentación relacionada con la correspondencia de entrada y salida. -La base de datos de Agenda gestiona los eventos que se han producido o se producirán en un futuro. -La base de datos de Entidades manipula todos los datos pertenecientes a los colegiados. -La base de datos de Entrevistas gestiona las entrevistas solicitadas por los colegiados o centros. -La base de datos de Correspondencia es la encargada de gestionar todo el flujo de datos entrante y saliente en forma de correo. 19 Requerimientos En la reunión mantenida, vimos que la aplicación deberá enlazar los datos de las diferentes tablas de las bases de datos, puesto que la mayoría de estos datos se necesitan en todo momento para trabajar. Entre los datos necesarios para trabajar, se necesitaran los de la base central de colegiados. Se deberá poder administrar la aplicación y además, tanto los miembros de la Junta como los administrativos podrán acceder a ella. Herramientas de desarrollo y solución propuesta La aplicación se va a desarrollar utilizando software libre (PHP, MySQL, editores freeware, PHPMyAdmin...). Para agilizar las operaciones en las bases de datos la aplicación las enlazará dichas bases de datos entre si, facilitando el acceso a la información y haciendo de ella una aplicación más eficiente y fiable. Además, la aplicación obtendrá datos externos desde la base central de colegiados. Se dispondrá de una Intranet para poder administrar on-line la aplicación. Para esto se que se requerirá una autentificación como administrador. Mediante la intranet los administrativos de la misma podrán consultar las decisiones que se toman en juntas, ver los expedientes de los colegiados, resolver sus peticiones, etc... Antes de empezar a explicar su funcionamiento veremos una captura que nos servirá como guía: Fig. 10. Tablas de la base de datos de Juntas 20 En un pequeño dibujo veremos las relaciones de las tablas entre si: El diseño de la base de datos sigue el conjunto de relaciones de la 3º Formal Normal. Vamos a explicar la razón por la que utilizamos estas relaciones y no otras. El proceso de normalización de una base de datos consiste en aplicar una serie de reglas a las relaciones obtenidas tras el paso del modelo E-R (entidad-relación) al modelo relacional. Las bases de datos relacionales se normalizan para: · Evitar la redundancia de los datos. · Evitar problemas de actualización de los datos en las tablas. · Proteger la integridad de los datos. Primera Forma Normal (1FN) Se eliminan los grupos repetitivos. Los atributos han de ser atómicos. Gráficamente las celdas de la tabla contienen solo un valor, en cada uno de los atributos sólo se puede incluir un dato, aunque sea compuesto, pero no se pueden incluir una lista de datos. Se trata de que cada atributo guarde la menor cantidad de información posible. Para eliminar los grupos repetitivos se pone cada uno de ellos en una tabla aparte, esa nueva tabla hereda la clave primaria de la relación en la que se encontraban; es decir ésta última se transforma en Llave foránea o FK 21 Segunda Forma Normal (2FN) Si la clave CP consta de más de un atributo y existe al menos un atributo (o conjunto de atributos) no-primo A de R que no depende completamente de CP, incumpliremos la segunda forma normal. Lo que dará lugar a problemas en la manipulación de los datos. Para evitar esto procederemos a crear una nueva relación en la que incluiremos el atributo en cuestión que se eliminará de la relación de origen, y como clave primaria el atributo o atributos de los que dependía que se mantendrán en la relación original. Tercera Forma Normal (3FN) Una relación R está en 3FN si está en 2FN y ningún atributo no-primo depende funcionalmente deforma transitiva de la clave primaria. Es decir, en una relación en 3FN no hay dependencias funcionales entre atributos no primos. Si existieran dependencias una vez más daría lugar a redundancias, y problemas de manipulación de los datos. Para evitarlo en esta ocasión crearemos una nueva relación en la que moveremos el atributo dependiente transitivamente, y además incluiremos también el atributo del que depende que será la clave primaria de la relación. 22 PARTE DE CORRESPONDENCIA La primera parte que vamos a explicar es la de correspondencia. En nuestra base de datos esta parte esta dividida en 4 tablas que son: Correo pendiente de administración, Correspondencia, Correo de salida y Correo de entrada. Analizando cada tabla vimos que sería más eficiente unirlas en una misma, ya que los campos mostrados eran los mismos, excepto por dos, como eran los del tipo de correspondencia (entrada, salida o correo interno) y el campo de estado (pendiente, contestado, archivado y cerrado). Pensamos en gestionar esta diferencia mediante un cuadro de selección, que mostrara el valor correspondiente en cada caso, pero todo ello en un mismo formulario, sin tener que cambiar de página. Seguro que todo esto se entiende mejor a medida que avanza la explicación. Para empezar nuestra tarea tuvimos que hacer la migración a MySQL de los datos que ya estaban almacenados en las bases del Colegio. Creamos una tabla de nombre ‘correspondencia’ mediante la herramienta PHPMyAdmin en nuestra intranet y usamos la opción exportar del menú de archivo de Access para proceder a la migración. La apariencia que presentará la herramienta tras la migración será la de la figura 11: Fig. 11. PhpMyAdmin de Correspondencia A partir de este momento pasamos a crear los formularios. La primera utilidad que queríamos que tuviera nuestra aplicación era un buscador. Por lo tanto creamos un formulario donde tendremos todos los campos con su valor en blanco para poder iniciar la búsqueda según las necesidades del cliente. Pasamos a ver el código poco a poco: 23 <form action='correspondencia.php?accion=buscar' method='post'> Aquí está la definición del formulario, donde se le indica en la etiqueta ‘action’ que al lanzarlo nos redirija a una página diferente para mostrar los resultados, y que para todo esto utilice el método post, ya que nos interesa que estos resultados no se muestren en el url de la página. A continuación veremos la primera parte del formulario, que corresponde a la fecha: <td align='center'><b>Desde:</b> <input readonly style='width:80px;' type='text' name='fecha' id='fecha' value='' /> <input name='fechaini' type='button' id='fechaini' value='Seleccionar Fecha' /> <script type='text/javascript'> Calendar.setup({ inputField : 'fecha', // id del campo de texto ifFormat : '%d/%m/%Y', // formato de la fecha que se escriba en el campo de texto button : 'fechaini' // el id del botn que lanzar el calendario }); </script> </td> <td align='center'><b>Hasta:</b> <input readonly style='width:80px;' type='text' name='fechafin' id='fechafin' value='".date("d/m/Y",time())."' /> <input name='fecha2' type='button' id='fecha2' value='Seleccionar Fecha' /> <script type='text/javascript'> Calendar.setup({ inputField : 'fechafin', // id del campo de texto ifFormat : '%d/%m/%Y', // formato de la fecha que se escriba en el campo de texto button : 'fecha2' // el id del botn que lanzar el calendario }); </script> </td> Para este diseño de la fecha hemos aprovechado lo realizado en la parte de votos, por lo que ya lo explicamos en dicha sección de la memoria. La correspondencia tiene tres campos con los cuales podemos diferenciarla. Estos campos son el número de registro, el número de expediente y el número de documento. Para su introducción en la búsqueda hemos incluido en el formulario tres objetos ‘input’ de tipo texto. Si rellenamos estos tres campos a la hora de buscar solo debe salir un resultado (si la base de datos no tiene duplicados). 24 A partir de ahora vamos a ver como hemos implementado los cuadros de selección para la elección del ‘tipo’, ‘estado’ y el ‘pasado a’. Para realizar estos cuadros se utilizan las etiquetas ‘SELECT’, no confundir con el select de las consultas. Explicando uno de estos campos se explican todos. Vamos a tomar como ejemplo el campo de ‘tipo’: <b>Tipo:</b> <SELECT NAME='IDTipoRegistro' SIZE='1'> <option value='TODOS'>TODOS</option>"; Al select se le asigna un nombre que será el identificador del campo. A continuación se le asigna un tamaño al desplegable. En este caso hemos decidido que se vea un nombre cada vez. Lo siguiente es mostrar las opciones que habrá en el select. Aparte de las que obtenemos de la base de datos, hemos incluido una opción que mostrará todos los resultados de la búsqueda sin diferenciar por el tipo, en este caso, mostrará toda la correspondencia de tipo salida, entrada e interno. include('adodb/adodb.inc.php'); $db = ADONewConnection('access'); $dsn = "Driver={Microsoft Access Driver (*.mdb)};Dbq=C:\SVRCOPPV\COP2000SVR\copaux.mdb;Uid=Admin;Pwd=;"; $db->Connect($dsn); $rs = $db->Execute('SELECT IDTipoRegistro,TipoRegistro FROM [AUXCorrespondencia-TipoRegistro]'); if (!$rs) echo $db->ErrorMsg(); else while (!$rs->EOF) { echo"<OPTION VALUE='".$rs->fields[0]."'>".$rs->fields[1]."</OPTION>"; $rs->MoveNext(); } echo"</SELECT> El resto del código del ‘SELECT’ es el que vemos arriba. Lo primero que podemos ver es como se incluye la conexión. Podemos observar que el fichero de conexión que incluimos no lo habíamos visto anteriormente. Esto es porque hemos usado otro modo de acceso a las bases de datos del que habíamos usado, ya que tuvimos problemas que explicaremos en la sección ‘Problemas encontrados’. Por ello que la sintaxis de la forma de acceder a las bases y los datos sean diferentes de lo visto hasta ahora. 25 $dsn = "Driver={Microsoft Access Driver (*.mdb)};Dbq=C:\SVRCOPPV\COP2000SVR\copdat3.mdb;Uid=Admin;Pwd=;"; $db->Connect($dsn); $sql = "SELECT [CORRESPONDENCIA-Documentos].CopNumero, ENTIDADES.ApellidosEntidad, ENTIDADES.NombreEntidad, [CORRESPONDENCIA-Documentos].IDExpediente, [CORRESPONDENCIA-Documentos].IDDocumento, [CORRESPONDENCIA-Documentos].Fecha, [CORRESPONDENCIADocumentos].TipoRegistro, [CORRESPONDENCIADocumentos].IDEstado, [CORRESPONDENCIA-Documentos].Texto, [CORRESPONDENCIA-Documentos].Destino, [CORRESPONDENCIADocumentos].IDPasadoA, [CORRESPONDENCIADocumentos].CodigoLibro FROM [CORRESPONDENCIA-Documentos], ENTIDADES WHERE ([CORRESPONDENCIA-Documentos].CopNumero = ENTIDADES.CopNumero) AND ([CORRESPONDENCIADocumentos].CopNumero LIKE '".$CopNumero."') AND ([CORRESPONDENCIA-Documentos].IDExpediente=".$IDExpediente.") AND ([CORRESPONDENCIADocumentos].IDDocumento=".$IDDocumento.")"; $rs = $db->Execute($sql); Una vez obtenidos los resultados hay que mostrarlos por la pantalla. Como el código del formulario es parecido al explicado al principio de esta parte no lo volveremos a ver; la única diferencia es que en cada ‘input’ habrá que incluir un atributo donde le diremos al formulario que su valor será el que hemos obtenido de la búsqueda. Por ejemplo <b>Nombre:</b> <input type='text' name='NombreEntidad' size='30' value='".$rs- >fields[2]."'> , en este caso le decimos que en el lugar del nombre el valor será el 3º resultado de la consulta que hemos ejecutado. En el resto de campos ocurrirá lo mismo, habrá que especificarle el valor correspondiente a cada campo en el formulario. Luego la parte de gestión es análoga a la anterior, misma consulta que en la búsqueda y en el momento de mostrar el formulario especificar el valor obtenido de la consulta para cada campo. Al igual que hemos hecho más arriba veremos un ejemplo de objeto input: 32 <b>Carpeta:</b> <input type='text' name='n-CARPETA' size='10' value='".$row["nCARPETA"]."'> En este caso hemos tomado como ejemplo el campo ‘numero de carpeta’. Al final del formulario situaremos el botón que hace la función de editar, y otro botón que permite cerrar la ventana actual para volver al resultado de la búsqueda: <input type='submit' name='editado' value='Editar' /> <input type='submit' name='Submit' value='Cerrar ventana' onClick='JavaScript: window.close();'> Para cerrar la ventana usamos el método JavaScript window.close() que se ejecuta al pulsar el botón ‘Cerrar ventana’. La última función que nos falta por ver es la que contiene la consulta de la modificación. A esta función la hemos llamado editado y para su realización también la hemos separado en dos consultas: la de la parte de gestión (odbc) y la parte que muestra los datos directamente desde la base de datos ‘Correspondencia Documentos’ (adodb). La primera consulta es la que actualiza los datos para esta parte. Hacemos la conexión tal y como hemos explicado en apartados anteriores y la consulta de actualización será la siguiente: $sql = "UPDATE [CORRESPONDENCIA-Documentos] SET [CORRESPONDENCIA-Documentos].Fecha = '".$_POST["fecha"]."', [CORRESPONDENCIA-Documentos].TipoRegistro= '".$_POST["IDTipoRegistro"]."', [CORRESPONDENCIADocumentos].IDEstado = '".$_POST["IDEstado"]."', [CORRESPONDENCIA-Documentos].Texto = '".$texto."', [CORRESPONDENCIA-Documentos].Destino='".$destino."', [CORRESPONDENCIADocumentos].IDPasadoA='".$_POST["IDPasadoA"]."' WHERE ([CORRESPONDENCIA-Documentos].CopNumero LIKE '".$CopNumero."') AND ([CORRESPONDENCIADocumentos].IDExpediente=".$IDExpediente.") AND ([CORRESPONDENCIADocumentos].IDDocumento=".$IDDocumento.")"; , y seguidamente la consulta para la actualización de la parte de la gestión: 33 $sql2= "UPDATE correspondencia SET FechaVisto='".$_POST["FechaVisto"]."',OBSERVACIONES='".$_POST[" OBSERVACIONES"]."',GESTION='".$_POST["GESTION"]."', ESTADO='".$_POST["ESTADO"]."',visto='".$_POST["visto"]."',ADMINIST RACION='".$_POST["ADMINISTRACION"]."' WHERE CodigoLibro='".$_POST["CodigoLibro"]."' AND IDDocumento='".$_POST["IDDocumento"]."' AND IDExpediente='".$_POST["IDExpediente"]."'"; En la figura número 14 vemos el formulario donde editaremos: Fig. 14. Editar correspondencia PROBLEMAS ENCONTRADOS Como hemos venido diciendo, en esta parte hemos utilizado un acceso las bases de datos que no habíamos usado en ningún apartado anterior. Una vez hecha la exportación a MySQL de las base de la tabla de ‘correspondencia’ y diseñado el formulario inicial, nos dispusimos a programar la función de la búsqueda usando ODBC como hasta ese momento habíamos hecho. Pero a la hora de mostrar los resultados, el tiempo requerido por la aplicación era muy elevado. Tras revisar las bases de datos por si esta tardanza se debiera a algún tipo de incongruencia en su estructura, comprobamos que todo estaba en orden y que no era motivo de ralentizar el funcionamiento de la aplicación. Llegados a este punto optamos por solucionar el problema cambiando la forma en la que accedíamos a las bases de datos. 34 En vez de utilizar el acceso mediante ODBC, utilizamos la librería ADODB. ADOdb es un conjunto de librerías de bases de datos para PHP y Python. Su ventaja reside en que la base de datos puede cambiar sin necesidad de reescribir cada llamada a la base de datos realizada por la aplicación. Esto hace que el tiempo de ejecución se reduzca y el funcionamiento sea el que deseábamos en un principio. De ahí lo que mencionábamos en la redacción de la memoria acerca del archivo de conexión y la forma de acceder a cada registro de las consultas. Este archivo lo incluiremos en el CD adjunto. 35 PARTE DE ENTREVISTAS Como hemos visto en la introducción, nuestro trabajo consiste en gestionar por medio de la intranet del Colegio unas determinadas bases de datos que se administran por medio de Microsoft Access. Estas bases de datos eran las de Correspondencia, Juntas, Expedientes, Agenda, Entrevistas y Entidades. Llegados a este punto decidimos llevar la gestión de las bases de Agenda, Entrevistas y Entidades en un mismo módulo, ya que los datos que mostraban estas bases se podían unificar. De una misma tabla llamada ‘administrar_entrevistas’ podriamos obtener los datos que se obtenían anteriormente consultando las tres bases mencionadas por separado. Para empezar esta tarea había que crear la tabla en la base de datos de la intranet del Colegio mediante la herramienta phpMyAdmin y crear los campos que queremos mostrar. La tabla tiene la siguiente estructura: ADMINISTRAR_ENTREVISTAS( id: int(11), num_colegiado: varchar(7), telefono3: varchar(9), entrevistado: varchar(150), entrevista_llamada: varchar(15), con_quien: int(11), carpeta: varchar(10), estado: varchar(10), tema: text , resumen: text, fecha: datetime) Listar entrevistas Para facilitar la localización de las entrevistas, como ya habíamos hecho en la parte de Correspondencia, introducimos un buscador por campos. Aprovechamos lo anteriormente realizado, ya que el funcionamiento era muy similar. Los campos por los que realizaríamos la búsqueda serían por la fecha, permitiendo elegir un intervalo de tiempo; por el campo ‘con_quien’, que indica la persona que realiza la entrevista; por el campo ‘estado’, que indica si la entrevista esta pendiente, realizada o solicitada; y por el campo ‘tipo’, que indica si la entrevista es una llamada o es una entrevista en persona. Lo primero que hay que definir es una función listar_entrevistas(). Empezamos incluyendo un form donde poner los campos para cumplimentar la búsqueda. El primer campo por el que tenemos que buscar es por la fecha de inicio y por la fecha de final. Esta parte la teníamos ya hecha en la parte de Correspondencia, así que usaremos la misma estructura. El siguiente campo es el de ‘con quien’ hace la entrevista, y para ello creamos una tabla donde relacionamos el id del ‘entrevistador’ con su nombre y su cargo. La tabla en cuestión la llamamos ‘entrevistas_quien’. Su estructura es la siguiente: ENTREVISTAS_QUIEN (id: int(11), nombre: varchar(150), cargo: varchar(100) ) Con esto conseguimos que si en un futuro quisiéramos añadir ‘entrevistadores’, solo añadiéndolos en la propia tabla bastaría, sin tener que cambiar el código. 36 Todo esto tenía que poder elegirse con un cuadro de selección para facilitar la búsqueda. Estos cuadros también se usaron en la parte anterior, así que también nos beneficiaremos de ello. Finalmente el código correspondiente a esta parte quedaría como sigue: <select name='con_quien' size='1' style='width:385px'>"; $sql="SELECT * FROM entrevistas_quien"; $result=mysql_query($sql); while($row=mysql_fetch_array($result)){ echo"<option value='".$row["id"]."'";if((isset($_POST["con_quien"]))&&($_POST["con_q uien"] == $row["id"])){echo" selected";}echo">".$row["nombre"]." - (".$row["cargo"].")</option>"; } echo" </select> Seguidamente introducimos la búsqueda por el campo ‘estado’. Para la introducción de datos también se optó por el modo de cuadro de selección, y en este caso al ser los valores que puede tomar este campo son invariables o, no pueden cambiar mucho no se usó ninguna tabla adicional de donde tomar estos datos. Por lo tanto los valores se introdujeron en el propio código PHP. El código será el siguiente: <select name='estado' size='1' style='width:385px'> <option value='TODOS'";if((isset($_POST["estado"]))&&($_POST["estado" ] == "TODOS")){echo" selected";}echo">TODOS</option> <option value='Realizada'";if((isset($_POST["estado"]))&&($_POST["estad o"] == "Realizada")){echo" selected";}echo">Realizada</option> <option value='Pendiente'";if((isset($_POST["estado"]))&&($_POST["estado"] == "Pendiente")){echo" selected";}echo">Pendiente</option> <option value='Solicitada'";if((isset($_POST["estado"]))&&($_POST["estad o"] == "Solicitada")){echo" selected";}echo">Solicitada</option> </select> Para el último campo de la búsqueda, el del tipo, seguiremos el mismo método que con el campo de estado. Por lo tanto el código quedará de la siguiente manera: <select name='entrevista_llamada' size='1' style='width:385px'> <option value='TODAS'";if((isset($_POST["estado"]))&&($_POST["estado"] == "TODAS")){echo" selected";}echo">TODAS</option> <option value='Entrevista'";if((isset($_POST["estado"]))&&($_POST["estad o"] == "Entrevista")){echo" selected";}echo">Entrevista</option> <option value='Llamada'";if((isset($_POST["estado"]))&&($_POST["estado "] == "Llamada")){echo" selected";}echo">Llamada</option> </select> Después de esto incluimos un botón para buscar; también usaremos el tipo submit para que envíe el formulario al pulsarlo. Ahora pasamos a la parte del muestreo de datos. Para ello tenemos que realizar la consulta que recorra los campos de la tabla y los muestre por pantalla. Las diferentes entrevistas se agruparían por el día, así que la consulta quedaría como sigue: $sql_dia = "SELECT *, CAST(fecha AS time) AS hora FROM administrar_entrevistas WHERE CAST(fecha AS date) = '".$row["fecha"]."'"; Aquí dentro de cada grupo de entrevistas agrupadas por fecha, cada una de las entrevistas esta separada por horas, así que debemos usar la función date como sigue, ‘date("H:i",strtotime($row2["hora"]))’, para separar la fecha en día, mes y año por una parte y por otra la hora. Luego hay que ir concatenando a la consulta el número de colegiado, su nombre y hasta 3 teléfonos posibles. El nombre y el teléfono los obtenemos a partir de los números de colegiados. Para ello hemos creado dos funciones, //AVERIGUAR NOMBRE function averiguar_nombre($num_colegiado){ $datos=""; $sql = "SELECT NombreEntidad, ApellidosEntidad, ParticularDireccion, ParticularPrefijo, ParticularTelefono, ParticularFax, ParticularMAIL, ProfMAIL FROM [ENTIDADES] WHERE CopNumero='". strtoupper($num_colegiado) ."'"; if ($fila=odbc_fetch_array(odbc_exec(conectar_access(),$sql),1)){ return utf8_encode($fila["NombreEntidad"]." ".$fila["ApellidosEntidad"]); } } //AVERIGUAR TELEFONO function averiguar_telefonos($num_colegiado){ $datos=""; $sql = "SELECT ParticularPrefijo, ParticularTelefono, ParticularFax FROM [ENTIDADES] WHERE CopNumero='". strtoupper($num_colegiado) ."'"; 38 if ($fila=odbc_fetch_array(odbc_exec(conectar_access(),$sql),1)){ $vector = array(); $vector[0] = str_replace(" ", "", utf8_encode($fila["ParticularPrefijo"].$fila["ParticularTelefono"])); $vector[1] = str_replace(" ", "", utf8_encode($fila["ParticularFax"])); return $vector; } } Con estas dos funciones ya podemos mostrar todos los datos requeridos accediendo a los diferentes campos de la tabla: $telefono = array(); $telefono = averiguar_telefonos($row2["num_colegiado"]); echo "<tr> <td style='padding-left:20px'>"; echo date("H:i",strtotime($row2["hora"])); echo" </td> <td> ".$row2["num_colegiado"]." </td> <td>". averiguar_nombre($row2["num_colegiado"]) ." </td> <td>".$telefono[0]." </td> <td>".$telefono[1]." </td>"; if($row2["telefono3"] != ""){ echo"<td>".$row2["telefono3"]."</td>"; En este punto, sabiendo que las entrevistas podrían llegar a ser numerosas, y para que fuese más cómoda la navegación por la página, decidimos hacer paginación. Para ello definimos el tamaño máximo de página a 10 grupos de fechas, y a partir de ahí pasar a la página siguiente. $num_total_registros = mysql_num_rows($resultado); $total_paginas = ceil($num_total_registros / $TAMANO_PAGINA); 39 , siendo el número total de registros, el número de filas del resultado de la consulta. Para el total de páginas usamos la función ceil(), a la que le pasamos el resultado de dividir el número total de registros entre el tamaño de página. Con esta función redondeamos ese resultado al número entero siguiente. El número de páginas lo situaremos al final de la ventana, y las páginas distintas a la que nos encontremos serán enlaces a ellas. if ($total_paginas > 1) { echo"<hr><div align='center' style='font-size: 10px; margin: 0px 0px 0px 5px; color: #666666; text-decoration: none'>"; for ($i=1;$i<=$total_paginas;$i++) { if ($pagina == $i) //si muestro el índice de la página actual, no coloco enlace echo $pagina . " "; else { //si el índice no corresponde con la página mostrada actualmente, coloco el enlace para ir a esa página echo "<a href='?seccion=entrevistas&pagina=" . $i ."'>" . $i . "</a> "; } } echo "</div><hr>"; } Todo el código anterior nos permite listar las entrevistas que tenemos almacenadas. La página queda como podemos ver en la captura siguiente: 40 Fig. 15. Listar entrevistas. Este tipo de visualización de los datos permite que al imprimir la página se muestre la información requerida sin necesidad de utilizar ninguna herramienta de diseño para configurar la página. Ver entrevistas En esta parte de listar entrevistas visualizaremos las entrevistas con sus fechas y sus entrevistados, pero no permite modificarlos ni borrarlos. Para ello hicimos una función ‘ver_entrevistas’. Esta función es similar a la anterior, con la diferencia que no muestra los teléfonos. Además añadimos tres elementos adicionales: un elemento de tipo imagen, que proporciona una información al situar el puntero sobre ella, una opción para editar la entrevista y una opción para borrarla. Como el código es similar solo vamos a incluir la parte correspondiente a estos tres elementos nuevos. Primeramente mostramos el código correspondiente a la imagen, a la que le daremos el nombre de ‘interrogante.gif’ y la tendremos almacenada en nuestro servidor en la carpeta server:\intranet\ imágenes. El código es el siguiente: <td style='width:1px' onMouseOver=\"return escape('<strong>".date("d/m/Y",strtotime($row2["fecha"]))." - ".date("G:i",strtotime($row2["fecha"]))."</strong><br /><strong>".$row2["num_colegiado"]." - ".averiguar_nombre($row2["num_colegiado"])."</strong><br /><br /><strong>Tipo: </strong><i>".$row2["entrevista_llamada"]."</i><br /><strong>Con quien: </strong><i>".averiguar_con_quien($row2["con_quien"])."</i><br /><strong>Estado: </strong><i>".$row2["estado"]."</i>";if($row2["carpeta"] !=""){echo"<br Hemos usado la etiqueta ‘label for’ que asocia un rótulo con un control; para ello el valor del atributo ‘id’ debe ser el mismo que el valor del atributo ‘for’. Para el siguiente par de opciones vamos a utilizar la misma metodología. En esta opción seleccionaremos si el que solicita la entrevista es o no un colegiado. La única diferencia será que al elegir una opción u otra la estructura del formulario cambiará, visualizando algunos campos y ‘escondiendo’ otros que no harán falta. Para ello creamos una función a la que llamaremos ‘ver’, y a la que le pasaremos un parámetro que le indique si el solicitante es un colegiado o no. Vimos para ello que el lenguaje JavaScript nos permitirá realizar lo que queremos. A partir del código podremos comprender mejor a lo que nos referimos: function ver(que) { if (que=='es_colegiado') { document.getElementById('es_colegiado').style.visibility='visible'; document.getElementById('es_colegiado').style.position='relative'; document.getElementById('es_colegiado').style.height='auto'; document.getElementById('no_colegiado').style.visibility='hidden'; document.getElementById('no_colegiado').style.position='absolute' ; document.getElementById('no_colegiado').style.height='0px'; } else if (que=='no_colegiado') { document.getElementById('es_colegiado').style.visibility='hidden'; document.getElementById('es_colegiado').style.position='absolute' ; document.getElementById('no_colegiado').style.visibility = 'visible'; 48 document.getElementById('no_colegiado').style.position='relative'; } } Así, dependiendo de si seleccionamos un colegiado o un no colegiado, el formulario cambiará sensiblemente. Esto se consigue haciendo dos tablas diferentes, y pasándole a la etiqueta ‘id’ el valor correspondiente. Si el valor de la ‘id’ es ‘es_colegiado’, el formulario muestra los campos de número de colegiado y el de nombre y apellidos; aquí vamos a reutilizar alguna parte del código que ya usamos en la parte de ‘Registrar Votos’ explicada en la parte 2 de la memoria. Utilizamos la función ‘leerColegiado’, que a partir del número de colegiado obtiene el nombre, teléfono, fax, email1, email2 y dirección del colegiado en cuestión. Como esta función fue explicada anteriormente omitiremos el código. A parte de esta función también reutilizamos la búsqueda del colegiado por nombre y apellidos. Esta búsqueda también fue usada y explicada en la parte de los votos y por ello tampoco daremos más detalles sobre ella. Si por el contrario el valor de la ‘id’ es ‘no_colegiado’, los campos que se mostrarán serán el de número de Z, que es el prefijo que se adjudica a los solicitantes no colegiados, seguido por su identificador. Además se muestran el nombre de centro en caso que la entrevista sea solicitada por un centro y el nombre del entrevistado en el caso que lo hubiera. Análogamente al caso anterior, hicimos una función ‘leerZ’ para obtener los datos correspondientes al número de Z. Los datos que se obtienen son el nombre del centro, el número de teléfono, el número de fax, email1, email2 y dirección. Para ello, al igual que hace la función ‘leerColegiado’, se llama a un archivo que mediante una consulta obtiene los datos requeridos. La función se llama ‘leerZ’ y la consulta en cuestión es: $sql = "SELECT NombreEntidad, ApellidosEntidad, ParticularDireccion, ParticularTelefono, ParticularFax, ParticularMAIL, ProfMAIL FROM [ENTIDADES] WHERE CopNumero='". strtoupper($_GET["q"]) ."'"; En este caso también usaremos una búsqueda de centros para facilitar la tarea de introducción de datos. Al igual que tenemos un listado de colegiados, también disponemos de un listado de centros y el archivo PHP para obtener los datos de los centros no diferirá mucho del archivo que obtiene los datos de los colegiados. La consulta que nos permite la obtención de los datos es la siguiente: 49 $sql = "SELECT * FROM [ENTIDADES]"; $sql .= " WHERE ( ( UCase(ApellidosEntidad) +' '+ UCase(NombreEntidad) LIKE '%%".strtoupper($_GET["busqueda"])."%%' ) OR ( UCase(ApellidosEntidad) LIKE '%%".strtoupper($_GET["busqueda"])."%%' ) OR ( UCase(NombreEntidad) LIKE '%%".strtoupper($_GET["busqueda"])."%%' ) )"; $sql .= " AND (CopNumero LIKE 'Z%%')"; $sql .= " AND (CopNumero NOT LIKE 'CV%%')"; $sql .= " AND (CopNumero NOT LIKE 'X%%')"; $sql .= " ORDER BY ApellidosEntidad;"; $sql2 = "SELECT COUNT(CopNumero) AS numero_registros FROM [ENTIDADES]"; $sql2.= " WHERE ( ( UCase(ApellidosEntidad) +' '+ UCase(NombreEntidad) LIKE '%%".strtoupper($_GET["busqueda"])."%%' ) OR ( UCase(ApellidosEntidad) LIKE '%%".strtoupper($_GET["busqueda"])."%%' ) OR ( UCase(NombreEntidad) LIKE '%%".strtoupper($_GET["busqueda"])."%%' ) )"; $sql2.= " AND (CopNumero LIKE 'Z%%')"; $sql2.= " AND (CopNumero NOT LIKE 'CV%%')"; El cambio es que en la definición del WHERE, se le especifica que los datos que solicitamos son los de los ‘Z%%’, y no los de los ‘CV%%’. A partir de aquí los campos del formulario para ambos casos son los mismos. Al final de la página podremos el botón que nos permitirá añadir la entrevista a la base de datos y un enlace al apartado de ‘ver entrevistas’ explicado anteriormente. <input name='boton' type='button' onclick='this.form.submit();' value='Añadir' /> echo "<br /><a href='index.php?seccion=entrevistas'><b>Ir a Ver entrevistas</b></a>"; 50 Fig. 18. Añadir entrevista colegiado 51 Fig. 19. Añadir entrevista no colegiado • Funciones En este apartado vamos a exponer las funciones que hemos usado para borrar, editar y añadir entrevistas. Estas funciones contienen básicamente las consultas que nos permitirán realizar las acciones que anteriormente hemos definido. - Primeramente vemos la función ‘borrar_entrevista($id,$conexion)’, a la cual se le pasa la ‘id’ de la entrevista que queremos borrar y la conexión a la base de datos. Esta función contiene la consulta sql para la acción de borrar: $sql="DELETE FROM administrar_entrevistas WHERE id = ".$id." LIMIT 1"; , y ponemos LIMIT 1 para que borre solo una entrevista cada vez que hagamos clic en el link. - La siguiente función que veremos es la de ‘añadir_entrevista($conexion)’. Aquí tenemos que determinar antes si la entrevista que queremos añadir es a un colegiado o a un no colegiado. En este caso no le pasamos la ‘id’ ya que como es autonumérica se asigna automáticamente. 52 if(($_POST["centro"] != "") && ($_POST["num_z"] != "")){ $numero = $_POST["num_z"]; } if(($_POST["num_colegiado"] != "") && ($_POST["nombre"] != "")){ $numero = $_POST["num_colegiado"]; } Si hay ‘centro’ y ‘num_z’ la entrevista será a un no colegiado y si hay ‘num_colegiado’ y ‘nombre’ la entrevista será a un colegiado. A partir de aquí la consulta de la función es común: $sql="INSERT INTO administrar_entrevistas (id, num_colegiado, telefono3, entrevistado, entrevista_llamada, con_quien, carpeta, estado, tema, resumen, fecha) VALUES ('', '".$numero."', '".$_POST["telefono3"]."', '".$_POST["entrevistado"]."', '".$_POST["entrevista_llamada"]."', '".$_POST["con_quien"]."', '".$_POST["carpeta"]."', '".$_POST["estado"]."', '".$_POST["tema"]."', '".$_POST["resumen"]."', '".cambiaf_a_mysql($_POST["fecha"])." ".$_POST["hora"]."')"; Para que estos datos se actualicen en la base de datos de entidades donde tenemos los datos de los colegiados creamos la función ‘actualizar_datos_colegiado($_POST["numero_colegiado"],$_POST["telefono"], $_POST["fax"],$_POST["email1"],$_POST["email2"])’, a la cual le pasamos los datos recién introducidos. Esta función también consiste en una consulta de actualización sobre la base de datos: $sql="UPDATE entidades SET ParticularTelefono='". $telefono ."', ParticularFax='".$fax ."', ParticularMAIL='". $email1 ."', ProfMAIL='". $email2 ."' WHERE CopNumero LIKE '". strtoupper($numero) ."'"; , usando otra vez la función strtoupper() para pasar a mayúsculas las letras ‘cv’. Una vez se introduce la entrevista se muestra la lista de entrevistas actualizada con la entrevista añadida. - La función que nos queda por mostrar es la de modificación de una entrevista existente. Aquí también diferenciamos entre colegiados y no colegiados. El código correspondiente a esta separación es el de los dos bucles if que hemos visto en la función ‘añadir_entrevista($conexion)’, así que la explicación es la misma. Lo que cambia es la consulta, que en este caso será una consulta de actualización. El aspecto que tendrá será el siguiente: $sql="UPDATE administrar_entrevistas SET telefono3 = '".$_POST["telefono3"]."', entrevistado = '".$_POST["entrevistado"]."', entrevista_llamada = '".$_POST["entrevista_llamada"]."', con_quien = '".$_POST["con_quien"]."', carpeta = '".$_POST["carpeta"]."', estado = '".$_POST["estado"]."', tema = '".$_POST["tema"]."', resumen = '".$_POST["resumen"]."', fecha = '".cambiaf_a_mysql($_POST["fecha"])." ".$_POST["hora"]."' WHERE id = ".$_POST["id"]; El resto de la función también es igual que la de añadir, llamando a la función ‘actualizar_datos_colegiado’ y luego a la de ‘ver_entrevistas’. Para acceder a este apartado de entrevistas del Colegio, se nos pidió que estableciéramos un nombre de usuario y una contraseña. Esto lo conseguimos creando una función llamada ‘autorización()’. Para hacer este tipo de funciones se usan unas variables denominadas variables de sesión. Estas variables permiten la autentificación de usuarios en páginas restringidas. Mediante PHP hay que comprobar que los datos introducidos por el usuario en el formulario de autentificación son válidos en la base de datos, y si es así iniciar una sesión guardándolos en la variable $_SESSION. En cada página que se quiera restringir el acceso deberá haber una comprobación del contenido de esta variable las variables de sesión y si éstas coinciden con algún registro de la base de datos. En caso contrario el usuario no es válido y deberá identificarse de nuevo. El código esta compuesto de tres bucles ‘if’ para dicha comprobación. if(!isset($_SESSION['loggedIn'])){ session_register("loggedIn"); $_SESSION['loggedIn'] = false; if ($_SESSION['loggedIn'] == false ){ echo"<form name='login' method='post'> <table border='0' class='login' align='center'> <tr><td></td><td colspan='3'> <tr><td></td><td>Nombre:</td><td><input type='text' name='nombre' maxlength='9' /></td><td></td></tr> <tr><td></td><td>Contraseña:</td><td> <input type='password' name='password' maxlength='10' /></td><td></td></tr> <tr><td></td><td></td><td><input type='submit' value='Aceptar' /></td><td></td></tr> </table> </form>"; die(); } Comprobamos si el valor de la variable $_SESSION. Si es igual a false vuelve a mostrar el formulario para tener la oportunidad de volver a introducir el usuario y la contraseña. Luego con la función die() finalizamos el script, porque de lo contrario pediría la autorización cada vez que cambiáramos de página. 54 if ($_POST["nombre"]=='*****' && $_POST["password"]=="*****"){ session_register("loggedIn"); $_SESSION['loggedIn'] = true; } En este if se pone el valor de la variable $_SESSION a true si los datos son los correctos. Una vez comprobados, y explicado el funcionamiento de la variable sesión y mostrado su código, ya podemos pasar a presentar la parte que hace que todo funcione, donde llamamos a las funciones. Para ello usamos un switch y según el nombre que le hayamos dado a la acción anteriormente, ejecutamos una función u otra. Cada ‘case’ tendrá el nombre de la acción: if(isset($_GET["accion"])) { switch($_GET["accion"]) { case "borrar": borrar_entrevista($_GET["id"],$conexion); break; case "ver": ver_entrevista($_GET["id"],$conexion); break; case "anadir": anadir_entrevista($conexion); break; case "editar": editar_entrevista($conexion); break; case "listado": listar_entrevistas($conexion); break; default: ver_entrevistas($conexion); break; } } else{ ver_entrevistas($conexion); } Primero comprobamos que la variable ‘accion’ esta definida con la función isset(), a la cual le pasamos la variable por GET(en el url de la página). Si esta definida entramos al switch. Su funcionamiento es como el de un bucle if, cada ‘case’ es excluyente de los demás. Si no estuviera definida la variable ‘accion’ se llama a la función ‘ver_entrevistas’. Hay que reseñar que este apartado de entrevistas puede ser modificado, ya que la forma en la cual esta realizado lo permite, es decir, es un código flexible. Se podrá, por ejemplo, añadir otro campo en la búsqueda si así lo precisara el cliente; insertar más campos a la tabla mediante la herramienta PhpMyAdmin y añadirlos después al formulario tal y como hemos hecho con los demás, etc… PROBLEMAS ENCONTRADOS En esta parte se puede decir que los problemas encontrados fueron de “desconocimiento”. Nos encontramos con casos en los que debíamos usar métodos o funciones que aun no conocíamos, y por lo tanto recurrimos a la red para documentarnos. Más allá de esto no tuvimos problemas con las bases de datos, y el cliente quedó satisfecho con el funcionamiento y la apariencia final de la aplicación, además de tener la posibilidad de ampliarla. 56 PARTE 4. CSS Además de la programación del código PHP, hemos incluido hojas de estilo CSS para definir la apariencia de las páginas que hemos realizado. CSS es un formato usado en las páginas Web para separar el estilo (la forma en la que se ve una página Web) de la estructura (o código). Es una característica del HTML que da más control a los programadores, diseñadores y usuarios de la Web sobre cómo se muestran las páginas Web. Como estas páginas van a estar incluidas en la intranet del Colegio, empezaremos por exponer los estilos que tiene dicha intranet. Primeramente veremos una captura: Fig. 20. Intranet Nuestros ‘.css’ los hemos incluido en un archivo diferente, para que podamos reutilizar los estilos en diferentes páginas. Este archivo se llama styles.css, y lo llamamos al principio de la página que contiene el código PHP para la intranet. 57 Conclusiones Después de haber trabajado en el proyecto hemos comprobado las dificultades que entrañan las bases de datos gestionadas con MS/Access, dada su nula comprobación de errores y duplicación de datos. Hemos dado las soluciones que hemos estimado oportunas para solventar estos contratiempos. No hemos quedado del todo satisfechos porque no hemos completado la propuesta inicial del proyecto, pero dadas las dificultades que entrañaba la tarea podemos decir que hemos hecho todo lo posible por acabarla. Creemos que estas dificultades nos pueden ayudar en un futuro a solventar otros problemas y saber como ‘buscarnos la vida’ delante de las posibles adversidades que nos surjan en el mundo de la programación. Hemos aprendido una metodología a la hora de trabajar y nos hemos introducido en un mundo que nos será de mucha utilidad como es el diseño de páginas Web. Es una parte de la informática que nos atraía y de la cual ya tenemos una buena base para trabajos futuros en el mismo campo. Además de todo esto hemos adquirido otros conocimientos debidos a las necesidades y funcionamiento propios de la empresa, como configuraciones de correo, servidores, redes…Esto no forma parte del proyecto pero estamos contentos de haber sido de ayuda en estos menesteres. Aunque el cliente ha quedado satisfecho con los diseños de las aplicaciones, hemos de reconocer que el aspecto de estas se puede mejorar. Como el tiempo se nos echaba un poco encima no pudimos dedicar todo lo que merece este apartado. Por lo tanto podemos extraer que la parte de hojas de estilo es en la que hemos de mejorar de cara a un futuro si optáramos por el diseño de páginas web. 64 Bibliografía • Wikipedia: http://es.wikipedia.org/ • C Sharp: http://msdn2.microsoft.com/es-es/vcsharp/default.aspx • PHP.net: http://es.php.net/, http://www.php.net/ • PHPMyAdmin: http://www.phpmyadmin.net/home_page/index.php • MySQL: http://www.mysql.org/ • HTML: http://www.webestilo.com/html/ • ADOdb: http://adodb.sourceforge.net/ • También damos las gracias a Alberto Martinez Herrero, cuyo proyecto realizado en el Colegio nos ha servido de ayuda. 65 Índice de figuras Figura 1. Aspecto inicial de la aplicación de la revista……………………...Pág. 5 Figura 2. Menú de revistas…………………………………………………......Pág. 6 Figura 3. Pantalla de búsqueda…………………………………………….…..Pág.7 Figura 4. Resultado de la búsqueda………………………………………...…Pág.9 Figura 5. Captura de intranet/PHPMyAdmin………………………………..Pág. 10 Figura 6. Registrar voto……………………………………………………....Pág. 16 Figura 7. Buscar colegiado……………………………………………..…….Pág. 17 Figura 8. Elegir listado…………………………………………………………Pág. 17 Figura 9. Ver listado……………………………………………………………Pág. 18 Figura 10. Tablas de la base de datos de Junta……………………………Pág. 20 Figura 11. PHPMyAdmin de Correspondencia…………………………..…Pág. 23 Figura 12. Búsqueda de correspondencia…………………………………..Pág. 26 Figura 13. Resultados de la búsqueda……………………………………...Pág. 31 Figura 14. Editar correspondencia………………………………………...…Pág. 34 Figura 15. Listas entrevistas……………………………………………….....Pág. 40 Figura 16. Ver entrevistas…………………………………………………….Pág. 43 Figura 17. Editar entrevista no colegiado………………………………..….Pág. 47 Figura 18. Añadir entrevista colegiado……………………………………....Pág. 51 Figura 19. Añadir entrevista no colegiado…………………………………..Pág. 52 Figura 20. Intranet……………………………………………………………..Pág. 57 Figura 21. Tabla de Juntas en Access………………………………………Pág. 62 Figura 22. Tabla de Expedientes en Access………………………………..Pág. 63 66