Anda di halaman 1dari 314

Este libro sigue estando dedicado a ya sabis quines, incluso aunque las personas en cuestin no lo sepan.

A ver si logramos mantener el secreto otro libro ms.

Agradecimientos
Son muchas las personas con las que tengo una deuda de gratitud pero poco el espacio disponible para pagarles; toca generalizar. Gracias a todas aquellas personas que me estn ayudando a apreciar las cosas sencillas como, por ejemplo, los momentos que puedo compartir con ellas. Y claro, le tengo que dar las gracias a Ignacio Cerro por poner prlogo a esta obra y ponerla en perspectiva, y a Guadalupe Torres por darle un toque de color y de estilo al libro con una portada tan maravillosa. Por cierto, quiz en la dedicatoria no ha quedado del todo claro que este libro va para toda la familia de Guille, que tan bien se est portando con l.

Introduccin
Revolucin? No, realidad. Est usted leyendo la introduccin de un libro que contiene las claves para convertir sus pginas Web en aplicaciones Web, cuyo contenido se obtiene a partir de una base de datos, y que permite a sus usuarios almacenar informacin en esa misma base de datos. Y si tiene usted esta gua en sus manos no hace falta que le convenza (al menos, no mucho) de la formidable pareja que hacen MySQL y PHP. ste es un mundo de descubrimientos. Y de maravillas. Y est en continuo cambio. Fue en el ao 1990 cuando comenz todo, de mano del investigador Tim Berners-Lee, el padre de la criatura. No ha pasado tanto tiempo desde entonces, verdad? Y sin embargo, han pasado tantas cosas que parece casi increble. En primer lugar, estn las pginas Web, escritas en leguaje HTML. Este lenguaje permite describir la ubicacin de diferentes elementos en una pgina, adems de sus propiedades (tamao, color, etc.). Salvando las distancias, sera una tarea similar a la de un pintor trabajando con un lienzo. No en vano la tarea de crear pginas HTML se deja en manos de los diseadores, los artistas de la Web. Estas pginas reciben el calificativo de estticas porque, una vez publicadas, su contenido permanece inalterable. Hasta que decidamos modificarlas, claro est, pero en este caso se tratara de otra pgina. Y es aqu donde aparece PHP. PHP es un lenguaje, como HTML, pero con una diferencia notable: tanto los elementos de una pgina como su ubicacin dentro de ella pueden variar dependiendo de las condiciones que creamos oportunas. Esto permite crear contenidos totalmente flexibles. Una sencilla aplicacin de las posibilidades de PHP consiste en incluir detalles de la fecha y la hora actuales en las pginas aunque, obviamente, esto no se queda ah. Puede variar el contenido de las pginas dependiendo del cliente Web que se est utilizando para ver las pginas. As, si utiliza Firefox, puede mostrar la pgina de una manera y si utiliza Internet Explorer de otra totalmente diferente. Por otro lado estn las bases de datos, presentes en multitud de aspectos de la vida cotidiana: en el mvil, en el banco, en el supermercado. Sin que seamos conscientes de ello, convivimos con estos sistemas. Inicialmente, su alto coste no haca previsible esta expansin. Pero la situacin ha cambiado considerablemente porque hoy en da podemos encontrar sistemas gestores de bases de datos que utilizar libremente. Entre ellos destaca uno, MySQL, el ms utilizado de los de su clase. Y por ltimo, est su unin. Para que se haga una idea

del potencial que la combinacin de estas tecnologas tiene, suponga que quiere poner a disposicin de todo el mundo, en su propio servidor Web, informacin sobre su coleccin de pelculas. Normalmente esto significara crear una pgina por cada pelcula. Sin embargo, utilizando MySQL y PHP juntos, podr crear una nica pgina cuyo contenido variar dependiendo de la pelcula que quiera seleccionar. En esta gua aprender a hacerlo. La unin hace la fuerza, nada ms cierto. Combinando las tecnologas necesarias para ofrecer pginas Web, para administrar bases de datos y el lenguaje de pginas dinmicas PHP, podr poner a disposicin de todos aquellos que tengan acceso a Internet un catlogo de productos o cualquier otra informacin que desee mostrar. Y las posibilidades no se limitan a Internet. La red local de su empresa puede ser tambin el medio de difusin ideal, ya se trate de una aplicacin para la gestin de las tareas asignadas a cada departamento o de un boletn de noticias privadas. El lmite lo marca su imaginacin. Estamos hablando de medios de difusin, equiparando una red de ordenadores con una red de peridicos, de televisin o de radio, porque es as. Las principales cadenas de radio del mundo emiten en Internet desde hace tiempo, los peridicos ms importantes tienen su versin digital, e incluso las televisiones se intentan abrir hueco. Muchos asisten perplejos al nacimiento de un nuevo sistema de comunicacin de noticias basado en el mismo esquema: un servidor de bases de datos que almacena las noticias y un servidor Web que, gracias al uso de lenguajes como PHP, las ofrece a todos los que quiera leerlas o publicarlas. Muchos de estos sistemas, conocidos como blogs (de Web Logs) utilizan PHP y MySQL para su funcionamiento. Hemos empezado dicindole que estamos frente a una realidad y hay varios hechos que lo constatan. El ms significativo de ellos es la aparicin, sin pausa, de versin tras versin de PHP, cada una de ellas incorporando interesantes novedades, hacindolo an ms potente y capaz de lo que ya era. Si a esto unimos la madurez en la que se encuentra MySQL tras el lanzamiento de su versin 5.1 (que bien podra haber sido llamada la versin 6), no podemos equivocarnos: PHP y MySQL es la pareja ganadora. Decidirse por ellos es unirse a una de las mayores comunidades de desarrolladores de nuestro planeta, una gran ventaja, ya que se cuenta con mucha experiencia acumulada que puede ser de utilidad. Acompenos en lo que le prometemos ser un viaje de descubrimientos y de maravillas. No le defraudaremos.

Cmo usar este libro


El objetivo de esta gua es que, a su fin, sea capaz de desarrollar aplicaciones para la Web basadas en MySQL y PHP. Tanto si ya ha trabajado con ellos por separado o conjuntamente como si ste es su primer contacto, est en buenas manos. En primer lugar queremos que sepa exactamente qu es lo que lograr si sigue con nosotros durante el resto del viaje. Para ello hemos preparado un primer captulo equiparable a una terapia de choque. Durante este captulo configurar un completo sistema de desarrollo y aprender qu son un servidor Web, un servidor de bases de datos y dnde encaja PHP dentro de todo esto. Para ilustrar esta explicacin nada mejor que un sencillo ejemplo. Al terminar este captulo debera tener una visin de conjunto de todas las tecnologas que va a utilizar. El segundo captulo es una introduccin al lenguaje PHP para aquellos que an no lo conozcan: desde la declaracin de variables y sus posibles tipos hasta las instrucciones de control. En la misma lnea que el anterior, el tercer captulo se dedica al sistema gestor de bases de datos MySQL. Hablaremos sobre sus caractersticas, veremos qu son bases de datos y tablas y los tipos de datos que podemos almacenar. Los captulos cuarto y quinto estn dedicados a ampliar los conocimientos adquiridos en el segundo y el tercero. De nuevo estn dedicados a PHP y MySQL, pero a aspectos que an no se han tratado y cuya importancia es fundamental. En concreto, funciones y programacin orientada a objetos en lo que se refiere a PHP y diseo de bases de datos con respecto a MySQL, ya que antes de entrar en el meollo de la cuestin, disearemos la base de datos con la que vamos a trabajar. En el sexto captulo aprender a utilizar el lenguaje SQL para obtener la informacin que desee de una base de datos, as como para modificarla. La verdadera accin comienza en el captulo sptimo. En l MySQL y PHP unen sus fuerzas. Para acceder a bases de datos de MySQL desde PHP utilizaremos la nueva interfaz entre ambos que PHP present en la versin anterior a la actual, la 5. Veremos con detalle el ejemplo expuesto durante el primer captulo, combinado con la base de datos diseada en el captulo anterior, y lo ampliaremos. En el captulo octavo hablaremos sobre los formularios en HTML y JavaScript. Hasta ahora se habr limitado a obtener informacin de una base de datos y mostrarla en una pgina Web, pero con lo que aprenda en este captulo ser capaz de permitir que el usuario de sus aplicaciones Web tambin pueda guardar datos. Entre otros usos, JavaScript le ayudar a comprobar que estos datos son

correctos, ahorrndole trabajo en sus pginas PHP y evitando posibles errores. El noveno captulo est dedicado a uno de los aspectos que ms se descuidan durante la creacin de un programa en PHP: la gestin de errores. Ver cmo configurar PHP y MySQL en este aspecto, y cmo crear sus propios gestores de error. A estas alturas de la gua ya habr visto lo complicado que es mantener dos lenguajes como PHP y HTML en un nico archivo. Lo ideal es que el trabajo de diseo y el de programacin se puedan hacer de forma independiente. Esto es posible gracias al uso de plantillas, que veremos durante el captulo dcimo. Los captulos decimoprimero, decimosegundo y decimotercero estn dedicados a los procedimientos almacenados, los desencadenadores y las vistas, respectivamente. Se trata de caractersticas avanzadas de MySQL que le resultarn extremadamente tiles. Esta gua se cierra con un captulo dedicado a XML, un estndar con el que tanto MySQL como PHP pueden trabajar. En dicho captulo veremos cmo utilizar sus caractersticas de forma conjunta. En un mundo que evoluciona tan rpido como el de la informtica, no hay nada peor que un libro que no evoluciona al mismo paso. Por ello hemos puesto a su disposicin la pgina Web: http://enreas.com/amp/ Los productos que utilizamos en este libro dan el nombre a la pgina: Apache, MySQL y PHP (AMP). En ella podr encontrar los ejemplos del libro, contactar con el autor de esta gua y mucho ms.

Prlogo
Perspectiva. La velocidad a la que se suceden los acontecimientos en nuestros das nos dejan, en muchos casos, carentes de perspectiva para entenderlos. En el da de ayer mi hijo de nueve aos se acerc al frigorfico de la casa y sac un batido. Estaba fro, que es lo que se espera cuando uno saca una bebida del frigorfico. A continuacin, se sent delante de un porttil que suele estar en la cocina y abri Spotify. Eligi su lista de canciones favoritas y comenz a escuchar msica. La msica estaba donde deba y haca lo que se esperaba que hiciese. Todo ocurri con la misma coherencia y trasparencia que cuando tom el batido en sus manos. Todo segn lo esperado. En apenas 30 segundos, dos electrodomsticos le ofrecieron lo que l buscaba. Con naturalidad, con claridad, sin interrogantes y sin perspectiva. Nos estamos convirtiendo, con el paso del tiempo y con la ayuda de las nuevas tecnologas, en autnticos devoradores. Devoradores de datos, de imgenes, de opciones, de contactos. A veces tiendo a imaginarme lo que Internet ofrece como un ente fsico, con estructura y vida propia, con extremidades copadas de conocimientos y ansioso por atravesar el umbral de la puerta de mi casa. Qu difcil es parar y cargar una dosis de perspectiva. Perspectiva para entender que las cosas no suceden porque s, que el fruto de muchos aos de trabajo puede hacer que algo parezca evidente pero es la consecuencia de horas y horas con muchos interrogantes y pocas respuestas. Qu difcil es entender que nuestra obligacin pasa tanto por respetar lo que hay como por arrasarlo para construir algo nuevo. Recibir y ofrecer. En esta direccin he debido hacer un ejercicio de autocrtica. Parar y pensar un poquito. Pensar sin muchos datos. Yo solito, sin Google, sin Wikipedias a mi alcance. Pensar en lo que hago cada da. Cuestionarme por qu est fro el batido, por qu usaron ese plstico para distribuirlo, por qu el color del envase coincide con el del contenido, por qu tiene ese tamao si suelo quedarme con ganas de coger otro. No dar nada por supuesto. No aceptar nada porque exista desde hace tiempo. Y en esta senda me topo con algo que uso a diario para mi trabajo, que me ofrece informacin, herramientas, soluciones. Algo que nunca me par a mirar y que forma parte de mi da a da como si de un grifo se tratase. Lo abro y all est la respuesta. Comienza mi jornada delante del ordenador y algunos actos se suceden a lo largo del da, un da tras otro: consulto una enciclopedia, accedo a un foro, comento en un blog, publico en otro, relleno un formulario. Me siento como un funcionario del control de aduanas de Andorra. Veo pasar todo ante m fluyendo sin aparente esfuerzo.

Pero qu hay detrs de todo eso? Qu es lo que lo sostiene? No puedo negar que ltimamente me siento fuertemente atrado por eso que llaman software libre. Lo reconozco con cierta vergenza, pues durante muchos aos me fue muy ajeno. Pero es que no puedo dejar de imaginarme a una legin de programadores, semejante en nmero y constancia a un pilago de orcos camino del Abismo de Helm, levantndose cada da para hacer que todo siga funcionando. Ahora est pasando las primeras pginas de un libro que pretende mostrar algunas de las cualidades de dos de estos hermanitos que dan de comer a la legin que nombramos anteriormente: PHP y MySQL. Si he de ser sincero, para m no son ms que un conjunto de letras reunidas con poca gracia, pero ya advert que era el momento de parar y pensar. Muchas de las tareas que realizo a diario estn soportadas por bases de datos construidas con MySQL y se muestran en pginas programadas con PHP. Pero a m me da igual y, aunque hoy lo que pretendo es rendir un pequeo homenaje a aquellos que hacen posible que esto siga creciendo, lo que me dejan es su eficiencia. Su engranaje es sublime. Quien los puso a todos de acuerdo para que la mquina funcionara? Cul fue el origen? Qu puerta hay que cruzar para dejar de ser un devorador y formar parte de la legin? Dnde est la clave para dar soporte y nimo al grupo? El software libre se nos ha metido en casa. Lo usamos a diario con la misma naturalidad que tenemos al coger el mando a distancia de la televisin. Entenderlo un poco nos ayudara a respetarlo. Conocerlo nos permitira hacerlo crecer. Creer que est a nuestro alcance el participar de la batalla no es algo insensato. Por este motivo les invito a que, conmigo, sigan pasando pginas y que puedan encontrar en lo que viene a partir de este momento al menos una respuesta a tanto interrogante. Les dejo ahora con uno de esos disciplinados orcos. Doy fe de que no es mala compaa. Ignacio Cerro

MySQL y PHP
Para el impaciente. Este captulo est pensado para aquel lector que no est muy seguro de lo que podr encontrar en este libro. Durante las siguientes pginas crearemos una pequea aplicacin Web que muestre el contenido de una base de datos en una pgina HTML, utilizando PHP como unin. Veremos que es posible tener una base de datos, extraer los datos almacenados en ella y mostrarlos en una pgina Web. Y veremos que, si cambia alguno de los datos de una tabla, el contenido de la pgina Web cambiar sin que por ello tenga que cambiar ni una sola lnea de la pgina PHP. No se preocupe si muchos de los conceptos que se presenten durante este captulo le son desconocidos: profundizaremos en todos ellos durante el resto del libro. Antes de que el lector pueda comenzar a realizar sus propios desarrollos ser necesario que pasemos por algunos captulos que le mostrarn las caractersticas principales de MySQL y PHP. No queremos engaarle, hay que tener paciencia para contener los deseos de avanzar captulos sin prestar la debida atencin a los pilares fundamentales del desarrollo de pginas Web de contenido dinmico. Una vez tenga esos conocimientos bsicos, aprender a utilizar de forma conjunta ambas tecnologas. MySQL y PHP son grandes productos por s solos, pero juntos forman una de las parejas ms formidables del mundo del software libre. Plantese la lectura de este captulo como la de una novela: le narraremos una historia que habla del futuro, de su futuro, de las maravillas que podr construir tras el trabajo que supondrn los captulos siguientes a ste.

La primera aplicacin
Cul es nuestro objetivo? Construir una aplicacin que muestre el contenido de una base de datos en una pgina Web. Pero es mejor concretar un poco ms. Vamos a desarrollar una pequea aplicacin Web que permita gestionar nuestra videoteca. Sera muy ambicioso por nuestra parte comenzar esta gua con un trabajo de tales caractersticas, as que iremos por partes: nos limitaremos a crear una aplicacin para realizar el mantenimiento de una lista de gneros cinematogrficos. Este trabajo formar luego parte de la aplicacin que gestionar nuestra videoteca. Las aplicaciones Web que veremos se componen de varias partes:

Un servidor de bases de datos: MySQL ha sido la eleccin lgica, debido a su potencia y a que es uno de los ms utilizados. Una base de datos: Contiene las tablas y los datos con los que queremos trabajar. Puede modificar el contenido de la base de datos y ver cmo el contenido de las pginas Web de su aplicacin cambia sin que tenga que alterar una sola lnea de cdigo. Un servidor Web: Aunque podramos escoger cualquier servidor Web que permita la ejecucin de PHP, nos decantamos por Apache por varios motivos. Entre ellos, que se trata del servidor Web ms utilizado en el mundo y es libre, por lo que todos podemos utilizarlo en Windows, Linux o Mac OS X. PHP: El nexo de unin entre la base de datos y los clientes potenciales de nuestra aplicacin Web. Clientes: Los clientes son los usuarios de nuestra aplicacin Web. Sea un desarrollo hecho para nuestro propio disfrute o para el de los dems, si nadie (persona o mquina) va a utilizarlo quiz su existencia carezca de sentido. La figura 1.1 muestra las relaciones existentes entre los diferentes elementos que acabamos de enumerar.

Figura 1.1. Aplicaciones Web

Por lo tanto, el primer paso ser disponer de todos los servicios necesarios: MySQL para las bases de datos y Apache (con PHP) para las pginas Web. Tras ello, podremos comenzar con a trabajar. Nuestro desarrollo va a comenzar con la creacin de la base de datos. Posteriormente poblaremos dicha base de datos con las tablas y los registros necesarios. Continuaremos con la programacin en PHP de la pgina que mostrar el contenido de una de las tablas de la base de datos. Al terminar podremos contemplar algo parecido a lo que se puede ver en la figura 1.2.

Figura 1.2. Nuestro objetivo

Not a: No preste atencin al diseo de la pgina, a su aspecto, y concntrese en el contenido de la misma, en que todo funciona como se espera. En el captulo dedicado a Smarty aprenderemos a separar la lgica (funcionamiento, programacin) de la representacin (aspecto, diseo).

XAMPP
Como acabamos de comentar, para que se pueda poner manos a la obra necesita disponer de un sistema con Apache, PHP y MySQL instalados y en funcionamiento. Francamente, hara falta un libro como ste slo para comenzar a explicar cmo instalar y configurar correctamente estos tres componentes en los tres sistemas operativos ms utilizados del mercado (Windows, Linux y Mac OS X). Pues, aunque le parezca mentira, existe una forma rpida y sencilla de instalar y configurar todo esto, de un plumazo, en cualquiera de los sistemas operativos antes mencionados: XAMPP. Puede encontrarlo en la pgina: http://apachefriends.org/
Not a: XAMPP son las siglas de X, Apache, MySQL, PHP y Perl. Se utiliza una X para representar al sistema operativo y no una W (de Windows) o una L (de Linux), como en WAMP o LAMP. En este libro no utilizaremos esa ltima P.

Un par de aclaraciones. En primer lugar, XAMPP es ideal para entornos de desarrollo. Sin embargo, la opcin recomendada para un servidor de produccin (es decir, aquel en el que se encontrarn las aplicaciones Web una vez concluido su desarrollo) sigue siendo la ms compleja: la instalacin, configuracin y mantenimiento de cada uno de los componentes de forma individual. Obviamente, se trata de un trabajo que es necesario dejar en manos de expertos capaces de garantizar la seguridad y el rendimiento del servidor. En segundo lugar, XAMPP no es algo nico. Existen muchas otras soluciones para instalar Apache, PHP y MySQL con facilidad. La razn por la que lo utilizaremos en este libro es mltiple: Est a su disposicin ya utilice Windows, Linux o Mac

OS X. El equipo responsable de su desarrollo se preocupa de mantenerlo actualizado para que ofrezca la ltima versin de cada componente. Incluye multitud de herramientas como, por ejemplo, phpMyAdmin, una aplicacin Web para la administracin de bases de datos MySQL. Proporciona una interfaz de usuario muy fcil de utilizar para poner en marcha y detener los servicios, de forma individual. No es obligatorio que use XAMPP, podr seguir los ejemplos de este libro siempre y cuando disponga de un equipo con Apache, PHP y MySQL correctamente instalados y configurados.

Puesta en marcha de XAMPP


Independientemente del sistema operativo, la instalacin de XAMPP es prcticamente idntica: tendr que descargar un archivo, extraer su contenido y ejecutar una orden para poner en marcha los servicios necesarios. Puesta en marcha en Windows La forma ms sencilla de disponer de la versin para Windows de XAMPP es utilizar el asistente para la instalacin disponible en la siguiente direccin: http://apachefriends.org/en/xampp-windows.html Cuando termine de descargar el instalador haga doble clic sobre l y siga los pasos del mismo. Como podr comprobar, se trata de un proceso muy simple. El ms complejo de ellos, que puede ver en la figura 1.3, consiste en seleccionar la ruta en la que se instalar XAMPP.

Figura 1.3. Instalacin de XAMPP en Windows

Advert encia: Por qu es el paso ms complejo? Porque, segn se comenta en la pgina dedicada a la versin para Windows de XAMPP, la mejor forma de evitar problemas con los permisos de la carpeta de archivos de programa si se instala en Windows Vista es utilizar una carpeta que se encuentre en la raz del disco como, por ejemplo, C:\xampp.

Las opciones predeterminadas de los pasos del asistente sern las ms adecuadas en la mayora de los casos. Cuando el proceso de instalacin concluya se le ofrecer la opcin de ejecutar el panel de control de XAMPP. Responda que s: podr ver un cuadro de dilogo similar al que muestra la figura 1.4.

Figura 1.4. Panel de control de XAMPP

En lo que a esta gua respecta slo nos interesarn los botones asociados a Apache y a MySQL. Haga clic en Start para poner en marcha un servicio. Cuando est en funcionamiento aparecer una etiqueta a su derecha con el texto Running y el nombre del botn cambiar por Stop. Utilcelo para detener el servicio correspondiente cuando lo desee. El panel de control de XAMPP se encuentra dentro del men Inicio, haciendo clic en Programas o Todos los programas y, a continuacin, en Apache Friends>XAMPP>XAMPP Control Panel. Puesta en marcha en Linux La instalacin y puesta en marcha de XAMPP en Linux no podra ser ms sencilla: 1. Descargue la versin para Linux de XAMPP, que se encuentra en la pgina: http://apachefriends.org/en/xampp-linux.html 2. Inicie una sesin como administrador del sistema o utilice la orden su para obtener sus privilegios. 3. Utilice la siguiente orden para extraer su contenido, sustituyendo X e Y por los nmeros correspondientes a la versin de XAMPP que haya descargado: tar xvfz xampp-linux-X.Y.tar.gz -C /opt 4. Como resultado, XAMPP se encontrar en dentro de la carpeta /opt . 5. Por ltimo, ejecute la orden /opt/lampp/lampp start para poner en marcha XAMPP y /opt/lampp/lampp stop para detenerlo.
Consejo: Pngase en contacto con el administrador de su sistema Linux si tiene dificultades para seguir las anteriores instrucciones o si el resultado obtenido no

es el deseado, algo que puede ocurrir si en su equipo ya estn instalados y en funcionamiento Apache o MySQL.

Puesta en marcha en Mac OS X De nuevo, al igual que en los dos apartados anteriores, dedicados a Windows y Linux, es necesario decir que la instalacin de XAMPP en Mac OS X es muy sencilla: 1. Descargue la versin para Mac OS X de XAMPP, que se encuentra en la pgina: http://apachefriends.org/en/xampp-macosx.html 2. Haga doble clic sobre el archivo DMG descargado. 3. Una vez la imagen de disco se monte haga doble clic sobre el archivo XAMPP for MacOS X.pkg y siga los pasos del instalador. 4. Cuando el proceso de instalacin concluya slo restar poner en marcha los servicios. Para ello abra un terminal y ejecute la orden sudo /Applications/XAMPP/xamppfiles/mampp start . Podr ver algo parecido a lo que muestra la figura 1.5.

Figura 1.5. Puesta en marcha de XAMPP en Mac OS X

6. De igual forma, para detener los servicios deber ejecutar, tambin desde un terminal, la orden sudo /Applications/XAMPP/xamppfiles/mampp stop. Con independencia del sistema operativo que utilice, XAMPP estar disponible a travs de la direccin http://localhost/. Vaya all con su cliente Web favorito; podr ver una pgina de presentacin con diferentes enlaces, uno por cada idioma disponible. La figura 1.6 muestra el resultado de hacer clic sobre Espaol y, despus, sobre Estado en la parte izquierda de la pgina.

Figura 1.6. Estado de los servicios de XAMPP

El aspecto de estas pginas es prcticamente idntico en Windows, Linux y Mac OS X. Ahora que ya tiene XAMPP instalado asegrese de que Apache y MySQL estn en funcionamiento antes de pasar al siguiente apartado, donde nos pondremos manos a la obra.

Trabajando con MySQL


Nuestro primer paso, siempre que comencemos el desarrollo de una aplicacin Web que trabaje con MySQL, debera ser disear la base de datos. Existen herramientas que pueden ayudarnos a realizar esta tarea. De entre todas ellas, le recomendamos MySQL Workbench, disponible para Windows, Linux y Mac OS X. Pero antes de utilizar herramienta alguna hemos de tener claro qu informacin debe contener la base de datos. Para ello, nada mejor que el dilogo con aquellos que lo sepan. Si vamos a desarrollar una aplicacin para una empresa, hemos de hablar todo lo que sea necesario con aquellos que tengan ms informacin al respecto, que de verdad sepan cmo debe funcionar. En nuestro caso lo tenemos ms fcil: sabemos lo que queremos, puesto que durante este aprendizaje seremos nuestro propio jefe. Vamos a guardar en una tabla dentro de una base de datos de MySQL informacin sobre gneros cinematogrficos. Posteriormente utilizaremos estos gneros conjuntamente con otras tablas, que contendrn informacin sobre pelculas.

Creacin de la base de datos

Aunque existen herramientas en lnea de rdenes para realizar operaciones con MySQL, dejaremos esa opcin para aquellos lectores que lo encuentren necesario. MySQL pone a nuestra disposicin una herramienta mucho ms amable: MySQL Administrator. Puede encontrarla en la siguiente pgina, formando parte del paquete MySQL GUI Tools: http://dev.mysql.com/downloads/gui-tools/
Not a: Si instal XAMPP tambin podr utilizar phpMyAdmin para realizar estas operaciones en el servidor de base de datos MySQL de su ordenador. phpMyAdmin estar a su disposicin a travs del URL http://localhost/phpmyadmin/.

La primera vez que se ejecuta MySQL Administrator se presenta un cuadro de dilogo para conectarse a un servidor, que puede ver en la figura 1.7.

Figura 1.7. Conexin con un servidor MySQL

Este cuadro de dilogo le pedir todos los datos necesarios para que se pueda establecer comunicacin con el servidor MySQL con el que quiere trabajar. Basta con que introduzca el nombre del servidor en el cuadro de texto Server Host (si se trata del mismo en el que se est ejecutando MySQL Administrator este nombre ser localhost ) y el nombre del usuario en Username. En este caso, como estamos utilizando XAMPP, este nombre ser root y no tendr contrasea asignada, algo que supondra un problema de seguridad en un servidor de produccin pero que permite trabajar mucho ms gilmente en un puesto personal. Por supuesto, si el servidor est en otro ordenador, introduzca su nombre o IP en el cuadro de texto Server Host , y utilice el nombre de usuario y la clave correspondientes para intentar conectarse. Haga clic en OK cuando haya terminado. La figura 1.8 muestra el aspecto de MySQL Administrator tras realizar la conexin con el servidor. En dicha figura puede observarse que, en el panel de la izquierda, abajo del todo, aparece un nodo llamado Catalogs. Haga clic con el botn izquierdo del ratn sobre ese nodo. Bajo l aparecer una lista con todos los catlogos (bases de

datos) disponibles. Haga clic con el botn derecho sobre este nuevo panel y seleccione la opcin Create New Schema del men desplegable que aparecer.

Figura 1.8. MySQL Administrator, en funcionamiento

MySQL Administrator le presentar un cuadro de dilogo en el que slo se le pedir que introduzca el nombre de la nueva base de datos. Escriba videoteca. Ese ser el nombre de la base de datos con la que trabajaremos durante el resto del libro. Cuando haga clic en OK el panel que contiene la lista de catlogos mostrar un aspecto similar al de la figura 1.9, donde la base de datos recin creada est seleccionada.

Figura 1.9. Nuestra nueva base de datos

sta, videoteca, ser la base de datos con la que trabajaremos a partir de ahora. No preste demasiada atencin al resto de bases de datos que aparecen en este panel, no las utilizaremos para nada. Si lo desea, puede crear sus bases de datos a partir de scripts SQL. Esta forma de trabajo tiene algunas ventajas sobre la que acaba de ver. Por ejemplo, permite repetir la operacin de creacin de la base de datos tantas veces como sea necesario, tenga acceso a MySQL Administrator o no. Para ello, una vez conectado con el servidor de bases de datos, seleccione la opcin MySQL Query Browser del men Tools, lo que ejecutar otra de las herramientas de MySQL, pensada para la ejecucin de consultas.

MySQL Query Browser permite dar rdenes al servidor MySQL utilizando el lenguaje SQL. Por ejemplo, para crear la base de datos videoteca podra utilizar las siguientes instrucciones:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca;

La primera de estas lneas borra la base de datos videoteca en caso de que exista. La segunda, la crea. De esta forma evitar que ocurran errores si intenta crear la base de datos cuando sta ya existe. Tenga presente, sin embargo, que si existe la borrar y perder todos los datos que contenga. Para ejecutar las instrucciones anteriores seleccione la opcin New Script Tab del men File. Aparecer una nueva ficha con el ttulo Script 1. Escriba las dos lneas anteriores en el rea central de MySQL Query Browser y haga clic en el botn Execute, que se encuentra en la barra de herramientas (es de color verde y tiene algo as como un rayo en el centro). La figura 1.10 muestra el aspecto de este programa tras ejecutar las dos instrucciones anteriores. El puntero de ratn est sobre el botn Execute. Ahora que tiene la base de datos necesita crear la tabla que contendr los detalles de cada gnero.

Figura 1.10. SQL para crear una base de datos

Creacin de la tabla
Qu detalles queremos guardar de cada gnero? Por una parte, vamos a guardar su descripcin. Esta descripcin define el gnero cinematogrfico de forma completa: ciencia ficcin, aventuras, drama, etc. Tambin puede ser de utilidad guardar una abreviatura de dicha descripcin. Por ltimo, vamos a guardar un identificador numrico que ser nico para cada gnero. Utilizaremos este identificador para relacionar cada pelcula con el

gnero cinematogrfico correspondiente. Ya sabe los detalles que debe guardar de cada gnero. Ahora decida el tipo de datos que tendr cada uno de ellos. El identificador ser un nmero. Vamos a limitar la longitud del nombre que le damos a ese gnero, su abreviatura, a dos caracteres, mientras que su descripcin podr tener hasta 32. La figura 1.11 muestra el aspecto que podra tener esta tabla una vez la cree utilizando MySQL Workbench.

Figura 1.11. La tabla de gneros

Not a: El diseo de bases de datos es una tarea fundamental e importante. Puede encontrar algunos consejos al respecto en el captulo 5.

La figura 1.11 muestra la tabla de gneros despus de disearla utilizando MySQL Workbench. Este programa nos permite crear tablas y relacionarlas de forma muy sencilla. En la figura 1.12 vemos el panel de MySQL Workbench con el que hemos creado la tabla de gneros.

Figura 1.12. Diseando la tabla de gneros

Pero lo mejor de todo es que puede obtener el cdigo SQL necesario para crear esta tabla de forma automtica, tras realizar el diseo. Slo ha de hacer clic con el botn derecho sobre la tabla que acabamos de crear en MySQL Workbench y seleccionar la opcin Copy SQL to Clipboard del men contextual que aparecer. Abra su editor de texto favorito (el bloc de notas, por ejemplo) y pegue el contenido del portapapeles utilizando la combinacin de teclas Control-V. Por ejemplo, el siguiente es el cdigo necesario para crear la tabla de gneros:
CREATE TABLE genero ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, nombre VARCHAR(2) NOT NULL, descripcion VARCHAR(32) NOT NULL, PRIMARY KEY (id) );

En el apartado anterior vimos cmo ejecutar cdigo SQL

utilizando MySQL Query Browser. Vamos a utilizar esa tcnica de nuevo para crear la tabla de gneros. En primer lugar seleccione la opcin New Script Tab del men File, dentro de MySQL Query Browser. Se abrir una ficha con un ttulo similar a Script 1 (el nmero final puede variar, dependiendo de si existen o no otras fichas del mismo tipo). Escriba la siguiente instruccin en el rea central de MySQL Query Browser y haga clic en el botn Execute:
USE videoteca;

A partir de ese momento, todas las operaciones que realice estarn referidas a dicha base de datos. As, cuando creemos la tabla de gneros lo haremos en la base de datos videoteca. Vamos a ello: escriba en la ventana de consultas la instruccin para creacin de tabla que vimos anteriormente y haga clic en el botn Execute. Si todo ha ido bien dispondr de una base de datos y de una tabla, ms que suficiente para comenzar a introducir datos. Existen otras formas de crear tablas, utilizando otras herramientas, pero no podemos dejar de mencionar una de ellas, que seguro ser de utilidad para aquellos que quieran permanecer lo ms alejados que sea posible de SQL.
Consejo: Desde aqu queremos recomendarle que aprenda SQL si an no tiene soltura con este lenguaje. Le aseguramos que todo el tiempo que emplee en dicho aprendizaje ser una inversin que comenzar a ser rentable en un periodo de tiempo muy breve. Garantizado.

Igual que utiliz la interfaz de usuario de MySQL Administrator para crear la base de datos, puede utilizarla para crear tablas. Slo tiene que hacer clic sobre la base de datos videoteca en el panel de catlogos, que aparece en la parte inferior izquierda cuando se selecciona el nodo Catalogs. En la parte derecha parecer un panel que, entre otros elementos, contiene un botn llamado Create Table. Haga clic sobre l. MySQL Administrator mostrar una nueva ventana desde la que podr crear tablas con slo rellenar los huecos. En la figura 1.13 puede ver cmo la hemos rellenado para crear la misma tabla de gneros que obtuvimos con MySQL Workbench.

Figura 1.13. Crear tablas con MySQL Administrator

Cuando haga clic en el botn Apply Changes, sobre el que est el puntero del ratn en la figura 1.13, se le preguntar que confirme la ejecucin de la instruccin SQL correspondiente. Para ello, haga clic en Execute. Tanto si cre la tabla con SQL como si se ayud de la interfaz de MySQL Administrator, el aspecto de este ltimo al seleccionar el nodo Catalogs y, posteriormente, videoteca, debe ser similar al que puede verse en la figura 1.14.

Figura 1.14. Nuestra nueva tabla

Ya puede realizar las primeras inserciones de datos.

Inserciones

El ltimo paso que tiene que dar antes de comenzar a trabajar con PHP es poblar la tabla de gneros con algunas entradas. Por ejemplo, puede aadir los valores necesarios para representar los gneros de ciencia ficcin, aventuras y drama. Si utiliza SQL puede escribir las siguientes instrucciones en una nueva ficha del tipo Script (recuerde: File>New Script Tab) dentro de MySQL Query Browser y hacer clic en el botn Execute:
USE videoteca;

INSERT INTO genero(nombre, descripcion) VALUES('CF', 'Ciencia Ficcin');

INSERT INTO genero(nombre, descripcion) VALUES('A', 'Aventuras');

INSERT INTO genero(nombre, descripcion) VALUES('D', 'Drama');

De nuevo, adems de SQL, tiene la opcin de utilizar las herramientas de MySQL Administrator. Seleccione el nodo Catalogs en el panel de la izquierda, haga clic sobre la base de datos videoteca y, por ltimo, haga clic con el botn derecho sobre la tabla de gneros y seleccione la opcin Edit Table Data del men desplegable que aparecer. Oh, sorpresa! Se ha abierto MySQL Query Browser pero, en lugar de una ficha del tipo Script hay una del tipo Resultset con una consulta ya introducida y ejecutada. Puede verlo en la figura 1.15. Haga clic sobre el botn Edit , que aparece en la parte inferior de la ventana de MySQL Query Browser (el puntero del ratn est sobre l en la figura 1.15).

Figura 1.15. Insercin de datos en MySQL Query Browser

Not a: Las fichas de tipo Script de MySQL Query Browser permiten ejecutar instrucciones SQL que no devuelven resultados como, por ejemplo, las de creacin de tablas o insercin de datos. Utilice las fichas de tipo Resultset para realizar consultas en los datos contenidos en las tablas de una determinada base de datos.

MySQL Query Browser entrar en el modo de insercin de datos, lo que le permitir escribir directamente los valores de las columnas que desee aadir con slo hacer doble clic sobre el hueco del campo correspondiente. Por ejemplo, en la figura 1.16 se est insertando el primero de los gneros.

Figura 1.16. Insertando registros

Not a: No es necesario que se introduzca el identificador del gnero (campo id). MySQL se encarga de asignar ese valor automticamente debido a que uno de los modificadores de su tipo es AUTO_INCREMENT . Para saber ms al respecto consulte el captulo 5, "Diseo de bases de datos".

Esta caracterstica de MySQL Query Browser no slo le permite insertar nuevos registros, tambin editar los existentes. Cuando termine de introducir los datos de los gneros haga clic en el botn Apply Changes, que se encuentra justo a la derecha del botn Edit (el que tuvo que pulsar para comenzar a aadir registros en la tabla de gneros). La figura 1.17 muestra el aspecto de la ventana de consultas despus de introducir los tres nuevos gneros.

Figura 1.17. Los tres gneros de partida

Cierre MySQL Query Browser. Puede hacerlo pulsando la combinacin de teclas Control-F4 o seleccionando la opcin Exit del men File. Hemos completado el primer paso de nuestro pequeo proyecto. Dispone de una base de datos, videoteca. Dentro de ella, en una tabla llamada genero, tiene tres registros, cada uno de ellos con un nombre, una descripcin y un nmero que los identifica de forma nica. El siguiente paso consiste en utilizar PHP para acceder al contenido de esta tabla y poder mostrar su contenido en una pgina Web. Realmente, no queda mucho por hacer, tan solo utilizar las herramientas que PHP nos ofrece para conectar con el servidor de bases de datos. As que abra su editor de textos favoritos: vamos a programar!

Trabajando con PHP


La anterior versin de PHP, la 5, incorporaba novedades realmente interesantes. La mayor parte de ellas estaban relacionadas con la programacin orientada a objetos, de la que hablaremos detenidamente en posteriores captulos. Una de las novedades que no estaba relacionada con la programacin orientada a objetos nos resulta ahora especialmente interesante: el acceso mejorado a MySQL.
Not a: Aunque quiz s hay relacin, ya que esta nueva interfaz mejorada de acceso a MySQL viene en dos sabores: funcional y orientado a objetos. Por ahora slo veremos la primera.

Esta nueva forma de acceder tiene nombre: MySQLi. La i latina final viene de improved (mejorado). Y tiene una limitacin: slo permite acceder a servidores MySQL modernos. Aunque gracias a esta restriccin el equipo de desarrolladores de PHP ha podido crear un conjunto de funciones cuyo rendimiento y forma de funcionamiento superan en muchos aspectos a las interfaces de acceso anteriores. Acceder a MySQL a travs de esta interfaz es tarea muy sencilla. En primer lugar, ha de establecer una conexin con el servidor. Para ello utilice la funcin mysqli_connect().
Not a: Todas las funciones de la interfaz de acceso a MySQL que vamos a ver comienzan con el prefijo mysqli_. De esta forma es sencillo reconocer a las funciones de este grupo.

La funcin mysqli_connect() recibe como parmetros la direccin en la que se encuentra el servidor (o su nombre), el nombre de usuario, la clave de acceso y el nombre de la

base de datos con la que queremos conectar. Si todo ha funcionado correctamente, el resultado de esta funcin nos permitir realizar operaciones en el servidor de base de datos. En caso de error, el resultado de llamar a esta funcin es FALSE . Dicho esto, puede utilizar el siguiente cdigo para realizar la conexin:
<?php

$conexion = mysqli_connect( 'localhost', 'root', '', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); } ...

En el cdigo anterior suponemos que el servidor est en el mismo ordenador en el que estamos trabajando (localhost ), que el nombre de usuario es root y que no tiene clave (un claro problema de seguridad pero, como ya hemos comentado anteriormente, se trata del funcionamiento predeterminado de XAMPP). Sustituya las credenciales de acceso por las correspondientes a su entorno de trabajo. El nombre de la base de datos tiene que ser videoteca en este caso. Tras llamar a mysqli_connect() comprobamos si el valor de $conexion es FALSE . Si es as es que la conexin no se ha realizado correctamente, de forma que informamos del error en la conexin y terminamos el programa llamando a exit(). Pero si todo ha ido bien podemos continuar para bingo. El siguiente paso es obtener todos los valores almacenados en la tabla genero. Para ello, haga doble clic sobre la base de datos videoteca, en el panel de la derecha, Schemata. As le indicar a MySQL Query Browser que quiere trabajar con esa base de datos. A continuacin ejecute esta consulta SQL:
SELECT * FROM genero;

En la figura 1.18 puede ver el resultado de ejecutar esta consulta utilizando MySQL Query Browser.

Figura 1.18. Recuperando todos los registros

Puede utilizar esa consulta desde PHP gracias a la funcin mysqli_query(). Esta funcin recibe como parmetros el valor devuelto por mysqli_connect() y una cadena de caracteres que contenga la consulta a ejecutar. El resultado de esta funcin, como en la funcin de conexin, es un objeto si se pudo ejecutar la consulta, o FALSE en caso contrario. Podra usarla as:
... $resultado = mysqli_query( $conexion, 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); } ...

Este fragmento de cdigo es muy similar al anterior. Primero llame a la funcin mysqli_query() con los parmetros necesarios, guardando el valor de respuesta en una variable ($resultado). A continuacin compruebe que $resultado no sea FALSE . Si lo es, es que ha ocurrido un error al realizar la consulta, as que informe de ello, cierre la conexin (con mysqli_close()) y salga del programa con exit().
Advert encia: Es conveniente dejarlo todo como estaba antes de comenzar el programa. Si abre una conexin con un servidor MySQL, debe cerrarla antes de terminar el programa; si obtiene un conjunto de registros, debe liberar la memoria que hayan ocupado.

Si no ha ocurrido ningn error, ya dispone de los datos que quiere mostrar: todos los gneros que tiene almacenados en la tabla genero de la base de datos videoteca. Slo tiene que mostrarlos. La funcin mysqli_fetch_row() le permite recuperar los registros obtenidos uno por uno, dentro de una matriz, de forma que puede utilizarla en un bucle while:
... while($fila = mysqli_fetch_row($resultado)){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] ); } ...

Es decir, llame a la funcin mysqli_fetch_row() y guarde el resultado en $fila. Si la funcin devolvi algn registro, $fila ser diferente de FALSE , as que ejecute la funcin printf(), que muestra en la pgina los valores de ese registro. La siguiente llamada mysqli_fetch_row() devuelve el siguiente registro, y as hasta que no quede ningn registro por mostrar. Cuando ocurre eso, $fila valdr FALSE y saldr del bucle. Para terminar, como dijimos, deje todo como estaba, liberando el espacio ocupado por el resultado de la consulta y cerrando la conexin con la base de datos:
... mysqli_free_result($resultado); mysqli_close($conexion);

?>

A continuacin, el cdigo de este ejemplo, completo:


<?php

$conexion = mysqli_connect( 'localhost', 'root', '', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); }

$resultado = mysqli_query( $conexion, 'SELECT * FROM genero' );

);

if ($resultado == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); }

while($fila = mysqli_fetch_row($resultado)){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] ); }

mysqli_free_result($resultado); mysqli_close($conexion);

?>

Guarde esta pgina en la carpeta htdocs, que se encuentra dentro de aquella en la que haya instalado XAMPP, con el nombre generos.php. Entonces, visite la pgina http://localhost/generos.php. El resultado puede verse en la figura 1.19.

Figura 1.19. Los gneros, en PHP

Y ahora un detalle curioso: nuestra primera pgina PHP no ha tenido ms que una etiqueta HTML, la que indica nueva lnea: <br/>. Pero eso podemos solucionarlo, vuelva a escribir el bucle while, pero ahora use tablas. Sustituya el cdigo del bucle por el siguiente:
... ?>

<table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcion</th> </tr>

<?php

while($fila = mysqli_fetch_row($resultado)){ printf('<tr>');

printf('<tr>'); printf( "<td>%u</td><td>%s</td><td>%s</td>", $fila[0], $fila[1], $fila[2] ); printf('</tr>'); }

?>

</table> <?php ...

El cdigo completo de esta nueva pgina, que debe guardar con el nombre generos2.php en la misma ubicacin que generos.php, es el siguiente:
<?php

$conexion = mysqli_connect( 'localhost', 'root', '', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); }

$resultado = mysqli_query( $conexion, 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); }

?>

<table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcion</th> </tr>

<?php

while($fila = mysqli_fetch_row($resultado)){ printf('<tr>');

printf('<tr>'); printf( "<td>%u</td><td>%s</td><td>%s</td>", $fila[0], $fila[1], $fila[2] ); printf('</tr>'); }

?>

</table>

<?php

mysqli_free_result($resultado); mysqli_close($conexion);

?>

El resultado de cargar esta nueva pgina puede verse en la figura 1.20. El contenido es el mismo, pero la apariencia cambia. Gracias a este ejemplo hemos podido comprobar de primera mano lo complejo que puede llegar a ser incluir cdigo HTML dentro del cdigo PHP. En el captulo dedicado a las plantillas, veremos algunas de las opciones que tenemos para separar la lgica de la representacin, facilitando la tarea tanto a programadores como a diseadores.

Figura 1.20. Nuestro ejemplo, con tablas

Y ahora, por fin, lo ms espectacular: contemplar cmo cambia la pgina PHP cuando aadimos algn nuevo registro a la tabla genero, sin necesidad de cambiar el cdigo. La siguiente instruccin SQL inserta un nuevo registro:
INSERT INTO genero(nombre, descripcion) VALUES('T', 'Terror');

Utilice MySQL Query Browser para ejecutar el cdigo anterior. El resultado es que nuestra tabla tendr un nuevo registro, como puede ver en la figura 1.21.

Figura 1.21. Un nuevo gnero

Este cambio en la tabla se reflejar en la pgina si vuelve a cargarla. El resultado debera ser algo parecido a lo que puede ver en la figura 1.22.

Figura 1.22. Un nuevo gnero, en PHP

Impresionante, verdad? Y esto no ha hecho ms que empezar.

PHP
Aunque se utiliza para crear pginas Web dinmicas, PHP est ms cerca de lenguajes como C++ o Java que del propio HTML. Se trata de una excelente combinacin de las mejores caractersticas de los lenguajes de programacin ms utilizados, con un nico objetivo: que la programacin de pginas dinmicas sea pan comido. Durante este captulo nos concentraremos en las caractersticas de PHP como lenguaje de programacin, as que no tenga el ms mnimo reparo en pasar al siguiente captulo si cree que tiene los conocimientos necesarios. Por el contrario, si decide quedarse con nosotros, no tenga miedo, ser entretenido. Repasaremos los conceptos bsicos de programacin tal y como los entiende PHP, intentando evitar en lo posible la jerga de los programadores, aunque en ocasiones no nos quedar ms remedio. Veremos cmo guardar valores en variables y de qu tipo pueden ser. Despus manipularemos esos valores, realizando operaciones sobre ellos (sumas, restas, etctera). Usaremos el resultado de esas manipulaciones para tomar decisiones, como qu acciones debemos realizar. Estas decisiones las realizaremos utilizando instrucciones condicionales. Tambin utilizaremos instrucciones iterativas, que permitirn realizar la misma accin varias veces. Entre estas acciones puede estar el mostrar o no informacin en una pgina Web. Al terminar este captulo tendr las nociones bsicas necesarias para comprender cualquier programa escrito en PHP y, lo que es ms importante, avanzar un poco ms hacia el objetivo final: combinar la potencia de MySQL con la flexibilidad de PHP.

Introduccin
Qu es PHP? A estas alturas ya sabr que es un lenguaje de programacin y que est muy vinculado con las pginas Web que, a su vez, se escriben en el lenguaje HTML. HTML son unas siglas que significan "lenguaje de marcas de hipertexto" (Hypertext Markup Language). Este lenguaje sirve para describir las propiedades y la ubicacin de una serie de elementos dentro de una pgina Web, como texto, imgenes, etctera.
Truco: Asustado por la cantidad de siglas que se nos vienen encima? No tema, todas ellas encuentran su traduccin en http://www.acronymfinder.com/.

Por ejemplo, el siguiente es un fragmento de cdigo en lenguaje HTML.


<html> <head> <title>Prueba</title> </head> <body> <h1>Esto es una pgina HTML.</h1> </body> </html>

Este cdigo describe una pgina muy sencilla. Si la guarda con el nombre prueba.html y la pone en la carpeta de archivos del servidor Web, podr ver lo que aparece en la figura 2.1.

Figura 2.1. Una pgina HTML muy sencilla

Not a: Si ley el captulo anterior y decidi seguir nuestra recomendacin de utilizar XAMPP, la carpeta de archivos del servidor Web es ht docs y se encuentra dentro de aquella en la que decidiese instalar XAMPP.

En este ejemplo puede comprobar que el lenguaje HTML utiliza etiquetas. Estas etiquetas se distinguen del resto porque estn entre los smbolos menor que (<) y mayor que (>). Tambin puede ver cmo estas etiquetas definen la posicin de los elementos: si un determinado texto est entre las etiquetas head y title aparecer en la barra de ttulo del cliente Web que est utilizando, mientras que la etiqueta h1 permite indicar que el texto ser un encabezado de nivel 1.
Consejo: Se supone que si est leyendo esta gua es porque ya tiene unas nociones bsicas de HTML. Si no es el caso, no se preocupe, puede seguir leyendo sin miedo a perderse.

Como ya sabr, una de las caractersticas ms interesantes de las pginas HTML es la posibilidad de hacer referencia a otras pginas mediante hiperenlaces (hyperlinks), a los que abreviadamente se les llama enlaces. Mediante estos enlaces podemos vincular unas pginas con otras que pueden estar en nuestro sitio Web o en otro diferente. Independientemente de la calidad del contenido de una pgina, de su inters, son estas relaciones entre diferentes pginas las que hacen de la Web una herramienta verdaderamente nica. Muy por encima, hemos visto qu son las pginas HTML:

archivos de texto con unas etiquetas especiales que determinan la posicin y el formato de sus elementos. Cmo encaja PHP en todo esto? PHP son tambin unas siglas, que vienen de PHP: Hypertext Preprocessor (preprocesador de hipertexto). Son unas siglas recursivas: estn dentro de la definicin, un chiste de informticos que difcilmente hace gracia al resto del mundo. La figura 2.2 muestra el reconocible logotipo de PHP.

Figura 2.2. El logotipo de PHP

Como su propio nombre indica, PHP es un preprocesador de hipertexto. Es decir, con PHP puede crear programas cuyo resultado sea cdigo HTML. Ese resultado puede variar en funcin de la lgica del programa. Como consecuencia, el resultado de una misma pgina PHP puede ser distinto dependiendo de algunos factores. Un ejemplo puede ayudarnos a entender mejor para qu sirve PHP. Y nada ms sencillo que crear una pgina que muestre la hora. El siguiente cdigo realiza esta tarea:
La hora es: <?= date('H:i:s') ?>.

El resultado se puede ver en la figura 2.3.

Figura 2.3. La hora, con PHP

Si recarga la pgina, pulsando F5, comprobar que la hora ha cambiado. El contenido de la pgina depende de la hora a la que sta se cargue. Por eso a las pginas PHP se las conoce como pginas dinmicas, frente a las pginas HTML, que son estticas.
Not a: Aunque vamos a concentrarnos en las capacidades de PHP para producir pginas Web, tenga presente que no es lo nico que puede hacer. Por poner un ejemplo, PHP tambin puede usarse para crear aplicaciones de escritorio. Puede visitar http://gtk.php.net/ si desea ms informacin al respecto.

Vamos a intentar aclarar an ms las diferencias que hay entre HTML y PHP. Como ya sabr, cuando utiliza un cliente Web (como Internet Explorer o Firefox) para ver una pgina hay tres elementos en juego: usted, el medio (Internet) y el servidor Web. Seguramente lo primero que hace es escribir la

direccin de la pgina que quiere ver (su URL) y, a continuacin, pulsar la tecla Intro. En ese momento, a travs de Internet, se enva la peticin al servidor. ste localiza esa pgina y la devuelve tal y como la encuentra. La figura 2.4 ilustra el proceso.

Figura 2.4. Una pgina esttica

El proceso es ligeramente diferente si se trata de una pgina PHP. Todo es igual hasta que el servidor localiza la pgina que le pedimos. El servidor se da cuenta de que su extensin no es la de una pgina HTML. Sabe que tiene que procesarla antes de devolverla, as que invoca al preprocesador de PHP y le pasa el control. Este preprocesador busca algunos caracteres especiales. All donde los encuentre, realizar las operaciones que el creador de la pgina haya indicado. Cuando termine de procesar la pgina, devolver el resultado, que ser lo que el servidor Web enve como respuesta a quien le haya pedido la pgina PHP. Algo parecido a lo que podemos ver en la figura 2.5.

Figura 2.5. Una pgina dinmica

Slo hay una diferencia entre las figuras 2.4 y 2.5, pero como sabe se trata de una muy importante. Ahora que hemos abierto boca, seguro que tiene ganas de ms. En un momento iremos a ello, pero antes vamos a buscar algunas herramientas que puedan ayudarle en la tarea.

Editores

Para programar en PHP slo hace falta un editor de texto, como el bloc de notas de Windows, vi en Linux o TextEdit en Mac OS X. S, tambin hace falta un servidor de pginas Web, pero se supone que ya contamos con l. Aunque estos son ejemplos de editores de texto decentes, son precisamente eso y slo eso, editores de texto. Y nada ms. Existen otras herramientas desarrolladas exclusivamente para editar PHP que pueden ser de mucha ms ayuda en las tareas de programacin. Un editor de estas caractersticas no es slo un editor: es un entorno de desarrollo o IDE (Integrated Development Environment, entorno integrado de desarrollo). Como es costumbre en el mundo del software libre, las alternativas son muchas. Posiblemente el ms completo de todos sea Zend Studio. Si puede permitirse pagar los casi 400 euros que cuesta, no lo dude: evalelo y adquiera una copia si lo encuentra satisfactorio. Pero, como decimos, existen muchas otras alternativas. Nuestra recomendacin es que utilice Eclipse PDT (en concreto, la versin 2), un producto multiplataforma libre que puede encontrar en la direccin: http://eclipse.org/pdt/
Not a: Repetimos, existen muchas otras alternativas tanto a Zend Studio como a Eclipse PDT. Entre, por slo mencionar algunas, estn NetBeans, Aptana PHP, Codelobster o Nusphere PhpED. Pero no se limite a estas, una bsqueda en Google bastar para que encuentre ms editores de PHP. Ms que la potencia del editor, la clave es que encuentre uno con el que se sienta cmodo.

Casi todos los IDE tienen muchas caractersticas en comn. Si el IDE que va a utilizar no es ninguno de los que le hemos recomendado, asegrese de que, como mnimo, le proporciona las siguientes herramientas: Resalte de sintaxis: Las palabras clave del lenguaje, las cadenas de texto, los comentarios, cada diferente elemento del cdigo fuente de un archivo PHP, tendr un color diferente, algo de gran ayuda para encontrar determinadas secciones de cdigo, localizar errores, etctera. Aunque ms avanzado el captulo veremos ejemplos en los que el resalte de sintaxis ser ms obvio, queremos ensearle en la figura 2.6 el aspecto que tiene el fragmento de cdigo que dio como resultado la pgina que pudimos ver en la figura 2.3. Fjese en que el color de las etiquetas <? y ?> y de lo que aparecen entre comillas simples es diferente del resto.

Figura 2.6. Resalte de sintaxis

Asistente de cdigo para nombres de funcin: El nmero de funciones que PHP pone a su disposicin es, a falta de mejores palabras, realmente asombroso. Y una memoria asombrosa hace falta para recordar el nombre de todas ellas. A medida que escriba, un asistente de cdigo permitir ver en una lista desplegable cuntas funciones comienzan con los caracteres que ha escrito, como puede verse en la figura 2.7, donde an sin haber terminado de escribir el nombre de la funcin date(), el IDE ya le muestra su nombre completo. Esta caracterstica no hace necesario saber el nombre exacto de una funcin, basta con saber al menos cmo empieza para obtener una lista de la que seleccionar la que desee. El nmero de errores que cometa al escribir su cdigo ser menor si utiliza esta caracterstica cuando no est seguro de un nombre.

Figura 2.7. Lista de funciones

Asistente de cdigo para argumentos de funcin: De forma similar al asistente para nombres de funcin, el de argumentos muestra la lista de argumentos que admite una funcin, nada ms escribir el parntesis a continuacin de su nombre. Bueno, la verdad es que an no hemos visto qu es una funcin, pero no se preocupe que sus preguntas tendrn respuesta. Por ahora baste con decir que las funciones permiten obtener valores o realizar tareas concretas. En el ejemplo con el que mostramos la hora en una pgina Web utilizamos la funcin date(). La figura 2.8 muestra un asistente de cdigo para argumentos en plena accin con dicha funcin. Podr ver tanto los argumentos como el valor que devuelve la funcin.

Figura 2.8. Argumentos de una funcin

Ayuda integrada: Los dos asistentes para funciones son muy tiles. A medida que programe con PHP le resultarn hasta imprescindibles. Pero no hay nada

que pueda sustituir a un buen sistema de ayuda integrada en el entorno de desarrollo. Este sistema le permite obtener ayuda sobre PHP (sintaxis, funciones, etc.) sin tener que vagar por la documentacin en lnea de PHP. Por ejemplo, en Eclipse PDT bastara con situar el putero del ratn la funcin date() para obtener toda la ayuda disponible en la documentacin sobre dicha funcin, precisamente como muestra la figura 2.9.

Figura 2.9. Ayuda integrada

Not a: Por supuesto, cualquier otra ayuda a la programacin ser bienvenida. Pruebe todo aquello que pueda hacer ms productivo su trabajo, juegue con todas las caractersticas que el IDE con el que trabaje le proporcione, personalice el entorno de trabajo hasta que lo sienta como suyo propio.

Ahora que ya dispone de un editor de cdigo medianamente decente para trabajar con PHP comienza la diversin!

Estructura de un archivo PHP


Un archivo PHP no es ms que un archivo de texto. No es necesario compilarlo, puede leerse con cualquier editor de texto. Lo primero que tiene que saber sobre un archivo PHP es que podra contener slo HTML y seguira siendo un archivo PHP vlido. Como vio en el anterior apartado, cuando alguien pida una pgina de estas caractersticas, el servidor Web se la pasar al preprocesador de PHP. ste buscar fragmentos de cdigo PHP. Al no encontrar ninguno, el resultado ser la pgina PHP tal y como la recibi el preprocesador. Por lo general, ste no ser el caso. Lo normal es que en una misma pgina coexistan HTML y PHP. Pero, cmo se diferencia el cdigo PHP del cdigo HTML?

Escapar de HTML
Parece el ttulo de una pelcula, pero no lo es. Se dice que estamos "escapando de HTML" cuando escribimos una serie de caracteres que le indican a PHP que lo que aparece a continuacin ser cdigo PHP. Como ya sabe, el preprocesador deja pasar tal cual el texto en formato HTML, pero ejecuta las instrucciones

texto en formato HTML, pero ejecuta las instrucciones PHP. Cuando escapa de HTML entra en PHP. Ya hemos visto un ejemplo de cmo escapar de HTML en el primer fragmento de cdigo PHP de este captulo:
La hora es: <?= date('H:i:s') ?>.

En la anterior instruccin, PHP deja pasar tal cual todo el texto hasta llegar a los caracteres <?. Sabe que todo lo que encuentre desde ese momento hasta que aparezca la pareja de caracteres ?> ser PHP. Y esta operacin se repite hasta llegar al final del archivo. Existen varias formas de escapar de HTML, pero nosotros slo vamos a comentar dos: 1. <?php ... ?> 2. <? ... ?> De estas dos, la ms recomendable es la primera, por varias razones: Con independencia de la configuracin de PHP, siempre debera ser posible escapar de PHP de esa forma, algo que no es cierto para la segunda, que puede estar desactivada. Una pgina PHP que utilice la primera forma es, adems, una pgina que cumple el estndar XHTML, algo que puede ser til en determinadas situaciones. Por ello, en adelante, utilizaremos la primera va de escape de HTML: <?php ... ?>. De forma que una pgina PHP puede ser como una pgina HTML normal y corriente, con una salvedad: en aquellas partes en las que quiera introducir algn valor que se genere de forma dinmica, escapar de HTML para entrar en PHP.
Not a: Con el paso de las pginas, descubrir que mientras mayor sea el proyecto para el que est empleando PHP, ms complicado ser trabajar mezclando HTML y PHP, sobre todo si el grupo de trabajo lo conforman varios programadores y diseadores. El captulo dedicado a las plantillas propone algunas soluciones interesantes que le recomendamos.

Funciones de salida
Aunque hablaremos de las funciones en general con posterioridad, vamos a ver ahora las que se utilizan para mostrar informacin en la pgina HTML resultante de procesar una pgina PHP, ya que nos sern de mucha utilidad. Ya hemos utilizado una de ellas: <?= es una forma ms corta de escribir <? echo. Por lo tanto, estas dos lneas de cdigo son equivalentes:
La hora es: <?= date('H:i:s') ?>. La hora es: <? echo date('H:i:s') ?>.

De igual forma puede utilizar la funcin print() para que el parmetro que le pase se muestre en la pgina HTML resultante:
La hora es: <? print(date('H:i:s')) ?>.

Aunque existen otras funciones para mostrar informacin, dejaremos para otro momento hablar de ellas.

Comentarios
PHP nos permite escribir texto que el preprocesador ignorar, lo que se conoce como comentarios. Los comentarios son tiles para explicar qu intentamos hacer a lo largo de un determinado programa. Algo que hoy nos parece obvio puede ser difcil de entender cuando volvamos a ver el cdigo pasados unos meses. Existen dos tipos de comentarios: de lnea y de prrafo. Si comenzamos una lnea con la pareja de caracteres //, esa lnea ser tomada por PHP como un comentario. No nos cuesta ningn esfuerzo modificar el programa que muestra la hora para aadir comentarios de esta forma:
<?php // El siguiente programa muestra la hora // actual. // // La funcin date() recibe como parmetro el // formato en el que se mostrar. La hora se // representa como H y los segundos como s, // pero atencin que para los minutos se // utiliza i y no m. // // Las horas, los minutos y los segundos se // separarn con dos puntos. ?> La hora es: <?= date('H:i:s') ?>.

La pgina HTML resultante del cdigo anterior es exactamente la misma que se puede ver en la figura 2.3, a pesar de la existencia de comentarios al comienzo. Los comentarios de prrafo comienzan con la pareja de caracteres /* y terminan con */. Todo lo que PHP encuentre en medio lo considerar un comentario, as que podemos volver a escribir el cdigo anterior as:
<?php /* El siguiente programa muestra la hora actual.

La funcin date() recibe como parmetro el formato en el que se mostrar. La hora se representa como H y los segundos como s, pero atencin que para los minutos se utiliza i y no m.

Las horas, los minutos y los segundos se separarn con dos puntos. */ ?> La hora es: <?= date('H:i:s') ?>.

El resultado seguir siendo el mismo. El resalte de sintaxis tambin tiene en cuenta los comentarios, mostrndolos de un color diferente al del resto del cdigo. El ltimo fragmento de cdigo se puede ver resaltado en la figura 2.10.

Figura 2.10. Comentarios resaltados

Truco: Lo ms probable es que su IDE permita cambiar los colores de resalte de cada tipo de elemento del cdigo PHP. Le recomendamos que seleccione un color lo ms apagado posible para los comentarios, pero que sea legible. De esta forma, podr ignorarlos sin dificultad cuando no le sean necesarios, pero podr leerlos si lo desea.

Otra costumbre saludable es comenzar sus programas con un encabezado comn. Este encabezado podra contener el nombre del autor del cdigo, la fecha en la que comenz a escribirlo y una breve descripcin del objetivo de dicha pgina. Cuando usted, o cualquier otra persona vuelva a trabajar con esa pgina sabr slo con echar un vistazo al encabezado contra el trabajo de quin va a luchar, la antigedad del mismo y podr partir con ventaja al conocer de mano del autor algo sobre el funcionamiento de la pgina. Podemos modificar la pgina PHP de prueba para que incluya ese encabezado. El resultado podra ser el siguiente:
<?php /* Autor: Juan Diego Gutirrez Gallardo Fecha: mircoles 24 de junio de 2009 Descripcin: El siguiente programa muestra la hora actual.

Se trata de un ejemplo de pgina

Se trata de un ejemplo de pgina dinmica muy sencillo. La funcin date() recibe como parmetro el formato en el que se mostrar. La hora se representa como H y los segundos como s, pero atencin que para los minutos se utiliza i y no m.

Las horas, los minutos y los segundos se separarn con dos puntos. */ ?> La hora es: <?= date('H:i:s') ?>.

Not a: Quiz le interese echar un vistazo a PHPDoc, un estndar para la documentacin de PHP con el que Eclipse PDT es compatible. Su pgina Web se encuentra en la direccin http://phpdoc.org/. Por cierto, sta ha sido la ltima vez que utilizamos la forma abreviada de escapar de HTML.

Hemos comentado que a partir de una sola pgina PHP puede obtener diferentes pginas HTML, dependiendo de las circunstancias. En el ejemplo anterior, como el tiempo va pasando, los segundos avanzando, cada vez que cargue la pgina el resultado ser diferente. Nuestras posibilidades estaran muy limitadas si eso fuese todo lo que podemos hacer en PHP. A continuacin veremos qu son las variables y de qu tipo las hay. Gracias a ellas nos acercaremos an ms a descubrir el verdadero potencial que hay tras PHP.

Variables
Los datos no son etreos, es necesario almacenarlos en algn lugar. Una variable es el lugar en el que vamos a guardar los valores que necesitaremos ms adelante, ya sea para consultarlos o para modificarlos. En la jerga de los programadores, reservar el espacio necesario para guardar dichos valores se conoce como "declarar una variable". Este espacio se encuentra en la memoria principal del ordenador, es decir, en la RAM. Una variable tiene un nombre, un tipo y un valor. Para diferenciar las variables de otros elementos dentro de PHP, el nombre de stas comienza siempre con el smbolo del dlar ($ ). El primer carcter a partir del $ debe ser una letra o un carcter de subrayado (_). Despus puede incluir nmeros.
Advert encia: Y mucho cuidado: PHP diferencia entre maysculas y minsculas.

Para declarar una variable en PHP slo tiene que escribir el nombre de la variable y asignarle un valor. Por ejemplo:
<?php

<?php $hora = date('H:i:s'); ?>

Advert encia: Es posible que se haya fijado en que aparece un punto y coma al final de la lnea en la que se asigna un valor a la variable $hora . En PHP, una lnea de cdigo se diferencia de la siguiente utilizando precisamente dicho carcter. Se trata de algo muy importante, recuerde utilizar dicho separador.

El cdigo anterior almacena en la variable $hora la hora tal y como la mostrbamos en los ejemplos anteriores. Las siguientes lneas son ejemplos de declaraciones correctas:
$hora = date('H:i:s'); $Hora = date('H:i:s'); $_hora = date('H:i:s'); $_1hora = date('H:i:s');

Sin embargo, esta declaracin es incorrecta, ya que su nombre comienza con un nmero:
$1hora = date('H:i:s');

En una variable, su tipo determina la naturaleza de los datos que almacena. Qu tipos de datos nos ofrece PHP?

Tipos de datos
PHP dispone de varios tipos de datos. De todos ellos vamos a ver los que ms tiles le pueden ser durante el comienzo de su aprendizaje: tipos booleanos, enteros, decimales, cadenas y matrices.
Not a: A diferencia de otros lenguajes de programacin, en PHP el tipo de una variable no se declara de forma explcita, sino que lo determina el valor que se le asigna para crear la variable.

Booleanos Una variable de tipo booleano puede tener dos posibles valores: verdadero o falso. PHP se reserva dos palabras para indicar esos valores: TRUE (verdadero) y FALSE (falso). Puede utilizar cualquier combinacin de maysculas y minsculas para escribir estos valores: PHP siempre los reconocer. Para declarar una variable de este tipo slo tiene que escribir su nombre y asignarle el valor correspondiente. En el siguiente fragmento de cdigo declaramos dos variables de tipo booleano:
$millonario = false; $hipotecado = true;

Internamente, un valor booleano FALSE equivale al cero, mientras que cualquier otro valor numrico sera equivalente al valor booleano TRUE . Enteros En una variable de tipo entero puede almacenar valores

enteros positivos y negativos, incluido el cero. Por ejemplo:


$i = 20; $j = -40; $k = 0;

Existen lmites en cuanto a los valores que puede almacenar en una variable de tipo entero. Dicho lmite depende del sistema operativo en el que PHP est instalado. Si intenta asignar a una variable de tipo entero un valor superior al lmite, PHP transformar de forma automtica esa variable al siguiente tipo de datos que vamos a ver, el decimal. Decimales Una variable de tipo decimal puede contener cualquier nmero en coma flotante. De esta forma, la siguiente instruccin nos sirve para declarar una variable de tipo decimal:
$pi = 3.14;

Not a: Paradjicamente, lo que llamamos nmero en coma flotante utiliza como separador de decimales un punto. Se trata de un convenio que vara entre pases.

Cadenas Y llegamos a las cadenas, posiblemente el tipo de datos que ms vamos a utilizar en PHP. Esto se debe a que la mayora de la informacin que se va a mostrar en una pgina HTML es de este tipo. Una cadena de texto no ms que una secuencia de caracteres. PHP permite definir cadenas de tres formas diferentes: 1. Con comillas simples. 2. Con dobles comillas. 3. En bloque. Las cadenas ms sencillas son las que se especifican entre comillas simples:
$cadena = 'Esta es una simple cadena.';

Si quiere incluir una comilla simple dentro de una cadena de este tipo, debe incluir una barra invertida antes del carcter, as:
$cadena = 'Esto es una comilla simple: \'.';

Las cadenas entre comillas dobles tienen una caracterstica aadida que las hace muy interesantes: si contienen el nombre de una variable existente, PHP sustituir la variable por su valor. Por ejemplo:
$i = 12; $cadena = "Un ao tienen $i meses.";

Tras ejecutar estas dos lneas, el contenido de la

variable $cadena ser "Un ao tiene 12 meses.". Otra diferencia entre las cadenas con comillas simples y las cadenas con comillas dobles son los caracteres de escape, una serie de caracteres especiales que comienzan con la barra invertida. Igual que para incluir una comilla simple utilizbamos \' en el primer tipo de cadenas, utilizaremos \" en el segundo. Pero tambin puede incluir retornos de lnea con \n, tabuladores con \t , el smbolo del dlar con \$ , y algunos otros. Le recomendamos que consulte la documentacin de PHP si desea ms informacin al respecto de estos caracteres de escape.
Truco: No se deje llevar por la tentacin de rodear siempre sus cadenas entre comillas dobles porque sean ms flexibles. Esas ventajas tienen un inconveniente: PHP tardar ms en procesarlas. Utilice comillas simples siempre que no sea necesario utilizar sustitucin de variables.

Pero atencin! Si incluye un retorno de lnea en una cadena de texto y luego muestra esa cadena en la pgina Web, no ver retorno alguno. Esto se debe a que HTML ignora los retornos de lnea. Para separar su texto en diferentes lneas ha de utilizar la etiqueta <br/>. Lo veremos en algunos de los ejemplos posteriores. El tercer tipo de cadenas, en bloque, es muy similar al segundo tipo. La diferencia principal est en la forma de utilizarlas. Se trata de la sintaxis ms adecuada para cadenas de gran longitud. Y nada mejor que utilizar un ejemplo para explicar cmo utilizar este tipo de cadenas:
$i = 12; $cadena = <<<CADENA Esto es una cadena definida en bloque. Podemos utilizar variables como en las cadenas de dobles comillas. Esto es un ejemplo: $i. CADENA;

Podramos haber definido esa cadena utilizando dobles comillas, as:


$i = 12; $cadena = "Esto es una cadena\n definida en bloque.\n Podemos utilizar variables como\n en las cadenas de dobles comillas.\n Esto es un ejemplo: $i.\n";

Es mucho ms sencillo manejar este tipo de cadenas en bloque que con las dobles comillas, principalmente porque no es necesario utilizar caracteres especiales para indicar los retornos de lnea. Si conoce algn otro lenguaje de programacin, habr observado el trabajo con cadenas con PHP es mucho ms

flexible, con ms posibilidades. Esto es an ms cierto para las matrices. Matrices Imagine que quiere guardar en variables el nmero de pelculas que ha visto cada mes del ao. Con lo aprendido hasta ahora podra hacerlo as:
$peliculas_enero = 9; $peliculas_febrero = 12; $peliculas_marzo = 21;

En otra parte del cdigo podra utilizar estas instrucciones para mostrar dichos valores:
echo <<<PELICULAS Pelculas vistas:<br/> - en enero: $peliculas_enero.<br/> - en febrero: $peliculas_febrero. <br/> - en marzo: $peliculas_marzo. <br/> PELICULAS;

Las matrices le permiten tener esa informacin mucho ms organizada, pudiendo acceder a travs de una sola variable y utilizando un ndice como modificador. La siguiente es una de las posibles formas de declarar una matriz que contenga los tres valores anteriores:
$peliculas = array(9, 12, 21);

Hemos creado una matriz con tres elementos: el primero es 9, el segundo 12 y el tercero 21. Al utilizar la palabra reservada array para asignar valores a la variable $peliculas, PHP comprende que queremos crear una matriz. Examinar entonces cuntos elementos aparecen entre los parntesis, reservando el espacio necesario para poder guardarlos. Para acceder a estos elementos slo necesita indicar el ndice de cada elemento tras el nombre de la variable, entre corchetes. Podra mostrar las pelculas vistas en cada mes con el siguiente cdigo:
echo <<<PELICULAS Pelculas vistas:<br/> - en enero: $peliculas[0].<br/> - en febrero: $peliculas[1]. <br/> - en marzo: $peliculas[2]. <br/> PELICULAS;

Not a: El primer elemento disponible en una matriz es el cero (0). Es muy importante tenerlo en cuenta para no cometer errores al trabajar con matrices.

Puede aadir nuevos elementos a una matriz despus de haberla creado. Por ejemplo, para aadir el nmero de pelculas vistas en abril:
$peliculas[] = 17;

PHP se encargar automticamente de crear el cuarto elemento de la matriz. Para ver el contenido de la matriz tras aadir este nuevo elemento, puede utilizar una funcin muy til: print_r(), que recibe como argumento una matriz. El cdigo resultante podra ser el siguiente:
<?php $peliculas = array(9, 12, 21); $peliculas[] = 17; print_r($peliculas); ?>

El resultado lo puede ver en la figura 2.11.

Figura 2.11. Matriz, nuevo elemento y contenido

La funcin print_r() nos presenta los datos que contiene la matriz de una forma muy curiosa. En primer lugar nos dice que se trata de una matriz con la palabra Array. A continuacin y entre parntesis podemos ver los elementos que componen la matriz. Entre corchetes aparece el ndice del elemento y a continuacin, tras los caracteres =>, el valor del elemento. As podemos ver que en la posicin cero est el 9, en la una el 12, en la dos el 21 y en la tres el 17. En realidad, tras las matrices en PHP hay mucho ms que lo que parece a primera vista. Ms que matrices, podramos considerar que PHP nos proporciona diccionarios, con los que podemos traducir de un valor a otro. En nuestro ejemplo de pelculas podramos decir que queremos traducir el 0 por un 9, el 1 por un 12 y as sucesivamente, aunque en realidad lo que queremos es traducir enero por un 9, febrero por un 12, etc. No sera fantstico poder hacer esa traduccin, en lugar de tener que utilizar nmeros? Pues podemos. La declaracin de una matriz que hemos utilizado anteriormente es la versin simplificada de la misma, en la que slo se asignan valores. PHP crea los ndices de forma automtica, comenzando por el 0. Pero puede indicar los ndices usted mismo y no limitarse a los nmeros. Por ejemplo, esta sera una forma igualmente vlida de declarar la misma matriz:
$peliculas = array( 'enero' => 9, 'febrero' => 12, 'marzo' => 21, 'abril' => 17 );

El resultado de utilizar print_r() con la matriz anterior puede verse en la figura 2.12.

Figura 2.12. ndices no concordantes

Not a: En algunos textos puede encontrar que a este tipo de matriz se le llama matriz asociativa, porque permite asociar dos valores entre s.

Ha de ser cauto con los ndices al aadir nuevos elementos a una matriz. Si no indica ndice alguno, PHP utilizar el siguiente que est disponible, el que l crea ms adecuado. Considere las siguientes instrucciones:
$peliculas = array( 'enero' => 9, 'febrero' => 12, 'marzo' => 21, 'abril' => 17 ); >$peliculas[] = 14;

Ya sabe que la ltima lnea aade un nuevo elemento a la matriz, pero qu ndice tendr ese elemento? La figura 2.13 nos muestra el resultado de utilizar print_r() con dicha matriz.

Figura 2.13. Matriz asociativa

Como no hemos utilizado ndice alguno, PHP ha considerado que el ms adecuado es el primero libre, el cero. Esta decisin, totalmente correcta, puede sin embargo dar lugar a confusiones, puesto que nosotros esperaramos que el ndice del mes de mayo fuese el 5. Para evitar este tipo de situaciones, asigne nuevos elementos a una matriz ya creada indicando el ndice de los mismos, utilizando la siguiente sintaxis:
$peliculas['mayo'] = 14;

Otra de las peculiaridades de las matrices de PHP frente a las de otros lenguajes es que no todos sus elementos deben ser del mismo tipo. La matriz con la que hemos estado jugando hasta ahora slo contena nmeros

enteros, pero perfectamente podramos haber aadido un nuevo elemento de tipo cadena.
Advert encia: Que algo sea posible no quiere decir que deba hacerlo. Aunque en determinadas circunstancias esta caracterstica puede serle til, le recomendamos que sea ordenado y metdico al programar. Si una matriz contiene valores enteros representando el nmero de pelculas vistas durante los meses del ao procure que todos sus elementos sean enteros.

Hemos hecho un repaso de los tipos bsicos de las variables con las que va a trabajar en los programas de PHP. Veamos ahora cmo realizar operaciones sobre ellas.

Operadores
Por s sola, una variable tiene utilidad. Puede asignarle un valor (por ejemplo, la hora en un formato determinado) y luego mostrarla como respuesta a quin vea su pgina. Pero ya sabe que puede obtener el mismo resultado sin utilizar variables. El verdadero potencial de las variables se descubre cuando aprendemos a realizar operaciones sobre ellas. No se trata de nada que no conozca ya: si sabe sumar, restar y multiplicar, ya sabe qu son los operadores.
Not a: Tenga presente que PHP ofrece ms operadores de los que vamos a ver en esta seccin. Slo los que vamos a ver son ms que suficientes para realizar la mayora de las tareas del resto del libro. Si est interesado en aprender ms sobre los operadores que veremos y los que no veremos, no dude en consultar la documentacin de PHP.

Operador bsico de asignacin


Ya hemos trabajado con el operador de asignacin, el signo igual. Lo hemos utilizado en expresiones como:
$hora = date('H:i:s');

En dicha expresin, lo que est a la derecha del operador de asignacin, el signo igual, se guarda en lo que est a la izquierda.

Operadores aritmticos
Son los que aprendimos a utilizar en la escuela, para sumar, restar, multiplicar y dividir. De forma bastante previsible, dispone de operadores para: Suma: +. Resta: -. Multiplicacin: *. Divisin: /. Combinando estos operadores con el operador de asignacin puede comenzar a realizar tareas verdaderamente tiles. Por ejemplo, puede calcular la

suma de dos nmeros:


$i = 2 + 3; echo $i;

Igual que suma valores numricos directamente, tambin puede guardar esos valores en variables y posteriormente realizar la suma, as:
$i = 2; $j = 3; $i = $i + $j;

Existen unos operadores que combinan las asignaciones con los operadores aritmticos. Utilizando uno de estos operadores podemos volver a escribir el fragmento de cdigo anterior de esta forma:
$i = 2; $j = 3; $i += $j; // Equivale a $i = $i + $j.

Lo mismo puede aplicarse al resto de operadores aritmticos, con lo que dispone de -=, *= y /=. Podramos considerarlos como operadores extendidos de asignacin.

Operadores de comparacin
Permiten comparar dos valores. Como veremos ms adelante, en el apartado dedicado a las instrucciones de control, nos basaremos en estas comparaciones para tomar decisiones en nuestro cdigo. El resultado de utilizar este operador es un valor booleano (verdadero o falso), en funcin de si la comparacin se satisface o no. Para realizar comparaciones dispone de varios operadores, que puede ver resumidos en la tabla 2.1.
Tabla 2.1. Operadores de comparacin

O p eraci n $i == $j $i != $j (o <>) $i < $j $i > $j

D escrip ci n TRUE si son $i es igual que $j. TRUE si son $i no es igual que $j. TRUE si $i es menor que $j.

TRUE si $i es mayor que $j. $i <= $j $i >= $j TRUE si $i es menor o igual que $j. TRUE si $i es mayor o igual que $j.

Operadores lgicos
Operan con valores booleanos, devolviendo TRUE o FALSE dependiendo de si se cumple una condicin o no. Veremos cuatro operadores lgicos: and, or , xor y not . and El resultado de utilizar este operador sobre dos valores slo es TRUE si los dos valores sobre los que se est realizando la operacin son TRUE . Suponiendo que las variables $i y $j son de tipo booleano, la tabla 2.2 muestra las posibles combinaciones.
Tabla 2.2. Posibles combinaciones de and

$i FALSE FALSE TRUE TRUE

$J FALSE TRUE FALSE TRUE

$i an d $j FALSE FALSE FALSE TRUE

or A diferencia del operador and, el resultado de utilizar or sobre dos valores slo es FALSE si los dos valores sobre los que se est realizando la operacin son FALSE . De nuevo suponga que las variables $i y $j son de tipo booleano; la tabla 2.3 muestra las posibles combinaciones.
Tabla 2.3. Posibles combinaciones de or

$i FALSE FALSE TRUE TRUE

$j FALSE TRUE FALSE TRUE

$i o r $j FALSE TRUE TRUE TRUE

xor Devuelve TRUE cuando los dos valores son distintos. Puede verlo en la tabla 2.4.
Tabla 2.4. Posibles combinaciones de xor

$i FALSE FALSE TRUE TRUE

$j FALSE TRUE FALSE TRUE

$i xo r $j FALSE TRUE TRUE FALSE

not El operador not es un operador unario, puesto que se aplica a una sola variable, en contraste con el resto de operadores lgicos que hemos visto, que son binarios. En la tabla 2.5 puede ver los posibles valores que obtiene al aplicar este operador a una variable booleana.
Tabla 2.5. Posibles combinaciones de not

$i FALSE TRUE

! $i TRUE FALSE

Operadores de incremento
Y tambin de decremento. Gracias a estos operadores puede simplificar operaciones como stas:
$i = $i + 1; $i = $i - 1;

Que son equivalentes a las siguientes:


$i++; $i--;

Aunque ayudan a simplificar, en ocasiones pueden

complicarlo todo. PHP le deja situar estos operadores antes y despus de la variable a la que modifican, pero dependiendo de dnde los coloque el resultado puede variar. Comprobarlo es muy sencillo:
$i = 1; $j = $i; // Tanto $i como $j valen 1. echo $i++; echo '<br/>'; echo ++$j;

Mientras que el resultado de la primera expresin de salida es uno, el de la segunda es dos. Esto es as porque PHP entiende que si sita el operador de incremento despus del nombre de la variable, querr realizar la operacin despus del resto de operaciones (en este caso, una operacin de salida), mientras que situarla antes del nombre de la variable da prioridad al incremento, que se realiza antes de cualquier operacin. Por lo tanto, preste especial atencin a este tipo de operadores: puede que obtenga resultados imprevisibles si no anda con cuidado.

Concatenacin de cadenas
La operacin ms importante que puede realizar sobre una cadena es la concatenacin: unir dos cadenas para formar una sola. Para ello PHP ofrece un operador que puede ver en funcionamiento a continuacin:
$cadena1 = 'Esto es'; $cadena2 = 'una cadena.'; $cadena3 = $cadena1.' '.$cadena2; echo $cadena3;

El resultado de esta operacin es la cadena "Esto es una cadena.". Como habr podido observar, el operador de concatenacin es un punto que habr que situar entre las cadenas que quiera unir. Igual que en las operaciones aritmticas, puede combinar una concatenacin con una asignacin para simplificar el cdigo, as:
$cadena1 = 'Esto es'; $cadena2 = 'una cadena.'; $cadena1 .= ' '.$cadena2; echo $cadena1;

El resultado ser el mismo en ambos casos.

Precedencia de operadores
Debe estar siempre seguro del orden en el que PHP realizar las operaciones que le indique. Lo est ahora? Cul ser el resultado de esta operacin, qu contendr $i?
$i = 2 + 3 * 2;

Contendr 10? Contendr 8? Depende de la precedencia que tengan los operadores. En este caso concreto, el resultado ser 8, porque el operador de

multiplicacin tiene prioridad sobre el de suma. Pero y si quisiera que la suma se realizase antes que la multiplicacin? Puede modificar la precedencia de los operadores utilizando parntesis para envolver las operaciones que quiera realizar antes. La operacin anterior puede ser modificada para obtener 10 como resultado:
$i = (2 + 3) * 2;

PHP realizar primero la operacin que est entre parntesis, cuyo resultado es cinco. A continuacin multiplicar ese valor por dos, y el resultado, diez, lo almacenar en $i.

Cambios de tipo
Como resultado de las diferentes operaciones que realice sobre las variables, es posible que modifique el tipo de alguna de ellas. S, pero es normal. Imagine que realiza la siguiente operacin:
$i = 100; // Una variable de tipo entero. $cadena = 'veces'; // Una cadena. // Concatenamos el nmero y la cadena. $i .= ' '.$cadena; echo $i;

Cul ser el resultado de estas operaciones? En la pgina Web resultante podr leer el texto "100 veces". Ha ocurrido algo ms? Vamos a ayudarnos de la funcin gettype(). Esta funcin recibe como argumento el nombre de una variable y devuelve una cadena de texto que contiene el tipo de la variable pasada. Cambiemos el cdigo anterior por el siguiente:
$i = 100; // Una variable de tipo entero. $cadena = 'veces'; // Una cadena. echo 'Tipo de $i: ' . gettype($i) . '<br>'; // Concatenamos el nmero y la cadena. $i .= ' ' . $cadena; echo $i; echo '<br/>'; echo 'Tipo de $i: ' . gettype($i);

Como puede comprobar, antes de la concatenacin $i es de tipo entero (integer ), pero despus pasa a ser de tipo cadena (string). Para liar an ms las cosas, resulta que tambin podemos hacer esto otro:
$cadena = 'Soy una cadena'; echo gettype($cadena) . '<br>'; $cadena = 20; echo gettype($cadena);

Y hemos cambiado el tipo de una variable que era una cadena a un entero. Qu est pasando?

PHP no permite que declare el tipo de una variable. En su lugar, es el contexto el que determina su tipo. As, si asigna un valor numrico a una variable, su tipo ser numrico. Si posteriormente concatena ese valor con una cadena, el tipo resultante ser una cadena. Esta flexibilidad es muy til, ya que permite realizar concatenaciones entre nmeros y cadenas sin necesidad de realizar conversiones de tipo de forma explcita. La contrapartida: ha de ser muy cauto si no quiere obtener resultados imprevisibles. Si lo necesita puede comprobar el tipo de las variables utilizando la funcin gettype(), aunque tambin puede aprovecharse de otra de las caractersticas de PHP y forzar el tipo de las variables. Puede obligar a que una variable de un tipo determinado se comporte como una de otro tipo con solo indicar entre parntesis y antes de la variable el tipo que desea. As, puede conseguir que una variable de tipo cadena se comporte como una de tipo entero:
$cadena = '10'; $entero = (integer) $cadena; echo gettype($cadena); echo '<br/>'; echo gettype($entero);

Lo mismo puede aplicarse al resto de tipos, cuyos nombres en ingls puede consultar en la documentacin de PHP. Tenga precaucin, sin embargo. En el ejemplo anterior $entero contendr el valor entero 10, pero si $cadena hubiese contenido la cadena "texto" , el resultado sera que $entero contendra el valor 0:
$cadena = 'texto'; $entero = (integer) $cadena; echo $entero;

Por regla general, si la conversin entre tipos no resulta posible, PHP asignar valores predeterminados, como el cero o una cadena vaca. Hay que reconocer que, hasta ahora, lo que hemos visto en este captulo no ha sido muy divertido. Pero prometemos que esto va a cambiar, porque en los siguientes apartados vamos a examinar las instrucciones de control, que utilizan las variables que acabamos de ver para conseguir que el contenido de la pgina HTML resultante de procesar la pgina PHP sea dinmico.

Instrucciones de control
En un programa escrito en PHP las instrucciones de control constituyen las herramientas ms importantes para hacer que sus pginas sean dinmicas. Son estas instrucciones las que le permiten evaluar el contenido de las variables y tomar decisiones en consecuencia.

S, hemos visto cmo crear una pgina en la que aparece un elemento que cambia en cada llamada, la hora. Pero no sera mucho ms interesante poder cambiar el contenido de la pgina dependiendo de la hora? Por ejemplo, podramos mostrar un mensaje de saludo. Este mensaje podra decir "Buenos das" si la hora est entre las 8 y las 14, "Buenas tardes" desde las 14 hasta las 19 y "Buenas noches" de las 19 hasta las 8. Pues esto y mucho ms es lo que vamos a conseguir con las instrucciones de control, de las que existen dos tipos: las condicionales y las iterativas.

Instrucciones condicionales
Como su propio nombre indica, permiten determinar qu acciones realizar en funcin de una condicin. La ms simple de este tipo de instrucciones es if, que en su expresin ms sencilla tiene este aspecto:
if (condicin) accin

PHP evala la condicin. Si el resultado de esta evaluacin es TRUE , la accin asociada se ejecutar. En caso contrario, la accin se ignora y no se ejecuta. Por ejemplo, puede almacenar la hora en una variable. Ya sabe cmo hacerlo. Despus puede comparar ese valor con uno en concreto, algo que tambin sabe hacer gracias al trabajo que ha realizado con los operadores. Y, entonces, si ambos valores coinciden, realizar la accin que haya escrito. Concretando an ms, si la hora es menor que las 12, escriba un mensaje indicando que an no es medioda. Algo as:
<?php $hora = date('H'); if ($hora < '12') echo 'An no es medioda.'; ?>

El resultado del cdigo anterior variar dependiendo de si vemos la pgina antes o despus de las 12. De hecho, si la vemos despus de las 12, la pgina estar en blanco. Puede mejorar este pequeo programa utilizando else junto con if. As podr indicar la accin a seguir en caso de que la condicin no se cumpla:
<?php $hora = date('H'); if ($hora < '12') echo 'An no es medioda.'; else echo 'Ya es medioda.'; ?>

Esto marcha! Ahora el que vea la pgina siempre obtendr un mensaje... aunque no se trata de un mensaje

muy exacto si lo ve pasadas las 12, digamos a las 8 de la tarde. A esa hora ya no es medioda, verdad? Para ser ms precisos en nuestros mensajes, vamos a utilizar una nueva instruccin condicional, elseif, que permite evaluar una nueva condicin en caso de que la anterior no se cumpliese. Podemos entonces ejecutar instrucciones cuando an no sean las 12, cuando ya hayan pasado las 12 y (el caso que no cubramos) cuando sean las 12 en punto:
<?php $hora = date('H'); if ($hora < '12') echo 'An no es medioda.'; elseif ($hora == '12') echo 'Ya es medioda.'; else echo 'El medioda ya pas.'; ?>

Las instrucciones condicionales pueden anidarse, es decir, pueden escribirse unas dentro de otras, gracias a lo que podemos volver a escribir el cdigo anterior as:
<?php $hora = date('H'); if ($hora < '12') echo 'An no es medioda.'; else if ($hora == '12') echo 'Ya es medioda.'; else echo 'El medioda ya pas.'; ?>

Ahora, una pregunta con trampa. Examine este fragmento de cdigo y dganos el resultado si se ejecuta antes de las 12 del medioda:
<?php $hora = date('H'); if ($hora < '12') echo 'An no es medioda.'; else echo 'Es medioda.'; echo 'Queda menos para ir a comer!'; ?>

Si su respuesta fue que slo veremos el texto "An no es medioda", la respuesta no es correcta! Aunque el fallo no ser por desconocimiento, si no porque no le hemos dicho que a cada parte de la condicin slo se asocia una instruccin. Es decir, la ltima lnea, la que nos avisa que queda menos para ir a comer, se ejecuta siempre, se cumpla o no se cumpla la condicin. Para solucionar ese problema puede utilizar las llaves ({}), que permiten asociar grupos de lneas a cada parte de la condicin. Su respuesta sera correcta si volvisemos a

escribir el cdigo anterior as:


<?php $hora = date('H'); if ($hora < '12'){ echo 'An no es medioda.<br/>'; }else{ echo 'Es medioda.<br/>'; echo 'Queda menos para ir a comer!<br/>'; } ?>

Not a: Le recomendamos que siempre utilice llaves con sus instrucciones condicionales if , aunque a cada parte slo asocie una lnea de cdigo. Podra olvidar incluirlas si ms adelante decide aadir una lnea ms alguna de las partes de la condicin, lo que podra provocar un fallo en la lgica de su programa.

Utilizando instrucciones if y else puede complicar el programa anterior todo lo que quiera; por ejemplo, comprobando la hora y escribiendo mensajes en funcin de la misma. As, para informar de que a las 9 de la maana entra a trabajar, a las 14 sale a comer, a las 16 vuelve a entrar y a las 19 se va para casa escribira el siguiente cdigo:
<?php $hora = date('H'); if ($hora == '9'){ echo 'Bienvenido al curro.'; }elseif ($hora == '14'){ echo 'Que aproveche.'; }elseif ($hora == '16'){ echo 'Lstima de siesta...'; }elseif ($hora == '19'){ echo 'Hasta maana.'; } ?>

PHP nos proporciona otra instruccin condicional que permite escribir un programa equivalente al anterior, pero de forma ms clara: la instruccin switch. El resultado de utilizarla sera el siguiente:
<?php $hora = date('H'); switch ($hora){ case '9': echo 'Bienvenido al curro.'; break; case '14': echo 'Que aproveche.'; break; case '16': echo 'Lstima de siesta...'; break; case '19': echo 'Hasta maana.';

echo 'Hasta maana.'; break; } ?>

Como puede comprobar, le indicamos a la instruccin sobre qu variable se realizarn las comparaciones. Despus escribimos las instrucciones asociadas a cada caso. PHP recorrer cada instruccin case, comparando el valor de $hora con el valor correspondiente. Si son iguales, ejecutar las instrucciones asociadas con ese case y terminar de ejecutar la instruccin switch.
Not a: La instruccin break es la que marca la salida del swit ch. De ella hablaremos ms adelante.

Incluso puede indicar qu hacer en caso de que no se cumpla ninguna de las condiciones, es decir, cuando no haya un case que satisfaga la igualdad. Puede utilizar la instruccin default , con lo que el cdigo resultante mostrara un mensaje de su eleccin cuando la pgina se vea a una hora que no est contemplada:
<?php $hora = date('H'); switch ($hora){ case '9': echo 'Bienvenido al curro.'; break; case '14': echo 'Que aproveche.'; break; case '16': echo 'Lstima de siesta...'; break; case '19': echo 'Hasta maana.'; break; default: echo 'A trabajar.'; } ?>

Instrucciones iterativas
Estas instrucciones permiten ejecutar un bloque de cdigo tantas veces como sea necesario, mientras se cumpla una determinada condicin. Bucle For La primera que vamos a ver es la instruccin for , que permite ejecutar un bloque de instrucciones un nmero concreto de veces. La sintaxis de esta instruccin es la siguiente:
for (expresin1; expresin2; expresin3) accin

Cuando PHP encuentra una de estas instrucciones, lo primero que hace es evaluar expresin1. Esto slo se hace la primera vez. Cada vez que se d una vuelta en la instruccin de iteracin, se evaluar expresin2. Las iteraciones continuarn mientras se evale como TRUE . Cada vez que se termine una vuelta en la instruccin de iteracin se evaluar expresin3. Resumiendo: expresin1: Slo una vez, al comienzo del bucle. expresin2: Antes de comenzar cada iteracin. expresin3: Al terminar cada iteracin. El siguiente fragmento de cdigo contiene un bucle for que se ejecuta tres veces. Cada vez que lo hace, escribe el mismo texto:
<?php for ($i = 1; $i <= 3; $i++){ echo 'Probando un bucle for...<br/>'; } ?>

Cuando PHP encuentra el bucle for, asigna 1 a la variable $i. Slo lo hace la primera vez. A continuacin, comprueba que $i no sea mayor que 3. Como $i contiene 1, la condicin se cumple, as que ejecuta la instruccin echo(). Al encontrar el cierre de llave descubre que la primera iteracin ha terminado, as que vuelve al comienzo del bucle y evala la tercera de las expresiones, que incrementa en uno el valor de $i. Segunda iteracin: comparamos el valor de $i con 3, pero como $i vale 2, despus de haber sido incrementada, la condicin se cumple. Volvemos a ejecutar la instruccin echo(), a incrementar el valor de $i, a compararlo con 3 y a ejecutar la instruccin echo. La cuarta vez que pasemos por la comparacin, $i valdr 4, la comparacin se evaluar como FALSE y habr terminado la ejecucin del bucle for. El resultado de ejecutar este cdigo puede verse en la figura 2.14.

Figura 2.14. Ejecucin de un bucle for

El siguiente es un ejemplo mucho ms vistoso de bucle

for:
<?php for ($i = 1; $i <= 3; $i++){ echo '<h'.$i.'>Bucle for</h'.$i.'>'; } ?>

En la figura 2.15 puede ver el efecto del cdigo anterior.

Figura 2.15. Encabezados dinmicos

Un bucle for puede utilizarse para recorrer todos los elementos de una matriz y mostrar su contenido. Esa matriz podra ser, por ejemplo, la que contena las pelculas vistas durante cada mes:
<?php $peliculas = array( 'enero' => 9, 'febrero' => 12, 'marzo' => 21, 'abril' => 17 ); // Cuntos meses hay en la matriz? $meses = count($peliculas); for ($i = 1; $i <= $meses; $i++){ echo $i . ': ' . $peliculas[$i] . '<br/>'; } ?>

Vaya, el resultado de ejecutar este bucle no es el esperado. Claro, resulta que los ndices utilizados no son nmeros, son cadenas de texto. Vamos a solucionarlo utilizar otra instruccin de iteracin: foreach. Bucle For Each Traducido como "para cada", con foreach puede recorrer todos los elementos de una matriz sin necesidad de saber cuntos elementos la componen. Puede utilizar este bucle as:
foreach (matriz as $valor) accin

El bucle se ejecutar tantas veces como elementos tenga la matriz. En cada iteracin, se avanzar al siguiente elemento, cuyo valor se ir guardando dentro de $valor .

Dentro del bloque de cdigo asociado al bucle puede realizar operaciones con ese valor. Pero tambin puede ejecutar el bucle foreach de esta otra forma:
foreach (matriz as $clave => $valor) accin

Con esta segunda forma tambin tendr acceso al valor del ndice asociado con el valor. Esto le puede ser de mucha utilidad en el ejemplo de las pelculas por mes:
<?php $peliculas = array( 'enero' => 9, 'febrero' => 12, 'marzo' => 21, 'abril' => 17 ); foreach ($peliculas as $mes => $vistas){ echo 'En ' . $mes . ' vi ' . $vistas . '.<br/>'; } ?>

Puede ver el resultado de usar foreach en la figura 2.16.

Figura 2.16. Uso de foreach

Las dos instrucciones de iteracin que acabamos de ver se ejecutan un nmero determinado de veces, que puede ser conocido previamente. PHP ofrece otras dos instrucciones de control que iteran mientras se cumplan una serie de condiciones: los bucles while y do while. Bucles While En su forma ms sencilla, el bucle while sigue la sintaxis:
while (condicin) accin

Es decir, mientras se cumpla la condicin, ejecutamos la accin. Esta accin puede ser un bloque de instrucciones envuelto entre llaves. La accin puede modificar los factores que se evalan en la condicin para que, en un momento dado, la condicin no se cumpla y se pueda salir del bucle.

Por ejemplo, puede crear un bucle de este tipo que mantenga el control mientras el segundo de la hora en la que nos encontremos no sea cero:
<?php $segundo = date('s'); while($segundo != '0'){ $segundo = date('s'); } echo 'Comienza un nuevo minuto.'; ?>

Este sencillo programa guarda en la variable $segundo el segundo en el que se encuentra. A continuacin, comienza el bucle while. Compara el segundo actual con cero. Si no es cero, entre en el cuerpo del bucle, donde vuelve a obtener el valor del segundo. PHP vuelve a comparar el contenido de la variable $segundo con cero y sigue iterando mientras se cumpla la condicin. Pero tarde o temprano no se cumplir. Cuando eso ocurra, terminar la ejecucin del bucle y llegar a la instruccin echo, que le muestra un mensaje. La otra variante de este bucle sigue la siguiente sintaxis:
do accin while(condicin)

Este bucle sigue las mismas premisas que el anterior, pero con algunas salvedades que comprenderemos mejor con un ejemplo:
<?php do{ $segundo = date('s'); }while($segundo != '0'); echo 'Comienza un nuevo minuto.'; ?>

El resultado de este bloque de cdigo es ligeramente diferente al anterior, aunque buscamos el mismo objetivo. Dejando a parte diferencias de sintaxis, el cuerpo del bucle do while se ejecuta al menos una vez, mientras que en el bucle while podra darse el caso de que el cuerpo del bucle no se ejecutase ninguna si $segundo valiese cero desde el principio. Por lo tanto, debe utilizar do while cuando quiera que el cuerpo del bucle se ejecute al menos una vez y while en caso contrario.
Advert encia: Asegrese de que siempre exista un camino de salida de estos bucles. En caso contrario PHP no podra terminar la ejecucin del bucle y el programa se ejecutara indefinidamente. Como consecuencia, la pgina Web nunca le sera devuelta al que desee verla.

Salida de bucles

Es posible alterar el flujo de la ejecucin de un bucle mediante algunas instrucciones especiales. Una de ellas ya la vio cuando aprendi a utilizar la instruccin switch: se trata de break. break Puede utilizar esta instruccin para detener la ejecucin de los bucles for , foreach, while y do while. Cuando PHP encuentra esta instruccin dentro del cuerpo de cdigo asociado al bucle entiende que quiere salir de l y continuar con el resto de lneas del programa. Podra utilizar esta instruccin en un bucle do while del que quiera salir antes de que se cumplan todas las iteraciones. En el ejemplo anterior, suponga que no quiere estar esperando demasiado tiempo a que acabe el minuto. Si est en los primeros diez segundos del minuto y no quiere permanecer dentro del bucle el cdigo resultante sera el siguiente:
<?php do{ $segundo = date('s'); if ($segundo <= '10'){ break; } }while($segundo != '0'); echo 'Comienza un nuevo minuto.'; ?>

continue Utilice continue cuando quiera saltarse el resto de lneas de cdigo asociadas a un bucle y continuar con la siguiente iteracin. Podra utilizarlo en el ejemplo de las pelculas vistas cada mes. Si en alguno de los meses no se vio ninguna pelcula se continuar con la siguiente iteracin y no se mostrar informacin alguna. Hemos modificado el mes de marzo para que el nmero de pelculas sea cero:
<?php $peliculas = array( 'enero' => 9, 'febrero' => 12, 'marzo' => 0, 'abril' => 17 ); foreach ($peliculas as $mes => $vistas){ if ($vistas == 0){ continue; } echo 'En ' . $mes . ' vi ' . $vistas . '.<br/>'; } ?>

Como resultado, el cdigo anterior slo mostrar informacin sobre los meses de enero, febrero y abril. Enhorabuena! Acaba de pasar por un intenso curso de aprendizaje de PHP, una terapia de choque. Ha sido duro, verdad? Y eso que hemos dejado muchos temas en el tintero, como la escritura de funciones o cmo reutilizar cdigo.

MySQL
El mundo de los sistemas gestores de bases de datos ha estado reservado a una lite desde el principio. Sus administradores eran considerados poco menos que magos, dueos de sortilegios para desfacer cualquier entuerto. Tras muchos aos la situacin ha cambiado radicalmente, pero para ello han tenido que coincidir mil circunstancias. Cuando se es nuevo en el mundo de las bases de datos, lo ms complicado es llegar a entender de qu se nos est hablando, qu es una base de datos. Y eso es algo que no se puede aprender con teora. Es necesario pasar a la accin. Considere este tercer captulo como una unidad autosuficiente en la que crear su primera base de datos, que ver funcionando y sobre la que aprender a realizar operaciones de insercin (para incorporar nuevos datos), consulta (para extraer informacin), modificacin (para cambiar los datos almacenados) y borrado (para eliminar datos obsoletos o incorrectos). En resumen, lo que veamos en este captulo le servir para tener una visin de conjunto de las operaciones necesarias para manejar un sistema gestor de bases de datos, desde los cimientos hasta los procedimientos ms complejos. En captulos sucesivos profundizaremos en estos conocimientos, hasta completar todas las tareas que debera controlar o, al menos, conocer, para desempear su trabajo con MySQL y PHP. Acompenos en el descubrimiento de las bases de datos y, en concreto, de la ms utilizada en el mundo del software libre.

Bases de datos
Una base de datos es una buena forma de organizar y compartir informacin. Le permite mantener todos los datos que nos interesan en un formato tabular unificado, con diferentes tablas para cada grupo de datos con caractersticas comunes. Las tablas que mantienen datos que tienen que ver entre si estn agrupadas en un mismo contenedor: la base de datos. Quienes necesiten extraer informacin de esos datos slo tienen que realizar una consulta a la base de datos. La figura 3.1 simboliza las relaciones entre estos elementos.

Figura 3.1. Tablas, base de datos y consulta

Not a: Fjese en la diferencia entre datos e informacin. En el caso de un actor, los datos representan hechos acerca de l (su nombre, su fecha de nacimiento, etctera). Sin embargo, la informacin se extrae a partir de esos datos: en qu pelculas ha participado, cuntas son en total, etc.

Existe un lenguaje especialmente diseado para realizar consultas a bases de datos. Este lenguaje, llamado SQL, es comn para la mayora de sistemas gestores de bases de datos que existen hoy en da. SQL son las siglas de lenguaje estructurado de consultas (Structured Query Language). Gracias a este lenguaje podemos realizar preguntas a los servidores de bases de datos. Desde la aparicin de las redes informticas, el modelo representado en la figura 3.1 se ha extendido, pudiendo realizarse varias consultas de forma simultnea y desde diferentes ubicaciones geogrficas, como intenta representar la figura 3.2.

Figura 3.2. Consultas remotas simultneas

Ms an, se ha desarrollado la tecnologa necesaria para publicar bases de datos a travs de medios muy asequibles para el pblico en general. La tabla 3.1 muestra los datos de un determinado actor, John Cleese, ms o menos como estaran almacenados dentro de una base de datos. En la figura 3.3 podemos ver cmo se mostraran en una pgina Web. En concreto, se trata de la pgina dedicada a ese actor en IMDb (en la direccin http://imdb.com/). La publicacin Web puede verse como una forma ms de permitir consultas simultneas a travs de redes.
Tabla 3.1. Los datos de John Cleese

C amp o Nombre Apellidos Fecha de nacimiento Ubicacin de la foto

Valo r John Cleese 1939-10-27 /fotos/actores/john_cleese.jpg

Figura 3.3. John Cleese en IMDb

Como puede comprobar, la pgina Web muestra las referencias que la base de datos tiene del actor, pero distribuidas de manera que sean legibles por un ser humano, presentadas de una forma ms atractiva, lo que facilita la localizacin de los datos que ms interesantes. Adems de poder utilizar una interfaz Web para la consulta de la informacin tambin se puede utilizar para la introduccin de los datos. Este modelo de trabajo es muy verstil: los encargados de la tarea pueden estar en diferentes ubicaciones geogrficas, trabajando sobre la misma base de datos. Es precisamente en este tipo de aplicaciones donde MySQL tiene mayor aceptacin, en el grupo de aplicaciones conocido como LAMP : Linux, Apache, MySQL y PHP, Python o Perl, aplicaciones desarrolladas sobre Linux, con el servidor de pginas Web Apache, que utilizan como el enlace entre las bases de datos y la Web alguno de los lenguajes antes mencionados.
Not a: Apache, MySQL y los lenguajes mencionados pueden funcionar sobre Windows, lo que permite hablar tambin de WAMP. De hecho, a lo largo de las pginas de este libro utilizaremos principalmente el sistema operativo de Microsoft. La razn por la que se ha escogido Windows en lugar de Linux o Mac OS X es, sencillamente, que an sigue siendo el sistema operativo ms utilizado del mundo, lo que hace mucho ms probable que usted, lector, tenga acceso a l. Sin embargo, podr aprovechar lo que vea en este libro sin ningn esfuerzo tanto en Mac OS X como en Linux. Se lo dice alguien que trabaja con los tres a diario.

Qu es una tabla?

En el mundo de las bases de datos, una tabla es un "lugar" en el que se almacenan una serie de datos de similares caractersticas. En el mundo de la carpintera es otra cosa. Los datos pertenecientes a un mismo elemento estn organizados en campos o columnas, cada una de un determinado tipo. Se llama registro a cada una de las filas de una tabla. En la figura 3.4 podemos ver un ejemplo de tabla.

Figura 3.4. Una tabla, sus campos y sus registros

Todos los datos pertenecientes a la misma columna de una tabla (el ttulo de las pelculas, por ejemplo) son del mismo tipo. En este caso concreto se trata de informacin de texto, con una longitud mxima de 64 caracteres. Antao, este "lugar" con el que nos hemos referido a una tabla era un archivo y dentro de este archivo se organizaban los datos. Hoy en da no es correcto establecer una relacin directa entre tabla y archivo, ni entre base de datos y archivo ya que por cuestiones de rendimiento y aprovechamiento de espacio, una base de datos y una tabla pueden estar dispersos en varios archivos, incluso en varios ordenadores diferentes.

Base de datos de ejemplo


Quien ms y quien menos tiene alguna pelcula en su casa. La mayora tiene ms de una. Incluso los hay que tienen un verdadero videoclub en el saln. Si su caso es este ltimo seguro que no tendr dificultad para comprender la utilidad de una base de datos de pelculas: mantener un control sobre cules tiene en su coleccin, poder pasar una lista de las mismas a otros videoadictos o controlar a quines ha prestado alguna. Estas posibilidades, ya de por s, son interesantes. Pero gracias a organizar los datos de las pelculas en una base

de datos obtendr otras ventajas de forma automtica, como poder consultar cules de sus pelculas fueron dirigidas por un determinado director, cules las protagoniza un determinado actor, cules son de un determinado ao, en definitiva, poder hacer preguntas y conseguir respuestas. Comenzaremos la creacin de la base de datos de ejemplo de forma muy sencilla, almacenando slo el ttulo de la pelcula, el nombre del director y el de uno de los actores. La figura 3.5 muestra el diseo de esta tabla: el nombre de la misma en la parte superior, y una lnea describiendo cada columna de la tabla, con el nombre a la izquierda y el tipo de datos a la derecha.

Figura 3.5. Nuestra tabla de pelculas

Not a: No se preocupe en absoluto por el significado de los tipos de datos. El objetivo de este ejemplo es que comprenda lo que se puede hacer con una base de datos. Ms adelante veremos dichos tipos de datos.

En esta tabla guardar los datos de las pelculas de su coleccin. Son pocos datos, pero cubren a la perfeccin lo necesario para este ejemplo. A continuacin crearemos la base de datos que contendr los datos de las pelculas y, dentro de ella, la tabla de pelculas.

Herramientas de consulta
Vamos a utilizar la ms sencilla de las herramientas de consulta a nuestra disposicin, una que funciona igual en cualquier sistema operativo: la consola. Para ello, si est utilizando el sistema operativo Windows, deber hacer clic en Inicio>Todos los programas>Accesorios>Smbolo del sistema. Si est utilizando Linux tendr que abrir un terminal. El terminal de Mac OS X se encuentra en la carpeta de utilidades. Cuando tenga acceso a la consola, escriba:
mysql -u root -p

Pulse la tecla Intro. Se le pedir que introduzca la contrasea del usuario root . Si est utilizando XAMPP bastar que pulse la tecla Intro de nuevo, puesto que dicho usuario no tiene contrasea alguna asignada. Puede verlo en la figura 3.6.

Figura 3.6. Cliente de MySQL

Cuando introduzca la contrasea correcta, el programa esperar que se le indique qu rdenes desea ejecutar. Lamentablemente, XAMPP no incluye las rdenes de MySQL en la ruta del sistema. Si utiliza Windows tendr que modificar las variables de entorno de su sistema, aadiendo la ruta en la que se encuentre MySQL instalado (por ejemplo, C:\xampp\mysql\bin\) a la variable Path. En Windows Vista podr llegar al cuadro de dilogo correspondiente haciendo clic con el botn derecho sobre Equipo, en el explorador de archivos, y seleccionando la opcin Propiedades del men desplegable que aparecer. A continuacin haga clic en Configuracin avanzada del sistema, en el panel de la izquierda del cuadro de dilogo que aparecer. Podr ver el cuadro de dilogo Propiedades del sistema. Active la ficha Opciones avanzadas, haga clic en Variables de entorno y acceder al cuadro de dilogo Variables de entorno, que le permitir modificar la variable Path. Aada al final la nueva ruta y guarde los cambios realizados. En Linux o Mac OS X, si MySQL se encontrase instalado en /usr/local/mysql/, la orden para conectar el servidor de bases de datos sera: /usr/local/mysql/bin/mysql -u root -p Hemos tenido que escribir la ruta completa de la orden para poder conectar con el servidor de bases de datos. Si no quiere tener que escribir la ruta completa de cada una de las rdenes de MySQL que necesite ejecutar tendr que modificar la ruta del sistema. Para ello, abra un terminal (utilizando la aplicacin del mismo nombre que se encuentra en la carpeta de utilidades), escriba la orden nano .profile estando en su carpeta personal (por lo general, es aquella en la que estar al abrir el terminal) y pulse la tecla Intro. Podr ver una lnea similar a sta:
export PATH=/opt/local/bin:/opt/local/sbin:$PATH

Aada /usr/local/mysql/bin al final, antes de $PATH:


export PATH=/opt/local/bin:/opt/local/sbin: /usr/local/mysql/bin:$PATH

Guarde los cambios realizados y cierre el terminal. La

prxima vez que vuelva a abrir un terminal tendr acceso a las rdenes de MySQL sin necesidad de escribir la ruta completa de acceso.

Creacin de la base de datos


Es el primer paso, la creacin de la base de datos. Aunque existen varios mtodos para crear bases de datos con MySQL, el ms verstil consiste en la utilizacin de scripts. Un script es un fragmento de texto con instrucciones para MySQL. Por lo general, estos scripts se guardan en archivos de texto con la extensin SQL, aunque mientras el contenido del archivo sea correcto, la extensin no es demasiado importante. La extensin SQL se utiliza porque el lenguaje utilizado para escribir estos scripts es precisamente ese, SQL, del que hablaremos con detalle ms adelante. El nombre de la base de datos que vamos a crear ser videoteca. De ello se encargan las dos primeras lneas de este script:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca;

USE videoteca;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula ( titulo VARCHAR(64), director VARCHAR(128), actor VARCHAR(128) );

Sin entrar a comentar el significado de cada lnea de este script, ya se puede apreciar que parece que estemos dando rdenes en ingls. Si ha trabajado con algn lenguaje de programacin ver que ste no se parece a ninguno que conozca, est mucho ms prximo al lenguaje natural que a uno de programacin.
Not a: Habr notado que estamos escribiendo pelicula y no pelcula , es decir, omitimos el acento. La razn es que no todas las herramientas de acceso a datos se comportan igual con los caracteres internacionales, como los acentos, por lo que evitaremos utilizarlos en los nombres de bases de datos y tablas siempre que sea posible. Esto no es aplicable a los datos que luego contendrn, slo a los nombres de bases de datos y tablas.

Tambin se habr fijado en que las palabras reservadas del lenguaje que utilizamos para dar rdenes a MySQL estn en maysculas, mientras que los nombres de bases de datos, tablas y campos estn en minsculas. Se trata de un convenio ampliamente aceptado que permite diferenciar de un vistazo las diferentes partes de estas instrucciones. Qu quieren decir las dos lneas dedicadas a la

creacin de la base de datos? Con la primera de ellas se le dice a MySQL que borre la base de datos videoteca en caso de que exista. Suponga que ha utilizado en ms de una ocasin estas lneas porque est volviendo a probar los ejemplos que acompaan este libro. Si intentase crear la base de datos y sta ya existiese, MySQL le dira que no es posible llevar a cabo la accin, porque la base de datos ya existe, algo no deseable si quiere comenzar con los ejemplos desde cero. Traduciendo del ingls, la primera lnea le dice a MySQL algo as como: "Borra la base de datos videoteca en caso de que exista". La segunda lnea es la que se encarga de la creacin: "Crea la base de datos videoteca". Tras la ejecucin de la segunda lnea, la base de datos habr sido creada. Lleg el momento: vamos a crear nuestra primera base de datos. Escriba en el smbolo del sistema las dos lneas que acabamos de comentar y pulse la tecla Intro al terminar. La figura 3.7 muestra el aspecto de dicha ventana tras ejecutar las instrucciones.

Figura 3.7. SQL para crear una base de datos

Vaya, qu decepcin! El resultado no es demasiado espectacular. Los mensajes indican que las consultas se han ejecutado correctamente. Es posible que hayamos conseguido nuestro objetivo? Para comprobarlo basta con que ejecute la siguiente instruccin:
SHOW DATABASES;

En la figura 3.8 puede ver que una de las bases de datos existentes es, precisamente, la que acabamos de crear: videoteca. Enhorabuena.

Figura 3.8. Nuestra primera base de datos

Para que la base de datos sea realmente til, es decir, para que pueda almacenar datos que posteriormente podamos consultar, es necesario crear tablas dentro de ella. Precisamente lo siguiente que haremos. Vuelva a examinar las instrucciones anteriores:
DROP DATABASE IF EXISTS videoteca;

CREATE DATABASE videoteca;

USE videoteca;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula ( titulo VARCHAR(64), director VARCHAR(128), actor VARCHAR(128) );

Al igual que con las dos primeras instrucciones, slo necesita traducir al castellano lnea por lnea. La tercera lnea permite indicarle a MySQL la base de datos con la que debe trabajar: "Utiliza la base de datos videoteca". De esa forma, MySQL sabr que las siguientes instrucciones que reciba irn referidas a esa base de datos. En la cuarta lnea se le pide a MySQL que borre la tabla pelicula si ya existe. Como puede comprobar, en esta instruccin no se hace referencia a base de datos alguna. Esto es as gracias a la instruccin anterior, en la que se indic con qu base de datos se iba a trabajar.
Not a: Podramos haber incluido el nombre de la base de datos antes del nombre de la tabla, separados por un punto, en la instruccin de creacin de la tabla: CREATE TABLE videot eca.pelicula . Sin embargo, gracias a la instruccin USE nos lo ahorramos.

Y llega la parte complicada. A partir de la quinta lnea se instruye a MySQL para que cree una tabla nueva, llamada pelicula, dentro de la base de datos videoteca. No se preocupe demasiado por la sintaxis de estas instrucciones, basta con que sepa que estas instrucciones le indican a MySQL las columnas que tendr la tabla pelicula y el tipo de datos de cada una de ellas. En este caso, todos los campos contendrn informacin de texto. Escriba esas instrucciones y, de nuevo, pulse Intro cuando termine. Quiere asegurarse de que la tabla se ha creado? Escriba la siguiente instruccin:
DESCRIBE pelicula;

La figura 3.9 muestra los mensajes que ver tras crear la tabla de pelculas y ejecutar posteriormente la instruccin DESCRIBE .

Figura 3.9. Creacin de la tabla

Ahora tiene una base de datos con una tabla, y la ha creado usted mismo. Con lo aprendido hasta el momento estamos listos para comenzar a ver las operaciones bsicas de manipulacin. Es realizando estas operaciones como comprender para qu sirve realmente una base de datos. Pero antes de aprender a realizar estas operaciones bsicas, detengmonos un momento y veamos qu operaciones se pueden llevar a cabo sobre las propias tablas.

Operaciones sobre tablas


A continuacin aprender a realizar las operaciones bsicas de creacin, modificacin y borrado de tablas. Aunque con lo que ver tendr las nociones mnimas necesarias, las instrucciones que ver disponen de muchas ms opciones de las que comentaremos, por lo que le recomendamos que acuda a la documentacin de MySQL y complete sus conocimientos sobre ellas si as lo desea. Para explicar la forma en la que debe utilizar estas instrucciones recurriremos a la sintaxis que MySQL sigue en su documentacin. As le ser ms sencillo entenderla cuando acuda a ella en busca de ms informacin. Slo hay que seguir tres normas muy simples: Aquellos fragmentos incluidos entre corchetes ([]) son opcionales, lo que quiere decir que no es obligatorio utilizarlos en las consultas. Si encuentra instrucciones entre llaves ({}) separadas por el smbolo | querr decir que son alternativas: puede utilizar una u otra, pero ha de utilizar una de ellas. Si estn entre corchetes, puede utilizar una o ninguna de ellas. Por ltimo, para simplificar la forma en la que la sintaxis est expresada, grandes partes de la descripcin pueden sustituirse por un nombre cuya sintaxis se explicar posteriormente. Ver ejemplos de estas tres normas con la sentencia de

creacin de tablas descrita a continuacin.

Creacin
La creacin de una tabla debe hacerse de acuerdo a la siguiente sintaxis:
CREATE TABLE [IF NOT EXISTS] nombre [(definicin, ...)] [opciones]

Si lo desea, puede incluir IF NOT EXISTS cuando cree una tabla. Esto evitar que MySQL le informe del error que ocurre al intentar crear una tabla que ya existe. La descripcin de las caractersticas de cada columna se realiza en definicin:
definicin: columna tipo [NOT NULL | NULL] [DEFAULT valor_predeterminado]

Debe incluir una definicin por cada columna que desee utilizar. El tipo de la columna se indica tras su nombre. Ms adelante, en este mismo captulo, hablaremos sobre los tipos de datos. Si lo desea puede incluir un valor predeterminado. De esa forma, en cada insercin se asignar ese valor a su columna, aunque no haya especificado valor alguno. Si indica NULL para una columna (o no indica nada, pues NULL es la opcin predeterminada), MySQL le permitir insertar registros sin asignar un valor a dicha columna. El valor guardado ser NULL . Si no desea que esto sea as indique NOT NULL . Entre otras opciones, es posible indicar el tipo de tabla que se desea utilizar:
ENGINE = { ARCHIVE | CSV | FEDERATED | MEMORY | InnoDB | MERGE | MYISAM | NDBCLUSTER }

En breve explicaremos las caractersticas de los diferentes tipos de tabla existentes, centrndonos en los ms utilizados. Para ver cmo se crea una tabla nada mejor que un ejemplo. Vamos a crear una nueva base de datos en la que realizar las pruebas de este captulo. Es ms que probable que MySQL ya disponga de una base de datos de pruebas llamada test, que podramos utilizar para crear tablas de ejemplo. Sin embargo, no va a ser ste el caso. Ejecute las siguientes rdenes para crear la base de datos pruebas:
DROP DATABASE IF EXISTS pruebas;

DROP DATABASE IF EXISTS pruebas; CREATE DATABASE pruebas;

Ejecute ahora las siguientes rdenes para crear la tabla persona:


USE pruebas;

CREATE TABLE persona( id INT NOT NULL, nombre VARCHAR(16) NOT NULL, apellidos VARCHAR(64) NOT NULL DEFAULT '' );

Las instrucciones anteriores crean una tabla siguiendo las normas sintcticas que se vieron anteriormente. Ahora bien, es posible modificar las caractersticas de una tabla ya existente? La respuesta es s, como ya sabr.

Modificacin
Las caractersticas de una tabla pueden ser modificadas despus de que haya sido creada, incluso si ya contiene datos. Para ello debe utilizar la instruccin ALTER TABLE , que sigue la siguiente sintaxis:
ALTER TABLE nombre modificacin [, modificacin, ...]

A su vez, cada modificacin se define de la siguiente forma:


modificacin: ADD definicin | ADD (definicin, definicin,...) | MODIFY columna { SET DEFAULT valor_predeterminado | DROP DEFAULT } | CHANGE columna definicin | DROP columna | opciones

Por definicin se entiende la sintaxis vista en la creacin de tablas. Con esta instruccin se pueden aadir nuevas columnas a una tabla (ADD), modificar las existentes (CHANGE ), cambiar valores predeterminados (MODIFY) o eliminarlos, eliminar columnas (DROP ) o cambiar el tipo de tabla. Como ejemplo, nada mejor que modificar la tabla creada en la seccin anterior. Vamos a cambiar el tipo del campo nombre para que pueda almacenar cadenas de mayor longitud. Adems, aadiremos un nuevo campo que permitir guardar la edad. Para lograr ambos objetivos utilice las siguientes instrucciones:
USE pruebas;

ALTER TABLE persona MODIFY nombre VARCHAR(32) NOT NULL, ADD edad INT NOT NULL;

Tambin es posible cambiar el nombre de las tablas existentes:


RENAME TABLE actual TO nuevo[, actual2 TO nuevo2,...]

El nombre de la tabla actual se cambiara por el nuevo. Si lo desea, puede cambiar el nombre de ms de una tabla a la vez. Las siguientes instrucciones permiten cambiar el nombre de la tabla persona por individuo:
USE pruebas;

RENAME TABLE persona TO individuo;

Borrado
La sintaxis de la instruccin de borrado de tablas es:
DROP TABLE [IF EXISTS] nombre [, nombre, ...]

En dicha sintaxis, nombre es el nombre de la tabla que se quiere eliminar. Como puede ver, es posible borrar ms de una tabla a la vez con slo indicar sus nombres separados por comas. Si lo desea, puede incluir IF EXISTS en la consulta de borrado. Esto evitar que MySQL le informe del error que surge al intentar eliminar una tabla que no existe en la base de datos que est utilizando en ese momento. Para borrar la tabla que se ha estado utilizando hasta ahora utilice las siguientes instrucciones:
USE pruebas;

DROP TABLE IF EXISTS individuo;

Tipos de tabla
Al contrario que otros sistemas gestores de bases de datos, MySQL permite utilizar diferentes tipos de tabla, dependiendo de sus necesidades. Si precisa velocidad de proceso puede utilizar tablas que estarn directamente en la memoria RAM del servidor. Si la prioridad es ahorrar espacio de almacenamiento, MySQL puede comprimir las tablas para que ocupen lo menos posible. Es posible utilizar transacciones si se trata de uno de los requisitos de la aplicacin. Y lo mejor de todo: si slo necesita un sistema para almacenar datos y posteriormente consultarlos, sin quebraderos de cabeza, puede olvidar que existen los diferentes tipos de tabla que se vern a continuacin. En los siguientes apartados describiremos los tipos de tabla ms utilizados: MyISAM e InnoDB. Sin embargo, existen muchos otros como, por ejemplo: ARCHIVE: Permite almacenar grandes cantidades de

informacin sin utilizar ningn ndice. Como consecuencia es muy veloz, pero slo si el propsito de la tabla es archivar informacin. La recuperacin de la misma ser ms lenta en la mayora de los casos puesto que no se podr utilizar ndice alguno para acelerarla. CSV: Son las siglas de Comma Separated Values (valores separados por comas). Permite almacenar datos en archivos de texto separando los valores con comas. FEDERATED: Permite que se pueda acceder a los datos de una tabla desde servidores remotos. NDBCLUSTER: Tipo de tabla para entornos distribuidos y de alta disponibilidad.
Truco: Quiere saber qu tipos de tabla puede utilizar en su servidor MySQL? Realice la consulta SHOW ENGINES; .

Ms an, no dejan de aparecer tipos de tabla nuevos para cubrir todas las necesidades de los usuarios de MySQL.
Not a: Existen un par de tipos de tablas muy curiosos que no hemos mencionado an. El primero de ellos es EXAMPLE (ejemplo). Como su nombre indica, se trata de un simple ejemplo que no cumple ms funcin que ilustrar el funcionamiento interno de MySQL en su cdigo fuente. El otro tipo de tabla es BLACKHOLE (agujero negro) y funciona como tal: todo lo que se arroja dentro de una tabla de este tipo desaparece y cualquier consulta devuelve un conjunto vaco. Se utiliza en entornos en los que no es necesario guardar los datos en el servidor local pero s enviarlos a otros servidores de forma distribuida.

MyISAM
El tipo predeterminado de tablas que MySQL proporciona es MyISAM, una evolucin del tipo de tabla original, conocido como ISAM (ya descatalogado), con mejoras como un superior aprovechamiento del espacio y ms velocidad en el acceso a datos. El nombre de este tipo de tablas viene de la forma en que MySQL accede a sus datos. ISAM son las siglas de mtodo de acceso secuencial indexado (Indexed Sequential Access Method). Al crear tablas sin indicar de qu tipo sern, MySQL utilizar el tipo MyISAM. Lo mismo har si no es capaz de crear el tipo de tabla que se indique, para evitar complicaciones.
Aviso: Existe una excepcin a la afirmacin anterior. El tipo predeterminado de las tablas ser InnoDB si ha instalado MySQL en Windows utilizando el asistente. Si tiene alguna duda sobre el tipo de una determinada tabla, utilice la instruccin SHOW CREATE TABLE seguida del nombre de la tabla en cuestin y busque el valor que toma ENGINE.

Las tablas de tipo MyISAM pueden, a su vez, ser de tres tipos:

Estticas: De forma automtica, si la tabla que est creando no contiene ningn campo de tipo VARCHAR, VARBINARY, TEXT o BLOB, MySQL har que sea de tipo esttico. En una tabla de tipo esttico, cada registro ocupa siempre el mismo tamao. Este tipo de tablas es el ms rpido cuando se trata de leer datos del disco: para recuperar los de un registro en concreto slo es necesario realizar unos sencillos clculos. Por el contrario, ocupa ms espacio que las tablas dinmicas. Dinmicas: Si crea una tabla con algn campo de tipo VARCHAR, VARBINARY, TEXT o BLOB, MySQL har que sea de tipo dinmico. Delante de cada registro almacenar el espacio que ocupa. Como consecuencia, estas tablas ocupan menos espacio que las tablas estticas. La contrapartida: es necesario ms tiempo para acceder a un registro en particular, puesto que se necesita leer antes el espacio ocupado por cada registro y hacer los clculos oportunos. Comprimidas: Si necesita que el espacio ocupado por sus tablas sea mnimo ste es su tipo de tabla. Si su tabla est en este formato slo podr leer de ella, por lo que deber realizar las inserciones en tablas sin comprimir y alterar posteriormente las propiedades de la tabla para comprimirla. Un efecto secundario muy interesante de este tipo de tablas es que mejora el tiempo de acceso a los datos si estn almacenados en dispositivos muy lentos, como algunos discos extrables u pticos. Esto se debe a que en cada lectura se pueden recuperar ms datos que si la tabla no estuviese comprimida, algo recomendable en aplicaciones de bases de datos que funcionen desde unidades pticas, como el CD-ROM, por ejemplo. Por sus caractersticas, las tablas MyISAM son especialmente tiles cuando los datos no cambian con frecuencia y la operacin ms utilizada es la de lectura. Si las inserciones de nuevos datos y las modificaciones van a ser algo frecuente o necesita utilizar transacciones en sus operaciones con registros, es recomendable que utilice tablas de tipo InnoDB.

InnoDB
Las tablas InnoDB proporcionan bloqueo por registro y control de transacciones, cumpliendo con el estndar ACID. Para lograr estos dos objetivos se sacrifica un poco de la velocidad de la que MySQL presume. MySQL bloquea las tablas de tipo MyISAM cuando se realiza una insercin o una actualizacin en un registro hasta que la operacin termine. Sin embargo, si las tablas son InnoDB, el bloqueo slo se realiza en el registro que se est modificando, lo que permite que ms usuarios utilicen de forma simultnea la base de datos. Las transacciones son necesarias en multitud de situaciones. El ejemplo ms utilizado transcurre en la base de datos de un banco, durante una transferencia entre dos cuentas.

Si piensa en esta transferencia en el mundo real, como un traspaso de dinero de una persona a otra, no ver que existan problemas: uno le da el dinero a otro y asunto resuelto. La situacin se complica en el entorno informtico, donde el saldo de las cuentas de ambos clientes debe estar almacenado en un registro dentro de una tabla de una base de datos. Se trata de un valor numrico en coma flotante. Cree una tabla muy sencilla para los saldos de los clientes del banco dentro de la base de datos de pruebas utilizando las siguientes instrucciones:
USE pruebas;

DROP TABLE IF EXISTS cuenta; CREATE TABLE cuenta( idcliente INT NOT NULL, saldo DOUBLE NOT NULL DEFAULT 0 ) ENGINE = InnoDB;

A continuacin, inserte un par de valores para almacenar el saldo de dos clientes:


USE pruebas;

INSERT INTO cuenta VALUES(212, 220.50); INSERT INTO cuenta VALUES(555, 1200.00);

Para realizar la transferencia han de completarse dos pasos: la cantidad transferida debe sumarse en la cuenta de destino y restarse de la cuenta que origina la transferencia. Una operacin tras la otra:
USE pruebas;

UPDATE cuenta SET saldo = saldo + 300 WHERE idcliente = 212;

UPDATE cuenta SET saldo = saldo - 300 WHERE idcliente = 555;

En qu situacin estaremos si ocurre algn problema entre el primer y el segundo paso, como un corte de suministro elctrico, un fallo en el hardware del ordenador que hospeda el servidor de bases de datos, etctera? El importe a transferir se habr sumado a la cuenta destino, pero no se habr restado de la emisora. Para el banco no se trata de algo deseable. Claro que es todo lo contrario para los clientes.

El estndar ACID se propuso para solucionar este tipo de situaciones. ACID son las siglas de atmico, consistente, aislado y duradero (Atomic, Consistent, Isolated, and Durable). Se dice que uno o ms cambios en una base de datos componen una operacin atmica si forman una unidad indivisible: o todos se completan con xito, o ninguno lo har. El estado de una base de datos es consistente mientras cumpla unas reglas, definidas por el diseo. En el ejemplo del banco, una de las reglas de consistencia podra ser que toda transferencia de capital debe estar correspondida por un ingreso. Al comienzo de una transaccin, el estado de la base de datos debe ser consistente. Sin embargo, mientras dure la transaccin, es posible que se pierda la consistencia. Esto es permisible siempre y cuando al terminar la transaccin se retorne al estado de consistencia inicial. Mientras dure una transaccin, las instrucciones que la conforman deben tener la impresin de que slo ellas estn en funcionamiento, aunque en realidad se puedan estar realizando otras operaciones en la base de datos, incluso otras transacciones. En ltimo lugar, los cambios realizados por una transaccin deben permanecer cuando sta termine. Por el contrario, si la transaccin se interrumpe en medio de su trabajo (por un corte de luz, por ejemplo), ninguno de los cambios que haya realizado se habrn guardado, permaneciendo la base de datos en el mismo estado en el que se encontraba antes de comenzar la transaccin. La gestin de las transacciones se realiza mediante unas instrucciones muy sencillas. Siguiendo con el ejemplo, la transferencia se realizara de la siguiente forma:
USE pruebas;

START TRANSACTION;

UPDATE cuenta SET saldo = saldo + 300 WHERE idcliente = 212;

UPDATE cuenta SET saldo = saldo - 300 WHERE idcliente = 555;

COMMIT;

Con la primera instruccin se le dice a MySQL que va a comenzar un bloque de sentencias SQL dentro de una transaccin. Es decir, MySQL no har efectivo los cambios hasta que encuentre una instruccin COMMIT . A continuacin de esta primera instruccin estn las operaciones a realizar con los valores dentro de la base de datos. El bloque termina con la instruccin COMMIT , que finaliza la transaccin. Si existiese un problema antes de ejecutar la instruccin COMMIT , todas las instrucciones anteriores a COMMIT se descartaran, eliminando el problema de la inconsistencia. Los bancos son muy listos.
Not a: Existe un motivo ms para utilizar tablas del tipo InnoDB, ya que permiten la existencia de claves externas, algo vital para el funcionamiento de la integridad relacional. Ver qu quiere decir esto en el captulo dedicado al diseo de bases de datos.

Tipos de datos
Dependiendo de la naturaleza de los datos que queramos guardar, el tipo de cada columna debe ser diferente. A continuacin veremos cules pone MySQL a nuestra disposicin.

Tipos de texto
En la jerga informtica, se utiliza la expresin cadena de texto cuando se hace referencia a una sucesin de caracteres que pueden formar palabras o frases. MySQL dispone de varios tipos de datos diferentes para almacenar esta clase de informacin: CHAR: Permite definir cadenas de texto de longitud fija. La longitud se especifica entre parntesis a continuacin del nombre del tipo y puede estar entre 0 y 255 caracteres. Si la columna puede tener veinte caracteres, siempre se ocuparn esos caracteres, aunque el texto a guardar sea menor. En la figura 3.10 puede ver cmo almacenara MySQL los valores de una tabla con una sola columna de tipo CHAR. El tipo CHAR admite el modificador BINARY, que permite determinar si en las consultas se diferenciar entre maysculas y minsculas. Ver un ejemplo ms adelante.

Figura 3.10. Ocupacin de CHAR

VARCHAR: Tiene el mismo rango de longitud que el t i p o CHAR. Sin embargo, si define una columna de veinte caracteres y guarda una cadena de diez, slo se ocuparn esos diez caracteres ms uno para guardar la longitud. Es decir, para una cadena de diez caracteres, u n CHAR ocupara veinte caracteres, mientras que un VARCHAR slo once. La figura 3.11 muestra cmo asignara MySQL el espacio si la nica columna de la tabla mostrada en la figura 3.10 estuviese creada con un tipo VARCHAR. Compare el espacio ocupado por los datos en las figura 3.10 y 3.11. Utilizando CHAR se tienen cinco filas de 14 caracteres cada una, lo que da un resultado de 70 caracteres. Con VARCHAR tendra que sumar el nmero de caracteres de cada fila, en total 38, ms un carcter extra por cada fila; en total, 43 caracteres. Tambin VARCHAR admite el m o d i f i ca d o r BINARY para determinar si se diferenciarn maysculas de minsculas en las consultas.

Figura 3.11. Ocupacin de VARCHAR

Not a: El tipo CHAR ocupa ms espacio, pero la recuperacin de los datos al hacer consultas es ms veloz. Por ejemplo, MySQL sabe que el tercer elemento de la tabla se encuentra tres veces la longitud de la columna a partir del inicio de la tabla.

BINARY: Equivalente al tipo CHAR, con la salvedad de que las cadenas se almacenan en formato binario, no como cadenas de caracteres. No confundir con el tipo de datos CHAR BINARY. VARBINARY: Equivalente al tipo VARCHAR, con la salvedad de que las cadenas se almacenan en formato binario, no como cadenas de caracteres. No confundir con el tipo de datos VARCHAR BINARY. BLOB: Aunque no se trata de un tipo de texto propiamente dicho, es necesario hablar de l porque est ntimamente relacionado con el siguiente, TEXT . El nombre BLOB significa objeto binario de gran tamao (binary large object). Este tipo de columnas puede utilizarse para guardar informacin binaria, como el contenido de un archivo JPG, un archivo comprimido con ZIP, etctera. Y claro est, tambin puede utilizarse para guardar texto cuya longitud est por encima de la permitida por los tipos CHAR o VARCHAR. Las consultas realizadas sobre este tipo de columnas diferenciarn entre maysculas y minsculas, el mismo comportamiento de CHAR y

VARCHAR cuando se utiliza el modificador BINARY. Los tipos TINYBLOB, MEDIUMBLOB y LONGBLOB son BLOB de diferentes tamaos.
Not a: Aunque es posible almacenar imgenes y cualquier archivo binario en un campo de tipo BLOB dentro de una tabla de MySQL, existen otras alternativas, como relacionar de alguna manera un archivo en disco con un registro dentro de una tabla. Por ejemplo, podra guardar la ruta en la que el archivo se encuentra en un campo de tipo VARCHAR, haciendo menor el espacio ocupado por la base de datos.

TEXT: Exactamente igual que un BLOB, con la salvedad de que TEXT no distingue entre maysculas y minsculas en las consultas. Los tipos TINYTEXT , MEDIUMTEXT y LONGTEXT son TEXT de diferentes tamaos. ENUM: La enumeracin es una clase especial de tipo de cadena. Al definir la columna se indican los posibles valores que puede tomar. Posteriormente, en esa columna slo se podr insertar alguno de los valores definidos. Internamente, MySQL sustituye la cadena por un nmero, ahorrando espacio en cada insercin. Enseguida veremos un ejemplo. SET: Similar a ENUM , los conjuntos se diferencian en que se pueden insertar varios de los valores definidos al crear la tabla. Con el ejemplo que veremos en breve quedar ms claro cmo se insertan estos valores. MySQL utiliza un ingenioso sistema para no tener que guardar las cadenas en la base de datos, ahorrando espacio. Cree una nueva tabla llamada texto, la utilizaremos para hacer pruebas con los tipos de texto. Esta tabla estar dentro de la base de datos de pruebas que creamos al principio de este captulo:
USE pruebas;

DROP TABLE IF EXISTS texto; CREATE TABLE texto( cadena VARCHAR(32) );

Inserte algunas cadenas de texto:


USE pruebas;

INSERT INTO texto VALUES('d'); INSERT INTO texto VALUES('a'); INSERT INTO texto VALUES('A'); INSERT INTO texto VALUES('b');

Y realice una consulta a los valores de esa tabla, ordenndolos de forma alfabtica:
USE pruebas;

SELECT *

* FROM texto ORDER BY cadena;

Puede ver el resultado de esta consulta en la figura 3.12.

Figura 3.12. Ordenacin alfabtica

Ahora, repita los pasos anteriores, pero cree la tabla con las siguientes instrucciones:
USE pruebas;

DROP TABLE IF EXISTS texto; CREATE TABLE texto( cadena VARCHAR(32) BINARY );

Vuelva a insertar los mismos valores y, de nuevo, seleccinelos ordenados alfabticamente. Esta vez el resultado ser diferente, como puede verse en la figura 3.13.

Figura 3.13. Otra ordenacin alfabtica

Como puede comprobar, la primera consulta devuelve los registros ordenados alfabticamente, pero no diferencia entre maysculas y minsculas. Ante la duda, se basa en el orden de insercin, razn por la que a aparece antes que A. Sin embargo, el resultado de la segunda consulta s se obtiene diferenciando entre maysculas y minsculas. Por ello A aparece antes que a. Tngalo en cuenta cuando desee obtener listados ordenados alfabticamente. Ahora, un ejemplo de enumeraciones. Suponga que

quiere almacenar en un campo de su base de datos dedicada a pelculas el soporte en el que se encuentran las grabaciones. Como slo dispone de reproductor de vdeo VHS y de DVD le bastar con que la columna tenga esos dos valores. Es posible crear en la base de datos de pruebas una tabla con una columna dedicada al soporte en el que se encuentra la grabacin, de esta manera:
USE pruebas;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula( titulo VARCHAR(64), soporte ENUM( 'VHS', 'DVD' ) );

Puede insertar valores en esa tabla como si de cadenas de texto se tratasen:


USE pruebas;

INSERT INTO pelicula VALUES ('Alien', 'VHS');

INSERT INTO pelicula VALUES ('TRON', 'DVD');

El resultado de una consulta de todos los valores de esta tabla puede verse en la figura 3.14.

Figura 3.14. Enumeracin para soportes de grabacin

MySQL no permite insertar valores que no estn dentro de los definidos al crear la tabla. La siguiente insercin generar un error:
USE pruebas;

INSERT INTO pelicula VALUES( 'Blade Runner', 'VCD' );

Puede ver el mensaje devuelto en la figura 3.15.

Figura 3.15. Insercin que no pertenece a la enumeracin

Aunque puede simplificar mucho trabajo, el uso de enumeraciones no es una buena idea si queremos permitir la insercin de nuevos formatos de grabacin. Si utilizsemos enumeraciones tendramos que modificar las caractersticas de la tabla. En el captulo dedicado al diseo de bases de datos veremos cmo permitir que los formatos de grabacin puedan ser modificados sin cambiar la estructura de la tabla. El tipo de datos SET tambin podra utilizarse en este ejemplo. Suponga que quiere guardar en una columna el gnero al que pertenece una pelcula. Como a veces no es posible encuadrar un ttulo dentro de una nica categora sera interesante poder indicar varas a la vez. Se podra lograr algo similar creando la columna categoria mediante las siguientes rdenes:
USE pruebas;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula( titulo VARCHAR(64), categoria SET( 'ciencia-ficcin', 'terror', 'thriller' ) );

La insercin de registros en una tabla con una columna de tipo SET se realiza de la siguiente manera:
USE pruebas;

INSERT INTO pelicula VALUES( 'Alien', 'ciencia-ficcin,terror' );

INSERT INTO pelicula VALUES( 'Blade Runner', 'ciencia-ficcin,thriller' );

INSERT INTO pelicula VALUES( 'Contact', 'ciencia-ficcin' );

El resultado de una consulta sobre los valores insertados en esta tabla puede verse en la figura 3.16. Las inserciones de valores no existentes en la definicin del campo de tipo SET daran lugar a la insercin de cadenas vacas.

Figura 3.16. Utilizacin del tipo SET

Tipos numricos
MySQL proporciona diferentes tipos de datos para que almacenemos nmeros en las columnas de nuestras tablas. Como existe una gran variedad, es posible seleccionar el tipo de datos ms adecuado para cada caso. No es lo mismo guardar el nmero de veces que se ha visto una pelcula que su precio. La primera cantidad es un nmero entero positivo, mientras que la segunda es decimal. Por cuestiones relacionadas con la forma en la que los programas estn construidos y con el hardware en el que se ejecutan, es ms costoso almacenar y realizar operaciones con nmeros decimales que con nmeros enteros. Se estaran desaprovechando recursos si se utilizase una columna de tipo decimal para almacenar informacin de tipo entero. De igual manera, estaramos perdiendo informacin (y eso puede ser ms grave) si la columna destinada a almacenar el precio de una pelcula fuese de tipo entero, puesto que la parte de la derecha de la coma, la parte decimal, se perdera. Nmeros enteros MySQL proporciona suficiente variedad de tipos para cubrir todas sus necesidades. Existen seis tipos bsicos para almacenar enteros, diferenciados por el rango de valores que pueden contener. Cuanto mayor sea el rango, ms espacio se ocupar en la base de datos. Estos tipos son: TINYINT: El ms pequeo de los enteros, con un rango entre -128 y 127 con signo, o de 0 a 255 sin signo. Ocupa un solo byte. SMALLINT: Oscila entre -32768 y 32767. Si no se

incluye signo, puede ir desde 0 a 65535. Dos bytes de espacio. MEDIUMINT: Con signo desde -8388608 a 8388607. Sin signo desde 0 a 16777215. El espacio consumido es de 3 bytes. INT: El tipo entero ms comn. Puede ir desde 2147483648 a 2147483647 si utiliza signo, o desde 0 hasta 4294967295 si no lo utiliza. Al ocupar 4 bytes est especialmente indicado si desea aprovechar las caractersticas de la mayora de procesadores del mercado de hoy en da. BIGINT: El mayor de los tipos enteros ocupa 8 bytes. Con signo, puede almacenar valores desde 9223372036854775808 hasta 9223372036854775807, mientras que sin signo el rango est entre 0 y 18446744073709551615. Utilice la base de datos creada en el apartado anterior para las pruebas con los tipos de texto. Cree dentro de ella una tabla con un nico campo de tipo INT :
USE pruebas;

DROP TABLE IF EXISTS enteros; CREATE TABLE enteros(entero INT);

La columna entero de la tabla enteros puede almacenar nmeros enteros con signo dentro del rango que se encuentra entre -2147483648 a 2147483647.
Advert encia: Aunque es posible realizar inserciones fuera de ese rango, MySQL recortar el nmero hasta el lmite ms cercano sin avisarnos.

Si quisiese almacenar enteros sin signo en ese campo debera cambiar la tercera lnea, que se encarga de la creacin de la tabla, aadiendo el modificador UNSIGNED, como puede verse a continuacin:
USE pruebas;

DROP TABLE IF EXISTS enteros; CREATE TABLE enteros(entero INT UNSIGNED);

Como puede comprobar, slo se ha aadido el modificador UNSIGNED despus del indicador del tipo de la columna, cambiando as el tipo de datos que la columna podr guardar. Existen otros modificadores que, utilizados de forma conjunta, pueden resultarnos interesantes. Con uno de ellos, ZEROFILL , se le puede indicar a MySQL que rellene con ceros a la izquierda el nmero, hasta los dgitos seleccionados con el segundo modificador. Si se sabe que los valores de una determinada columna no podrn tener ms de 4 dgitos es posible utilizar otro modificador para que los nmeros devueltos siempre ocupen esos 4 dgitos, rellenando con ceros a la izquierda aquellos que ocupen menos.

Puede que un ejemplo sirva para explicar mejor el funcionamiento de ZEROFILL . La siguiente consulta reconstruye la tabla de enteros, cambiando las caractersticas de su nica columna:
USE pruebas;

DROP TABLE IF EXISTS enteros; CREATE TABLE enteros( entero INT(4) UNSIGNED ZEROFILL );

Como ve, el segundo de los modificadores antes mencionado se aade a continuacin del tipo, entre parntesis. Pruebe a insertar algunos valores para despus seleccionarlos, y as ver el efecto que tienen en las consultas. Primero las inserciones:
USE pruebas;

INSERT INTO enteros values(1); INSERT INTO enteros values(10); INSERT INTO enteros values(100); INSERT INTO enteros values(1000);

Y luego la consulta de seleccin:


USE pruebas;

SELECT * FROM enteros;

La figura 3.17 muestra el resultado de esta consulta.

Figura 3.17. Seleccin de valores enteros

Como puede comprobar, el tipo de la columna entero es entero relleno de ceros hasta cuatro dgitos, el 1 aparece como 0001, el 10 como 0010, el 100 como 0100 y el 1000 tal cual. Qu ocurrira si se insertase un valor con ms dgitos de los indicados al crear la tabla? Pruebe:
USE pruebas;

INSERT INTO enteros VALUES(10000);

Como comprobar, MySQL le permite realizar la insercin sin ningn problema: los modificadores aadidos al tipo de la columna entero slo afectan a la forma en la que los datos se presentan al consultarlos. Por cierto, qu se obtendr al consultar ahora los datos de la tabla? Valo en la figura 3.18.

Figura 3.18. Valor con ms dgitos

A aquellos valores que estn por debajo del ancho establecido al definir el tipo del campo se les aadirn ceros por la izquierda, mientras que el resto se mostrarn tal cual.
Advert encia: Desde aqu queremos recomendarle que slo utilice este tipo de modificaciones cuando sea estrictamente necesario. Existen otras formas de dar formato a los nmeros que no pasan por alteraciones en la definicin de las columnas de una tabla. Una regla podra ser: mantenga los datos tal como son, modifique su presentacin en la aplicacin que haga uso de ellos.

Si tiene conocimientos de programacin, habr visto que no se han mencionado otros tipos de datos, como los lgicos o booleanos, al enumerar los tipos existentes. MySQL ofrece diferentes seudnimos para cada tipo de datos. Puesto que un tipo booleano es el que permite diferenciar entre los estados cierto y falso, en un entero de un dgito tendramos ms que suficiente. El tipo BOOLEAN (o BOOL ) es un seudnimo de TINYINT(1). Utilice las constantes TRUE , true, FALSE y false para trabajar con tipos booleanos. De igual forma, existe un seudnimo llamado BIT para trabajar con bits. Tras comentar los tipos enteros, continuaremos repasando los tipos numricos con los tipos decimales. Nmeros en coma flotante Como ya sabr, los nmeros en coma flotante contienen una parte entera y una parte decimal. Esta ltima se utiliza para describir cantidades inferiores a la unidad. El ejemplo ms claro: los precios, en los que la parte entera se refiere a mltiplos de la moneda, y la parte decimal a la moneda fraccionaria. Por ejemplo, si el precio de un DVD es 29,99 euros, en realidad cuesta 30 euros menos un cntimo, no se deje engaar. Pero para lo que interesa ahora mismo, la parte entera es 29 y la parte decimal 99. Los nmeros en coma flotante se llaman as porque se utiliza una coma para separar la parte entera de la decimal. Sin embargo, en la sintaxis de SQL se utiliza un punto como separador. Por ello, al insertar valores en coma flotante stos se escribirn utilizando el punto. De igual manera, en el resultado de las consultas ver el punto como separador. Sin embargo, fuera del contexto de las instrucciones SQL se utilizar la coma como separador.

MySQL proporciona tres tipos bsicos para los nmeros en coma flotante. A mayor precisin, mayor espacio ocupado por el nmero. Como con los nmeros enteros, es posible utilizar ZEROFILL con idnticos resultados. Por el contrario, especificar que se trata de nmeros sin signo utilizando UNSIGNED no proporcionar un rango de valores ms amplio, simplemente se ignorarn los valores negativos. Estos tipos son: FLOAT: Decimal de precisin simple, permite almacenar valores entre -3,402823466E+38 y 1,175494351E-38, y 1,175494351E-38 y 3,402823466E+38, cero incluido. DOUBLE: Decimal de precisin doble, con valores entre -1,7976931348623157E+308 y 2.2250738585072014E-308, y 2,2250738585072014E308 y 1,7976931348623157E+308, incluido el cero. DECIMAL: Los dos tipos vistos anteriormente codifican la informacin del nmero de manera que ocupe lo menos posible, utilizando aproximaciones. Sin embargo, este tipo guarda valores exactos. Aunque el rango de valores que puede almacenar es el mismo que el tipo DOUBLE , el espacio ocupado es bastante mayor. Para estos tres tipos se puede indicar el nmero de dgitos totales para mostrar y el nmero de dgitos decimales, entre parntesis y a la derecha del nombre del tipo. Por ejemplo, con DOUBLE(6, 2) se estara indicando que se quiere una columna que almacene nmeros en coma flotante, con seis dgitos y dos decimales a la derecha de la coma. El rango de valores que se podran almacenar en esta columna estara entre -9999,99 y 9999,99: cuatro dgitos antes de la coma y dos tras ella coma suman seis. Existe una forma alternativa de crear columnas para almacenar valores en coma flotante. Es posible utilizar FLOAT(N), donde N es un valor menor que 53. Si N fuese menor que 25, los valores de la columna se almacenaran con precisin simple, mientras que si N est entre 25 y 53 lo haran con precisin doble. Aprovechando que disponemos de una base de datos para pruebas, cree una nueva tabla en la que experimentar con valores en coma flotante. Para ello, utilice el siguiente cdigo:
USE pruebas;

DROP TABLE IF EXISTS decimales; CREATE TABLE decimales( precio FLOAT(6,2) );

Como vimos anteriormente, se pueden insertar valores entre -9999,99 y 9999,99. Inserte algunos y vea el resultado de una consulta de seleccin:
USE pruebas;

USE pruebas;

INSERT INTO decimales VALUES(29.99); INSERT INTO decimales VALUES(30); INSERT INTO decimales VALUES(199.994); INSERT INTO decimales VALUES(199.995);

SELECT * FROM decimales;

El resultado puede verse en la figura 3.19. El primer valor insertado ha sido 29,99.

Figura 3.19. Insercin de valores en coma flotante

El segundo valor insertado fue 30. MySQL aade automticamente dos ceros a la derecha de la coma, puesto que al crear la tabla se le indic que esa columna tendra dos decimales. Pero qu ha pasado con el tercer valor? Se insert 199,994, pero la consulta muestra 199,99! Esto se debe al redondeo que MySQL ha realizado. Puesto que tiene que almacenar el nmero con 2 decimales, descarta el tercero. Sin embargo, al examinar el cuarto valor insertado se puede comprobar que no se trata simplemente de descartar decimales. MySQL redondea el nmero. Si el dgito decimal a evaluar est entre 0 y 4, lo descarta. Si est entre 5 y 9 suma uno al siguiente decimal. Por eso 199,995 ha pasado a ser 200,00. De lo anterior se puede deducir que es muy importante definir correctamente la precisin de los decimales, ya que MySQL redondea las cifras que se salen de la definicin del tipo de la columna. Para el siguiente ejemplo, cree una nueva tabla:
USE pruebas;

DROP TABLE IF EXISTS decimales2; CREATE TABLE decimales2( precio FLOAT(10,5) );

Inserte un valor:
USE pruebas;

INSERT INTO decimales2 VALUES(3835.38000);

Ahora, vea lo que se ha insertado en la tabla:


USE pruebas;

SELECT * FROM decimales2;

Como puede comprobar en la figura 3.20, el valor mostrado en la consulta no es el mismo que se insert. Esto se debe a que, internamente, MySQL utiliza precisin doble para los clculos en coma flotante. Si utiliza columnas cuyo tipo sea de precisin sencilla es posible que experimente problemas al realizar clculos, por ejemplo la aparicin de decimales que no ha indicado, como acaba de ver. Por ello, si experimenta problemas de esta ndole, es recomendable que utilice el tipo DOUBLE para almacenar valores en coma flotante.

Figura 3.20. Problemas de redondeo

Como ha podido comprobar, con los tipos numricos que MySQL pone a nuestra disposicin debera tener suficiente para cubrir la mayora de sus necesidades. MySQL ofrece seudnimos de los tipos aqu presentados. Estos seudnimos no son ms que tipos bsicos cuyas caractersticas se han modificado, o simples nombres alternativos. Ya vio el tipo BOOL como ejemplo al hablar de los enteros.

Fechas y horas
MySQL permite utilizar los siguientes tipos de datos para almacenar valores relacionados con el tiempo, como fechas y horas: DATE: Permite almacenar fechas con el formato AAAA-MM-DD (ao, mes y da), entre 1000-01-01 y 9999-12-31. TIME: Para guardar horas con el formato hh:mm:ss (horas, minutos y segundos) entre -838:59:59 y 838:59:59. Especialmente indicado para almacenar tiempos transcurridos entre dos eventos. DATETIME: Combinacin de los dos tipos anteriores, primero la fecha y luego la hora. El formato de este tipo es AAAA-MM-DD hh:mm:ss. El rango permitido para la parte de la fecha es el mismo que para el tipo DATE , pero la parte de la hora debe estar entre 00:00:00 y 23:59:59. Permite almacenar la fecha y la hora de un determinado instante.

determinado instante. YEAR: Un ao indicado con dos o cuatro dgitos, dependiendo del valor del modificador. Si utiliza dos dgitos, el valor almacenado puede estar entre 1970 y 2069, mientras que con cuatro dgitos est entre 1901 y 2155. Adems se puede almacenar el ao 0000. TIMESTAMP: Tipo de datos un poco conflictivo. Su comportamiento vara dependiendo de la versin de MySQL que se utilice. En lneas generales, se puede decir que una columna de este tipo debera cambiar su valor cada vez que se produzca una insercin o una actualizacin en el registro. De esta forma se puede controlar cundo se cre un registro o cundo cambi su valor. El siguiente es un ejemplo de funcionamiento del tipo TIMESTAMP . Lo utilizaremos para saber la fecha de la ltima modificacin de un determinado registro. Vuelva a crear la tabla pelicula de la base de datos de pruebas para este ejemplo:
USE pruebas;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula( titulo VARCHAR(64), modificado TIMESTAMP );

Realice una insercin en esta tabla:


USE pruebas;

INSERT INTO pelicula(titulo) VALUES('Alieni');

Al consultar los registros de esta tabla ver que se ha insertado un valor en el campo modificado, aunque no incluy ninguno en la insercin. Puede comprobarlo en la figura 3.21.

Figura 3.21. Contenido de una columna TIMESTAMP

La columna modificado contiene la fecha y la hora en la que se realiz la insercin. Vaya, se ha cometido un error! El ttulo de la pelcula es incorrecto. Solucinelo:
USE pruebas;

UPDATE pelicula SET titulo = 'Alien'

titulo = 'Alien' WHERE titulo = 'Alieni';

La figura 3.22 muestra el resultado de una consulta sobre la tabla tras la actualizacin de la columna errnea. Como puede ver, el valor de la columna modificado representa ahora un instante posterior al que poda verse en la figura 3.21, aunque de nuevo no se ha indicado valor alguno para esa columna.

Figura 3.22. TIMESTAMP cambia automticamente

El repaso a los tipos de datos que MySQL permite utilizar en sus tablas ha concluido. Si desea ms informacin sobre los tipos de datos no dude en acudir a la documentacin de MySQL, disponible en la siguiente pgina Web: http://dev.mysql.com/doc/mysql/en/column-types.html

PHP orientado a objetos


Nuestro tercer encuentro con PHP lo hacemos con bastante ventaja, conociendo las bases del lenguaje y habiendo programado varios ejemplos. Ahora tenemos mucho ms claro qu podemos esperar de una herramienta como sta. Durante este captulo, el ltimo dedicado al aprendizaje de PHP, ver cmo debe escribir sus programas para que ese trabajo pueda aprovecharse con posterioridad. Para lograrlo tiene varias opciones. La primera de ellas consiste en agrupar fragmentos de cdigo en unidades funcionales o funciones. Estas funciones pueden ser invocadas con solo una lnea de cdigo, quedando oculto el verdadero trabajo que estn realizando, ya que slo nos interesa el resultado de utilizar la funcin. Otra manera de lograr el mismo objetivo consiste en situar todo el cdigo PHP comn en archivos independientes. Luego podr incluir el cdigo de esos archivos en sus programas, sin necesidad de volver a escribirlo varias veces. Por supuesto, puede combinar el uso de funciones con los archivos externos anteriormente descritos. La mayora de los cambios que la versin 5 introdujo afectaban a la programacin orientada a objetos. Veremos qu es esta forma de programacin, tal y como la entiende PHP y, de nuevo, cmo podemos aprovecharla para que no tengamos que escribir el mismo cdigo dos veces. Preste especial atencin a este captulo para poder sacar el mximo partido a la versin orientada a objetos de la nueva interfaz de acceso a MySQL.

Funciones
Una funcin es un fragmento de cdigo agrupado bajo un mismo nombre, que tiene este aspecto:
function nombre ([lista de parmetros]){ instrucciones }

El nombre de la funcin debe seguir las mismas reglas que mencionamos en el captulo 2 para los nombres de las variables.
Not a: La lista de parmetros de la funcin aparece entre corchetes, lo que indica que su definicin es opcional. Es decir, puede crear funciones que no reciban ningn parmetro.

Ya hemos utilizado funciones con anterioridad. Por ejemplo, printf() en el captulo 2. Esta funcin puede recibir como argumento una cadena de texto que ser mostrada en el cliente Web cuando se vea la pgina. Internamente, esa funcin realiza una serie de operaciones que no es necesario que conozca. Lo nico que le interesa es saber que la cadena que pase como parmetro a la funcin se le mostrar al usuario.

Parmetros
La declaracin de la lista de parmetros que una funcin recibe es similar a la declaracin de variables. De hecho, dentro de la funcin esos parmetros se utilizarn como si de variables se tratasen, por lo que sus nombres deben seguir las mismas reglas que definimos en el segundo captulo. Para declarar ms de un parmetro ha de separarlos mediante comas. Veamos un sencillo ejemplo. Vamos a crear una funcin que reciba como parmetro un nmero entero y escriba en la pgina Web si el nmero es par o impar. Su cdigo es el siguiente:
function par_impar($numero){ if($numero % 2 == 0){ print('par'); }else{ print('impar'); } }

El nombre de esta funcin es par_impar(). La funcin recibe un solo argumento, $numero. En el cuerpo de la funcin utilizamos una instruccin condicional. La condicin es que el resto de dividir el nmero pasado como argumento entre dos sea cero. Si lo es, escribimos par, en caso contrario, impar. A continuacin puede ver el cdigo de una pgina PHP en la que se define y utiliza la funcin anterior:
<?php function par_impar($numero){ if($numero % 2 == 0){ printf('par'); }else{ print('impar'); } } par_impar(7); ?>

Not a: El operador utilizado en la funcin par_impar() devuelve el resto de dividir los dos operandos, en este caso $numero y dos. Si el resto de dividir un nmero entre dos es cero, significa que ese nmero es par.

El resultado: una pgina que muestra el texto impar.

Slo tiene que cambiar el valor que se pasa por un nmero par (digamos seis) para que la pgina resultante muestre el texto par . Valor y referencia La funcin par_impar() recibe un nmero como parmetro, comprueba que el valor sea par o impar y escribe un mensaje. El valor recibido no sufre alteracin. Pero qu pasara si lo modificsemos? Fjese en el siguiente cdigo, no lo escriba en una pgina para probarlo:
<?php function incrementar($numero){ $numero++; } $i = 7; incrementar($i); print($i); ?>

Qu pasar, qu valor mostrar una pgina con este cdigo? Claro, si se lo estamos preguntando ser porque no es obvio. Tiene razn. Podra suponer que la pgina resultante mostrar el nmero ocho, resultado de incrementar el parmetro de la funcin. La realidad es otra: se muestra el nmero siete. PHP permite que los parmetros de una funcin se pasen de dos formas: por valor y por referencia. Un parmetro se pasa por valor de forma predeterminada, sin necesidad de hacer nada ms, como en nuestra funcin incrementar(). En realidad, a la funcin le estamos pasando una copia de la variable $i. Cualquier modificacin que hagamos a dicha variable se perder al terminar la funcin. Si quiere que los parmetros que pase a la funcin puedan ser modificados y que esos cambios sobrevivan a la llamada de la funcin, ha de indicarle a PHP que ese parmetro se va a pasar por referencia. Entonces, en lugar de pasar una copia de la variable, PHP pasar la variable en s misma. Para lograrlo, debe volver a escribir la funcin aadiendo un ampersand (&) al argumento en la definicin de la funcin de la siguiente forma:
function incrementar(&$numero){ $numero++; }

Not a: En la mayora de los casos, nuestras funciones no necesitan modificar los valores de los parmetros que recibe. Utilice esta tcnica slo cuando tenga soltura con la programacin en PHP. Si desea que su funcin devuelva algn valor, consulte el apartado Devolucin de valores, ms adelante.

Parmetros predeterminados

PHP nos permite determinar qu valor debe tener un parmetro si al llamar a una funcin dicho parmetro no se ha proporcionado. Se tratara de este caso:
<?php function par_impar($numero){ if($numero % 2 == 0){ printf('par'); }else{ print('impar'); } } par_impar(); ?>

Si intenta cargar la pgina anterior, PHP le avisar que no se ha pasado argumento alguno a la funcin par_impar(), como puede verse en la figura 4.1. Sin embargo, al tratarse de un aviso (o warning), el cdigo de la pgina se ejecutar. Puede comprobarlo porque al final de la misma puede leerse el texto par. Efectivamente, el resto de dividir cero entre cero es cero, por lo que la funcin determina que el nmero pasado como parmetro es par.

Figura 4.1. Aviso de PHP

Not a: En el mensaje de aviso puede verse la ruta en la que se encuentran las pginas. La carpeta en la que est instalado Apache en su ordenador puede ser otra.

Es muy sencillo evitar el aviso anterior. Slo tiene que especificar el valor predeterminado del parmetro, que es el valor que toma cuando ese parmetro no se pasa:
function par_impar($numero = 0){ if($numero % 2 == 0){ printf('par'); }else{ print('impar'); } }

El comportamiento de la funcin es idntico al que tena antes, con la salvedad de que no se produce ningn aviso. Argumentos variables Como hemos comentado, puede crear funciones que acepten ms de un parmetro. Pero PHP ofrece una posibilidad muy interesante: crear funciones que aceptan

un nmero variable de parmetros. Para ello, ha de crear una funcin sin parmetro alguno y luego ayudarse de las funciones de PHP func_num_args(), func_get_arg() y func_get_args(). La primera de estas funciones devuelve el nmero de argumentos que la funcin ha recibido, la segunda un argumento en concreto de la lista de argumentos y la tercera una matriz con todos los argumentos que se han pasado a la funcin. Gracias al uso de estas funciones podr crear con mucha facilidad una funcin que reciba una lista de valores y muestre en la pgina el resultado de sumarlos todos:
<?php function sumatorio(){ $parametros = func_num_args(); for($i = 0; $i < $parametros; $i++){ $resultado += func_get_arg($i); } printf($resultado); } sumatorio(3, 14, 15); ?>

La funcin sumatorio(), en primer lugar, guarda en la variable $parametros el nmero de argumentos que ha recibido. Despus, usando un bucle for recupera uno por uno el valor de los parmetros y los suma. Para terminar, muestra el resultado. En este ejemplo, 32. Utilizando la funcin func_get_args(), que devuelve una matriz con todos los argumentos y el bucle foreach podemos simplificar bastante el cdigo:
<?php function sumatorio(){ foreach(func_get_args() as $parametro){ $resultado += $parametro; } printf($resultado); } sumatorio(3, 14, 15); ?>

Como recordar, la instruccin foreach permite iterar por todos los elementos de una determinada matriz. La variable $parametro contendr en cada iteracin un elemento diferente de la matriz. Al finalizar todas las iteraciones, $resultado contendr la suma de todos los argumentos pasados a la funcin. El resultado ser idntico tanto usando un bucle for como usando un bucle foreach. La diferencia est en que el cdigo del segundo es mucho ms simple. Un momento! Vamos a parar un momento. Qu es eso de que la funcin func_get_arg() devuelve una matriz?

Cmo puedo hacer para que mis funciones devuelvan valores?

Devolucin de valores
Nada ms fcil que conseguir que una funcin escrita por usted devuelva un valor. Slo ha de utilizar la instruccin return. A continuacin de ella indique el valor que la funcin debe devolver. En ese punto la funcin terminar, devolviendo el valor que ha indicado al cdigo que la llam. Por ejemplo, puede cambiar el cdigo de la funcin par_impar() que construimos anteriormente. Ahora la funcin devolver TRUE si el nmero pasado es par y FALSE en caso contrario:
function par_impar($numero){ if($numero % 2 == 0){ return(TRUE); }else{ return(FALSE); } }

De esta forma, cedemos la decisin de escribir un texto en la pgina Web resultante al cdigo que llama a la funcin, en lugar de hacerlo directamente desde dentro de ella. El cdigo completo del programa podra ser el siguiente:
<?php function par_impar($numero){ if($numero % 2 == 0){ return(TRUE); }else{ return(FALSE); } } if(par_impar(7) == TRUE){ print('par'); }else{ print('impar'); } ?>

Trabajando con funciones


Hasta ahora, en este libro hemos tenido dos contactos con PHP. En el primer captulo fue un encontronazo, slo nos interesaba tener una visin de conjunto de las posibilidades que MySQL y PHP ofrecan. El segundo, ms sosegado, nos permiti aprender las principales reglas del lenguaje. Vamos a quedarnos con el primer captulo. Si recuerda, construimos un pequeo programa para mostrar los gneros cinematogrficos que se encontrasen almacenados dentro de la tabla genero de la base de datos videoteca. Fue entonces cuando comprobamos que, al aadir nuevos registros a dicha tabla, el contenido de la

al aadir nuevos registros a dicha tabla, el contenido de la pgina Web cambiaba sin necesidad de modificar el cdigo PHP. Por si acaso se salt el primer captulo, resumiremos. Ejecute el siguiente cdigo SQL para crear la base de datos videoteca y la tabla genero e insertar los valores iniciales:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca;

USE videoteca;

CREATE TABLE genero ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, nombre VARCHAR(2) NOT NULL, descripcion VARCHAR(32) NOT NULL, PRIMARY KEY(id) );

INSERT INTO genero(nombre, descripcion) VALUES('CF', 'Ciencia Ficcin');

INSERT INTO genero(nombre, descripcion) VALUES('A', 'Aventuras'); INSERT INTO genero(nombre, descripcion) VALUES('D', 'Drama'); INSERT INTO genero(nombre, descripcion) VALUES('T', 'Terror');

La versin final del cdigo de dicha pgina es el siguiente:


<?php $conexion = mysqli_connect( 'localhost', 'root', '', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); } $res = mysqli_query( $conexion, 'SELECT * FROM genero' ); if ($res == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); } ?>

<table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcion</th> </tr> <?php while($fila = mysqli_fetch_row($res)){ printf('<tr>'); printf( "<td>%u</td><td>%s</td><td>%s</td>", $fila[0], $fila[1], $fila[2] ); printf('</tr>'); } ?> </table>

<?php mysqli_free_result($res); mysqli_close($conexion); ?>

La figura 4.2 muestra el resultado de ejecutar el cdigo PHP anterior.

Figura 4.2. Lista de gneros

Si se fija en el listado de la pgina podr comprobar que el cdigo PHP est muy mezclado con el cdigo HTML. Ha sido necesario escapar de PHP en varias ocasiones. No sera mucho ms cmodo disponer de todo el cdigo que se encarga de obtener el listado de gneros agrupado? Un primer intento podra consistir en situar todo lo relacionado con MySQL al comienzo del programa. Puede cambiar el comportamiento del bucle while, para que cree una cadena de texto a partir de los resultados obtenidos al realizar la consulta. A continuacin escaparamos de PHP. Slo tenemos que volver a PHP desde HTML para escribir la cadena que contiene el listado de gneros. Podra ser algo as:
<?php $conexion = mysqli_connect( 'localhost',

'root', '', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); }

$res = mysqli_query( $conexion, 'SELECT * FROM genero' );

if ($res == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); }

while($fila = mysqli_fetch_row($res)){ $generos .= '<tr>'; $generos .= sprintf( "<td>%u</td><td>%s</td><td>%s</td>", $fila[0], $fila[1], $fila[2] ); $generos .= sprintf('</tr>'); }

mysqli_free_result($res); mysqli_close($conexion); ?>

<table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcion</th> </tr> <?php print($generos); ?> </table>

El resultado es el mismo que puede verse en la figura 4.2, aunque el cdigo est algo ms ordenado, con dos bloques: uno con PHP y otro con HTML. Y qu nos impide ubicar todo el cdigo PHP en una nica funcin, que devuelva como resultado una cadena de texto con todos los gneros cinematogrficos en filas para insertar en una tabla? Por ejemplo, as:
<?php function cargar_generos(){

function cargar_generos(){ $conexion = mysqli_connect( 'localhost', 'root', '', 'videoteca' ); if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); } $res = mysqli_query( $conexion, 'SELECT * FROM genero' ); if ($res == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); } while($fila = mysqli_fetch_row($res)){ $generos .= '<tr>'; $generos .= sprintf( "<td>%u</td><td>%s</td><td>%s</td>", $fila[0], $fila[1], $fila[2] ); $generos .= sprintf('</tr>'); }

mysqli_free_result($res); mysqli_close($conexion); return $generos; } ?>

<table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcion</th> </tr> <?php print(cargar_generos()); ?> </table>

Not a: Queda como ejercicio para el lector conseguir que la funcin cargar_generos() devuelva una cadena con toda la tabla en formato HTML, en lugar de devolver slo las filas.

Hemos conseguido colocar en una funcin todo el cdigo necesario para cargar el listado de gneros cinematogrficos. Puede cargar ese listado todas las veces que quiera llamando a la funcin varias veces.

Ahora bien, si quiere escribir otra pgina diferente, que tambin muestre el listado de gneros tendr que escribir de nuevo el cdigo de la funcin. Aunque existe una forma de ahorrarse ese trabajo.

Inclusin de archivos
Vamos a crear un nuevo archivo PHP cuyo contenido ser nica y exclusivamente la funcin de carga de gneros que acabamos de crear. Ese archivo podra llamarse generos.php:
<?php function cargar_generos(){ $conexion = mysqli_connect( 'localhost', 'root', '', 'videoteca' ); if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); } $res = mysqli_query( $conexion, 'SELECT * FROM genero' ); if ($res == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); } while($fila = mysqli_fetch_row($res)){ $generos .= '<tr>'; $generos .= sprintf( "<td>%u</td><td>%s</td><td>%s</td>", $fila[0], $fila[1], $fila[2] ); $generos .= sprintf('</tr>'); }

mysqli_free_result($res); mysqli_close($conexion); return $generos; } ?>

A continuacin, crearemos un segundo archivo PHP con el siguiente contenido:


<?php include('generos.php'); ?> <table border="1">

<table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcion</th> </tr> <?php print(cargar_generos()); ?> </table>

Ambos archivos deben estar en la misma carpeta. Podr comprobar que, al cargar la segunda pgina, obtendr el mismo resultado que pudo verse en la figura 4.2. Sin embargo, el cdigo de esta segunda pgina es considerablemente menor que el que se utiliz anteriormente. Cuando PHP analiza el archivo para saber qu tiene que hacer cuando alguien le pide esa pgina, encuentra la instruccin include. Entonces busca el archivo indicado a continuacin y lo incluye en la pgina actual, como si efectivamente ambos fragmentos de cdigo fuesen parte de la misma pgina. Qu ocurre si el archivo que se intenta incluir no existe? PHP nos avisar de ello, pero an as intentar ejecutar el cdigo del resto de la pgina. Si quiere evitar que el resto de la pgina se siga ejecutando, puede utilizar la instruccin requiere, que s provoca un error. Puede ver un error de este tipo en la figura 4.3.

Figura 4.3. Archivo no encontrado

Not a: Si desea incluir un determinado archivo slo una vez dentro del contexto de una misma pgina utilice include_once(). Tambin existe require_once(). Las diferencias entre estas dos son las mismas que entre include() y require().

Ha aprendido a reutilizar el cdigo mediante funciones, guardando esas funciones en archivos independientes que luego pueden ser incluidos en otros archivos PHP. Un paso ms all est la programacin orientada a objetos, que tambin permite reutilizar cdigo pero que proporciona otras ventajas que veremos a continuacin.

Orientacin a objetos

Ros de tinta han corrido hablando de la programacin orientada a objetos, tan de moda durante mucho tiempo como XML lo est siendo ahora. La versin de PHP 5 incorpor muchas novedades, pero la mayora de ellas en lo referido a la orientacin a objetos. Sera muy pretencioso por nuestra parte intentar exponer todas esas novedades con el espacio del que disponemos, de manera que vamos a limitarnos a sentar las bases necesarias para que esta metodologa de programacin no le sea desconocida. La programacin orientada a objetos tiene como finalidad una mejor organizacin de cdigo y su posible reutilizacin. Para lograrlo hemos de intentar localizar las diferentes entidades con las que trabajamos en nuestros programas y aislarlas. Por ejemplo, los programas anteriores mostraban la lista de categoras disponibles. Podramos intentar escribir un programa cuyo resultado fuese el mismo, pero utilizando orientacin a objetos. Qu es un objeto? Un ejemplar de una clase. Y una clase, qu es una clase?

Clases
Podemos definir una clase como la plantilla utilizada para crear un objeto. En una clase se definen las propiedades y los mtodos de los objetos creados a partir de ella. Las propiedades de una clase describen su aspecto mientras que los mtodos se corresponden con su comportamiento. Intentemos crear una clase que represente a los gneros cinematogrficos almacenados en la base de datos. Las propiedades pueden ser de escritura, de lectura o de ambos tipos, dependiendo de si puede asignarles valores o no. Qu puede ser "el aspecto" de la lista de gneros? Por ejemplo, su ordenacin. Una propiedad de la clase para los gneros podra determinar si el resultado se debe ordenar alfabticamente o no. En cuanto al comportamiento, lo tenemos fcil: necesitamos poder pedir a la clase de gneros que cargue los gneros de la base de datos. El resultado de esta operacin ser una cadena de texto con las filas en formato HTML, como la devuelta por la funcin cargar_generos(). La figura 4.4 muestra una posible representacin grfica de una clase. A la izquierda de la caja, los mtodos de la clase, a la derecha sus propiedades. Una flecha de entrada indica si la propiedad es de lectura, una de salida si es de escritura. Si un mtodo devuelve un valor, la flecha ser de salida.

Figura 4.4. Diagrama de una clase

Este diagrama describe a la clase perfectamente. La propiedad Ordenada es de escritura, mientras que el mtodo Cargar() devuelve un valor. El nombre de la clase es clsGeneros. Slo nos queda crear la clase. Para ellos vamos a utilizar un archivo que luego incluiremos en las pginas PHP que vayan a utilizar esta clase. El archivo se llamar generos.cls.php. El mtodo Cargar() ser similar a la funcin cargar_generos(). Este mtodo devuelve una cadena de texto que contiene todos los gneros de la base de datos. La propiedad Ordenada ser de tipo booleano, de forma que podr asignarle valores TRUE o FALSE . Si le asigna TRUE el resultado de llamar al mtodo Cargar() estar ordenado alfabticamente. En caso contrario, el resultado se mostrar tal cual est en la base de datos, sin ordenacin de ningn tipo.
Not a: Si desea ms informacin sobre consultas SQL consulte el captulo 6, que est dedicado a ello.

Por tanto, el contenido del archivo generos.cls.php podra ser el siguiente:


<?php class clsGeneros{ var $Ordenada = False;

function Cargar(){ $conexion = mysqli_connect( 'localhost', 'root', '', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); }

if($this->Ordenada == TRUE){

$res = mysqli_query( $conexion, 'SELECT * FROM genero '. 'ORDER BY nombre' ); }else{ $res = mysqli_query( $conexion, 'SELECT * FROM genero' ); } if ($res == FALSE){ echo('Error en la consulta.'); mysqli_close($conexion); exit(); } while($fila=mysqli_fetch_row($res)){ $generos .= '<tr>'; $generos .= sprintf( "<td>%u</td><td>%s</td><td>%s</td>", $fila[0], $fila[1], $fila[2] ); $generos .= sprintf('</tr>'); }

mysqli_free_result($res); mysqli_close($conexion);

return $generos; } }

?>

Como puede verse en el cdigo anterior, comenzamos la declaracin de la clase con la palabra reservada class. A continuacin, definimos el nombre de la clase: clsGeneros. El prefijo sirve para indicar que se trata de una clase. El cdigo de la clase est entre llaves. Dentro de una clase puede definir variables, como $Ordenada, cuyo valor predeterminado es FALSE . Esta variable es una de las propiedades de la clase. Es necesario utilizar la palabra reservada var antes de declarar una variable propia de una clase. El cdigo del mtodo Cargar() es como el de la funcin cargar_generos(), con la que hemos estado trabajando anteriormente, con una salvedad: la consulta que obtiene los gneros de la base de datos es diferente, dependiendo del valor que tenga $Ordenada, estando el resultado ordenado por nombre si su valor es TRUE .
Not a: PHP proporciona un objeto especial llamado $t his, que permite acceder a las propiedades y mtodos de una clase desde el cdigo de la propia clase.

Piense en esta clase como en una plantilla. La clase por s misma no hace nada, pero si crea en su programa una variable cuyo tipo sea la clase tendr acceso a toda la funcionalidad definida en dicha clase. Veamos un ejemplo:
<?php require('generos.cls.php');

$oGeneros = new clsGeneros; $oGeneros->Ordenada = TRUE; $sGeneros = $oGeneros->Cargar(); ?>

<table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcin</th> </tr> <?php print($sGeneros); ?> </table>

Nuestra pgina comienza incluyendo aquella en la que se encuentra el cdigo de definicin de la clase. Fjese en que utilizamos require en lugar de include, ya que dicha pgina es imprescindible para la ejecucin de sta. Cuando declaramos una variable cuyo tipo es una determinada clase se dice que estamos creando un ejemplar de esa clase. La clase es la plantilla, el ejemplar de la clase es el objeto. Para crear dicho ejemplar hemos de utilizar la palabra reserva new:
$oGeneros = new clsGeneros;

Es decir, esta lnea crea un nuevo ejemplar de la clase clsGeneros y lo asigna (lo guarda) en la variable $oGeneros. El prefijo o viene de objeto. Una vez tenga el objeto necesita acceder a sus propiedades para modificar su comportamiento y realizar tareas mediante sus mtodos. Para ello ha de utilizar los caracteres -> a continuacin del nombre del objeto, y tras estos caracteres, el nombre de la propiedad o el mtodo que quiere utilizar. En el programa anterior modificamos el valor de la propiedad Ordenada as:
$oGeneros->Ordenada = TRUE;

Y llamamos al mtodo de carga de los gneros as:


$sGeneros = $oGeneros->Cargar();

El resultado de este programa es similar al que pudimos ver en la figura 4.2, pero la ordenacin es diferente. Puede comprobarlo en la figura 4.5.

Figura 4.5. Gneros ordenados por nombre

Puede crear tantos ejemplares de la clase clsGeneros como necesite, y cada uno de ellos tendr sus propias propiedades. El siguiente cdigo es perfectamente vlido:
<?php require('generos.cls.php');

$oGeneros1 = new clsGeneros; $oGeneros2 = new clsGeneros;

$oGeneros1->Ordenada = TRUE; $oGeneros2->Ordenada = FALSE;

$sGeneros1 = $oGeneros1->Cargar(); $sGeneros2 = $oGeneros2->Cargar(); ?>

<table><tr><td> <table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcin</th> </tr>

<?php print($sGeneros1); ?>

</table> </td><td> <table border="1"> <tr> <th>id</th> <th>nombre</th> <th>descripcin</th> </tr>

<?php print($sGeneros2); ?>

</table>

</table> </td></tr></table>

Como resultado de cargar esta pgina obtendr dos tablas, la primera mostrar la lista de gneros ordenados por nombre, mientras que la segunda no. Puede verlo en la figura 4.6.

Figura 4.6. Con y sin orden

En la definicin de la clase asigne un valor inicial a la propiedad $Ordenada. Esa operacin puede realizarse de otra manera: utilizando un constructor. Constructores Dentro de una clase, el constructor es un mtodo especial que se ejecuta siempre que se crea un ejemplar de dicha clase. El nombre de ese mtodo especial debe ser el mismo que el de la clase. Si aade el siguiente mtodo al cdigo de la clase clsGeneros tendr su constructor. Hgalo justo debajo de la definicin del mtodo de carga:
var $Ordenada; ... function clsGeneros(){ $this->Ordenada = TRUE; }

Hemos trasladado la asignacin de un valor inicial a $Ordenada al constructor de la clase. Ahora, el comportamiento predeterminado del mtodo de carga ser devolver la lista de gneros ordenada. Como si de un mtodo normal y corriente se tratase, es posible definir una lista de argumentos que el constructor puede recibir. Sera interesante que recibiese si quiere o no la lista de gneros ordenada:
function clsGeneros($fOrdenada){ $this->Ordenada = $fOrdenada; }

Al crear el ejemplar de la clase indicaremos si queremos ordenacin o no:


$oGeneros = new clsGeneros(TRUE);

Ms all de las clases

Con lo visto en este captulo sobre las clases en PHP no hemos hecho ms que descubrir la punta del iceberg. En el tintero hemos dejado algunas de las caractersticas ms aplaudidas de la programacin orientada a objetos: encapsulacin, herencia y polimorfismo. De hecho, son estas tres caractersticas las que diferencian este sistema de programacin de otros. La encapsulacin, en la jerga de los programadores, es la capacidad de ocultar las interioridades de las clases a aquellos que las usan. Sin ir ms lejos, el mtodo de carga de la clase clsGeneros utiliza la interfaz mejorada de acceso a MySQL pero, si alguien utiliza esa clase para acceder al listado de gneros, debera saber que esos gneros estn en una base de datos? No necesariamente. Al usuario le basta con saber que cuando crea un ejemplar de la clase y llama a su mtodo de carga obtiene la lista de gneros. Si ms adelante, el programador de clsGeneros decide que el listado de gneros se debe obtener utilizando otra interfaz de acceso a datos, mientras mantenga el mismo sistema para obtenerlos, aquellos programas que utilicen esa clase no debern ser modificados. La programacin orientada a objetos busca smiles entre el mundo real y el de la programacin para simplificar la creacin y el mantenimiento de programas. La herencia es otro smil, muy prximo al significado de esta palabra en el mundo real. Puede crear una clase con unas determinadas caractersticas y, posteriormente, otra que herede de la primera. La clase heredera tendr todas las caractersticas de la primera pero podr incorporar novedades, lo que le ahorrar mucho trabajo. Por ltimo, el polimorfismo permite tratar clases de diferente tipo como si fuesen del mismo, algo que puede ser de gran utilidad en determinadas circunstancias. No nos extenderemos ms para hablar de estas caractersticas de la programacin orientada a objetos, algo que queda fuera de los objetivos de este libro. Sin embargo, queremos que conozca de su existencia y le recomendamos que busque ms informacin al respecto, ya que sus programas pueden beneficiarse enormemente de ellas.

Diseo de bases de datos


Por lo general, creamos bases de datos para poder extraer de ellas posteriormente todo tipo de informacin til. Pero los datos no deben guardarse de cualquier manera, hemos de buscar el mayor aprovechamiento de los recursos disponibles, tanto de espacio como de rendimiento. La consistencia de los datos ha de mantenerse durante todo el ciclo de vida de la base de datos, sobre todo si sta vaya a utilizarse en aplicaciones crticas, como las destinadas a emitir las nminas de los empleados de una empresa. Si los datos almacenados no mantuviesen la consistencia alguien podra acabar no cobrando este mes. El primer paso en la creacin de una base de datos es el anlisis del sistema que servir de modelo, la observacin de todos los elementos que lo componen y su descomposicin en partes ms pequeas. Tras el anlisis, procederemos con el diseo de la base de datos. Un diseo correcto puede ser crucial, de manera que debe dedicarle todo el tiempo necesario hasta estar completamente seguro de que no existan incongruencias y todos los aspectos del sistema estn reflejados en la base datos. Durante este captulo recorreremos todos los pasos que deben darse para dar vida a una base de datos, desde la idea inicial hasta su creacin, pasando por los pasos intermedios necesarios. Veremos qu herramientas estn a nuestra disposicin, tanto las conceptuales como los programas. Al terminar dispondremos de un diseo completo de la base de datos que utilizar como ejemplo durante el resto de captulos.

El ejemplo
En el captulo 3 se utiliz como ejemplo una pequea base de datos que contena una nica tabla en la que se almacenaban slo tres datos de cada pelcula de una videoteca: el ttulo, el nombre del director y el de uno de sus intrpretes. La figura 5.1 muestra el diseo que se hizo de dicha tabla.

Figura 5.1. Primer diseo del ejemplo

En esta tabla se pueden guardar perfectamente los datos de todas las pelculas que desee, aunque no sin

limitaciones. De hecho, se trata de una base de datos algo limitada... bueno, muy limitada. Bah, para qu engaarnos! La primera versin de la base de datos de ejemplo no sirve para nada. Se podra conseguir lo mismo usando una hoja de clculo creada con Excel, Gnumeric o Numbers. Al menos sirvi para su propsito: una primera toma de contacto con el servidor de bases de datos MySQL.

Limitaciones
La primera versin de la base de datos de ejemplo es demasiado simple. Slo se puede guardar el nombre de uno de los intrpretes de la pelcula, aunque sera mucho ms interesante tener los nombres de tantos actores relacionados con un ttulo en concreto como se quisiese. Y aunque no es muy frecuente, existen algunas pelculas con ms de un director. Tampoco se guarda detalle alguno sobre la duracin de la pelcula, su fecha de estreno, sus productores, guionistas, es decir, su ficha tcnica. Ni se pueden conocer detalles relativos a una copia de la pelcula en particular, como si el formato es VHS o DVD, o si se ha prestado, la opinin que le merece o les mereci a otros, etctera. Por otra parte, en esta primera versin, cada vez que se guarda una pelcula se han de guardar los datos del director y del actor, incluso si con anterioridad exista algn registro con el mismo actor o director. Quiz los datos podran estar mejor organizados.

Objetivos
Antes de disear de nuevo el ejemplo es necesario dar otros pasos. En primer lugar, debemos conocer las herramientas que tenemos a nuestra disposicin para la creacin de bases de datos. Por herramientas no slo nos referimos a los programas, tambin a otras de tipo conceptual de las que daremos buena cuenta durante este captulo. En la parte de los programas veremos cmo utilizar MySQL Workbench. Esta aplicacin le ayudar en la fase de diseo de bases de datos y en su posterior puesta en marcha, ya que genera de forma automtica el cdigo SQL necesario para la creacin de bases de datos y tablas. Se trata de un programa de cdigo abierto que se distribuye bajo licencia GPL, creado por la empresa detrs de MySQL sobre las cenizas de DBDesigner .
Not a: Aunque en el momento de escribir estas lneas las versiones para Mac OS X y Linux estn en fase alfa, el equipo de desarrollo de MySQL Workbench se ha comprometido a lanzarla en las tres plataformas.

En cuanto a las herramientas conceptuales, primero veremos algunos conceptos que no se han tratado an. Es el caso del modelo relacional, imprescindible como ayuda para mantener la integridad de los datos. El captulo

terminar con algunas indicaciones sobre los pasos a seguir para que las bases de datos puedan almacenar los datos de forma inequvoca.

MySQL Workbench
Segn las propias palabras del equipo encargado del desarrollo de esta aplicacin, "MySQL Workbench es una herramienta para el diseo visual de bases de datos desarrollada por MySQL. Se trata del esperado sucesor del proyecto DBDesigner4". DBDesigner era (y sigue siendo, visite http://fabforce.net/dbdesigner4/) un sistema para el diseo visual de bases de datos que integraba en un entorno unificado las fases de diseo, modelado, creacin y mantenimiento. Con MySQL Workbench es posible disear tablas, cambiar los tipos de las columnas, sus nombres, una y otra vez, sin tener que escribir ni una sola lnea de cdigo. Y cuando estemos satisfechos con nuestro trabajo, el programa puede generar por nosotros todo el cdigo necesario para crear la base de datos en MySQL. En la figura 5.2 puede ver el entorno que este programa proporciona.

Figura 5.2. Entorno de trabajo de MySQL Workbench

No se trata del nico programa de este tipo que existe. Otras alternativas son: Navicat, de PremiumSoft. PowerDesigner, de Sybase.

DataArchitect, de theKompany. Rational Rose, de IBM. Lo que diferencia a MySQL Workbench del resto es su licencia GPL, la disponibilidad para mltiples sistemas operativos y, sobre todo, que est mejor integrado con MySQL que los dems. Es normal, ambos productos estn desarrollados por la misma empresa.

Instalacin
MySQL Workbench est siendo desarrollado para tres plataformas muy diversas. Por lo que sabemos, aprovechar las caractersticas particulares de cada una de ellas, de manera que el proceso de instalacin ser diferente en cada sistema operativo: En Windows se utiliza el tpico programa de instalacin guiado por asistente. No existen demasiadas opciones que configurar, basta con seguir los pasos y podremos utilizar el programa en un periquete. En Linux, por el momento, las primeras versiones disponibles se estn ofreciendo a travs de sistemas tan utilizados como APT, disponible Debian y Ubuntu, por ejemplo. A medida de que esta versin madure estar disponible en los gestores para la instalacin de paquetes del resto de distribuciones. Las imgenes de disco (archivos DMG) se utilizan para la instalacin en Mac OS X. Basta con hacer doble clic sobre el archivo ofrecido para esta plataforma y arrastrar el contenido del mismo a la carpeta de aplicaciones.
Not a: De momento, MySQL Workbench se distribuir en dos versiones, siguiendo lo que parece ser una norma. Por una parte est la versin para la comunidad, disponible de manera gratuita y bajo licencia GPL. Por otra, la versin estndar, distribuida bajo una licencia comercial. Adivine cul de las dos versiones ofrece ms caractersticas. Es posible que, en el futuro, aparezcan ms ediciones para complementar a estas dos.

Conceptos varios
Antes de comenzar con el diseo del ejemplo que utilizaremos durante este libro es necesario que conozca algunos conceptos que se utilizan en la mayora de los sistemas gestores de bases de datos y, como no poda ser de otra manera, tambin en MySQL.

El valor NULL
O el infierno por el que han de pasar muchos. Pido disculpas si no puedo ser parcial en esta seccin: he sufrido mucho con NULL. El valor NULL es una de esas herramientas que no dejan indiferentes: muchos la encuentran indispensable, otros prefieren atravesarse el ojo con un hierro al rojo vivo hasta llegar al cerebro antes que utilizarlo.

Parece que he dejado clara mi opinin, mas no se deje influir, permtame que le explique con total imparcialidad cmo funciona NULL. Si no existe un valor para una determinada columna, se suele guardar uno representativo, como una cadena vaca o un cero, dependiendo del tipo de datos de la columna. Pero, qu hacer cuando no se conoce el valor de esa columna? Precisamente sa es la funcin de NULL: es el valor contenido en las columnas para las que no se ha introducido dato alguno. Cualquier columna que cree dentro de una tabla, independientemente de su tipo, puede almacenar este valor, a no ser que explcitamente se diga lo contrario. Recuerde que, cuando cre la tabla pelicula en el tercer captulo, lo hizo as:
USE videoteca;

CREATE TABLE pelicula( titulo VARCHAR(64), director VARCHAR(128), actor VARCHAR(128) );

Como ya insert algunos registros en esta tabla puede realizar consultas de seleccin sobre ella. La siguiente consulta muestra el ttulo de las pelculas en una columna y, concatenados, el nombre de director y el del actor, separados por comas:
USE videoteca;

SELECT titulo, CONCAT(director, ', ', actor) FROM pelicula;

La funcin CONCAT recibe como parmetros las cadenas que desee concatenar. En este caso se concatenan tres: el nombre del director, una coma seguida de un espacio y el nombre del actor. El resultado de esta consulta puede verse en la figura 5.3.

Figura 5.3. Concatenacin de dos cadenas

Ahora vamos a insertar una nueva pelcula. De ella conocemos el ttulo y el nombre del director, pero ningn intrprete:
USE videoteca;

INSERT INTO pelicula( titulo, director ) VALUES( 'Naves misteriosas', 'Douglas Trumbull' );

La insercin se realizar sin problemas. La columna actor contendr el valor NULL, ya que no se proporcion valor alguno durante la insercin. La siguiente consulta de seleccin devolver los valores que pueden verse en la figura 5.4:
USE videoteca;

SELECT * FROM pelicula;

Figura 5.4. Se ha insertado NULL

Qu ocurrir ahora si vuelve a utilizar la consulta que concatena el nombre del director y el del actor? Podramos esperar que slo devolviese el ttulo de la pelcula y el nombre del director, sin el actor. Pero la realidad puede verse en la figura 5.5.

Figura 5.5. Concatenacin con NULL

Y no se trata de un comportamiento errneo, as es como debe ser. El resultado de comparar cualquier valor

con NULL es NULL. Cualquier operacin aritmtica en la que participe un valor NULL da como resultado NULL. Cualquier concatenacin con NULL acaba siendo NULL. Existen variadas alternativas para evitar este comportamiento, como el uso de cadenas vacas. Por simplicidad, la recomendacin desde aqu es evitar en lo posible el uso de valores nulos. Quede claro que esta recomendacin se debe nada ms que a experiencias personales. Para evitar la insercin de valores nulos en los campos de la tabla de pelculas puede cambiar la forma en la que se crea:
USE videoteca;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula( titulo VARCHAR(64) NOT NULL, director VARCHAR(128) NOT NULL, actor VARCHAR(128) NOT NULL );

De esta forma, si en una insercin no indica el valor de alguna columna, como en la ltima que se ha utilizado para la pelcula "Naves misteriosas", se producir un error. Puede evitar la aparicin de dicho error si asigna un valor predeterminado para las columnas no obligatorias. En el caso de la tabla de pelculas podramos hacer obligatorio el ttulo, pero no el director ni el actor. El siguiente cdigo har que se guarde una cadena vaca en esas columnas si no se indica un valor para ellas durante las inserciones:
USE videoteca;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula( titulo VARCHAR(64) NOT NULL, director VARCHAR(128) NOT NULL DEFAULT '', actor VARCHAR(128) NOT NULL DEFAULT '' );

Tambin es posible cambiar las propiedades de la tabla de pelculas de acuerdo a lo que acaba de ver, pero sin eliminar los registros que ya ha insertado en ella. Empecemos por eliminar la pelcula que acabamos de aadir ya que el valor nulo en la columna actor de la tabla de pelculas impide la modificacin de dicha caracterstica de la tabla:
USE videoteca;

DELETE FROM pelicula WHERE titulo = 'Naves misteriosas'; Utilice la instruccin ALTER TABLE que vimos en el tercer captulo:

Utilice la instruccin ALTER TABLE que vimos en el tercer captulo: USE videoteca;

ALTER TABLE pelicula MODIFY titulo VARCHAR(64) NOT NULL, MODIFY director VARCHAR(128) NOT NULL DEFAULT '', MODIFY actor VARCHAR(128) NOT NULL DEFAULT '';

Si, tras modificar la tabla, vuelve a insertar la pelcula "Naves misteriosas" y, a continuacin, ejecuta la consulta de seleccin que concatena el nombre del director y el del actor, podr comprobar que el resultado ya no incluye ningn NULL, con lo que es posible utilizar la misma consulta para aquellas pelculas de las que no conozca su director o su actor. La figura 5.6 muestra el resultado de dicha consulta.

Figura 5.6. Concatenacin sin NULL

Claves primarias
Para explicar qu es una clave primaria vamos a volver a utilizar la tabla pelicula, que est dando mucho juego. Insertemos una ms, esta vez la segunda parte de "Alien", llamada "Aliens", dirigida por James Cameron y protagonizada, de nuevo, por Sigourney Weaver:
USE videoteca;

INSERT INTO pelicula VALUES( 'Alien', 'James Cameron', 'Sigourney Weaver' );

La insercin se realiza sin problemas. Ahora, consulte el contenido de la tabla pelicula y ordene el resultado por ttulo:
USE videoteca;

SELECT * FROM pelicula

pelicula ORDER BY titulo;

Vea el resultado de realizar esta consulta en la figura 5.7.

Figura 5.7. Con la segunda parte de "Alien"

Uy, qu torpe! El ttulo no se ha introducido correctamente, no era Alien sino Aliens. Pero aun as, MySQL ha permitido introducir dos pelculas con el mismo ttulo! Esto no est bien, el ttulo de la pelcula debera ser algo nico, algo que permita diferenciar una pelcula de otras. Y precisamente eso es una clave primaria, un valor mediante el cual se puede distinguir de forma nica cada elemento de una determinada tabla. Todos los registros deben tener algn valor almacenado en esa columna (no se permiten valores NULL), y todos los valores de dicha columna deben ser diferentes.
Not a: Se puede utilizar ms de una columna como clave primaria en aquellos casos en los que slo se consiguen valores nicos al combinar dos columnas. Veremos un ejemplo de esto al final del captulo, con las relaciones muchos a muchos.

Cambie la sentencia para crear la tabla pelicula de manera que el ttulo sea la clave primaria:
USE videoteca;

CREATE TABLE pelicula( titulo VARCHAR(64) NOT NULL, director VARCHAR(128) NOT NULL DEFAULT '', actor VARCHAR(128) NOT NULL DEFAULT '', PRIMARY KEY(titulo) );

Slo se ha aadido una lnea al final de las definiciones de las columnas para indicar qu campos componen la clave primaria. Tambin puede modificar la tabla ya existente, as no perder los datos almacenados en ella:
USE videoteca;

ALTER TABLE

ALTER TABLE pelicula ADD PRIMARY KEY(titulo);

Y, como ver, se produce un error: existe un valor duplicado para la clave que est intentado crear. Recuerda? "Alien" aparece dos veces. Solucionarlo es bien sencillo:
USE videoteca;

UPDATE pelicula SET titulo = 'Aliens' WHERE director = 'James Cameron';

Ahora que no existen dos pelculas con el mismo ttulo puede ejecutar la consulta que aade la clave primaria a la tabla sin que se produzca ningn error. Es muy importante seleccionar las claves correctas, de manera que sean nicas. Podra llevarse una sorpresa si, con el paso del tiempo, se encuentra con que s existen dos pelculas con el mismo ttulo.

ndices
Con un ndice es posible encontrar ms rpido los datos que se necesitan. Como en el que aparece al final de esta gua: busque el trmino que le interese, que encontrar rpidamente gracias a que est organizado por orden alfabtico, y all aparecer el nmero de pgina al que tiene que acudir. Bastante ms rpido que leer desde la primera pgina hasta localizarlo. Para las tablas se puede utilizar una tcnica similar. Si sabe que las bsquedas de valores de una determinada columna sern frecuentes, cree un ndice para ella. Hablaremos con ms detalle los ndices en el captulo dedicado a la optimizacin.

Columnas de incremento automtico


Todas las operaciones de insercin realizadas en los captulos anteriores tenan algo en comn: se conocan de antemano los valores a insertar en cada columna. Si insertbamos de forma explcita un valor, sabamos que ste sera el almacenado en la columna. Tambin hemos realizado un par de inserciones implcitas, las dos en el captulo dedicado a tipos de datos. Una de ellas, al explicar el uso del modificador DEFAULT , que le permita precisamente indicar qu valor se insertara en una columna si no se indicaba ninguno. La segunda insercin implcita tena lugar al utilizar el tipo TIMESTAMP . No era necesario indicar un valor porque MySQL insertaba la fecha y la hora en la que se estaba realizando la insercin del registro o su modificacin.

Existe otra forma de insertar valores de forma implcita en una columna: utilizando el incremento automtico. Anteriormente tomamos la decisin de utilizar como clave primaria de la tabla de pelculas el ttulo de las mismas, porque es algo que no se repite. Sin embargo, la historia del cine est plagada de pelculas con ttulos idnticos. Por ejemplo, "La cosa", dirigida por John Carpenter, es una nueva versin de la pelcula del mismo ttulo de 1951. No debera ser posible insertar en la tabla las dos pelculas, con el mismo ttulo? Una solucin podra consistir en aadir una columna ms y utilizarla como clave primaria de la tabla. La nica condicin que debe cumplir es que sea diferente para cada registro. Podra tratarse de un nmero, un identificador que permita diferenciar entre una y otra pelcula. Y para ahorrar esfuerzos, lo ideal sera que la columna fuese de incremento automtico, para que MySQL se encargase de hacer que todos sus valores fuesen diferentes. Utilice las siguientes instrucciones para crear una tabla con esas caractersticas:
USE videoteca;

CREATE TABLE pelicula( id INT NOT NULL AUTO_INCREMENT, titulo VARCHAR(64) NOT NULL, director VARCHAR(128) NOT NULL DEFAULT '', actor VARCHAR(128) NOT NULL DEFAULT '', PRIMARY KEY(id) );

Tambin existe la posibilidad de modificar la tabla para lograr el mismo resultado, manteniendo los registros ya existentes:
USE videoteca;

ALTER TABLE pelicula DROP PRIMARY KEY, ADD id INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY(id);

Con cada nueva insercin en la tabla, un nuevo valor se insertar de forma automtica en la columna id, diferenciando de forma nica cada registro de la misma. Si selecciona todos los registros de la tabla ver que a los existentes ya se les ha asignado un identificador nico. Puede comprobarlo en la figura 5.8. Es posible que el identificador asignado a cada pelcula que aparece en dicha figura no sea el mismo en su caso.

Figura 5.8. Nueva clave primaria

Puede que ahora mismo no encuentre demasiada utilidad a este tipo de columnas. Sin embargo, con el tiempo comprender que se trata de una herramienta imprescindible. Y con el tiempo es al terminar este captulo.

El modelo relacional
Es posible que haya escuchado en ms de una ocasin que MySQL es un sistema gestor de bases de datos relacionales. Qu significa esto? Entre otras cosas, que es posible relacionar entre s las diferentes tablas que componen una base de datos, de ah la palabra relacional. Tras este modelo para la organizacin de los datos existe amplia documentacin, tanto histrica como terica. A los ms puristas no les gustar nada que nos saltemos toda esa parte pero, a fin de cuentas, esto es una gua prctica. Por supuesto, si est interesado podr encontrar todas las fuentes de documentacin al respecto que necesite, tanto impresas como en Internet. Es ms, le recomendamos que lo haga. Sin embargo, en esta gua prima lo prctico. En el modelo relacional es necesario que las tablas compartan datos para poder relacionarlas. Cmo se consigue algo as? Vea en la figura 5.9 cmo ha quedado el diseo de la tabla de pelculas tras aplicar lo aprendido en los apartados anteriores.

Figura 5.9. La tabla de pelculas, tras algunos cambios

Si necesitase relacionar una pelcula con otra tabla slo tendra que incluir en esa tabla el identificador de la pelcula a la que hace referencia. Lo mejor para comprenderlo es un sencillo ejemplo. Suponga que tiene tantas buenas pelculas que sus amigos no hacen ms que pedrselas prestadas. Pero como de memoria no anda tan bien como de amigos y pelculas, y siempre se le olvida a quin deja qu pelcula, ha decidido guardar en otra tabla de la base de datos una lista de prstamos. En esa lista slo necesita almacenar el

nombre de la persona, la pelcula que se lleva prestada y en qu fecha se la llev, algo parecido a lo que se puede ver en la figura 5.10.

Figura 5.10. Tabla de prstamos

La primera columna, id, tiene las mismas caractersticas que la homnima de la tabla pelicula: un identificador de incremento automtico, que es la clave primaria de la tabla. La segunda columna, persona, contiene el nombre de quien se lleva la pelcula. En tercer lugar, el identificador de la pelcula, idpelicula. Como la tabla de pelculas contiene un campo llamado id que identifica a cada registro de forma inequvoca, puede guardar aqu ese campo para saber qu pelcula se llev su amigo. Pero claro, existe la posibilidad de que se inserte como identificador de la pelcula un valor sin contrapartida en la tabla pelicula. Lo ideal sera que MySQL controlase que en ese campo slo se pudiesen insertar valores existentes en dicha tabla. Cuando esa condicin se cumple, se dice que se est manteniendo la integridad referencial entre las tablas, y que idpelicula es una clave externa. Utilice las siguientes instrucciones para crear la tabla de prstamos:
USE videoteca;

DROP TABLE IF EXISTS prestamo; CREATE TABLE prestamo ( id INT NOT NULL AUTO_INCREMENT, idpelicula INT NOT NULL, persona VARCHAR(128) NOT NULL, fecha DATE NOT NULL, PRIMARY KEY(id), FOREIGN KEY(idpelicula) REFERENCES pelicula(id) );

Not a: La tabla prest amo, que contiene la clave externa, se conoce como tabla hija o secundaria, mientras que la tabla a la que hace referencia se conoce como tabla madre o principal.

Ahora que disponemos de dos tablas relacionadas vamos a comprobar que se cumple lo descrito acerca de las relaciones. Para ello slo tenemos que realizar inserciones en la tabla de prstamos. En primer lugar, vamos a prestar "Contact" a Kake. Como pudo verse en la figura 5.8, el identificador que MySQL asign automticamente a esa pelcula es el 4, as que:
USE videoteca;

INSERT INTO prestamo( idpelicula, persona, fecha ) VALUES( 4, 'Kake', CURRENT_DATE() );

Advert encia: Es posible que el identificador de "Contact" en su tabla de pelculas sea otro, no se preocupe en absoluto. Utilice el identificador asignado en su sistema para este ejemplo.

Como ve, hemos utilizado la funcin CURRENT_DATE() para guardar la fecha actual en la columna fecha. Si ahora selecciona todos los registros de la tabla prestamo podr ver algo parecido a lo que aparece en la figura 5.11.

Figura 5.11. El primer prstamo

Ahora comprobaremos cmo funciona la integridad relacional, intentando prestar una pelcula no presente en la base de datos. Utilice un identificador de pelcula que no exista:
USE videoteca;

INSERT INTO prestamo( idpelicula, persona, fecha ) VALUES( 123, 'Germn', CURRENT_DATE() );

MySQL le informar de que ha surgido un error... Cmo? Que no informa de ningn error? Que se ha podido realizar la insercin? Claro que se ha podido, slo intentaba comprobar si prestaba atencin. El propsito de esta jugarreta ha sido demostrarle lo sencillo que es perder la consistencia de los datos de una

base de datos si no se presta atencin durante la fase de diseo. Esta ltima insercin ha conseguido que se inserte un prstamo de la pelcula con identificador 123, pelcula que no existe en la base de datos. Localizar este tipo de problemas en una tabla con dos registros es sencillo pero, y si esta tabla tuviese miles? Por qu no se ha cumplido ni una palabra de cuanto ha aprendido sobre relaciones entre tablas? Muy sencillo: el tipo de tabla predeterminado de MySQL, MyISAM, no incorpora los mecanismos de integridad relacional. Cuando MySQL encuentra las instrucciones de integridad referidas a una tabla MyISAM, simplemente las ignora. Para lograr nuestro objetivo hemos de utilizar tablas InnoDB, de las que ya hablamos en el captulo tercero.
Not a: Aquellos usuarios de Windows que hayan instalado MySQL usando el asistente se preguntarn qu ha ocurrido y por qu no les ha dejado realizar la insercin anterior, que rompa la integridad referencial. Esto se debe a que, para ellos, el tipo de tabla predeterminado es InnoDB, no MyISAM. Si quiere comprobar de qu tipo es una tabla slo tiene que utilizar la instruccin SHOW CREATE TABLE seguida del nombre de la tabla en cuestin y localizar la palabra clave ENGINE.

El primer paso para lograr que la integridad referencial funcione es convertir la tabla de pelculas en una tabla InnoDB:
USE videoteca;

ALTER TABLE pelicula ENGINE = InnoDB;

Hecho, as de fcil. Ahora, elimine y vuelva a crear la tabla de prstamos:


USE videoteca;

DROP TABLE IF EXISTS prestamo; CREATE TABLE prestamo ( id INT NOT NULL AUTO_INCREMENT, idpelicula INT NOT NULL, persona VARCHAR(128) NOT NULL, fecha DATE NOT NULL, PRIMARY KEY(id), FOREIGN KEY(idpelicula) REFERENCES pelicula(id) ) ENGINE = InnoDB;

En este caso no bastara con cambiar el tipo de tabla ya que esa operacin no creara las estructuras necesarias para el mantenimiento de la integridad referencial. Intente ahora la insercin del prstamo de una pelcula inexistente:
USE videoteca;

INSERT INTO prestamo( idpelicula, persona,

persona, fecha) VALUES( 123, 'Germn', CURRENT_DATE() );

Como podr comprobar, MySQL ya no le permite insertar en la columna idpelicula identificadores de pelculas que no estn en la tabla pelicula. Hemos logrado (no sin esfuerzo) nuestro objetivo. La figura 5.12 muestra un diagrama de su primera base de datos con tablas relacionadas.

Figura 5.12. Relacin entre pelculas y prstamos

Para terminar este apartado vamos a ver qu clases de relaciones entre tablas existen atendiendo al nmero de elementos que se ven involucrados: Uno a uno: Un registro de una de las tablas slo puede estar relacionado con un registro de la otra tabla. Sera el caso de la relacin entre pelculas y prstamos si el identificador de la pelcula de esta ltima fuese la clave primaria, ya que as slo podra guardar un registro por pelcula. Resulta interesante si no se quiere almacenar un histrico de prstamos (algo que ahora s se puede hacer). Uno a muchos: Se da en el caso de que un registro de la tabla hija slo pueda estar relacionado con un registro de la tabla madre. A su vez, un registro de la tabla principal puede estar relacionado con ms de uno de la tabla hija. Es el caso de la relacin entre tablas que acaba de crear. Un prstamo slo se aplica a una determinada pelcula, aunque a lo largo del tiempo esa pelcula la ha podido tener mucha gente. Muchos a muchos: En esta relacin, un registro de la tabla hija puede estar relacionado con cualquier registro de la tabla madre y viceversa. Adelantando contenidos, en el siguiente apartado dividiremos la tabla de pelculas en otras tablas. Una de ellas contendr informacin sobre los actores, relacionada con la tabla de pelculas. Un actor puede haber participado en muchas pelculas y, a su vez, en una pelcula pueden participar muchos actores. Tras lo visto hasta ahora dispone de los conocimientos necesarios para afrontar el objetivo de este captulo, mejorar el diseo de esta base de datos. Una de las tcnicas ms empleadas en el mundo de las bases de datos, y en el de la informtica en general, es el "divide y vencers".

Divide y vencers
El punto de partida es la tabla pelicula de la base de datos videoteca que ha construido a lo largo de este captulo. Pudo ver su diseo en la anterior figura 5.9. Utiliz estas instrucciones para crearla:
USE videoteca;

CREATE TABLE pelicula( id INT NOT NULL AUTO_INCREMENT, titulo VARCHAR(64) NOT NULL, director VARCHAR(128) NOT NULL DEFAULT '', actor VARCHAR(128) NOT NULL DEFAULT '', PRIMARY KEY(id) ) ENGINE = InnoDB;

Creacin de tablas con MySQL Workbench


Vamos a mejorar el diseo de la tabla de pelculas, aadindole algunos campos ms en los que poder guardar otros datos que pueden resultar interesantes: soporte: Una cadena de tres caracteres que guardar el formato en el que est la grabacin (VHS, DVD, etctera). imdb_director: El identificador que la famosa Web IMDb (http://imdb.com/) dedicada al cine asigna a ese director. Una aplicacin podra utilizar este dato para mostrar una pgina con detalles de un director en concreto. Se guardar en una cadena de 32 caracteres. La figura 5.13 muestra la pgina del director Ridley Scott . Su identificador, nm0000631, aparece en la barra de direcciones.

Figura 5.13. Ridley Scott en IMDb

imdb_actor: Igual que el campo imdb_director , pero aplicado al actor. genero: Siglas del gnero cinematogrfico al que pertenece la pelcula. genero_desc: Descripcin de las siglas del campo anterior. Siga estos pasos para crear esta tabla utilizando MySQL Workbench: 1. Ponga en marcha MySQL Workbench. Inicialmente, el aspecto de este programa es que el puede verse en la figura 5.14.

Figura 5.14. MySQL Workbench

2. Para comenzar a trabajar con un documento en blanco seleccione la opcin New del men File. 3. Vamos a aadir un nuevo diagrama: seleccione la opcin Add Diagram del men Model. Tambin puede utilizar la combinacin de teclas Control-T . El aspecto de MySQL Workbench cambiar, mostrndole una rejilla en la que podr situar los diferentes elementos que compongan su base de datos, tal y como muestra la figura 5.15.

Figura 5.15. Diagrama en blanco

Not a: Fjese en que, bajo la barra de mens, aparecen ya dos fichas. La primera, MySQL Model, es la que pudo ver en la figura 5.14. La segunda, EER Diagram, significa diagrama entidad-relacin mejorado (Enhanced Entity Relationship).

4. Antes de nada, cambie el nombre de la base de datos. Fjese en el panel de la derecha llamado Catalog. El nombre de la base de datos actual es mydb. Haga clic sobre l, espere y vuelva a hacer clic para poder editar su nombre. Tambin puede hacer clic con el botn derecho sobre l y seleccionar la opcin Rename del men contextual. Escriba videoteca y pulse la tecla Intro. 5. Cree una nueva tabla. Para ello, haga clic en el icono Place a New Table de la barra de herramientas que se encuentra en la parte izquierda de la ventana del programa. El puntero del ratn cambiar de forma para indicarle que, cuando haga clic sobre la zona de edicin del documento, en la parte central de la ventana donde se encuentra la rejilla, se insertar una nueva tabla. 6. Haga clic en la zona de edicin del documento. Aparecer una nueva tabla con un nombre predeterminado table1, como puede ver en la figura 5.16.

Figura 5.16. Nueva tabla

7. Haga doble clic sobre el nombre de tabla que acaba de aparecer. MySQL Workbench le presentar el editor de tablas, en la parte inferior de la ventana del programa, desde el que puede aadir nuevos campos, cambiar sus propiedades, el tipo de tabla, etctera. La figura 5.17 le muestra este panel tal y como quedara tras introducir los detalles de las columnas de la tabla pelicula.

Figura 5.17. Diseando la nueva tabla

8. Para terminar, seleccione la opcin Save del men File o haga clic en el botn Save Model to File de la barra de herramientas para guardar el modelo que acaba de crear en la ubicacin que desee. Adems de tener una representacin visual de sus tablas, tambin puede obtener las instrucciones necesarias para crear la que acaba de disear. Haga clic con el botn derecho del ratn sobre la tabla y seleccione la opcin Copy SQL to Clipboard. Si luego pega el resultado usando Control-V en su editor de texto favorito ver un resultado similar al siguiente:
CREATE TABLE pelicula ( id INT NOT NULL AUTO_INCREMENT, titulo VARCHAR(64) NOT NULL, director VARCHAR(128) NOT NULL DEFAULT '', actor VARCHAR(128) NOT NULL DEFAULT '', soporte VARCHAR(3) NOT NULL DEFAULT '', imdb_director VARCHAR(32) NOT NULL DEFAULT '', imdb_actor VARCHAR(32) NOT NULL DEFAULT '', genero VARCHAR(2) NOT NULL DEFAULT '', genero_desc VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY (id) ) ENGINE = InnoDB;

La base de datos de pelculas que est diseando se encuentra ahora mismo en lo que algunos llaman la forma normal cero: contiene todos los datos que se desean mostrar y una clave primaria. Para crear esta tabla cree primero la base de datos

videoteca. Es posible que ya exista si la cre en el segundo captulo. Las siguientes instrucciones eliminarn esta base de datos si ya existiese y la volvern a crear:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca;

Cree ahora la tabla de pelculas (no se olvide de seleccionar antes en qu base de datos con USE videoteca;) y, a continuacin, inserte algunos datos en la tabla:
USE videoteca;

INSERT INTO pelicula( titulo, director, actor, soporte, imdb_director, imdb_actor, genero, genero_desc ) VALUES( 'Blade Runner', 'Ridley Scott', 'Harrison Ford', 'DVD', 'nm0000631', 'nm0000148', 'CF', 'Ciencia-ficcin' );

INSERT INTO pelicula( titulo, director, actor, soporte, imdb_director, imdb_actor, genero, genero_desc ) VALUES( 'Gladiator', 'Ridley Scott', 'Russell Crowe', 'DVD', 'nm0000631', 'nm0000128', 'A', 'Aventuras' );

INSERT INTO pelicula( titulo, director, actor, soporte, imdb_director, imdb_actor, genero, genero_desc ) VALUES( 'A propsito de Henry', 'Mike Nichols', 'Harrison Ford', 'VHS', 'nm0001566', 'nm0000148', 'D', 'Drama' );

El resultado de hacer una consulta de seleccin tras estas inserciones puede verse en la figura 5.18. Fjese en el uso de \G al final de la operacin de consulta.

Figura 5.18. Los datos de partida

Con este diseo y estos datos de partida, cmo se encuentra la base de datos? Busquemos todas las deficiencias de diseo que podamos: Cada vez que introduzca el nombre de un actor, si ese actor ya particip en alguna de las pelculas que tiene en la base de datos, estar duplicando los datos, ocupando ms espacio. Con relacin al punto anterior, es posible que cometa algn error al introducir el nombre de algn actor. Podra escribir Harrisond Ford como protagonista de

una de las pelculas de Indiana Jones. Si posteriormente hiciese una consulta de las pelculas protagonizadas por este actor, la de Indiana Jones no aparecera, por el error en el nombre. Esta misma fuente de errores se repite con el gnero de la pelcula y su descripcin, y con los cdigos de IMDb. Slo puede indicarse un director por pelcula. Algunas, como "Delicatessen", fueron dirigidas por dos personas. Lo mismo se puede decir, con ms razn, de los actores. Est claro que la base de datos es manifiestamente mejorable y muchas de estas mejoras se lograran dividiendo la tabla en fragmentos ms pequeos y ms manejables, haciendo bueno el dicho "divide y vencers".

Divisin de tablas
Vamos a comenzar con los directores. Por s misma, la creacin de una tabla para la gestin de los directores de pelculas podra tener sentido. Cree una nueva tabla en la que almacenar los detalles de cada uno de ellos. La figura 5.19 muestra el aspecto de dicha tabla, creada con MySQL Workbench.

Figura 5.19. Los datos de los directores

Fantstico! Ya tiene una tabla para los directores que, utilizando claves externas como las que vio en el apartado dedicado a las bases de datos relacionales, puede llevar a cabo correspondencias con cada pelcula. Pero an hay algo que falla en esta tabla. Aunque hemos comenzado con la divisin de la tabla principal, no hemos continuado con esa divisin en las tablas obtenidas. Los datos han de dividirse todo lo posible, siempre que esta divisin sea til. Qu ms se puede dividir en esta tabla? El nombre del director, por ejemplo, podra dividirlo en dos partes: nombre y apellidos. De esta forma, lo que antes era un nico campo (Ridley Scott, por ejemplo), que slo permita ordenacin por el nombre, ahora se convierte en dos. Esto le da la oportunidad de ordenar tambin por los apellidos, a la vez que se evitan errores en la introduccin del nombre. La figura 5.20 muestra este otro diseo de la tabla de directores.

Figura 5.20. Otro diseo de la tabla de directores

El cdigo necesario para crear esta tabla es el siguiente:


USE videoteca;

CREATE TABLE director ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) ENGINE = InnoDB;

Fjese en que la nica columna con un valor predeterminado es la que almacena el cdigo de IMDb: puede que no lo conozca para todos los directores. Por el contrario, es necesario introducir el resto de valores en cada insercin. El mismo razonamiento que se ha seguido para crear esta tabla de directores puede aplicarse para aquella en la que se guardan los datos de los actores. La figura 5.21 muestra el diseo de dicha tabla.

Figura 5.21. Los datos de los actores, por separado

El cdigo para crear esta tabla es el siguiente:


USE videoteca;

CREATE TABLE actor ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) ENGINE = InnoDB;

Relacionar tablas
El diseo de la tabla de pelculas ha de cambiarse para reflejar los cambios realizados en la seccin anterior. Ha de incluir una referencia al director de la pelcula, y otra al actor, para seguir guardando los mismos datos que antes. Este cambio se muestra en la figura 5.22.

Figura 5.22. Modificacin de la tabla de pelculas

Slo ha sido necesario sustituir los campos director y

actor, que guardaban sus nombres, por los identificadores correspondientes de las tablas que acaba de crear, y eliminar los datos de IMDb que se guardaban, ya que ahora estarn en las tablas correspondientes. Para terminar tenemos que relacionar las tres tablas existentes entre s: actor , director y pelicula. La columna iddirector debe estar relacionada con la columna id de la tabla director . Por otra parte, la columna idactor debe estar relacionada con la columna id de la tabla actor . La relacin entre directores y pelculas es lo que se defini anteriormente como una relacin uno a muchos. Traduciendo: por ahora, en este modelo, una pelcula slo la dirige un director, pero un director puede haber dirigido muchas pelculas. Siga estos pasos para crear relaciones utilizando MySQL Workbench: 1. Haga clic sobre la tabla pelicula para seleccionarla. 2. Active la ficha Foreign Keys, se encuentra en la parte inferior de la ventana de MySQL Workbench. 3. Introduzca el nombre que quiera dar a la relacin en la primera fila de la columna Foreign Key Name. Como se trata de saber quin ha dirigido cada pelcula, llammosla dirigida_por . 4. Introduzca el nombre de la tabla con la que quiere relacionar la actual en la primera fila de la columna Referenced Table . Una lista desplegable le permitir seleccionar entre las tablas existentes. En este caso hemos de seleccionar la tabla director . 5. Justo a la derecha del panel con el que hemos estado trabajando podr ver la lista de los campos de la tabla pelicula. Marque la casilla de verificacin del campo iddirector . Cuando lo haga se desplegar una lista con los campos de la tabla de directores. Seleccione el campo id. 6. Repita la operacin con la tabla de actores. 7. El aspecto del modelo en ese momento ser similar al que puede verse en la figura 5.23.

Figura 5.23. Primer paso de la creacin de relaciones

El modelo de datos que tiene ahora permite mantener una lista de directores, otra de actores y una ltima de pelculas, que toma datos de las dos primeras. Este

proceso de simplificacin, dividiendo el modelo, puede seguir aplicndose a la tabla de pelculas. El soporte en el que est grabada la pelcula puede ser otra tabla que, por ahora, slo contendr los valores DVD y VHS, pero que en el futuro puede contener los valores de los formatos que vaya aadiendo a su videoteca. Los gneros tambin podran llevarse a otra tabla. Debera aadir, de nuevo, los identificadores necesarios a la tabla de pelculas para mantener las relaciones entre pelculas, formatos y gneros. En la figura 5.24 puede ver el aspecto del modelo resultante tras la nueva divisin de los datos, que ocasiona la aparicin de dos nuevas tablas, soporte y genero, y la incorporacin de los campos idsoporte e idgenero a la tabla pelicula, tras eliminar los campos correspondientes de las nuevas tablas.

Figura 5.24. Pelculas, directores y actores

An se puede aadir una mejora ms al modelo, permitiendo que una pelcula pueda estar protagonizada por ms de un actor, algo que este no permite en este momento. La opcin ms sencilla sera incluir otro identificador de actor ms, idactor2. Pero entonces qu ocurre si se quiere guardar informacin sobre tres actores? Creamos un tercer campo, idactor3? Y si luego quisisemos aadir un cuarto actor?

Relaciones muchos a muchos


La forma ms eficaz de lograr este objetivo es cambiar el tipo de relacin que existe entre la tabla de actores y la de pelculas. Ahora mismo es una relacin uno a muchos, como ha visto. Hay que lograr convertirla en una relacin muchos a muchos. Para ello, es necesario utilizar una tabla intermedia, que almacenar las relaciones entre pelculas y actores. El identificador del actor dejar de estar en la tabla de pelculas y pasar a esta nueva tabla. La tabla de pelculas tendr una relacin de uno a muchos con la tabla de actores por pelcula, al igual que la tabla de actores. De esta manera, el resultado final es que la tabla de pelculas tendr una relacin de muchos a muchos con la de actores. Puede ver cmo quedar esta

parte del modelo de la base de datos en la figura 5.25. Se ha simplificado la tabla de pelculas para que slo incluya los campos interesantes para este apartado.

Figura 5.25. Una relacin muchos a muchos

Por ejemplo, para crear las tablas que se pueden ver en la figura 5.25 sera necesario ejecutar las siguientes instrucciones:
USE videoteca;

DROP TABLE IF EXISTS actor; CREATE TABLE actor ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula ( id INT NOT NULL AUTO_INCREMENT, titulo VARCHAR(64) NOT NULL, PRIMARY KEY(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS actores_por_pelicula; CREATE TABLE actores_por_pelicula ( idpelicula INT NOT NULL, idactor INT NOT NULL, PRIMARY KEY(idpelicula, idactor), INDEX actores_por_pelicula_fk1( idpelicula ), INDEX actores_por_pelicula_fk2( idactor ), FOREIGN KEY(idpelicula) REFERENCES pelicula(id), FOREIGN KEY(idactor) REFERENCES actor(id) ) ENGINE = InnoDB;

Tenga en cuenta que ahora, para guardar en la base de datos los detalles de una pelcula, es necesario realizar ms inserciones. Por ejemplo, "Blade Runner" requerira una insercin en la tabla de actores para disponer de Harrison Ford. Sera necesaria otra insercin en la tabla de pelculas para crear la pelcula, y por ltimo, una insercin

en la tabla de actores por pelcula para crear la asociacin entre ambos. Esta ltima insercin requiere que conozca los identificadores tanto del actor como de la pelcula, que pueden obtenerse mediante una consulta:
USE videoteca;

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Harrison', 'Ford', 'nm0000148');

INSERT INTO pelicula(titulo) VALUES('Blade Runner');

SELECT id FROM actor WHERE imdb = 'nm0000148';

SELECT id FROM pelicula WHERE titulo = 'Blade Runner';

INSERT INTO actores_por_pelicula( idpelicula, idactor ) VALUES( 15, 10 );

Not a: Es posible combinar los procedimientos almacenados y los desencadenadores para hacer ms sencillo el trabajo de insercin de pelculas en la base de datos. Encontrar ms informacin al respecto en los captulos correspondientes.

En las operaciones de insercin anteriores se ha supuesto que el identificador del actor es 10 y el de la pelcula es 15. Este modelo le permitira incluir un segundo actor relacionado con la pelcula de la siguiente forma:
USE videoteca;

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Rutger', 'Hauer', 'nm0000442');

SELECT id FROM actor WHERE imdb = 'nm0000442';

INSERT INTO actores_por_pelicula( idpelicula, idactor ) VALUES( 15, 11 );

Not a: En el siguiente captulo, dedicado a las consultas de datos, podr ver cmo recuperar la informacin de los actores que han trabajado en una determinada pelcula, as como otras consultas ms complejas.

El ejemplo finalizado
Si extiende la modificacin en el diseo a la tabla de directores podr tener varios directores para una pelcula. La figura 5.26 muestra el diseo final de la base de datos tras incorporar este cambio.

Figura 5.26. El diseo, por fin!

Existe un truquito de MySQL Workbench que permite trabajar con diseos grandes en poco espacio. Se ha fijado en el tringulo que aparece a la derecha del nombre de cada tabla? Si hace clic en l, MySQL Workbench ocultar los campos de las tablas, mostrando slo sus nombres. La figura 5.27 muestra el mismo diagrama que la 5.26, pero tras utilizar dicho tringulo para simplificar el aspecto del diagrama.

Figura 5.27. Simplificacin del diagrama

Durante este captulo se ha terminado de disear la base de datos con la que trabajaremos en los captulos sucesivos. Una nota final: queda como ejercicio mejorar el diseo de la tabla dedicada a almacenar los prstamos de las pelculas, as como la posibilidad de que una pelcula pertenezca a ms de un gnero y est en ms de un soporte. O, por ejemplo, aadir ms campos a la tabla principal para guardar la fecha de la pelcula, una calificacin sobre la misma o los comentarios que desee.

SQL
Las primeras veces que se encargue de l, el diseo de la base de datos le acarrear dolores de cabeza. La prctica lograr que se convierta en una tarea ms, que debe tener lugar al principio del proceso de desarrollo. Existe una tarea que le ocupar bastante ms tiempo que el diseo: las consultas a la base de datos, ya sean inserciones, actualizaciones, borrados o simples solicitudes de informacin. Mientras la base de datos se encuentre en funcionamiento estas cuatro operaciones sern fundamentales. El lenguaje estructurado de consultas, o SQL, le permite comunicarse con el sistema gestor de bases de datos para realizar todas esas operaciones. Existen herramientas visuales para llevar a cabo las tareas de mantenimiento de las bases de datos, que facilitan mucho las inserciones puntuales. Sin embargo, la utilizacin de SQL proporciona muchas ventajas de las que hablaremos a lo largo de este captulo. Comenzaremos creando desde cero la base de datos que diseamos en el captulo anterior, precisamente utilizando instrucciones SQL, lo que permitir ilustrar algunas de las ventajas de este mtodo de trabajo. Continuaremos insertando valores en las tablas de la base de datos. Estos valores se utilizarn durante el resto del captulo. Tras repasar las consultas para la creacin y el mantenimiento de bases de datos, exploraremos las diferentes variantes de consultas de seleccin que pueden ser tiles para el trabajo diario y continuaremos con las actualizaciones y las inserciones. Por ltimo, veremos los borrados.

La base de datos de ejemplo


Quiz sera interesante ofrecerle una lista de ventajas y desventajas comparando, por un lado, el uso de las herramientas visuales como MySQL Administrator y MySQL Query Browser para crear bases de datos y tablas y, por otro, el uso de archivos de instrucciones (tambin conocidos como scripts), pero no va a ser el caso. Le recomendamos que, siempre que sea posible, utilice archivos de instrucciones para este tipo de tareas, por varios motivos. El primero de ellos es que en la mayora de trabajos a los que se enfrentar con MySQL contar con un servidor de desarrollo, en el que podr hacer todas las pruebas necesarias, y un servidor de explotacin, en el que la aplicacin funcionar una vez se haya probado convenientemente.

En este tipo de entornos es mucho ms eficaz la utilizacin de los archivos de instrucciones obtenidos a partir de herramientas de diseo de bases de datos como MySQL Workbench. Una vez disponga de las instrucciones de creacin de la base de datos y de sus tablas, puede repetir la operacin de forma exacta e idntica todas las veces que lo necesite. Sin embargo, si tuviese que utilizar las herramientas visuales que ha visto hasta ahora cada vez que fuese necesario crear la base de datos y sus tablas, introducira un punto de fallo. Podra cometer algn error al repetir las operaciones una y otra vez. Ms an, una vez creados los archivos de instrucciones necesarios, cualquiera puede crear la bases de datos, dadas unas instrucciones muy sencillas, sin necesidad de tener el ms mnimo conocimiento acerca del diseo de la misma.
Consejo: Le recomendamos encarecidamente que, en cualquier operacin que tenga que realizar con MySQL, si existe la posibilidad de automatizarla mediante el empleo de archivos de rdenes, lo haga. Aunque le cueste ms esfuerzo al principio, ahorrar un valioso tiempo en el futuro.

Creacin de la base de datos


En los archivos de ejemplo de este libro, dentro del apartado dedicado a este captulo, podr encontrar un archivo llamado 01 - Crear la base de datos.sql. Este archivo contiene todas las instrucciones SQL necesarias para crear tanto la base de datos como las tablas de la videoteca que con tanto esfuerzo ha desarrollado durante los captulos previos. El contenido de ese archivo es el siguiente:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca;

USE videoteca;

DROP TABLE IF EXISTS director; CREATE TABLE director ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS genero; CREATE TABLE genero ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(2) NOT NULL, descripcion VARCHAR(32) NOT NULL, PRIMARY KEY(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS actor; CREATE TABLE actor ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS soporte; CREATE TABLE soporte ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(3) NOT NULL, descripcion VARCHAR(32) NOT NULL, PRIMARY KEY(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS pelicula; CREATE TABLE pelicula ( id INT NOT NULL AUTO_INCREMENT, titulo VARCHAR(64) NOT NULL, idsoporte INT NOT NULL, idgenero INT NOT NULL, PRIMARY KEY(id), INDEX p_FK1(idsoporte), INDEX p_FK2(idgenero), FOREIGN KEY(idsoporte) REFERENCES soporte(id), FOREIGN KEY(idgenero) REFERENCES genero(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS actores_por_pelicula; CREATE TABLE actores_por_pelicula ( idpelicula INT NOT NULL, idactor INT NOT NULL, PRIMARY KEY(idpelicula, idactor), INDEX app_FK1(idpelicula), INDEX app_FK2(idactor), FOREIGN KEY(idpelicula) REFERENCES pelicula(id), FOREIGN KEY(idactor) REFERENCES actor(id) ) ENGINE = InnoDB;

DROP TABLE IF EXISTS directores_por_pelicula; CREATE TABLE directores_por_pelicula ( idpelicula INT NOT NULL, iddirector INT NOT NULL, PRIMARY KEY(idpelicula, iddirector), INDEX dpp_FK1(idpelicula), INDEX dpp_FK2(iddirector), FOREIGN KEY(idpelicula)

FOREIGN KEY(idpelicula) REFERENCES pelicula(id), FOREIGN KEY(iddirector) REFERENCES director(id) ) ENGINE = InnoDB;

Si ha seguido los pasos dados en los captulos anteriores ya estar familiarizado con el proceso de ejecucin de instrucciones utilizando la consola. Ahora aprender una forma nueva de hacerlo. En primer lugar, necesita un archivo en el que guardar las instrucciones SQL que acaba de ver. Si tiene acceso a Internet no es necesario que las escriba usted mismo, ya sabe del archivo 01 - Crear la base de datos.sql, hablamos de l anteriormente. Si no tiene acceso a Internet tendr que teclear. En segundo lugar, guarde el archivo en el disco con el nombre crear.sql, abra una consola (o un terminal en el caso de Linux o Mac OS X) y cambie a la ubicacin en la que se encuentra el archivo. Lo ms sencillo: gurdelo en la raz del disco C: si utiliza Windows o su carpeta home si utiliza Linux o Mac OS X. Entonces, ejecute la siguiente orden:
mysql -u root -p < crear.sql

El cliente de MySQL le pedir que introduzca la contrasea y, tras pensrselo un momento, le devolver el control. Recuerde que si instal MySQL a travs de XAMPP y no cambi su configuracin predeterminada, el usuario root no tendr contrasea. El aspecto de la consola ser similar al que puede verse en la figura 6.1.

Figura 6.1. Creacin de la base de datos

Eso es todo. De un plumazo, la base de datos y sus correspondientes tablas, creadas. Y puede repetir la operacin las veces que sea necesario con la misma facilidad.

Insercin de datos
Tras la ejecucin de las instrucciones de creacin de la base de datos estaremos trabajando, usted y yo, con los mismos elementos. Ahora vamos a llenar las tablas de la base de datos con los registros que utilizaremos durante los siguientes apartados. De nuevo vamos a utilizar archivos de instrucciones. Puede utilizar un archivo que se encuentra en la misma ubicacin que el que utiliz anteriormente para crear la base de datos. Su nombre es 02 - Insertar valores iniciales.sql. Ejectelo siguiendo los mismos pasos que con el de creacin de base de datos y tablas. Las instrucciones de insercin incluidas en dicho archivo son las siguientes:

USE videoteca;

DELETE FROM actores_por_pelicula; DELETE FROM directores_por_pelicula; DELETE FROM actor; DELETE FROM director; DELETE FROM pelicula; DELETE FROM soporte; DELETE FROM genero;

INSERT INTO soporte(nombre, descripcion) VALUES('DVD', 'Digital Versatile Disc');

INSERT INTO soporte(nombre, descripcion) VALUES('VHS', 'Video Home System');

INSERT INTO genero(nombre, descripcion) VALUES('CF', 'Ciencia Ficcin');

INSERT INTO genero(nombre, descripcion) VALUES('A', 'Aventuras');

INSERT INTO genero(nombre, descripcion) VALUES('D', 'Drama');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Harrison', 'Ford', 'nm0000148');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Russell', 'Crowe', 'nm0000128');

INSERT INTO director(nombre, apellidos, imdb) VALUES('Ridley', 'Scott', 'nm0000631');

INSERT INTO director(nombre, apellidos, imdb) VALUES('Mike', 'Nichols', 'nm0001566');

INSERT INTO pelicula(titulo, idsoporte, idgenero) VALUES('Blade Runner', 1, 1);

INSERT INTO pelicula(titulo, idsoporte, idgenero) VALUES('Gladiator', 1, 2);

INSERT INTO pelicula(titulo, idsoporte, idgenero) VALUES('A propsito de Henry', 2, 3);

INSERT INTO actores_por_pelicula( idpelicula, idactor ) VALUES(1, 1);

INSERT INTO actores_por_pelicula( idpelicula, idactor

) VALUES(2, 2);

INSERT INTO actores_por_pelicula( idpelicula, idactor ) VALUES(3, 1);

INSERT INTO directores_por_pelicula( idpelicula, iddirector ) VALUES(1, 1);

INSERT INTO directores_por_pelicula( idpelicula, iddirector ) VALUES(2, 1);

INSERT INTO directores_por_pelicula( idpelicula, iddirector ) VALUES(3, 2);

La principal diferencia consiste en que hasta que no tenga valores en las tablas de las que depende la tabla pelicula no podr realizar inserciones en ella, porque han de cumplirse las reglas de integridad referencial. Por una parte, ha de tener soportes vlidos en la tabla de soportes de grabacin, y tambin gneros en la tabla de gneros cinematogrficos. Con valores en esas dos tablas s es posible realizar inserciones en la de pelculas. Pero hasta que tenga registros en las tablas de directores y actores no podr asociar valor alguno a la tabla de pelculas a travs de las tablas intermedias. Los pasos necesarios para insertar la pelcula "Blade Runner" en la base de datos, como si fuese la primera que se inserta, son los siguientes: 1. Inserte el soporte en que se encuentra la pelcula. Si, posteriormente, inserta otras pelculas que estn grabadas en el mismo formato, no tendr que insertar un nuevo registro en esta tabla, puesto que ya tendr almacenado el valor necesario.
USE videoteca;

INSERT INTO soporte(nombre, descripcion) VALUES('DVD', 'Digital Versatile Disc');

2. Ahora necesita un registro en la tabla de gneros cinematogrficos que se ajuste al de esta pelcula. "Blade-Runner" es de ciencia ficcin.
INSERT INTO genero(nombre, descripcion) VALUES('CF', 'Ciencia Ficcin');

3. Adelntese e inserte ya el actor de la pelcula, aunque tambin podra insertar en este momento la pelcula.
INSERT INTO actor(nombre, apellidos, imdb) VALUES('Harrison', 'Ford', 'nm0000148');

4. El ltimo paso previo a la insercin de la pelcula ser la insercin de su director en la tabla de directores.
INSERT INTO director(nombre, apellidos, imdb) VALUES('Ridley', 'Scott', 'nm0000631');

5. Llegado a este punto tiene toda la informacin necesaria para insertar la pelcula en la base de datos. Recuerde que los identificadores de cada uno de los registros insertados hasta ahora son de incremento automtico. La primera insercin de un valor en una columna de ese tipo toma el valor 1, la segunda el valor 2 y as sucesivamente. Como la base de datos est recin creada, cada uno de los elementos que insertados tiene el identificador 1 en su tabla correspondiente. Por lo tanto, puede insertar la pelcula utilizando 1 como referencia al formato de grabacin y 1 como referencia al gnero cinematogrfico.
INSERT INTO pelicula( titulo, idsoporte, idgenero ) VALUES('Blade Runner', 1, 1);

7. Siguiendo el mismo razonamiento, asocie a la pelcula su actor.


INSERT INTO actores_por_pelicula( idpelicula, idactor ) VALUES(1, 1);

8. Igualmente, asocie el director a la pelcula.


INSERT INTO directores_por_pelicula( idpelicula, iddirector ) VALUES(1, 1);

Las inserciones del resto de pelculas se han realizado siguiendo estos mismos pasos. Si examina el cdigo del archivo 02 - Insertar valores iniciales.sql podr comprobar que en primer lugar se borran todos los registros de todas las tablas de la base de datos. Tras ello se insertan todos los soportes en los que estn las pelculas que tenemos, luego todos los gneros, a continuacin los actores y por ltimo los directores. Y es en ese momento en el que se insertan las pelculas y se asocian con actores y directores.
Not a: Este proceso, mucho ms complejo que el utilizado en el diseo original de una sola tabla, tiene mltiples ventajas, aunque tambin una desventaja: la insercin de una pelcula requiere de comprobaciones e inserciones adicionales por su parte. Como ver en captulos sucesivos, esto no supone ningn problema:

existen formas de simplificar las inserciones para que no tenga que escribir una sola lnea de SQL una vez haya comprobado que la base de datos funciona correctamente.

Ahora que dispone de la misma base de datos, con los mismos registros ordenados de la misma forma, con los mismos identificadores, que la utilizada en este libro, comienza el trabajo. Existe un tercer archivo en el apartado de ejemplos de este captulo que le ser de utilidad. Se llama 03 - Resto de inserciones.sql. Ejecute las instrucciones de ese archivo para introducir muchos ms valores en la bases de datos de pelculas. Lo usar en el resto del captulo. Su contenido es el siguiente:
USE videoteca;

INSERT INTO soporte(nombre, descripcion) VALUES('LD', 'Laser Disc');

INSERT INTO genero(nombre, descripcion) VALUES('C', 'Comedia');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Lee', 'Marvin', 'nm0001511');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Clint', 'Eastwood', 'nm0000142');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Jean', 'Seberg', 'nm0781029');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Bruce', 'Dern', 'nm0001136');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Bruce', 'Boxleitner', 'nm0000310');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Rutger', ' Hauer', 'nm0000442');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Sean', 'Young', 'nm0000707');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Matthew', 'McConaughey', 'nm0000190');

INSERT INTO director(nombre, apellidos, imdb) VALUES('Robert', 'Zemekis', 'nm0000709');

INSERT INTO director(nombre, apellidos, imdb) VALUES('Douglas', 'Trumbull', 'nm0874320');

INSERT INTO pelicula(titulo, idsoporte, idgenero)

VALUES('Naves misteriosas', 1, 1);

Operadores
Desde que aprendi a sumar utiliza operadores: el smbolo de la suma (+) es un operador, como lo son el de la resta y el de la multiplicacin. Ya ha utilizado operadores en SQL con anterioridad, en el ejemplo dedicado a las transacciones. Si recuerda, sumaba y restaba cantidades a los saldos de dos personas para realizar una transferencia de capital. MySQL permite utilizar esos operadores dentro de las consultas, algo que puede ser de mucha utilidad. Durante los siguientes apartados aprender a manejar algunos de los operadores que MySQL proporciona.

Operadores aritmticos
En las cuentas sobre papel, las operaciones de suma, resta, multiplicacin y divisin se representan utilizando los operadores aritmticos +, -, * y /, respectivamente. Con SQL no es diferente. Puede utilizar una consulta de seleccin de SQL para comprobar el funcionamiento de estos operadores, no har falta base de datos alguna. Escriba la siguiente:
SELECT 2 + 2;

Y mirando a la figura 6.2, dgame, cuntas son dos ms dos?

Figura 6.2. Dos ms dos son cuatro, seor maestro

sta no era difcil, verdad? En lneas generales, as funcionan todos los operadores aritmticos: un valor, un operador y otro valor dan como resultado un tercer valor. Obviamente, el resultado vara dependiendo del operador que tenga entre los valores. Y de los valores, claro. Igual que se pueden realizar estas operaciones entre dos valores numricos en una consulta de seleccin, se pueden realizar entre un valor numrico y el valor de una columna de un determinado registro. Si la tabla de pelculas almacenase el ao en el que se estrenaron, podra saber cuntos aos hace que se estren una determinada pelcula con slo restar al ao actual el ao de estreno. La consulta podra ser sta:
USE videoteca;

SELECT YEAR(CURDATE()) - estreno FROM pelicula WHERE id = 12;

Donde 12 es el identificador de la pelcula en cuestin y YEAR(CURDATE()) devuelve el ao actual. La consulta anterior se realiza sobre un determinado valor de un registro pero, como ya sabr a estas alturas, las consultas de seleccin pueden devolver ms de un valor. Qu ocurre en estos casos, cmo se comporta MySQL cuando se le pide que realice una operacin aritmtica sobre una determinada columna de una tabla? La respuesta es muy sencilla: la operacin se realiza sobre todos los valores devueltos por la consulta. Si tiene algunas nociones de programacin, sabr que para sumar un determinado valor a todos los elementos de una lista es necesario utilizar un bucle que recorra todos los elementos de dicha lista, realizando la operacin sobre todos y cada uno de ellos. Sin embargo, con una sola instruccin en SQL obtendr los mismos resultados. Siguiendo con el ejemplo anterior, la siguiente instruccin calcula el tiempo pasado desde el estreno de todas las pelculas de la base de datos:
USE videoteca;

SELECT YEAR(CURDATE()) - estreno FROM pelicula;

La sencillez del lenguaje SQL es aparente: lo que parece una sola operacin aritmtica puede tener implcitas miles de ellas si la consulta devuelve miles de registros. Y esta sencillez tambin es aparente en otro aspecto, aunque esto lo va a ver con otro ejemplo. Vuelva a utilizar la base de datos de pruebas. Ya vio cmo crearla:
DROP DATABASE IF EXISTS pruebas; CREATE DATABASE pruebas;

Cree una tabla con dos columnas con las siguientes instrucciones:
USE pruebas;

DROP TABLE IF EXISTS operadores; CREATE TABLE operadores( uno TINYINT UNSIGNED, otro TINYINT UNSIGNED );

Ahora, inserte un registro:

USE pruebas;

INSERT INTO operadores VALUES(3, 7);

El resultado de sumar los valores almacenados en las dos columnas de esta tabla se consigue as:
USE pruebas;

SELECT uno + otro FROM operadores;

Obviamente, el resultado es 10. Pero, cul ser el resultado de esta misma consulta cuando inserte esta nueva pareja de valores?
USE pruebas;

INSERT INTO operadores VALUES(300, 500);

Uno dira que se obtendrn dos registros, el primero con el valor 10, resultado de la suma de las columnas de los primeros valores insertados, y el segundo con el valor 800. Pues hay una sorpresa, mire en la figura 6.3 cul ha sido el resultado real.

Figura 6.3. Fuera de rango

Y es que se ha salido de rango: ha insertado en una columna, que es de tipo TINYINT sin signo, valores superiores al mximo que puede almacenar una columna de este tipo (recuerde, el valor mximo es 255). Se trata de algo similar a lo que pasara si intentase multiplicar dos valores enteros muy grandes, cuyo resultado estuviese por encima del mximo permitido por esa operacin. Por ejemplo, tome el mayor nmero entero que se puede almacenar en MySQL y multiplquelo por 2:
SELECT 18446744073709551615 * 2;

El resultado: ese mismo nmero menos uno. La razn, de nuevo, que ha intentado almacenar en una columna un valor mayor que el que cabe en ella. Fjese en que el resultado cambia si en lugar de multiplicar por 2 (entero) lo hace por 2,0 (coma flotante):
SELECT 18446744073709551615 * 2.0;

Operadores de comparacin
Estos operadores permiten comparar dos valores. El resultado de dicha comparacin puede ser TRUE (verdadero), FALSE (falso) o NULL . El resultado de la comparacin ser NULL si uno de los valores comparados es NULL .

Not a: MySQL utiliza un cero como FALSE y un uno como TRUE. Tngalo presente al obtener los resultados de las consultas. Las constantes TRUE, t rue, FALSE y false estn a su disposicin.

MySQL proporciona operadores para comprobar si dos valores son iguales (=) o diferentes (<>), si uno es mayor (>) o menor (<) que otro, y las variantes mayor o igual (>=) y menor o igual (<=). stos son los operadores ms utilizados cuando se comienza a trabajar con MySQL, ya que los otros son un tanto esotricos y no es hasta despus de mucho trabajar con bases de datos cuando se encuentra su utilidad. Por ejemplo, existen operadores para comprobar si un determinado valor pertenece a un conjunto de valores, o si est dentro de un rango. Fjese en los quebraderos de cabeza que puede dar NULL . Tanto es as, que hasta existe un operador de igualdad "a prueba de NULL": es el <=>. Pruebe el operador de igualdad comparando dos parejas de valores:
SELECT 7 = 7, NULL = NULL;

Cualquiera dira que el resultado de esta consulta debera ser TRUE (cierto) en ambos casos. La realidad que muestra la figura 6.4 es otra: mientras que 7 s es igual a 7, cualquier comparacin de un valor con NULL tendr como resultado NULL .

Figura 6.4. NULL no es igual a NULL

De ah la existencia del operador "a prueba de NULL". Vea:


SELECT 7 <=> 7, NULL <=> NULL;

El resultado de esta consulta s es cierto en ambos casos, como puede verse en la figura 6.5.

Figura 6.5. Bueno, ahora NULL s es igual a NULL

Las comparaciones se pueden hacer entre cualquier tipo de valores, cadenas de texto, por ejemplo. El comparador de igualdad se puede utilizar para localizar aquellas cadenas iguales a una dada. Por ejemplo, para localizar en la base de datos de actores todos aquellos cuyo apellido

fuese Crow. Resulta que est buscando un determinado actor con ese apellido, pero no recuerda su nombre. Podra utilizar esta consulta:
USE videoteca;

SELECT * FROM actor WHERE apellidos = 'Crow';

El resultado: todos los actores con ese apellido, por ejemplo Russell, el famoso protagonista de "Gladiador"... que no? Ah, claro, es que su apellido es Crowe, no Crow. Bueno, para esos casos existe un operador especial para cadenas, LIKE . El operador LIKE permite realizar comparaciones con cadenas parciales, utilizando algunos caracteres especiales. Antes buscaba todos los actores cuyo apellido fuese Crow, pero ahora quiere que la consulta devuelva todos los actores con Crow como comienzo de su apellido. Utilice la siguiente consulta:
USE videoteca;

SELECT * FROM actor WHERE apellidos LIKE 'Crow%';

Como ve, se ha utilizado el carcter del tanto por ciento a continuacin de la cadena de comparacin. Ese carcter concordar con cuantos caracteres aparezcan tras Crow en los apellidos de la tabla de actores; aunque el apellido concuerde exactamente, se obtendr un resultado. Si lo desea, puede utilizar el carcter del guin bajo para buscar concordancias con un solo carcter, por ejemplo:
USE videoteca;

SELECT * FROM actor WHERE apellidos LIKE 'Crow_';

Esta consulta slo devuelve aquellos registros cuyo apellido sea Crow ms un carcter al final. Ambos caracteres (% y _) se conocen como comodines.

Operadores lgicos
Estn basados en las premisas de la lgica booleana, en

la que las operaciones bsicas son NOT , AND, OR y XOR. Y precisamente stos son los nombres de los operadores. Nada hay nada ms sencillo que saber cmo funcionan estos operadores. Por ejemplo, en la figura 6.6 se est investigando el funcionamiento del operador AND. Las pruebas con NOT deben hacerse de forma distinta, ya que se trata del operador de negacin y acta sobre un nico valor.

Figura 6.6. Cmo funciona AND?

Ah, no se olvide de hacer estas mismas pruebas con el valor NULL , ya sabe que no siempre se obtiene el resultado esperado.

Cambiando la precedencia
Se entiende por precedencia el orden en el que MySQL efecta las operaciones de una determinada consulta. Es sencillo saber el resultado de la operacin 2 + 2, aunque no es evidente si el resultado de 2 + 2 * 5 ser 12 o 20. Depender de si MySQL efecta antes la suma o la multiplicacin. Puede comprobar que el resultado es 12. MySQL no realiza las operaciones segn las va encontrando: existe una prioridad. Las multiplicaciones o divisiones se evalan antes que las sumas o las restas, por ejemplo. Sin embargo, es posible modificar esa prioridad siempre que lo desee, con slo utilizar parntesis. Aquellas operaciones rodeadas por parntesis se realizan antes. Esto permite modificar la operacin anterior para que la suma se realice antes que la multiplicacin: (2 + 2) * 5 s dar como resultado 20. Puede comprobarlo ejecutando la siguiente consulta:
SELECT 2 + 2 * 5, (2 + 2) * 5;

En la figura 6.7 puede ver el resultado.

Figura 6.7. Uso de parntesis

Manipulacin de bases de datos


Durante los captulos anteriores (incluso en ste) hemos creado y eliminado bases de datos, pero no hemos visto la sintaxis exacta de la instruccin de creacin de bases de datos.

Creacin
Las sintaxis de la sentencia de creacin de base de datos es muy sencilla:
CREATE DATABASE [IF NOT EXISTS] nombre;

Donde nombre es el nombre que quiera darle a la base de datos. Si intenta crear una base de datos cuyo nombre ya est asignado a otra base de datos, se producir un error del que MySQL avisar. Si no desea que dicho error se produzca, incluya IF NOT EXISTS. El resultado: si existe una base de datos con ese nombre, no se contina con la instruccin de creacin de bases de datos actual.

Borrado
Tan sencilla como la creacin, el borrado de bases de datos sigue la sintaxis:
DROP DATABASE [IF EXISTS] nombre;

Si la base de datos no existe, MySQL avisar de ello, aunque puede evitar el mensaje si utiliza IF EXISTS. En ese caso, MySQL slo ejecutar el borrado en caso de que la base de datos exista.
Advert encia: Tenga mucha precaucin antes de ejecutar una instruccin de borrado de una base de datos. Tanto la base de datos como la carpeta y los archivos que conforman la ubicacin en disco de la misma sern eliminados.

Consultas de seleccin
La sintaxis de las consultas SELECT o de seleccin de valores no es tan sencilla como las vistas hasta ahora, de manera que vamos a simplificar su definicin. Sin embargo, veremos las consultas ms frecuentemente utilizadas, las que ms tiles le sern durante su trabajo. Simplificando, una instruccin SELECT debe seguir la siguiente sintaxis:
SELECT lista de columnas [FROM lista de tablas] [WHERE lista de condiciones]

[ORDER BY campos por los que ordenar]

La lista de columnas que quiera obtener siempre debe estar presente aunque, como vio con los ejemplos de los operadores, no es necesario que sean nombres de columnas de tablas, pueden ser operaciones de algn tipo. La razn es la misma que hace opcional la lista de tablas de la que obtener las columnas: es posible que la consulta no necesite tabla alguna. La lista de tablas determinar qu columnas podr mostrar en la primera seccin de la consulta, es decir, las tablas sobre las que se realizar la seleccin. En tercer lugar, puede indicar una serie de condiciones que quiera que cumplan los campos de los registros sobre los que realiza la consulta, utilizando operadores de comparacin: un valor debe ser mayor que otro, o igual a otro, una cadena debe parecerse a otra, etctera. Por ltimo, podr determinar la ordenacin del resultado por una o ms columnas. A continuacin veremos algunos ejemplos de las consultas que ms tiles pueden serle en su quehacer diario. Trabajaremos con la base de datos de pelculas que construimos al empezar el captulo.
Not a: Para los ejemplos necesitaremos trabajar con la misma base de datos. Es necesario que haya ejecutado las instrucciones mostradas al principio de este captulo. Estas instrucciones estn tambin en los archivos 01 - Crear la base de dat os.sql, 02 - Insert ar valores iniciales.sql y 03 - Rest o de inserciones.sql que se encuentran en la Web de esta gua.

Listados de una tabla


En primer lugar, qu actores estn dados de alta en la base de datos? Seguro que sabe cmo obtener ese listado:
USE videoteca;

SELECT * FROM actor;

El resultado debera ser similar al que se puede ver en la figura 6.8.

Figura 6.8. Listado de actores

El asterisco permite seleccionar todos los campos de las tablas afectadas por las consultas. Podra indicar qu campos quiere obtener como, por ejemplo, el identificador, el nombre y los apellidos:
USE videoteca;

SELECT id, nombre, apellidos FROM actor;

Aunque tambin puede concatenar nombre y apellidos en un solo campo:


USE videoteca;

SELECT id, CONCAT(nombre, ' ', apellidos) FROM actor;

Esta ltima consulta tiene un problema "esttico": observe el encabezado de la columna que muestra la concatenacin en la figura 6.9.

Figura 6.9. Encabezado de una concatenacin

Es muy sencillo cambiar este comportamiento. Para asignar un nombre a esa columna ha de indicarlo tras su definicin en la instruccin de seleccin:
USE videoteca;

SELECT id, CONCAT(nombre, ' ', apellidos) AS nombre FROM actor;

Puede ver en la figura 6.10 cmo cambia el resultado, ahora la columna de la concatenacin se llama nombre.

Figura 6.10. Cambio del nombre de un resultado

Un posible cambio en esta consulta sera obtener el resultado ordenado por apellido:
USE videoteca;

SELECT id, CONCAT(nombre, ' ', apellidos) AS nombre FROM actor

actor ORDER BY apellidos;

Como puede ver, se ha aadido al final de la consulta la clusula ORDER BY, indicando a continuacin los campos por los que se quiere ordenar el resultado. Podra cambiar el orden de los resultados utilizando DESC despus de cada campo, as la ordenacin sera descendente (en lugar de ascendente). Pero, cmo ordenar el resultado usando un campo calculado (como la concatenacin)? Es posible si se indica la posicin que tiene ese campo en la lista de la seleccin. Por ejemplo, la funcin CONCAT es el segundo campo escrito tras SELECT . La siguiente consulta ordena el resultado de la consulta por el resultado de la concatenacin de nombre y apellidos de los actores:
USE videoteca;

SELECT id, CONCAT(nombre,' ',apellidos) AS nombre FROM actor ORDER BY 2;

Otra consulta que le resultar muy til es la que permite contar el nmero de elementos en una determinada tabla. La siguiente le dir el nmero de actores que tiene en la base de datos:
USE videoteca;

SELECT COUNT(*) FROM actor;

Puede cambiar el nombre de las columnas devueltas:


USE videoteca;

SELECT COUNT(*) actores FROM actor;

El resultado de esta consulta puede verse en la figura 6.11.

Figura 6.11. Actores y pelculas

Listados de varias tablas


Para sacar partido al modelo relacional es necesario poder extraer informacin a partir de datos repartidos por varias tablas; hasta ahora no podemos hacer algo as ya que slo hemos visto cmo realizar operaciones sobre una sola tabla. Para realizar consultas de seleccin sobre ms de una tabla es preciso indicarle a MySQL de qu tablas se trata y cmo estn relacionadas. De nada servira hacer una consulta como sta:
USE videoteca;

SELECT * FROM pelicula, actores_por_pelicula, actor;

El resultado es catico, 120 registros resultantes: ha obtenido todas las combinaciones posibles de los registros de las tres tablas envueltas en la seleccin. Para poder organizar la informacin de estas tres tablas ha de utilizar de forma diferente la parte del FROM de la consulta, indicando ah cmo se relacionan las tablas. Para simplificar las consultas se utilizarn seudnimos para los nombres de las tablas, como se hizo con los campos de las consultas. Construya una consulta que devuelva la lista de pelculas, con sus actores. En primer lugar, necesita saber qu campos desea obtener. Bastar con el ttulo de la pelcula y la concatenacin del nombre y los apellidos del actor. La primera parte de la consulta podra ser algo as:
... SELECT titulo, CONCAT(nombre, ' ', apellidos) AS interprete FROM ...

La parte "complicada" viene a partir del FROM . Es mejor ir poco a poco. El primer paso es determinar qu tablas estn envueltas en la consulta. En la figura 6.12 puede ver un fragmento del modelo relacional de la base de datos, el

dedicado a pelculas y actores.

Figura 6.12. Actores y pelculas, seleccionados

Considere como tabla principal la de pelculas, a la que llamaremos p en la consulta. La tabla de actores por pelcula une a los actores con las pelculas guardando parejas de identificadores de pelculas y actores. A esta tabla la llamaremos app. Por ltimo, la tabla de actores tendr el seudnimo a. Est claro que debemos utilizar los identificadores de actores y pelculas para enlazar las tablas entre s. La parte del FROM de la consulta que intentamos crear es similar a la siguiente: ...
FROM pelicula p JOIN actores_por_pelicula app ON p.id = app.idpelicula JOIN actor a ON app.idactor = a.id ...

Aunque parezca algo enrevesado, en realidad no lo es. En primer lugar aparece la primera tabla, la de pelculas. A continuacin de su nombre se indica su seudnimo. Como ve, no es necesario utilizar AS. La siguiente lnea comienza con la palabra reservada JOIN . Cuando utiliza esa palabra le est indicando a MySQL que quiere unir la tabla anterior (pelicula en este caso) con la indicada a continuacin (actores_por_pelicula). La palabra reservada ON se utiliza para especificar qu campos se utilizarn como enlace entre los resultados. Tras ella, la pareja de campos que han de ser iguales. En el primer caso, el identificador de la pelcula debe ser igual al campo idpelicula de la tabla de actores por pelcula.
Truco: Fjese en que utilizamos los seudnimos de las tablas inmediatamente. De esa manera se simplifica enormemente el cdigo, que de otra forma debera incluir los nombres completos de las tablas.

A continuacin puede ver la consulta completa:


USE videoteca;

SELECT titulo, CONCAT(nombre, ' ', apellidos) AS interprete FROM

pelicula p JOIN actores_por_pelicula app ON p.id = app.idpelicula JOIN actor a ON app.idactor = a.id;

La figura 6.13 muestra el resultado de esta consulta de seleccin sobre varias tablas, muy diferente al obtenido con el primer intento, sin JOIN .

Figura 6.13. Actores y pelculas, seleccionados

Vamos a incluir en esta consulta el director de la pelcula. Para ello necesitamos incluir ms campos en la seleccin, ms tablas en la parte del FROM y ms relaciones entre campos. Comencemos viendo los nombres de los campos:
... SELECT titulo, CONCAT(nombre, ' ', apellidos) AS interprete, CONCAT(nombre, ' ', apellidos) AS director ...

Parece correcto, pero no lo es. Existe un problema en esta seleccin: los nombres de los campos de la tabla de actores y de directores son los mismos. Si intenta hacer una consulta de esta forma, MySQL no ser capaz de determinar a qu tabla pertenece cada campo y le informar de un error. Solucionar este error es bien simple: slo necesitamos indicar tambin la tabla a la que pertenecen los campos, usando el seudnimo de la misma como prefijo del nombre de columna, separando ambos con un punto. La siguiente es la consulta que buscamos:
USE videoteca;

SELECT p.titulo, CONCAT(a.nombre, ' ', a.apellidos) interprete, CONCAT(d.nombre, ' ', d.apellidos) director FROM pelicula p JOIN actores_por_pelicula app

ON p.id = app.idpelicula JOIN actor a ON app.idactor = a.id JOIN directores_por_pelicula dpp ON p.id = dpp.idpelicula JOIN director d ON dpp.iddirector = d.id;

El resultado de esta consulta puede verse en la figura 6.14.

Figura 6.14. Pelculas, actores y directores

Las consultas que involucran datos de muchas tablas se pueden utilizar de varias formas. Una de ellas, la que acabamos de ver, para mostrar informacin conjunta. Otra aplicacin interesante sera calcular el nmero de pelculas en las que aparece un determinado actor. Podramos saberlo de un vistazo, mirando el resultado de la figura 6.14, pero si el resultado de la consulta fuesen miles de registros lo tendramos mucho ms complicado. La siguiente consulta devuelve dos columnas: el nombre del actor en una de ellas, el nmero de pelculas en las que ha participado en la otra:
USE videoteca;

SELECT CONCAT(a.apellidos, ', ', a.nombre) actor, COUNT(app.idpelicula) peliculas FROM actor a JOIN actores_por_pelicula app ON a.id = app.idactor ORDER BY a.apellidos, a.nombre;

El resultado, mostrado en la figura 6.15, no parece demasiado de fiar. El seor Ford, protagonista de tres pelculas en nuestra base de datos? Que sepamos, slo de dos.

Figura 6.15. Cuntas pelculas tiene un actor?

Para utilizar de forma conjunta y correcta COUNT y otros valores en la parte de seleccin de campos de una consulta es necesario indicar cmo agrupar la informacin. Fjese, le est diciendo a MySQL que quiere que cuente las veces que aparece idpelicula en la tabla actores_por_pelicula, pero esa cuenta puede realizarse de muchas formas: contando todos los registros que aparecen en la tabla, o para una determinada pelcula, o para un determinado actor. En este caso particular, quiere ver las pelculas de cada actor, as que tendra que agrupar por idactor , as:
USE videoteca;

SELECT CONCAT(a.apellidos, ', ', a.nombre) actor, COUNT(app.idpelicula) peliculas FROM actor a JOIN actores_por_pelicula app ON a.id = app.idactor GROUP BY a.id ORDER BY a.apellidos, a.nombre;

Esto es otra cosa: ahora puede ver en la figura 6.16 la informacin que buscaba.

Figura 6.16. Todos los actores y sus pelculas

Sin embargo, aqu hay algo que no cuadra, verdad? Como sabe, en la tabla de actores hay ms de dos registros, pero no aparecen como resultado de esta consulta. La razn: esos actores sin pelcula no tienen ningn registro en la tabla actores_por_pelicula, de manera que la consulta anterior no los incluye en el resultado. Pero, y si quiere que aparezcan tambin los actores sin pelcula en este listado? Podra utilizar esta otra consulta:
USE videoteca;

SELECT CONCAT(a.apellidos, ', ', a.nombre) actor, COUNT(app.idpelicula) peliculas FROM actor a LEFT JOIN actores_por_pelicula app ON a.id = app.idactor GROUP BY a.id ORDER BY a.apellidos, a.nombre;

Al usar LEFT JOIN se obtienen todos los registros de la tabla de actores (que est a la izquierda de LEFT JOIN ), aunque no exista correspondencia en la tabla de la derecha. El resultado de esta consulta puede verse en la figura 6.17.

Figura 6.17. Todos los actores y sus pelculas

Suponga que cambia la forma en la que est construida la consulta, el orden de aparicin de las tablas:
... FROM actores_por_pelicula app LEFT JOIN actor a ON app.idactor = a.id ...

El resultado variar. Volver a obtener lo que vio en la figura 6.16 porque ahora la tabla de la izquierda no contiene ms que esos dos actores. Pero es sencillo volver a obtener el resultado de la figura 6.17, utilice RIGHT JOIN en lugar de LEFT JOIN :
... FROM actores_por_pelicula app RIGHT JOIN actor a ON app.idactor = a.id ...

Truco: La clave es: en qu parte (izquierda o derecha) est la tabla que s contiene registros que no estn en la otra tabla? Si la que s contiene esos registros est a la izquierda, use LEFT JOIN, en caso contrario, use RIGHT JOIN.

Algunos de estos actores estn dados de alta porque participan en una de las pelculas, pero an no se les ha asociado a ella. Es el caso de Rutger Hauer y Sean Young, presentes en "Blade Runner". Inserte los registros necesarios para que esa asociacin exista. Primero necesita saber el identificador de la pelcula "Blade Runner":
USE videoteca;

SELECT id FROM pelicula WHERE titulo = 'Blade Runner';

Su identificador debera ser el 1. Ahora, los identificadores de los dos intrpretes:


USE videoteca;

SELECT id FROM actor WHERE nombre = 'Rutger' AND apellidos = 'Hauer';

Esta consulta le... no? No devuelve nada? Pruebe a buscar slo por el nombre, pero obtenga todos los campos, no slo el identificador. Ahora s, verdad? Fjese en la figura 6.18, que muestra el resultado de la consulta.

Figura 6.18. Aqu hay algo raro...

Efectivamente, fjese en la separacin que hay entre

Rutger y la lnea de la izquierda. No le parece que hay ms separacin entre Hauer y la lnea correspondiente? Quiz haya un espacio antes del nombre. Intntelo con esta consulta:
USE videoteca;

SELECT id FROM actor WHERE nombre = 'Rutger' AND apellidos = ' Hauer';

Fjese en que se ha dejado un espacio entre la comilla simple y Hauer. Ejecute la consulta. Ahora s, verdad?
Not a: En breve ver cmo modificar este registro para solucionar el problema.

El identificador de este actor es el 8. Y el de Sean Young?


USE videoteca;

SELECT id FROM actor WHERE nombre = 'Sean' AND apellidos = 'Young';

El ltimo que necesita, su identificador es el 9. Fjese en cmo se han utilizado condiciones en la parte del WHERE de la consulta en las consultas anteriores. Se trata de comparaciones entre valores, utilizando los operadores que vimos anteriormente. A continuacin veremos cmo se modifican los valores almacenados en una tabla.

Actualizaciones
Las actualizaciones de datos se rigen por la siguiente sintaxis:
UPDATE tabla [, tabla ...] SET columna = valor [, columna2 = valor2 ...] [WHERE condiciones]

Tras la palabra reservada UPDATE se indican las tablas sobre las que se quiere realizar la operacin de actualizacin de datos, a continuacin los valores que se tienen que asignar a los campos que interesa modificar.

Por ltimo, es posible utilizar una lista de condiciones que restringirn el conjunto de registros cuyo valor se modificar. Estas condiciones son similares a las utilizadas en las consultas de seleccin. Es necesario hacer un cambio en un determinado registro de la tabla de actores. Recuerde que el apellido de Rutger Hauer tena un espacio al comienzo, algo que caus problemas en el apartado anterior. Esta modificacin se puede realizar de la siguiente forma:
USE videoteca;

UPDATE actor SET apellidos = 'Hauer' WHERE nombre = 'Rutger';

Aunque puede que le asalte la duda: existir algn actor ms con un espacio delante del apellido, o del nombre? Lo ideal sera poder eliminar esos espacios de todas las columnas donde sea necesario. Puede hacerlo con una consulta de actualizacin sobre la tabla de actores y directores, que afecte a todos los registros, utilizando la funcin TRIM . Esta funcin elimina los espacios que anteceden o preceden a una cadena de texto. Ejecute esta consulta:
SELECT TRIM(' cadena ');

En la figura 6.19 puede comparar el aspecto de la cadena con sus espacios antes y despus, y el resultado de aplicarle la funcin TRIM .

Figura 6.19. Uso de TRIM

Puede eliminar los espacios que no le interesen de nombres y apellidos en las tablas de actores y directores utilizando la siguiente consulta:
USE videoteca;

UPDATE actor a, director d SET a.nombre = TRIM(a.nombre), a.apellidos = TRIM(a.apellidos), d.nombre = TRIM(d.nombre), d.apellidos = TRIM(d.apellidos);

Como ve, no se ha utilizado la clusula WHERE , lo que significa que se actualizarn todos los registros de ambas tablas. El apellido del actor Rutger Hauer ya es correcto, pero

an no aparece como intrprete de ninguna pelcula. El siguiente apartado est dedicado a las inserciones de datos, viendo de paso cmo realizar las asociaciones entre pelculas.

Inserciones
La sintaxis de la instruccin de insercin es la siguiente:
INSERT INTO tabla [(columna,...)] VALUES (expression,...);

La parte en la que se indican los nombres de las columnas se puede omitir si en la parte de los valores stos se escriben en el orden en el que se definieron al crear la tabla, y adems existe un valor para cada columna. Inserte los valores necesarios en la tabla de actores por pelcula para que Rutger Hauer y Sean Young aparezcan en el reparto de "Blade Runner". Podra insertar el primero as:
USE videoteca;

INSERT INTO actores_por_pelicula( idpelicula, idactor ) VALUES(1, 8);

Pero tambin puede hacer esto otro:


USE videoteca;

INSERT INTO actores_por_pelicula VALUES(1, 9);

La primera instruccin hace referencia a Rutger Hauer, la segunda a Sean Young. Vea el efecto que han tenido estas inserciones:
USE videoteca;

SELECT titulo, CONCAT(nombre, ' ', apellidos) AS interprete FROM pelicula p JOIN actores_por_pelicula app ON p.id = app.idpelicula JOIN actor a ON app.idactor = a.id WHERE p.titulo = 'Blade Runner';

Puede ver el resultado de esta consulta en la figura 6.20.

Figura 6.20. Varios actores para una pelcula

Como ve, es posible saber si una pelcula tiene ms de un actor si su ttulo aparece ms de una vez. Tambin podra construir una consulta que contase el nmero de actores que tiene cada pelcula. Ya debe tener los conocimientos suficientes para hacerla por s mismo, as que le proponemos que lo intente por su cuenta antes de mirar la solucin que se incluye a continuacin:
USE videoteca;

SELECT p.titulo, COUNT(app.idactor) interpretes FROM pelicula p LEFT JOIN actores_por_pelicula app ON p.id = app.idpelicula GROUP BY p.id;

El resultado de esta consulta puede verse en la figura 6.21. Como puede comprobar, "Blade Runner" tiene tres actores, ya lo sabamos. Pero esta consulta devuelve otra informacin digna de mencin. Hay una pelcula sin actores: Naves misteriosas.

Figura 6.21. Intrpretes por pelcula

Gracias a esta consulta de seleccin hemos localizado una inconsistencia en la base de datos: una pelcula sin actores. Existir algn actor de esa pelcula en la tabla de actores? "Naves misteriosas" fue protagonizada por Bruce Dern, entre otros. Si lo buscamos en la base de datos ver que aparece con el identificador 6. Para aadirlo como actor necesitamos conocer el identificador de la pelcula, que es el 4. Una nueva insercin en la tabla de actores por pelcula solucionar el problema:
USE videoteca;

INSERT INTO actores_por_pelicula(idpelicula, idactor) VALUES(4, 6);

Si vuelve a repetir la consulta que dice cuntos intrpretes tiene asociados una determinada pelcula, podr comprobar que "Naves misteriosas" ya tiene uno.
Not a: Queda como ejercicio para el lector repetir el mismo proceso con los directores. En caso de que encuentre alguna pelcula sin director, podemos decirle que Douglas Trumbull dirigi "Naves misteriosas".

Borrados
Una de las operaciones ms peligrosas es el borrado de registros. Una simple equivocacin en la condicin de borrado y se perdern datos. La sintaxis de esta instruccin es la siguiente:
DELETE FROM tabla [WHERE condicin];

La parte del WHERE es similar a la utilizada en consultas de seleccin y permite restringir los registros que se borrarn. Si no indica ninguna condicin se eliminarn todos los registros de la tabla. Quiz necesite hacer algn borrado en la base de datos. Compruebe qu formatos de grabacin estn disponibles:
USE videoteca;

SELECT * FROM soporte;

La figura 6.22 muestra el resultado. Existen pelculas en todos esos formatos?

Figura 6.22. Formatos de grabacin

Puede averiguarlo con la siguiente consulta:


USE videoteca;

SELECT s.nombre, COUNT(p.id) peliculas FROM soporte s LEFT JOIN pelicula p ON s.id = p.idsoporte GROUP BY s.id;

El resultado de esta consulta puede verse en la figura 6.23: no existe ninguna pelcula en formato LaserDisc.

Figura 6.23. Pelculas en cada formato

Puede que se haya deshecho de todas sus grabaciones en LaserDisc, o que el lector haya dejado de funcionar y las

pelculas ya no sean tiles. Elimine ese formato de la tabla de soportes de grabacin:


USE videoteca;

DELETE FROM soporte WHERE id = 3;

Adis, LaserDisc! Durante este captulo hemos visto la sintaxis de las instrucciones de seleccin, insercin, actualizacin y borrado de registros en tablas. Tambin hemos visto cmo crear y borrar bases de datos. La sintaxis real de las instrucciones que este captulo ha cubierto es ms compleja, en realidad. Las opciones y los modificadores son muchos, y el espacio disponible en esta gua es limitado. Sin embargo, ahora tiene la base necesaria para enfrentarse a la documentacin que MySQL proporciona en su Web sobre la sintaxis completa de su versin del lenguaje SQL con muchas ms posibilidades de xito. Lo ms importante de este captulo es que comprenda que con SQL se puede extraer cualquier informacin de una base de datos, siempre que la base de datos est diseada correctamente. Quiz unas consultas sean ms complicadas que otras, pero las herramientas estn ah. Y tan importante como extraer la informacin es saber guardarla, manteniendo la consistencia de los datos. Otra conclusin que debe sacar de este captulo es que el empleo de archivos de rdenes es mejor que el uso de herramientas visuales para tareas repetitivas.

PHP y MySQL
Hasta ahora nos hemos dedicado a adquirir los conocimientos bsicos de MySQL y PHP. Hemos visto lo ms destacado de ambas tecnologas, pero sin llegar a mezclarlas (exceptuando la toma de contacto del captulo primero, claro). Pero incluso en ese captulo nos limitamos a utilizar la cara funcional de MySQLi, la nueva forma de acceder MySQL desde PHP que apareci en la versin 5. Durante este captulo veremos cmo utilizar MySQLi en su vertiente orientada a objetos. Ha de prestar especial atencin a esta forma de trabajo, puesto que es la que utilizaremos en el resto de captulos. Comenzaremos viendo cmo se realiza una conexin con un servidor de bases de datos, nuestro primer paso para trabajar con MySQL. Utilizando esa conexin realizaremos operaciones de consulta, inserciones, actualizaciones y borrados sobre bases de datos existentes. Adems de stas, tambin es posible realizar operaciones de creacin de bases de datos y tablas. No dejaremos de ver las tcnicas necesarias para controlar los errores que se puedan producir en nuestros intentos de conexin y en posteriores consultas. Es muy importante que sepamos cmo reaccionar ante situaciones no previstas. Para terminar el captulo veremos cmo modificar el archivo de configuracin de PHP para influir en el comportamiento predeterminado de MySQLi. Estas opciones de configuracin tambin pueden incluirse en las secciones que se refieran a nuestro servidor Web, dentro de la configuracin de Apache.

Acceso mejorado a MySQL


Aunque el equipo de desarrollo de PHP 5 se centr en mejorar aspectos del lenguaje como la orientacin a objetos, no por ello se descuidaron otros. Sin ir ms lejos, la interfaz de acceso a MySQL fue mejorada.
Not a: No vamos a entrar en los detalles que hacen mejor a esta versin, pero no se trata slo de aspecto tcnicos: acceder a MySQL resulta mucho ms sencillo con esta nueva interfaz.

PHP agrupa las funciones dentro de extensiones. Existen extensiones para acceder a MySQL, para gestionar archivos XML, para trabajar con archivos en formato PDF y un largo etctera. Realmente largo: PHP dispone de extensiones para casi cualquier operacin que pueda imaginar.

Mientras que el nombre de la versin primigenia es MySQL, el nombre de la nueva versin es MySQLi. La creencia ms extendida es que la ltima "i" latina significa mejorado (improved) aunque no es descabellado pensar que su significado sea otro. A fin de cuentas, PHP son las siglas de PHP: Hypertext Preprocessor. La "compatibilidad hacia atrs" (backwards compatibility) es un aspecto fundamental en la vida de un lenguaje de programacin, las nuevas versiones deben ser capaces de ejecutar programas desarrollados para versiones anteriores. Para que los programas ya existentes fuesen compatibles con las nuevas versiones de PHP era necesario mantener las anteriores funciones de acceso, incluyendo las nuevas bajo una denominacin diferente. Tambin se hizo un esfuerzo para que aquellos que ya supiesen cmo utilizar la extensin original de acceso a MySQL no encontrasen complicado dar el salto a la nueva versin. Si es su caso, no tendr que desandar el camino: todo lo que sepa de MySQL podr aprovecharlo en MySQLi. Slo una cosa ms antes de empezar: esta extensin slo funciona con servidores MySQL a partir de la versin 4.1.

El ciclo de la vida
De la vida en comn de PHP y MySQL, se entiende. Todas las operaciones que realicemos desde PHP con MySQL van a seguir los mismos pasos: conexin, operacin y desconexin.

Conexin
El paso primordial de su relacin con MySQL es la conexin. Sin conexin no habr nada que pueda hacer con su servidor de bases de datos. Durante el proceso de conexin indique dnde est el servidor de bases de datos, con qu usuario quiere conectar, cul es su clave y cul es la base de datos con la que va a trabajar.
Not a: Aunque, opcionalmente, puede indicar otros valores al realizar la conexin, como el puerto o el socket, en la mayora de las ocasiones bastar con los cuatro parmetros antes enumerados.

Puede realizar la conexin en el mismo momento de crear el objeto que utilizar para conectar con la base de datos. Por ejemplo, recuerde el ejemplo del primer captulo. Entonces, conectbamos con la base de datos de pelculas utilizando el siguiente cdigo:
<?php

$conexion = mysqli_connect( 'localhost', 'root', 'clave', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); }

...

Not a: Recuerde que, si instal XAMPP para seguir el contenido de este libro, el usuario root de MySQL, por defecto, no tendr contrasea alguna asignada. Por lo tanto tendr que sustituir 'clave' por '' (una cadena vaca).

Este cdigo muestra cmo conectar con un servidor MySQL utilizando la versin funcional de MySQLi. El servidor de bases de datos se encuentra en la misma mquina que el servidor de pginas, el nombre del usuario es root , la clave es clave y el nombre de la base de datos es videoteca.
Not a: Sabemos que ambos servidores estn en la misma mquina porque se utiliza localhost como nombre del servidor. Este nombre se corresponde con la IP 127.0.0.1, que siempre se asigna al ordenador con el que estamos trabajando.

Volvamos a escribir el cdigo de conexin, pero ahora utilizando la versin orientada a objetos de MySQLi:
<?php

$videoteca = new mysqli( 'localhost', 'root', 'clave', 'videoteca' );

if ($videoteca->errno != 0) { echo('Error en la conexin.'); exit(); }

...

Si recuerda lo aprendido sobre programacin orientada a objetos en el captulo 4 reconocer que la primera lnea del fragmento de cdigo anterior crea un ejemplar de la clase mysqli, que hemos llamado videoteca. Como parmetros del constructor de la clase hemos pasado el nombre del servidor, el nombre del usuario, la

clave y el nombre de la base de datos con la que queremos trabajar. Es posible que ocurra algn error durante el intento de conexin: el servidor MySQL puede estar apagado, no existir la base de datos o quiz se haya equivocado en el nombre de usuario o en la contrasea. Para controlar esos casos, no tiene ms que utilizar la propiedad errno de la clase, que en caso de error devuelve el cdigo asociado al mismo. Si no se produjo ningn error, devolver cero. As, en caso de que no sea cero, informar de que ha ocurrido un error al realizar la conexin. Pero si no ha ocurrido ningn error, podr comenzar realizar operaciones con la base de datos.

Operacin
Una vez establecida la conexin, la ms comn de todas las operaciones que vamos a realizar es la recuperacin de informacin a travs de consultas. El objetivo de utilizar PHP y MySQL de forma conjunta es, por lo general, la creacin de aplicaciones Web. Por ejemplo, una tienda a travs de Internet. Por lo general los usuarios de estas aplicaciones realizarn consultas, mientras que los administradores se encargarn del mantenimiento de la base de datos. En la tienda que acabamos de mencionar, los clientes buscaran los productos que les interesasen (realizando consultas), mientras que los administradores se encargaran de aadir nuevos productos a la tienda, modificar los ya existentes o eliminar aquellos que estuviesen descatalogados. Siguiendo con nuestro ejemplo del primer captulo, este fragmento de cdigo era utilizado para obtener la lista de gneros cinematogrficos que hay en la base de datos:
...

$resultado = mysqli_query( $conexion, 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

...

La primera de las lneas anteriores utiliza la variable $conexin, que contiene la informacin devuelta por la funcin mysqli_connect() en el primer fragmento de cdigo. Es el primer parmetro de la funcin mysqli_query(). El segundo es la consulta que queremos realizar en la base de datos.

De igual forma que $conexion almacenaba la informacin necesaria para que MySQLi pudiese realizar operaciones con la base de datos tras realizar la conexin, $resultado contiene la informacin necesaria para poder recuperar todos los registros devueltos por la consulta. Puede recuperar esos registros utilizando el siguiente cdigo:
...

while($fila = mysqli_fetch_row($resultado)){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] ); }

...

Cada llamada a mysqli_fetch_row() devuelve un registro que se almacena en la variable $fila. Esta variable es, a su vez, una matriz, siendo cada uno de sus elementos un campo del registro. Utilizamos printf() para mostrar los datos que acabamos de obtener. Esta forma de trabajo es similar en otros lenguajes de programacin con acceso a bases de datos. Sin embargo, existe una ventaja que PHP tiene sobre algunos de ellos. Al obtener un elemento de la lista de registros devueltos, avanzamos automticamente al siguiente. Esto, que puede parecer una tontera, en realidad nos evita muchos problemas. Suponga que escribe el mismo bucle anterior, pero el avance automtico no se realiza. Si olvidase avanzar al siguiente registro, el bucle no terminara nunca y el programa no avanzara, quedando, como se suele decir coloquialmente, "colgado". Acaba de ver cmo se ejecuta una consulta y se obtienen los datos utilizando la versin funcional de MySQLi. El siguiente fragmento de cdigo muestra el equivalente utilizando la versin orientada a objetos, con la que se obtiene el mismo resultado:
...

$resultado = $videoteca->query( 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

while ($fila = $resultado->fetch_row()){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] );

); }

...

Una de las ventajas de la programacin orientada a objetos es que el cdigo resultante es ms fcil de comprender que el equivalente funcional. Veamos la instruccin que permite obtener uno por uno todos los registros, en su versin funcional:
$fila = mysqli_fetch_row($resultado)

Comparmosla con el equivalente orientado a objetos:


$fila = $resultado->fetch_row()

En la versin funcional, llamamos a una funcin que recibe como parmetro el resultado de realizar la consulta. Estamos trabajando con una funcin. Sin embargo, en la versin orientada a objetos trabajamos directamente con el resultado de la consulta, la variable $resultado. Y, efectivamente, lo ha adivinado: en este caso esa variable no es otra cosa que un objeto. Para terminar este ciclo de operaciones hemos de cerrar la conexin con la base de datos.

Desconexin
No por ser la ltima es la menos importante. El buen funcionamiento de sus aplicaciones depende de que sea civilizado en el empleo de los recursos a su disposicin. El servidor de bases de datos puede responder simultneamente a varios clientes, pero hasta un lmite. Una vez alcanzado ese techo, MySQL no podr responder ms peticiones. Una conexin no cerrada estar consumiendo recursos. El servidor de bases de datos es lo suficientemente inteligente para detectar aquellas conexiones ociosas, que no estn realizando alguna tarea, y pasado un tiempo, cerrarlas. Pero mientras pasa ese tiempo, los recursos seguirn malgastndose. Es curioso que, en muchas ocasiones, ese consumo de recursos se deba a que no se cierran las conexiones con la base de datos cuando se termina de trabajar con ella, algo tan sencillo de hacer utilizando la versin funcional de MySQLi como el cdigo que puede verse a continuacin:
...

mysqli_free_result($resultado); mysqli_close($conexion);

?>

Mientras que la primera lnea elimina de memoria el resultado de la consulta a la base de datos, la segunda cierra la conexin con MySQL. El mismo objetivo puede obtenerse con las siguientes lneas, utilizando la versin

orientada a objetos de MySQLi:


...

$resultado->close(); $videoteca->close();

?>

Acabamos de recorrer el ejemplo del primer captulo, viendo cmo se obtendra el mismo resultado utilizando la versin orientada a objetos de MySQLi. Vemoslo completo:
<?php

$videoteca = new mysqli( 'localhost', 'root', 'clave', 'videoteca' );

if ($videoteca->errno != 0) { echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query( 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

while ($fila = $resultado->fetch_row()){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] ); }

$resultado->close(); $videoteca->close();

?>

Aunque dista mucho de ser un programa profesional, cumple su funcin con dignidad, mostrando lo que le pedimos: la lista de gneros cinematogrficos que hay en nuestra base de datos. La figura 7.1 muestra el resultado de ejecutar esta pgina. Como puede comprobar es idntico al que se obtiene con la versin funcional de MySQLi, que pudo ver en la figura 1.19.

Figura 7.1. La lista de gneros, con objetos

Resumiendo, las operaciones que hemos tenido que realizar para realizar una consulta a nuestra base de datos de pelculas son siempre las mismas. La figura 7.2 describe las operaciones que tendr que realizar para lograr su objetivo.

Figura 7.2. El ciclo de la vida y los gneros

Not a: Como recordar, en el primer captulo ya realizamos estas operaciones, aunque entonces con la versin funcional de MySQLi. Durante este captulo utilizaremos la versin orientada a objetos.

Ahora que sabe cmo utilizar MySQLi para realizar las operaciones bsicas (conexin, consulta y desconexin) vamos a profundizar en algunos aspectos interesantes de esta biblioteca de funciones.

Conjuntos de registros
Ni la conexin ni la desconexin con MySQL guardan ningn misterio. Sin embargo, el resultado de realizar una consulta a la base de datos s. Recordemos cmo recuperamos los registros devueltos por una consulta:
...

$resultado = $videoteca->query( 'SELECT * FROM genero'

'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

while ($fila = $resultado->fetch_row()){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] ); }

...

En primer lugar, realice la consulta llamando al mtodo query() del ejemplar de la clase la clase mysqli que est utilizando. En este caso, ese ejemplar se llama $videoteca. Si la consulta tiene xito, podr acceder a los resultados gracias a la variable $resultado. Puede comprobar el tipo de esta variable utilizando la funcin gettype():
... printf("%s", gettype($resultado)); ...

El resultado ser la cadena object . Es decir, ha obtenido una referencia a un objeto, con sus mtodos y sus atributos. Pero, qu resultado obtendr si la consulta no tiene xito? Para comprobarlo, cambie en la consulta el nombre de la tabla (genero), de manera que no se corresponda con el nombre de ninguna tabla existente en la base de datos con la que est trabajando (por ejemplo, generos). Si intenta realizar la consulta ocurrir un error. Entonces, el tipo de la variable $resultado ser boolean, lo que permitir localizar el problema.
Not a: A estas variables, que pueden adoptar varios tipos en funcin de las circunstancias, se les da el nombre de mixed.

La variable $resultado es un ejemplar de la clase mysqli_result . Tras realizar una consulta con xito, puede acceder a sus mtodos y atributos. Veamos algunas de las propiedades ms interesantes: num_rows: Contiene el nmero de registros que la consulta ha devuelto. En nuestro ejemplo de la lista de gneros, puede ser interesante mostrar el nmero de registros encontrados. Slo tendra que incluir el siguiente fragmento de cdigo, siendo el resultado el que puede verse en la figura 7.3:
...

printf( "Registros encontrados: %s.<br/><br/>", $resultado->num_rows );

...

Figura 7.3. Nmero de registros encontrados

field_count: Devuelve el nmero de columnas que tiene cada uno de los registros devueltos. Este valor puede resultar interesante para controlar el ancho de una tabla en la que mostrar el resultado de la consulta, por ejemplo. Tambin merecen especial mencin los siguientes mtodos: fetch_field: Si fetch_row() permite obtener uno por uno los registros devueltos por la consulta, fetch_field() devuelve informacin sobre los campos del registro actual. El resultado lo devuelve en una matriz, como haca fetch_row(). La tabla 7.1 muestra los diferentes elementos en los que esta informacin est repartida, siendo cada uno un elemento de la matriz devuelta. Podra utilizar estos valores como encabezados de cada columna de una tabla HTML si decidiese mostrar la informacin de los gneros dentro de una.
Tabla 7.1. Elementos de fetch_field()

Pro p ied ad name orgname table orgtable def max_length flags type decimals

D escrip ci n Nombre de la columna. Nombre original de la columna, en caso de que se utilizasen alias en la consulta. Nombre de la tabla. Nombre original de la tabla, en caso de que se utilizasen alias en la consulta. Valor predeterminado. Tamao del campo. Atributos del campo, expresados de forma numrica. Tipo del campo. Si el campo es entero, indica el nmero de decimales empleados.

data_seek: Permite que nos desplacemos a un registro en concreto dentro de los resultados. Puede ser til cuando no quiera realizar una iteracin por todo el conjunto de resultados devuelto por la consulta que haya realizado. Por ejemplo si slo quiere mostrar los resultados en pginas de un nmero de elementos cada una, puede utilizar un bucle for controlado por una variable cuyo valor ir incrementando. Ese mismo

valor ser el que pasaremos a data_seek() para obtener uno por uno los registros que nos interesen. Si obtiene cuatro registros, para obtener el primero debe pasarle a la funcin un cero, para obtener el segundo un uno, y as sucesivamente. El siguiente fragmento de cdigo ilustra el concepto, recuperando slo el primer elemento devuelto por la consulta. Sustituya el bucle while por:
...

$resultado->data_seek(0); $fila = $resultado->fetch_row();

printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] );

...

Not a: Si lo desea puede encontrar ms informacin acerca de la clase mysqli_result , sus mtodos y sus atributos en la documentacin de PHP.

Otras consultas
Como ya hemos comentado, el mtodo query() puede utilizarse para ejecutar consultas, pero no tienen que ser slo consultas de seleccin: tambin puede tratarse de consultas de borrado, insercin o actualizacin. La nica diferencia est en que el resultado de ejecutar este tipo de consultas slo devolver TRUE en caso de xito y FALSE en caso contrario, pero no un conjunto de registros. Como ejemplo, el siguiente fragmento de cdigo, que nos permitira insertar un nuevo gnero en la base de datos, una vez establecida la conexin:
...

$sConsulta = <<<CONSULTA INSERT INTO genero( nombre, descripcion )VALUES( 'TH', 'Thriller' ); CONSULTA;

$resultado = $videoteca->query($sConsulta);

if ($resultado == FALSE){ echo('Error en la consulta.');

echo('Error en la consulta.'); }

...

Como resultado, en la carga de la pgina que muestra los gneros podr ver el que acabamos de aadir. Si la insercin no tuvo xito podr saberlo gracias al valor devuelto por el mtodo query().

Consultas escapadas
No se trata de aquellas consultas que se fugaron (perdn por el chiste fcil y malo). En la jerga de los informticos, "escapar" se entiende en algunos contextos como "realizar una conversin". En nuestro caso, el objetivo de esta conversin es hacer vlida una cadena que no lo es. Y esta cadena no es otra que una consulta. Existen ciertos caracteres que no pueden incluirse en una consulta, como las comillas simples. La siguiente insercin no sera vlida:
<?php

$videoteca = new mysqli( 'localhost', 'usuario', 'clave', 'videoteca' );

if (mysqli_connect_errno() != 0) { echo('Error en la conexin.'); exit(); }

$sTitulo = "Ocean's Eleven";

$sConsulta = "INSERT INTO pelicula(". " " " titulo,". idsoporte,". idgenero".

")VALUES(". " " " '".$sTitulo."',". 1,". 4".

")";

$resultado = $videoteca->query( $sConsulta );

if($resultado == FALSE){ echo('Error en la consulta.');

echo('Error en la consulta.'); echo($videoteca->error); }

$videoteca->close();

...

El problema se debe, simplemente, a que el ttulo tiene una comilla simple, y MySQL lo entiende como el cierre de una cadena. Pero luego encuentra otro carcter de apertura de cadena, no cerrado y se hace un verdadero lo. Hay soluciones para todo. Inserte la siguiente lnea antes de crear la variable $sConsulta:
...

$sTitulo = $videoteca->real_escape_string( $sTitulo );

...

El mtodo real_escape_string() har los cambios necesarios en el ttulo para que la consulta de insercin pueda realizarse.

Configuracin
Al comienzo del libro hablamos sobre cmo programar usando PHP, aunque no entramos en detalles tales como las posibles opciones de configuracin existentes para este lenguaje. Tampoco vamos a verlas todas ahora, debido a que son demasiadas y no es ste un manual de referencia. Existe numerosa documentacin al respecto en la Web de PHP; concretamente en la siguiente direccin: http://php.net/manual/es/configuration.php Lo que s trataremos en este apartado son las opciones de configuracin de PHP que afectan al funcionamiento de MySQLi. Y el primer paso es consultar los valores que estas opciones tienen en nuestro sistema.

Valores de configuracin
Aunque existen varias formas de consultar los valores de configuracin de MySQLi vigentes en nuestro sistema, la ms inmediata consiste en crear una pgina PHP con el siguiente contenido:
<?php

phpinfo();

?>

Una vez la tenga, puede acceder a ella con cualquier cliente Web. Utilizando las herramientas de su cliente Web, busque dentro de esa pgina el texto mysqli. El cliente le mostrar la seccin de parmetros de configuracin de la biblioteca de funciones MySQLi. Debera ver algo parecido a lo que muestra la figura 7.4.

Figura 7.4. Configuracin de MySQLi

Truco: El comportamiento de la funcin phpinfo() no es siempre el mismo. Compare el logotipo de PHP que aparece al principio de la informacin devuelta por la funcin, con la imagen que muestra si usted cambia la fecha de su ordenador al 1 de abril (el da de las inocentadas de los angloparlantes, april's fools). No cabe duda: tienen sentido del humor.

La informacin respecto a la configuracin de MySQLi est divida en dos partes. La primera de ellas muestra detalles sobre el funcionamiento de MySQL, la versin de la API y la ubicacin del socket (relacionado con la comunicacin del servidor MySQL y sus clientes).
Not a: API son las siglas de interfaz de programacin de aplicaciones (Application Programming Interface), es decir, del propio MySQLi.

La segunda seccin es la que nos interesa, ya que muestra los parmetros de configuracin aplicables en este momento, y que puede cambiar si lo considera oportuno. Son los siguientes: mysqli.default_host: Le permite indicar cul ser el servidor MySQL al que se conecte por defecto, si al establecer la conexin no ha indicado ninguno. Como puede ver en la figura 7.4, este parmetro no tiene ningn valor asociado, por lo que cualquier intento de conexin sin indicar servidor ser fallido. mysqli.default_port: Especifica el nmero de puerto predeterminado al que realizar las solicitudes de conexin. En este caso el valor predeterminado es

3306, el puerto estndar de MySQL. Es la existencia de este parmetro el que permite realizar la conexin sin indicar valor alguno para el puerto. Sin este parmetro de configuracin tendra que incluir el nmero de puerto al realizar la conexin, tras el nombre de la base de datos. mysqli.default_pw: Clave de acceso predeterminada, es decir, la que sus intentos de conexin utilizarn si no indica ninguna al intentar conectar. Por defecto no contiene ningn valor. mysqli.default_socket: Permite indicar el socket que se utilizar durante la comunicacin entre el servidor de bases de datos y el cliente. Si no se indica ningn valor (como es el caso) PHP utilizar los valores internos de los que dispone. mysqli.default_user: Nombre del usuario predeterminado si al intentar conectar no indica ninguno. Est obligado a especificar el nombre del usuario porque, por defecto, este parmetro no contiene ningn valor. mysqli.max_links: Nmero mximo de conexiones con MySQL permitidas desde sus aplicaciones PHP. Por defecto, sin lmite. Dependiendo de la naturaleza de las aplicaciones que est desarrollando, o de la potencia y recursos de su servidor, puede que quiera indicar un lmite, de forma que su servidor no se colapse ante un aluvin de peticiones. mysqli.reconnect: Por defecto desactivado. Permite que PHP intente, de forma automtica, la reconexin con el servidor MySQL en caso de que sta se perdiese.
Not a: En la figura 7.4 habr podido comprobar que existen dos columnas asociadas a valores: Local Value y Mast er Value (valores locales y maestros, respectivamente). La primera se refiere a los valores aplicables a la pgina que estamos viendo ahora, mientras que la segunda a los aplicables a todas las pginas. En breve veremos cmo hacer esta distincin.

Ahora ya conoce los valores predeterminados de estos parmetros de configuracin y cmo afectan al funcionamiento de la biblioteca de funciones MySQLi. Pero, cmo puede cambiar los valores de estos parmetros?

Modificacin de la configuracin
Todos los parmetros de configuracin de PHP se encuentran en el archivo php.ini. La ubicacin de este archivo vara dependiendo del sistema operativo que utilice y de cmo haya instalado PHP. Si utiliza Linux o Mac OS X, es ms que probable que pueda encontrar este archivo en algn lugar de la carpeta /etc. En cambio, en Windows, es una buena idea mantenerlo en la carpeta del sistema (C:\WINNT puede ser uno de los nombres que tome), aunque tambin puede estar en la carpeta en la que instal PHP.

Independientemente del sistema operativo, si utiliz XAMPP para instalar Apache, PHP y MySQL, el archivo php.ini se encontrar en la carpeta /apache/bin/php.ini dentro de la carpeta en la que XAMPP se instal. Est donde est el archivo, bralo con su editor de textos favoritos y busque la seccin MySQLi, indicando su nombre entre corchetes. En la figura 7.5 realizamos dicha bsqueda con el bloc de notas.

Figura 7.5. Seccin MySQLi en php.ini

Haga una prueba sencilla: cambie el servidor predeterminado al que conectar de manera que el valor de esta variable, que ahora mismo no tiene ninguno asignado, sea localhost . Cuando haya realizado el cambio y guardado el archivo, slo tiene que reiniciar el servidor de pginas Web, Apache. Una vez reiniciado podr utilizar la pgina PHP que llama a la funcin phpinfo() para comprobar que el valor del parmetro de configuracin es el que hemos indicado en el archivo php.ini. El resultado debera ser similar al que se puede ver en la figura 7.6.

Figura 7.6. Servidor MySQL predeterminado

Cmo puede aprovecharse de este cambio en sus programas? Por ejemplo, no indicando el servidor MySQL al que quiere conectar. El siguiente fragmento de cdigo le permite conectar con el servidor MySQL que tenga en el mismo ordenador en el que est trabajando:
<?php

$conexion = new mysqli( '', 'root', 'clave', 'videoteca' );

if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); }

...

Como puede ver, el primer parmetro que pasamos al constructor de la clase, que debera ser el nombre del servidor, ahora es una cadena vaca. Anteriormente esa cadena era localhost . Sin embargo, podr comprobar que la pgina sigue conectando, recuperando la lista de gneros cinematogrficos y mostrndolos perfectamente. Recapacitemos durante un momento: qu beneficio puede obtener modificando estos parmetros de configuracin?

Ventajas
Suponga que tiene una pgina PHP por cada lista de valores de la base de datos. En cada una de esas pginas debe realizar una conexin con el servidor MySQL para

posteriormente obtener los registros que quiere mostrar en la pgina, indicando el servidor, el nombre de usuario y la clave. Tiene entonces el nombre de usuario y su contrasea en todos los archivos que conectan con la base de datos. No sera mejor tenerlos escritos en un solo sitio, una sola vez? De esa forma, si por cualquier motivo tuviese que cambiar el nombre de usuario o su contrasea, podra hacerlo sabiendo que ese cambio en la configuracin de MySQL slo implica un cambio en su aplicacin Web. Esta ventaja supone comodidad para usted que, como programador, debe asegurarse de que la aplicacin funciona correctamente bajo cualquier circunstancia. Pero existe otra ventaja, relacionada esta vez con la seguridad. Digamos que tiene cinco pginas PHP y, en cada una de ellas, el nombre de usuario y la contrasea. Si logra que ese nombre de usuario y esa contrasea estn en un solo lugar habr reducido cinco veces la probabilidad de que alguien se haga con la forma de acceder a su base de datos. Adems, esta informacin se encuentra en un archivo de configuracin del sistema. El acceso por parte de desaprensivos a estos archivos es ms complicado, algo que puede ayudarle a mejorar la seguridad de su aplicacin Web.

Inconvenientes
No todo iban a ser ventajas, este mtodo tambin tiene sus inconvenientes. Uno de ellos, aunque no demasiado importante, es que tiene que dejar claro a otros que puedan trabajar con usted dnde estn almacenados tanto el nombre de usuario como la contrasea de acceso. Imagine lo desconcertante que puede ser ver una lnea de cdigo que conecta con un servidor MySQL que no se especifica, sin utilizar ni nombre de usuario ni contrasea. Tambin ha de asegurarse que en ninguna pgina de la Web se muestre la informacin devuelta por phpinfo(), ya que esa pgina mostrara a todo el mundo la forma de conectar con el servidor de bases de datos.
Not a: Existen otras tcnicas para almacenar en un nico lugar los parmetros de conexin al servidor MySQL. Podra utilizar archivos de inclusin, de los que hablamos en el captulo cuatro, o sus propios archivos INI.

Y por ltimo, estos valores son globales, es decir, se aplican a todas las aplicaciones Web que se ejecuten bajo su servidor PHP. Obviamente, no todas las aplicaciones utilizarn los mismos parmetros de conexin. Sin embargo, existe una forma de modificar las opciones de configuracin de MySQLi para sus aplicaciones, conservando las opciones globales del archivo php.ini tal y como estaban, antes de sus cambios.

Opciones de PHP en Apache


La opcin ms simple para probar los programas PHP de ejemplo que hemos estado estudiando durante esta gua es guardar los archivos correspondientes en la carpeta htdocs, en la ruta en la que Apache est instalado. Vamos a crear una nueva carpeta, dentro de htdocs, llamada pruebas. Guarde dentro de esta nueva carpeta una copia de la pgina PHP que llama a la funcin phpinfo() para mostrar las opciones de configuracin. Si abre dos clientes Web para observar la informacin devuelta por cada pgina podr comprobar que son idnticas. Es justo esto lo que queremos cambiar. PHP y Apache pueden trabajar de forma conjunta. Es posible incluir ciertas directivas en los archivos de configuracin de Apache que sern pasadas a PHP. Usando estas directivas, puede separar sus aplicaciones PHP, todas basadas en las opciones de configuracin contenidas en el archivo php.ini, pero cada una con sus particularidades. Vamos a editar el archivo de configuracin de Apache. Su nombre es httpd.conf y, si utiliza XAMPP, lo encontrar en la carpeta /apache/conf/, dentro de la carpeta en la que XAMPP se instal. Una vez tenga el archivo abierto con su editor preferido, busque la cadena de texto htdocs dentro de un elemento <Directory>. Debera ser algo as en Windows:
<Directory "C:/xampp/htdocs">

La ruta ser diferente en Linux y Mac OS X. Ahora, localice la etiqueta que cierra esta seccin de la configuracin:
</Directory>

A continuacin de esta etiqueta escriba las siguientes directivas de configuracin:


<Directory "C:/xampp/htdocs/pruebas"> Options Indexes FollowSymlinks AllowOverride None Order allow,deny Allow from all php_admin_value mysqli.default_host localhost </Directory>

Guarde los cambios, reinicie el servidor Apache y ahora recargue las dos pginas que muestran el resultado de llamar a la funcin phpinfo() que estn en las carpetas htdocs y htdocs/pruebas. Ahora, si revisa las opciones de configuracin de MySQLi que dichas pginas muestran, comprobar que han dejado de contener la misma informacin. Mientras que la primera no tiene valor definido para el servidor MySQL predeterminado, la segunda muestra el valor localhost, como en la figura 7.7.

Figura 7.7. Diferentes valores locales y globales

La lnea importante es la siguiente:


php_admin_value mysqli.default_host localhost

Puede ignorar las otras opciones de configuracin. Con php_admin_value le indica a Apache que lo que viene a continuacin es una variable de configuracin de PHP, en este caso slo aplicable a la carpeta pruebas. Ahora s que podra establecer un nombre de usuario y una clave diferente por cada aplicacin, siempre que las colocase en carpetas diferentes, pudiendo realizar las conexiones con las bases de datos as:
<?php

$conexion = new mysqli('', '', '', ''); if ($conexion == FALSE){ echo('Error en la conexin.'); exit(); }

...

Y cada una de sus aplicaciones utilizara los valores de configuracin de PHP que hubiera indicado en el archivo de configuracin de Apache. Y no slo puede establecer estas diferentes configuraciones para cada carpeta que le interese, tambin puede diferenciar entre servidores virtuales, por ejemplo.
Not a: Los pasos descritos anteriormente son aplicables a configuraciones estndar en las que tiene acceso a los archivos de configuracin de Apache. Si no tiene acceso a ellos o no puede solicitar estos cambios al administrador del sistema, sepa que puede utilizar archivos .ht access para modificar las opciones de Apache de las carpetas Web a las que tenga acceso. Para ms informacin consulte la documentacin de Apache y pngase en contacto con el administrador de sus sistemas.

Anteriormente hicimos un comentario no del todo favorable acerca de la profesionalidad de las pginas que hemos programado durante este captulo. Esto es as por tres motivos. El primero salta a la vista: el aspecto que tiene la lista de categoras no es demasiado vistoso. Lo solucionaremos en el captulo dedicado a Smarty. El segundo motivo es la falta de interactividad. Aunque se trata de una pgina dinmica, cuyo aspecto cambia a medida que cambia el contenido de la base de datos con la que est trabajando, no permite que realicemos cambios, es necesario llevarlos a cabo en la base de datos para poder mostrarlos en la pgina. En el captulo dedicado a los formularios HTML ver cmo modificar el contenido de la base de datos directamente desde una pgina Web. El ltimo motivo que vamos a mencionar es la gestin de errores. Y nunca ms cierto que en este caso: no por ser el ltimo es el menos importante de los motivos. S, es cierto que en el cdigo que acabamos de escribir hemos introducido algunos controles para los errores: al conectar y al realizar consultas. Pero, estamos seguros de que funcionan? La prueba ms simple consiste en parar el servidor de bases de datos y volver a cargar la pgina. Cuando el servidor de bases de datos est detenido, intente cargar de nuevo la pgina que muestra la lista de categoras. Podr ver el desastre que muestra la figura 7.8. La gestin de errores que hemos realizado hasta ahora no ha servido de nada.

Figura 7.8. Control de errores

Sin embargo, se trata de un proceso muy importante que con ms frecuencia de la deseada se descuida. Veremos cmo combinar las herramientas que PHP nos proporciona para procesar los errores con las propias de MySQL en el captulo dedicado a la gestin de errores. Hasta ahora, ha aprendido lo bsico de PHP, MySQL, adems de a usarlos de forma conjunta. A partir de aqu comienza la parte divertida.

Formularios
No slo de mostrar informacin vive la Web. Uno de los principales atractivos de la programacin con PHP y MySQL est en la interactividad, entendindola como la posibilidad de modificar desde nuestro propio cliente Web la forma en la que nos presentan los datos que solicitamos, e incluso los propios datos. El nico requisito necesario para que los usuarios de nuestras aplicaciones puedan decirnos qu quieren hacer es aprender a utilizar una de las caractersticas del estndar HTML: los formularios. Un formulario no es ms que un conjunto de elementos que podemos incluir en nuestras pginas HTML sobre los que los usuarios pueden realizar acciones y que, posteriormente, pueden enviarse de vuelta al servidor. Al igual que el servidor enva las pginas a los clientes, los clientes pueden responder con los valores que hayan introducido en los campos de los formularios. Durante este captulo ver cmo crear sus propios formularios, qu tipo de elementos puede incluir dentro de ellos para permitir que los usuarios le enven informacin y cmo procesar esa informacin en sus pginas PHP para poder atender as a sus peticiones. Ver tambin cmo orientar a los usuarios para que no enven valores incorrectos, como cadenas de texto donde se esperaba un nmero. Lograremos este objetivo utilizando scripts en el lado del cliente. Si con lo visto hasta este captulo ha logrado mostrar el contenido de una base de datos en una pgina Web, a partir de ahora ser capaz de modificarlo.

Cmo funcionan los formularios


Hablar de formularios es hablar de intercambio de informacin. Recuerda cmo, en el primer captulo, describimos la forma en la que un cliente Web solicitaba informacin a un servidor, y ste se la devolva? En el caso de los formularios se trata de algo parecido: desde una pgina, el usuario puede enviar, junto con la peticin de una nueva pgina, una serie de valores. La figura 8.1 ilustra el proceso.

Figura 8.1. Intercambio entre pginas

Es decir, desde el formulario (sea lo que sea) enviamos de forma simultnea la peticin de una nueva pgina y algunos valores. El servidor Web pasa esos valores a la pgina, que los procesa y devuelve un resultado. Si es la primera vez que se enfrenta a un formulario ahora veremos con un poco ms de detalle el aspecto de un formulario. En la figura 8.2 se puede apreciar el aspecto de un hipottico formulario para dar de alta nuevos gneros cinematogrficos.

Figura 8.2. Formulario para nuevos gneros

Not a: El aspecto de la pgina de la figura 8.2 es muy rudimentario, pero lo mejoraremos notablemente en el captulo dedicado a las plantillas.

En esta pgina hemos creado un formulario con tres elementos: dos cuadros de texto y un botn. Los cuadros de texto nos permiten introducir el nombre del nuevo gnero y su descripcin. Al hacer clic en el botn Guardar (el tercer elemento del formulario), los datos que el cliente introduzca en los dos cuadros de texto se enviarn a la pgina de destino. Esa pgina se encargar de dar de alta un nuevo gnero cinematogrfico con el nombre y la descripcin que el usuario de nuestra aplicacin Web haya introducido en los cuadros de texto. Para los formularios disponemos de muchos otros elementos, adems de los cuadros de texto y los botones. Veamos cmo crear utilizarlos.

Formularios HTML
Los formularios son como cualquier otro elemento que

pueda definir en una pgina HTML. Su declaracin sigue las mismas reglas que la creacin de tablas o la insercin de imgenes.

Creacin de formularios
Un formulario HTML debe comenzar con la etiqueta <form> y terminar con la etiqueta </form>. Se consideran elementos del formulario todos los que haya entre estas dos etiquetas, aunque slo algunos de ellos enviarn informacin al servidor. El elemento de apertura de un formulario dispone de algunos atributos con los que se puede modificar su comportamiento. Los ms importantes de estos aparecen en la tabla 8.1.
Tabla 8.1. Atributos de un formulario

At rib ut o name action method target

D escrip ci n Nombre con el que puede referirse al formulario. Pgina a la que se enviar la informacin del formulario. Forma en la que dicha informacin es enviada al servidor. Nos permite indicar en qu ventana se abrir la pgina indicada en el atributo action del formulario.

Es decir, la siguiente sera la declaracin del comienzo de un formulario:


...

<form name="frm_alta_genero" action="genero.php" method="get">

...

El nombre de este formulario es frm_alta_genero. Es un nombre que describe adecuadamente la funcin del formulario, puesto que se utilizar para dar de alta un nuevo gnero cinematogrfico en nuestra base de datos. La informacin del formulario se enviar a la pgina genero.php. Es esa pgina la que tendr que procesar los valores que el usuario haya introducido en el formulario y crear un nuevo gnero con ellos. Por ltimo, el mtodo determina cmo se enviarn los datos entre las dos pginas. No es sencillo de comprender sin ver un ejemplo, algo que haremos en breve. Por ahora, baste decir que el mtodo GET enva los datos en el mismo URL de llamada a la pgina de destino, mientras que el mtodo POST los incluye en los encabezados HTTP. Cada mtodo tiene sus ventajas e inconvenientes, que tambin comentaremos en este captulo.
Truco: Puede provocar que la pgina de destino del formulario, la indicada en act ion, se abra en una nueva ventana con slo aadir t arget ="_blank" como atributo de la declaracin del formulario.

Elementos de un formulario
Hasta ahora ha visto dos de los elementos que pueden componer un formulario: cuadros de texto y botones. Pero tambin dispone de otros, como casillas de verificacin, botones de opcin, mens desplegables, listas e incluso elementos ocultos. Antes de hablar de ellos, en la figura 8.3 puede verlos todos juntos.

Figura 8.3. Elementos de un formulario

Seguro que los elementos mostrados en la figura 8.3 le son familiares: son los mismos que puede encontrar en los programas de su gestor de ventanas y se comportan de igual forma que en ellos. La nica diferencia est en que ahora es usted el que crea la aplicacin y no otras personas.
Not a: Aunque existen otros elementos que puede incluir en un formulario HTML, con los que vea en este captulo podr satisfacer la mayora de las necesidades de sus aplicaciones Web.

Estos elementos se crean de igual forma que cualquier otro elemento dentro de una pgina HTML: utilizando etiquetas. Todos ellos comparten el nombre de la etiqueta, <input> y algunos atributos: type: Su valor determina de qu elemento se trata (cuadro de texto, botn, etctera). name: El nombre por el que tendr que referirse a los elementos del formulario para recuperar su valor. value: El valor que toma el elemento. Veamos ahora uno por uno todos los elementos que podemos incluir en un formulario, as como sus atributos. Cuadros de texto El ms sencillo de todos los elementos de un formulario, y con diferencia, es el cuadro de texto. Para crear uno dentro de sus formularios ha de crear un elemento input y asignar el valor text al atributo type. Un cuadro de texto puede tener los siguientes atributos:

size: Determina el ancho del cuadro de texto. maxlength: Limita el nmero mximo de caracteres que se pueden incluir en el cuadro de texto. Un cuadro de texto podra tener un tamao de 16 caracteres, lo que modificara su aspecto, su ancho, pero el nmero mximo de caracteres podra ser 32. type: Si este atributo est presente y su valor es password, cada carcter que introduzca en el cuadro de texto aparecer como un asterisco, para evitar que miradas indiscretas sepan lo que est escribiendo. En la figura 8.4 puede ver un cuadro de texto de 16 caracteres de ancho, con un mximo de 32 caracteres, y cuyo atributo type tiene el valor password.

Figura 8.4. Cuadro de texto

El cdigo HTML para generar este cuadro de texto es el siguiente:


...

<input name="texto" type="password" value="" size="16" maxlength="32">

...

Casillas de verificacin Una casilla de verificacin puede tener dos estados: marcada o no marcada. Son ideales para representar valores de tipo booleano, TRUE o FALSE. Las casillas de verificacin tambin pueden tener asociado un valor, pero es el atributo checked el que determina si la casilla est marcada o no. Si checked est presente en los atributos de la casilla de verificacin, sta aparecer marcada, independientemente de si ha asignado un valor a dicho atributo. As, por ejemplo, el siguiente cdigo HTML sirve para generar una casilla de verificacin, marcada por defecto:
...

<input name="casilla"

name="casilla" type="checkbox" value="checkbox" checked="true">

...

Botones de opcin En contraste con las casillas de verificacin, que permiten seleccionar entre dos valores (cierto o falso, activo o no), los botones de opcin suelen ir por grupos y permiten escoger entre valores con ms de una opcin. Si selecciona uno de los botones de opcin cancelar la seleccin de otro. Para lograr este comportamiento ha de llamar igual a todos los botones de opcin, utilizando el atributo name. Igual que las casillas de verificacin, el estado de un botn de opcin depende de la existencia o no del atributo checked. Si est presente, independientemente de su valor, el botn de opcin estar marcado. Si no est presente, no lo estar. La figura 8.5 muestra cmo puede utilizar estos elementos en un formulario.

Figura 8.5. Botones de opcin

Y a continuacin, el cdigo de los botones de opcin dentro del formulario que puede verse en la figura 8.5:
...

<input name="lenguaje" type="radio" value="php" checked="true"> PHP<br/> <input name="lenguaje" type="radio" value="asp"> ASP<br/> <input name="lenguaje" type="radio"

type="radio" value="perl"> Perl<br/> <input name="lenguaje" type="radio" value="mande"> Pginas dinmicas? Mande?<br/>

...

Mens desplegables Podramos establecer parecidos entre los botones de opcin y los mens desplegables, ya que ambos ofrecen una serie de opciones de las que slo puede seleccionar una. La figura 8.6 es una buena muestra de ello.

Figura 8.6. Gneros disponibles

Para crear una lista desplegable necesita dos elementos. El primero de ellos es el men, el segundo las opciones; el men contiene las opciones. As, el men de la figura 8.6 se crea con el siguiente cdigo:
...

<select name="genero"> <option value="1" selected="true"> Ciencia Ficcin </option> <option value="2"> Aventuras </option> <option value="3"> Drama </option> <option value="4"> Comedia </option> </select>

...

La declaracin del men slo precisa de un nombre. Por otra parte, cada una de las opciones necesita un valor y una de ellas, la seleccionada, dispondr del atributo selected. El valor de este atributo es indiferente. El texto que aparecer en cada una de las opciones del men debe

estar entre las etiquetas de apertura y cierre del elemento option. Listas Una lista es una variedad de men desplegable cuyo aspecto es el de una lista. Con la misma sintaxis que los mens y slo aadiendo el atributo size con un valor mayor de uno podr ver las opciones disponibles con otro aspecto. Por ejemplo, en la figura 8.7 puede ver una lista con los mismos valores que el men de la figura 8.6.

Figura 8.7. Los gneros, en una lista

Pero existe una diferencia, ya que la declaracin de esta lista es la siguiente:


... <select name="genero" size="4"> ...

Es decir, tiene un tamao de 4 elementos. An existe una variante ms que permite que se pueda seleccionar ms de un elemento de la lista, de nuevo modificando la declaracin de la lista. Observe el siguiente cdigo:
... <select name="genero" size="4" multiple="true"> ...

Como puede apreciar existe un atributo ms, multiple. Su valor es indiferente, basta con su existencia. El resultado: podr seleccionar ms de un elemento de la lista, como puede verse en la figura 8.8. Para lograrlo slo tiene que seleccionar un elemento y, posteriormente, mientras mantiene la tecla Control (o Comando en Mac OS X) pulsada, hacer clic sobre otro elemento.

Figura 8.8. Ms de un gnero seleccionado

Botones

Botones Se trata de uno de los elementos ms importantes de todo formulario: es el que permite enviar la informacin introducida en el formulario de vuelta al servidor, para que la pgina de destino (la indicada en el atributo action del formulario) la procese. Dos son los tipos de botn ms utilizados. El primero de ellos se utiliza para devolver a sus valores predeterminados a todos los elementos del formulario del que forma parte. El atributo type de estos botones toma el valor reset . El segundo tipo es el que permite enviar el formulario a la pgina de destino. En este caso, el atributo type toma el valor submit .
Not a: Existe un tercer tipo de botn que se utiliza cuando se desea que se ejecute alguna tarea al hacer clic sobre el botn, en lugar de provocar el envo de los campos del formulario.

Campos ocultos Hemos dejado para el final aquellos campos que, aunque no se vean, pueden formar parte de un formulario. Estos campos son muy tiles para enviar a la pgina de destino algn valor que no sea introducido o modificado por el usuario. Para crear un campo oculto, el atributo type del elemento input debe tomar el valor hidden, como muestra el siguiente fragmento de cdigo:
...

<input type="hidden" name="servidor" value="pruebas"/>

...

Cuando se enve la informacin a la pgina de destino, adems de todos los campos visibles, tambin se enviar una variable llamada servidor cuyo valor ser test . Y con esto ya hemos visto cmo crear un formulario y los elementos que lo integran. Seguramente estar deseando ponerse manos a la obra. Y a ello vamos.

Envo de informacin
Vamos a crear un formulario para enviar a otra pgina la informacin necesaria para dar de alta un nuevo gnero cinematogrfico. El aspecto de esta pgina pudo verse en la figura 8.2, pero no as su cdigo. Es el siguiente:
<html>

<head> <title>Nuevo gnero</title> </head>

<body>

<form name="frm_genero" method="get" action="">

<strong>Nombre:</strong><br> <input type="text" name="nombre"><br>

<strong>Descripcin:</strong><br> <input type="text" name="descripcion"><br>

<input type="submit" value="Guardar">

</form>

</body>

</html>

Puede guardar esta pgina con el nombre genero.html. Tras la descripcin que vimos anteriormente sobre los componentes de un formulario, y el mismo formulario, llaman la atencin dos cosas. La primera, que el atributo action del formulario no tiene ningn valor asociado. En estos casos, el cliente Web asume que el destino de la pgina ser la misma pgina. En segundo lugar, no hemos dado nombre al botn, entre otras cosas porque no nos interesa el nombre que tenga, slo que realice la accin de enviar los datos. No pasa lo mismo con los cuadros de texto: precisamente queremos enviar su contenido. Cree una pgina HTML cuyo cdigo sea el anterior y crguela en su cliente Web. Introduzca algn valor en los dos cuadros de texto, haga clic en el botn Guardar y fjese en el URL de la pgina que se cargar. Se tratar de la misma, no lo olvide. Ese URL puede verse en la figura 8.9.

Figura 8.9. Envo de informacin

Qu hemos logrado al hacer clic en el botn Guardar ? El cliente Web ha recogido los nombres y los valores de todos los elementos del formulario al que pertenece el botn. Luego, ha construido un URL que comienza con el destino del formulario. A continuacin de ese URL ha situado un signo de interrogacin para marcar el final del mismo y, tras dicho signo, el nombre de cada elemento de formulario y su valor, con un signo de igualdad entre ambos. Cada pareja est separada por un ampersand (&). As, tras la interrogacin tenemos nombre=T , que indica que el campo nombre tena el valor T , y descripcion=Terror , que nos indica que la descripcin del gnero es Terror . Esto es as porque hemos utilizado el mtodo GET para enviar los valores del formulario. Si hubisemos seleccionado el mtodo POST no veramos ningn valor en el URL puesto que todos se envan en los encabezados HTTP, slo visibles por el servidor, pero con los que de igual forma podr trabajar en sus pginas PHP. Hemos realizado esta primera prueba con una pgina HTML, que no nos permite trabajar con la informacin enviada desde un formulario. Por fortuna, con PHP podemos.

Recuperacin de informacin
El primer paso: convertir la pgina anterior a PHP. Es fcil, slo tiene que cambiar la extensin del archivo y seguir funcionando como hasta ahora. Su nombre ser genero.php. El segundo paso es aadir al principio de la pgina el cdigo PHP necesario para realizar alguna operacin con los valores recibidos. Pero antes, veamos dnde encontrar esos valores. En el segundo captulo vimos una de las caractersticas que ms sorprende a los que llegan a PHP desde otros lenguajes de programacin: las matrices. Como vimos, en PHP podemos utilizar lo que se conoce como matrices asociativas, en las que cada elemento de la misma dispone de un nombre y un valor asociado. Vaya, qu casualidad! Es justo lo que un formulario pasa a la pgina de destino, verdad? Para facilitarle la tarea, PHP pone a su disposicin dos matrices globales, disponibles en todas sus pginas, dentro de las que se encuentran todos los valores pasados desde una pgina a otra: $_GET y $_POST . Lgicamente, la primera de las matrices contendr los valores pasados a la pgina cuando el mtodo seleccionado sea GET , mientras que la segunda lo har cuando el mtodo sea POST . La forma ms sencilla, ms rpida, pero tambin la

menos elegante, de utilizar estas variables es incluir el siguiente cdigo al comienzo de la pgina PHP:
<?php

echo('<pre>'); print_r($_GET); echo('</pre>');

?>

...

Cargue de nuevo la pgina genero.php tras aadir ese cdigo al principio de la pgina. Ver algo parecido a lo que aparece en la figura 8.10, algo no demasiado agradable.

Figura 8.10. An no vemos nada

Y cuando introduzca valores en los cuadros de texto y haga clic en el botn Guardar , el aspecto de la pgina no va a mejorar, pero s podr ver que algo est empezando a funcionar: habr conseguido mostrar en la pgina los valores del formulario, como puede verse en la figura 8.11.

Figura 8.11. Mostramos los valores pasados

Como ve, la matriz $_GET tiene un elemento por cada uno de los pasados en el URL. De igual forma, si el mtodo empleado fuese el POST , utilizaramos la matriz $_POST . Pero qu ocurre cuando no sabe qu mtodo se emple para enviar la informacin a la pgina actual? La pgina que vamos a crear a continuacin le ser de mucha

utilidad, tanto ahora como en sus futuros desarrollos, para comprobar los valores que una pgina pasa a otra. Esta pgina, a la que llamaremos formulario.php, averiguar el mtodo empleado para el paso de valores desde el formulario que la llama y mostrar una tabla con todos los valores pasados. El primer paso ser aprovecharnos de una circunstancia: los valores se deben pasar con el mtodo POST o con el mtodo GET , pero no con los dos a la vez. Tanto $_GET como $_POST son matrices, de forma que puede saber el nmero de elementos que contienen. As que podemos tener una variable que apunte a una de las dos matrices, aquella que tenga elementos, no teniendo que elegir entre trabajar con una o con otra. El cdigo de formulario.php comienza as:
<?php

$pParametros = FALSE; if(count($_GET) != 0){ $pParametros = $_GET; }elseif(count($_POST) != 0){ $pParametros = $_POST; }

...

Con este bloque de cdigo hemos logrado nuestro objetivo. Creamos una variable llamada $pParametros. La p viene de puntero, apuntador, un lastre de tiempos pasados que tendr connotaciones malignas para aquellos que conozcan lenguajes como C. El valor predeterminado de esta variable ser FALSE . Si no se han pasado parmetros a la pgina, podr saberlo comprobando que $pParametros es FALSE . En ese caso no tendr que mostrar ninguna informacin. A continuacin, compruebe si $_GET contiene algn elemento. Si es as, sabr tambin que $_POST no contendr ninguno, as que haga que $pParametros apunte a $_GET . En caso contrario, $pParametros apuntar a $_POST . El resultado: sea cual sea el mtodo empleado para el paso de los valores a esta pgina, $pParametros contendr esos parmetros. Slo queda mostrar la informacin pasada a la pgina:
...

if($pParametros == FALSE){ echo('No se ha pasado valor alguno.'); exit(); }

echo('<table border="1">');

echo('<tr>'); echo('<th>Nombre</th><th>Valor</th>'); echo('</tr>');

foreach($pParametros as $nombre => $valor){ echo('<tr>'); printf( "<td>%s</td><td>%s</td>", $nombre,$valor); echo('</tr>'); }

echo('</table>');

?>

Guarde en una pgina llamada formulario.php el cdigo que acaba de ver. Ahora, en cualquiera de las pginas que hemos creado en este captulo como, por ejemplo, aquella cuyo cdigo se poda ver al principio del apartado 8.3, cambie el valor del atributo action por formulario.php. As, al hacer clic en el botn Guardar , la pgina de destino ser esta nueva. Abra la pgina HTML en un cliente Web, asigne valores a los cuadros de texto y haga clic en Guardar . Podr ver algo parecido a lo que muestra la figura 8.12.

Figura 8.12. Todos los valores pasados

Pruebe dos cosas ms. La primera, cambie el mtodo de envo de la pgina HTML, de get a post . Recargue la pgina en su cliente Web, introduzca valores en los cuadros de texto y haga clic en el botn. Seguir viendo lo mismo que en la figura 8.12, salvo que ahora los valores pasados no aparecern en el URL. En segundo lugar, intente cargar la pgina formulario.php directamente, sin llamarla desde ninguna otra. La pgina le informar de que no se le ha pasado ningn valor. A medida que vaya creando sus propios formularios, esta pgina le ser de mucha ayuda, ya que le permitir comprobar que una pgina pasa a la otra los valores que usted esperaba. Ahora ya puede emprender la tarea que era el objetivo desde que comenz este captulo: crear una pgina PHP

que le permita dar de alta nuevos gneros.

Insercin de registros
La verdad es que casi disponemos de todos los elementos necesarios para crear una pgina que nos permita insertar nuevos gneros cinematogrficos en la base de datos de pelculas: tenemos el formulario y sabemos cmo obtener los valores que necesitamos para realizar la insercin. Slo nos queda ponerlo todo junto. Vamos a utilizar una sola pgina, a la que llamaremos genero.php. Aunque ya hemos visto su cdigo, no est de ms recordarlo. Es el siguiente:
<html>

<head> <title>Nuevo gnero</title> </head>

<body>

<form name="frm_genero" method="get" action="">

<strong>Nombre:</strong><br> <input type="text" name="nombre"><br>

<strong>Descripcin:</strong><br> <input type="text" name="descripcion"><br>

<input type="submit" value="Guardar">

</form>

</body>

</html>

Como slo vamos a utilizar una pgina, introduciremos las instrucciones PHP al comienzo de ella. El primer paso consiste en crear la referencia a la matriz de valores pasados que corresponda, ya sea el mtodo GET o POST , con la misma intencin que en el apartado 8.4. El resultado es que tendremos todos los parmetros pasados a la pgina en $pParametros:
<?php

$pParametros = FALSE; if(count($_GET) != 0){ $pParametros = $_GET; }elseif(count($_POST) != 0){ $pParametros = $_POST;

...

En la pgina formulario.php, el siguiente paso era comprobar si $pParametros era FALSE , pero ahora nos interesa hacer justo lo contrario. Por lo tanto, slo realizaremos alguna accin si se pas algn parmetro a la pgina:
...

if($pParametros != FALSE){

...

...

Lo que nos interesa ahora es ver qu cdigo escribimos dentro del bloque if, puesto que ese ser el que realizar la insercin en la base de datos. Debemos llevar a cabo tres tareas: 1. Obtener los valores que necesitamos y comprobar que son vlidos. 2. Realizar la insercin en la base de datos. 3. Informar del xito o fracaso de la operacin. El primer paso es bien simple:
...

$sNombre = $pParametros['nombre']; $sDescripcion = $pParametros['descripcion'];

if(($sNombre == '') or ($sDescripcion == '')){ $sMensaje = 'El nombre y la descripcin '. 'del nuevo gnero no pueden '. 'ser cadenas vacas.'; echo($sMensaje); }else{

...

...

Es en la parte del else en la que realizaremos la insercin en la base de datos. Ya disponemos de todos los valores necesarios, as que vamos a ello. Primero, creamos la consulta:

...

$sConsulta = <<<CONSULTA INSERT INTO genero( nombre, descripcion )VALUES( '$sNombre', '$sDescripcion' ); CONSULTA;

...

Ahora slo tenemos que establecer la conexin con la base de datos, ejecutar la consulta y cerrar la conexin:
...

$videoteca = new mysqli( '', '', '', 'videoteca');

if ($videoteca == FALSE){ echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query($sConsulta);

if($resultado == FALSE){ echo('Error en la consulta.'); echo($videoteca->error); exit(); }

echo('Nuevo gnero aadido.<hr/>';

$videoteca->close();

...

Not a: Si le parece raro cmo realizamos la conexin con la base de datos, quiz necesite echar un vistazo al apartado 7.6 del captulo 7, en la que se comentan algunos aspectos de la configuracin de las aplicaciones PHP. En concreto, cmo incluir el nombre del servidor MySQL, el del usuario y su clave en los archivos de configuracin de Apache.

Nada ms sencillo, verdad? A continuacin puede ver el cdigo completo de est pgina, HTML incluido:
<?php

$pParametros = FALSE; if(count($_GET) != 0){ $pParametros = $_GET; }elseif(count($_POST) != 0){

$pParametros = $_POST; } if($pParametros != FALSE){

$sNombre = $pParametros['nombre']; $sDescripcion = $pParametros['descripcion'];

if(($sNombre == '') or ($sDescripcion == '')){ $sMensaje = 'El nombre y la descripcin '. 'del nuevo gnero no pueden '. 'ser cadenas vacas.'; echo($sMensaje); }else{

$sConsulta = <<<CONSULTA INSERT INTO genero( nombre, descripcion )VALUES( '$sNombre', '$sDescripcion' ); CONSULTA;

$videoteca = new mysqli( '', '', '', 'videoteca');

if ($videoteca == FALSE){ echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query($sConsulta);

if($resultado == FALSE){ echo('Error en la consulta.'); echo($videoteca->error); exit(); }

echo('Nuevo gnero aadido.<hr/>');

$videoteca->close();

?>

<html>

<head> <title>Nuevo gnero</title> </head>

<body>

<form name="frm_genero" method="get" action="">

<strong>Nombre:</strong><br> <input type="text" name="nombre"><br>

<strong>Descripcin:</strong><br> <input type="text" name="descripcion"><br>

<input type="submit" value="Guardar">

</form>

</body>

</html>

La figura 8.13 muestra el aspecto de esta pgina tras aadir una nueva categora a la base de datos. En el URL se pueden ver los parmetros que se han pasado a la pgina.

Figura 8.13. Nuevo gnero aadido

En el captulo anterior creamos una pgina que nos permita ver la lista de gneros disponibles en nuestra base de datos. Pruebe a cargarla ahora, podr comprobar que dispone de un gnero ms: el que acaba de aadir gracias a nuestro formulario. Puede mejorar el funcionamiento de sus formularios aadiendo un nivel ms de control, verificando en el lado del cliente, adems de en el lado del servidor, que los valores que se van a enviar cumplen los criterios que necesita.

Control en el lado del cliente


Este libro es como una torre de Babel: hasta ahora hablamos HTML, PHP y SQL. Como puede que a alguien le parezca poco, vamos a por otro lenguaje ms: JavaScript. JavaScript es un lenguaje que permite comprobar que los valores que los clientes intentan enviar en los formularios son correctos, ajustndose a los parmetros que usted decida. Su sintaxis es muy similar a la de PHP (o deberamos decir lo contrario?). Aunque puede incluir el cdigo JavaScript en el mismo archivo PHP o HTML, lo normal es guardarlo en archivos independientes de la propia pgina. En concreto, qu nos interesa hacer con la pgina para dar de alta nuevos gneros? Comprobar, antes de enviar nada al servidor, que se han introducido tanto un nombre como una descripcin para el gnero. De esta forma evitaremos ms de una llamada errnea a la pgina. La siguiente funcin realiza la tarea que nos interesa:
function comprobar_valores(){

var frm = document.frm_genero; var sNombre = frm.nombre.value; var sDescripcion = frm.descripcion.value;

if(sNombre == ''){ alert('Falta el nombre.'); frm.nombre.select(); return(false); }

if(sDescripcion == ''){ alert('Falta la descripcin.'); frm.descripcion.select(); return(false); }

return(true);

Antes de ver cmo insertar este cdigo en su pgina, veamos qu hace. En primer lugar, la variable frm es una referencia a document.frm_genero, el formulario que contiene los valores que queremos comprobar. Desde JavaScript dispone de una jerarqua de clases que le permite acceder a cualquier elemento o atributo de la pgina. Ahora mismo slo nos interesan los formularios y los valores de sus elementos. El elemento que comienza la jerarqua es document y representa a la pgina Web. Dentro de l est nuestro formulario, al que asignamos el nombre frm_genero, as que podremos acceder a l

mediante document.frm_genero. De igual forma, accedemos a los elementos del formulario por su nombre: frm.nombre ser el cuadro de texto para el nombre, y frm.descripcion el cuadro de texto para la descripcin. De ambos cuadros de texto nos interesa su valor. Lo guardamos en sendas variables. Posteriormente comprobamos que no estn vacas, comparando su valor con una cadena vaca. Si una de ellas est vaca, mostramos un mensaje al respecto y seleccionamos el cuadro de texto que corresponda. Ahora, cmo asociamos este cdigo a la pgina PHP? Con una sencilla lnea:
...

<script language="javascript" src="genero.js"> <!---> </script>

...

Esta instruccin debe ir antes del fin la etiqueta <head>, de forma que la parte HTML de la pgina genero.php debe quedar as:
<html>

<head> <title>Nuevo gnero</title> <script language="javascript" src="genero.js"> <!---> </script> </head>

<body>

<form name="frm_genero" method="get" action="">

<strong>Nombre:</strong><br> <input type="text" name="nombre"><br>

<strong>Descripcin:</strong><br> <input type="text" name="descripcion"><br>

<input type="submit" value="Guardar">

</form>

</body>

</html>

Ahora slo tenemos que asociar la funcin comprobar_valores() al botn Guardar , para que cuando se haga clic en dicho botn el cliente Web intente ejecutarla. Para ello utilizamos el evento onClick del botn, que se lanza cada vez que se hace clic sobre dicho botn. El cdigo de la etiqueta del botn sera el siguiente:
...

<input type="submit" value="Guardar" onClick="return comprobar_valores()">

...

Cada vez que se haga clic, el cliente Web llamar a la funcin. Si todos los valores necesarios han sido introducidos, la funcin devolver true. En ese caso, el formulario se enviar a la pgina de destino. Pero si no se cumple algn requisito, como la funcin devuelve false, el envo del formulario se cancela. La figura 8.14 muestra lo que ocurrira si intentsemos crear un nuevo gnero sin descripcin asociada.

Figura 8.14. Sin descripcin, no hay gnero

Truco: Quiere acceder y manipular an ms fcilmente los elementos de los formularios desde el cdigo JavaScript? Eche un vistazo a jQuery: http://jquery.com/.

Durante este captulo ha visto una coleccin de diferentes tecnologas trabajando juntas para conseguir el mismo resultado: que desde una pgina Web, un usuario pueda modificar valores de una base de datos. El mayor esfuerzo debe ponerse en asegurar que la informacin que el cliente enva cumpla los criterios que buscamos. La existencia del campo es el primer paso, pero

buscamos. La existencia del campo es el primer paso, pero no el nico. Si pide al cliente que introduzca una fecha, un precio o una direccin de correo electrnico en algn campo del formulario habr de comprobar que se trata de una fecha razonable, un valor numrico o una direccin de correo electrnico con el formato correcto, respectivamente.

Gestin de errores
Es curioso como, a veces, las tareas ms importantes son relegadas a un segundo plano. Los programadores tendemos a pensar que, cuando logramos que un programa se comporte de la forma esperada, nuestro trabajo est hecho. Y, bueno, aunque es cierto, no lo es del todo. Un programa slo puede darse por bueno cuando su comportamiento es el adecuado, bajo cualquier circunstancia. Concretando, en nuestro caso, las pginas PHP que hagamos deben devolver informacin de las bases de datos: por ejemplo, una lista de registros. Pero como hemos dicho, la pgina debe comportarse adecuadamente bajo cualquier circunstancia: cuando el servidor de bases de datos no est funcionando debe avisar de ello, as como cuando la consulta que se est intentando ejecutar no sea correcta tanto porque los elementos involucrados en ella no existan como porque est mal construida. Las herramientas que proporciona PHP para la gestin de errores son muchas y muy variadas. De igual forma, MySQL tambin proporciona medios para informar sobre los errores que se produzcan y profundizar en las causas de los mismos. Durante este captulo ver cmo configurar PHP para que su comportamiento frente a los errores sea el que usted desee. Tambin ver cmo MySQL informa de los errores que ocurren. Y aprender a utilizar de forma conjunta la gestin de errores de PHP y MySQL para sacarles el mayor partido. Porque, a veces, el problema no est en que ocurra un error en una de sus pginas sino en no saber tratarlo adecuadamente.

PHP y los errores


Incluso antes de saber nada sobre la gestin de errores de PHP ya nos estamos aprovechando de ella. Recuerda cmo terminamos el captulo 7? El comportamiento de la pgina que mostraba la lista de los gneros disponibles fallaba miserablemente cuando el servidor de bases de datos no estaba funcionando. Aquellos que intentasen consultar el listado en ese momento se encontraran con algo parecido a lo que se puede ver en la figura 9.1.

Figura 9.1. No hay servidor de bases de datos

Qu determina la forma en la que se presentan estos mensajes de error? La configuracin de PHP.

Configuracin
Situmonos de nuevo en el captulo 7. En su apartado 7.6 explicbamos cmo modificar la configuracin de PHP para que pudisemos conectar con el servidor de bases de datos sin especificar ni su nombre, ni el nombre del usuario ni su contrasea, slo indicando la base de datos predeterminada. En ese captulo consultbamos los parmetros de configuracin de PHP con una pgina en la que llambamos a la funcin phpinfo(). Vamos a repetir la jugada, pero ahora nos vamos a fijar en otros valores. La figura 9.2 muestra los valores que ms nos interesan de la seccin PHP Core de la configuracin de PHP, tal y como nos la muestra la funcin antes mencionada.

Figura 9.2. Configuracin para los errores

Como puede ver, existen tres columnas. La primera (Directive) es el nombre de la opcin de configuracin. La segunda (Local Value) es el valor de esa opcin de configuracin para la zona de la Web en la que se encuentra la pgina, mientras que la tercera (Master Value) determina el valor global de esa opcin, el que se aplica por defecto a todas las zonas de Web.
Not a: Recuerde del sptimo captulo que puede tener una configuracin

diferente para algunas de las carpetas del servidor de pginas Web que utilice. Dependiendo de la ubicacin de la pgina PHP dentro del rbol de directorios del servidor se aplicar una configuracin u otra.

Son estos valores los que determinan cmo se comportarn nuestras aplicaciones en caso de que ocurra un error. Veamos para qu sirve cada uno de ellos. display_errors Dependiendo del valor de esta variable, los errores que se provoquen en nuestras pginas producirn mensajes o no. En la figura 9.2 se puede observar que estos mensajes estn activos, como pudo comprobar en la figura 9.1. Veamos el impacto que desactivar esta opcin tiene sobre los mensajes de error. Suponga que est trabajando en la ruta predeterminada de Apache, la carpeta htdocs. Cree una carpeta llamada errores dentro de esa carpeta y, dentro de ella, ponga un archivo PHP que llame a la funcin phpinfo(). Ahora vamos a editar el archivo de configuracin de Apache para que pueda modificar los valores de configuracin de PHP de esa carpeta, como ya hicimos en el captulo 7. En concreto, deber aadir las siguientes lneas al archivo de configuracin de Apache:
...

<Directory "C:/xampp/htdocs/errores"> Options Indexes FollowSymlinks AllowOverride None Order allow,deny Allow from all php_admin_value display_errors "0" </Directory>

...

Not a: La ruta de la carpeta en el fragmento de configuracin de Apache, como es obvio, se corresponde con un sistema Windows. Ms detalles al respecto en el apartado 7.6.5.

Tras reiniciar el servidor Apache, si carga la pgina que muestra las opciones de configuracin de PHP podr comprobar que ahora el valor local de display_errors es Off, como pretendamos, algo que puede verse en la figura 9.3.

Figura 9.3. Desactivamos display_errors

Qu efecto tendr este cambio en la pgina que pudimos ver en la figura 9.1? Si intenta cargarla cuando

MySQL est detenido podr ver algo similar a lo que muestra la figura 9.4.

Figura 9.4. Controlamos los mensajes de error

La conclusin: durante el proceso de desarrollo, en el que est probando el funcionamiento de sus pginas, esta opcin de configuracin debe estar activada, mientras que durante su vida til debe desactivarla y ser usted quien controle los mensajes de error. Pero, un momento! Aqu hay algo que no cuadra. Cmo es que, si ha fallado la conexin, el mensaje de error que vemos es "Error en la consulta."? Algo no es del todo correcto. Si recuerda, el cdigo de esta pgina era el siguiente:
<?php

$videoteca = new mysqli( 'localhost', 'usuario', 'clave', 'videoteca' );

if ($videoteca->errno != 0){ echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query( 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

while ($fila = $resultado->fetch_row()){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] ); print_r($resultado->fetch_field()); }

$resultado->close(); $videoteca->close();

?>

Por qu no se informa de un error en la conexin? Porque, al no llegar a realizarse, la instruccin new mysqli no ha logrado crear un ejemplar de la clase mysqli y, por lo tanto, $videoteca->errno no contiene informacin alguna del cdigo de error. Lo correcto es utilizar una funcin para comprobar si hubo errores durante el proceso de conexin:
...

if (mysqli_connect_errno()){ echo('Error en la conexin.'); exit(); }

...

Si prueba a cargar esta pgina, ahora que hemos modificado la comprobacin de los errores de conexin podr ver que s obtiene la informacin correcta, como demuestra la figura 9.5.

Figura 9.5. Ahora s, error en la conexin

display_startup_errors No slo se producen errores al cargar una pgina. Es posible que, durante el proceso de carga de PHP en memoria, se produzca algn error. Estos errores no sern visibles a menos que el valor de esta opcin de configuracin sea On. docref_ext y docref_root Como hemos visto, cuando se produce un error al llamar a una funcin PHP muestra un mensaje de error al respecto slo si la opcin display_errors est activa. En dicha pgina aparece, adems, un enlace a la documentacin de PHP donde se describe la forma de utilizar la funcin en la que se produjo el fallo. Vamos a provocar un error. Con el servidor MySQL detenido y display_errors activa, cree una pgina con el siguiente cdigo y brala:
<?php

$videoteca = mysqli_connect();

?>

Y se produce un error como el que muestra la figura 9.6. El cuadro de dilogo que acompaa a la figura es el resultante de hacer clic con el botn derecho sobre el enlace y seleccionar la opcin Propiedades del men desplegable que aparece. En l puede ver que dicho enlace apunta al servidor local. Sin embargo, si hace clic sobre ese enlace no encontrar ayuda alguna porque esa pgina no existe.

Figura 9.6. Error en la conexin

Las opciones de configuracin docref_ext y docref_root permiten modificar la forma en la que se crean estos enlaces. El primero de ellos determina la extensin de las pginas a las que apuntan mientras que el segundo la ubicacin de las mismas. Aadamos dos lneas a la configuracin de la carpeta errores en Apache:
...

php_admin_value docref_ext ".php" php_admin_value docref_root "http://php.net/manual/es/"

...

Reinicie el servidor Web y vuelva a cargar la pgina de la figura 9.6. Ahora, el enlace ser el que se puede ver en la figura 9.7.

Figura 9.7. Enlaces a la documentacin

Si hace clic sobre dicho enlace ver la documentacin de la funcin mysqli_connect(), y en espaol.
Truco: Para aprovechar al mximo estas opciones de configuracin es necesario que disponga de conexin a Internet mientras trabaja. De lo contrario no podr acceder a esta documentacin. Si lo desea, puede instalar la documentacin en su propio servidor para poder consultarla en cualquier momento. Deber modificar la configuracin de PHP adecuadamente.

error_prepend_string y error_append_string Asocie una cadena de texto a estas opciones de configuracin. A partir de ese momento, dichas cadenas aparecern antes y despus del mensaje de error, respectivamente. error_reporting Quizs una de las ms importantes de las opciones de configuracin relacionadas con la gestin de errores. Contiene un valor numrico que determina el nivel de detalle de los mensajes de error. Las posibles constantes que se pueden combinar para asignar un valor a esta opcin de configuracin son las siguientes: E_ERROR: Errores fatales. Se detiene la ejecucin del programa. E_WARNING: Errores no fatales. No se detiene la ejecucin del programa. E_PARSE: En nuestro cdigo hay algo que no sigue las reglas sintcticas de PHP.

E_NOTICE: Avisos sobre posibles fallos en nuestro cdigo. E_CORE_ERROR: Error fatal ocurrido durante la carga de PHP en memoria. E_CORE_WARNING: Error no fatal ocurrido durante la carga de PHP en memoria. E_COMPILE_ERROR: Relacionado con Zend Script Engine, est fuera del alcance de este libro. E_COMPILE_WARNING: Relacionado con Zend Script Engine, est fuera del alcance de este libro. E_USER_ERROR: Error generado por el programador mediante el uso de la funcin trigger_error(). E_USER_WARNING: Advertencia generada por el programador mediante el uso de la funcin trigger_error(). E_USER_NOTICE: Aviso generado por el programador mediante el uso de la funcin trigger_error(). E_ALL: Todos los errores, salvo E_STRICT antes de la versin 5.4.0 de PHP. A partir de esa versin, E_ALL incluye a E_STRICT . E_STRICT: Consejos dados por PHP acerca de cmo mejorar el cdigo que escribimos. E_RECOVERABLE_ERROR: Error fatal que quiz no dej en un estado inutilizable al motor de PHP.
Consejo: Por defecto, el valor de esta opcin de configuracin es E_ALL & ~E_NOTICE. Le recomendamos que cambie ese valor por E_ALL & E_STRICT , con lo que PHP le ayudar en sus programas todo lo que pueda.

html_errors Slo si esta opcin de configuracin est activa podr ver los mensajes de error con formato HTML, con enlaces a la documentacin de PHP cuando sea necesario. Si est desactivada, los mensajes de error tendrn el aspecto que puede ver en la figura 9.8.

Figura 9.8. Formato HTML desactivado

La direccin de la pgina de la documentacin describiendo la funcin en la que se produjo el error sigue estando ah pero ya no como un enlace. ignore_repeated_errors Si activa esta opcin y un mensaje de error se produce de forma consecutiva en varias ocasiones en la misma pgina PHP no se informar de l ms que la primera vez. ignore_repeated_source

Si activa esta opcin y un mensaje de error se produce de forma consecutiva en varias ocasiones, sin importar si se produjo en la misma pgina o en otra, no se informar de l ms que la primera vez. log_errors y error_log Si log_errors est activo, podr modificar el valor de error_log. Este ltimo le permite seleccionar un archivo en el que se guardar un registro de todos los errores que sus pginas PHP vayan mostrando. Es imprescindible que indique un archivo de este tipo una vez sus aplicaciones estn en funcionamiento para poder estudiar su comportamiento y localizar la causa de posibles errores. Existe un valor especial para esta opcin de configuracin. Si en lugar de la ruta de acceso a un archivo indica el valor syslog, los mensajes de error se guardarn en el log del sistema, que en Windows es el registro de eventos (accesible a travs del visor de eventos) y en Linux y Mac OS X es syslog. log_errors_max_len Tamao mximo de los mensajes que se almacenar en el registro de errores. Si no se indica ningn valor no habr lmites de tamao. report_memleaks Si en sus programas se produce algn problema relacionado con la gestin de memoria y esta opcin de configuracin est activa, PHP informar de dicho problema. track_errors Si esta opcin de configuracin est activa, siempre podr acceder en sus programas a la informacin del ltimo error que se produjo a travs de la variable $php_errormsg. Esta variable slo contiene la descripcin del error. Tras conocer las posibles opciones de configuracin relacionadas con la gestin de errores, veamos qu funciones pone PHP a su disposicin para gestionarlos.

Funciones
PHP es, posiblemente, uno de los lenguajes de su clase que proporciona las funciones de gestin de errores ms sencillas y tiles. No son slo las que vamos a ver, nos centraremos en las ms importantes. error_log() Permite enviar un mensaje de error a cuatro destinos diferentes: al sistema de registro de PHP (ver seccin dedicada a log_errors y error_log), a una direccin de

correo electrnico, a un depurador de errores remoto o a un archivo (al final del cual se aade el mensaje). Esta funcin acepta cuatro argumentos, en este orden: el mensaje de error, el tipo de destino (cualquiera de los cuatro antes mencionados), el destino propiamente dicho y, por ltimo, informacin asociada al tipo de destino, en caso de que sea necesario. Suponga que su aplicacin est terminada, instalada y funcionando en los sistemas de su cliente, aquel que le encarg su desarrollo. Se trata de una aplicacin Web, continuamente conectada a Internet. No se engae: las aplicaciones pueden fallar, por cientos de razones diferentes. A veces, incluso no es por su culpa. No sera fantstico que, cuando algn fallo ocurriera en las aplicaciones que ha desarrollado, se le enviase un mensaje de error a su direccin de correo electrnico? Antes incluso de que el cliente le llamase por telfono para, indignado, decirle que lo que ha programado no sirve para nada, usted tendra constancia de ello, y por correo electrnico! Volvamos a nuestro ejemplo, la lista de gneros. Suponga que, efectivamente, no se ha podido establecer una conexin con la base de datos. Suponga tambin que, en lugar del cdigo que informa sobre el error en la conexin, tiene este otro:
...

if (mysqli_connect_errno()){ echo('Error en la conexin.'); error_log( "No se pudo conectar con MySQL.", 1, "videoteca@example.com", "Subject: Error en la videoteca\n". "From: Servidor en produccin\n" ); exit(); }

...

Cada vez que se produzca un error al conectar con la base de datos le llegar un mensaje de correo electrnico a la direccin videoteca@example.com, con el remitente Servidor en produccin, para que sepa de qu servidor le llega el mensaje, y con el asunto describiendo qu es lo que ha pasado.
Truco: Adems de esta informacin, sera muy interesante incluir otra en el cuerpo del mensaje como, por ejemplo, las variables pasadas a la pgina, en caso de que esta pgina se intentase cargar tras enviar informacin con un formulario, o cualquier otro detalle que pueda ayudarle a resolver el problema que provoc que se le enviase el mensaje de correo electrnico.

error_reporting() Esta funcin permite modificar en tiempo de ejecucin, es decir, desde el mismo cdigo de una pgina, el nivel de detalle con el que se informar de los errores. Utilizar esta funcin modifica el parmetro de configuracin error_reporting, del que acabamos de hablar. trigger_error() Utilice esta funcin cuando ocurra alguna circunstancia que PHP no entienda como error pero que usted desea que se trate como tal. Por ejemplo, recuerde el captulo anterior, la pgina PHP que le permita dar de alta nuevos gneros cinematogrficos. Cuando esta pgina no reciba el nombre del gnero o su descripcin, mostraba un mensaje:
...

if($pParam != FALSE){

$sNombre = pParametros['nombre']; $sDescripcion = pParametros['descripcion'];

if( ($sNombre == '') or ($sDescripcion == '') ){

$sMensaje = 'El nombre y la descripcin '. 'del nuevo gnero no pueden '. 'ser cadenas vacas.';

echo($sMensaje);

}else{

...

Podramos cambiar la llamada a la funcin echo() por una llamada a la funcin trigger_error():
...

$sMensaje = 'El nombre y la descripcin '. 'del nuevo gnero no pueden '. 'ser cadenas vacas.';

trigger_error($sMensaje, E_USER_ERROR);

...

El resultado, en lugar de un simple mensaje, viene adornado como un mensaje de error de los que ya conocemos, como puede ver en la figura 9.9.

Figura 9.9. Error definido por el usuario

Pero cuando quiz resulta ms interesante informar sobre errores de este tipo es cuando definimos nuestras propias funciones para gestionarlos. set_error_handler() No le gusta la informacin que PHP sobre los errores? No se preocupe, puede solucionarlo ya que existe la posibilidad de que cree su propia rutina de gestin errores. La funcin de gestin de errores slo tiene que ser capaz de recibir cuatro parmetros que, en este orden, representan: 1. 2. 3. 4. El cdigo del error. La descripcin del error. El archivo PHP en el que se produjo el error. La lnea en la que se produjo el error.
Not a: Existe un quinto argumento que puede utilizarse en este tipo de funciones pero su significado queda fuera del alcance de esta gua. Si desea ms informacin al respecto consulte la documentacin de PHP.

La siguiente es una versin minimalista de una funcin de gestin de errores:


function informar_error( $codigo, $descripcion, $archivo, $linea ){

printf("Ha ocurrido un error.<br/>"); printf("<b>Cdigo:</b> %s.<br/>", $codigo); printf("<b>Descripcin:</b> %s.<br/>", $descripcion); printf("<b>Archivo:</b> %s.<br/>", $archivo); printf("<b>Lnea:</b> $s.<br/>", $linea);

error_log( "Error.", 1, "videoteca@example.com",

"Subject: ".$descripcion."\n". "From: Servidor en produccin\n" );

Si quiere que esta funcin informe sobre los errores que ocurran en sus pginas slo tiene que colocarla en un lugar al que todas ellas tengan acceso, utilizar las instrucciones de inclusin que vimos durante el captulo 4 y hacer la siguiente llamada al comienzo de la pgina:
...

$gestor_anterior = set_error_handler("informar_error");

...

La variable $gestor_anterior contendr lo necesario para poder restaurar el anterior gestor de errores cuando lo consideremos oportuno utilizando la funcin que veremos a continuacin, restore_error_handler . La nica ventaja que nuestra funcin aporta sobre la predeterminada de PHP es que, adems de informar sobre el error de forma diferente, se enva un mensaje de correo electrnico con informacin al respecto: as que nos evitamos tener que aadir esa lnea tras cada error que se produzca. La figura 9.10 muestra el aspecto de los mensajes de error utilizando nuestra funcin.

Figura 9.10. Nosotros informamos del error

Not a: Por otra parte, el resultado de utilizar esta funcin para informar sobre los errores es mucho ms pobre, visualmente hablando. Queda como ejercicio para el lector mejorarla.

restore_error_handler() Llamando a esta funcin restauramos la funcin de gestin de errores que pasemos como parmetro. En el ejemplo del apartado anterior se tratara de la variable $gestor_anterior.

Excepciones
La gestin de errores que hemos realizado hasta ahora es la ms utilizada, podramos hasta decir que es la

clsica. Sin embargo, PHP ofrece la posibilidad de gestionarlos utilizando excepciones, igual que muchos otros lenguajes modernos. El primero paso para utilizar excepciones consiste en localizar aquellos fragmentos de cdigo susceptibles de fallo. Un buen candidato podra ser el momento de realizar una consulta en una base de datos:
... $resultado = $videoteca->query( 'SELECT * FROM genero' ); ...

Para controlar las excepciones que pudiesen tener lugar slo es necesario incluir el cdigo en cuestin en un bloque try:
...

try{ $resultado = $videoteca->query( 'SELECT * FROM genero' ); }

...

La gestin de la posible excepcin (es decir, del error) tiene lugar en el bloque catch definido a continuacin del bloque try:
...

catch (Exception $e) { echo 'Error: ' . $e->getMessage() . '<br/>'; }

...

Entre parntesis, un objeto de tipo Exception que contiene toda la informacin que necesite mostrar para informar sobre el error como, por ejemplo, el cdigo, la lnea o el archivo en el que tuvo lugar el error. La principal ventana de utilizar bloques try y catch es que el cdigo resultante est mucho ms estructurado, ms organizado, que si no se utilizasen.

MySQL y los errores


Cada vez que ejecuta una consulta cuya sintaxis no es correcta o sobre unos datos inexistentes, el cliente de MySQL que utilice (como, por ejemplo, MySQL Query Browser o MySQLi) le informar sobre dichos errores. Pero qu podra hacer si le interesase conocer lo ocurrido hace unos das en un servidor de bases de datos MySQL? Para esos casos, MySQL proporciona gran cantidad de datos en

sus archivos de registro (log en ingls).

Archivos de registro
Las capacidades de administracin de MySQL Administrator son suficientes si quiere saber qu esta pasando en el servidor en un preciso instante, pero y si le interesa saber qu pas hace unos das? Para esos casos, MySQL proporciona gran cantidad de datos en sus archivos de registro (log en ingls). MySQL mantiene registros de su actividad en diferentes archivos: 1. El registro de errores: Guarda informacin sobre los errores aparecidos durante el proceso de arranque o de parada de MySQL, adems de durante su funcionamiento. Tambin registra las paradas y arranques del servicio. Examinar este archivo puede ayudarle a determinar por qu el servidor no se pone en marcha. 2. El registro de consultas: O registro general. Todas las conexiones que se establezcan con MySQL y las posteriores consultas quedan registradas aqu. 3. El registro binario: Aquellas instrucciones que realicen algn cambio quedan registradas en este archivo. 4. El registro lento: Almacena informacin sobre aquellas consultas que tardan mucho tiempo en completarse, o aquellas que no utilizan ndices.
Not a: Si tiene algn problema utilizando MySQL y necesita buscar ayuda sobre el mismo, examine los archivos de registro. A veces no bastar con la descripcin del problema, le har falta incluir informacin que aparezca en estos archivos. El buscador de mensajes en los grupos de noticias http://groups.google.com/ puede serle til.

Existen otros archivos de registro de los que no se hablar porque no le sern tiles por el momento. Puede encontrar ms informacin sobre ellos en la documentacin de MySQL. El registro de errores ser el que ms utilice cuando comience a trabajar con MySQL, para localizar problemas en caso de que los tenga. La ubicacin de este archivo variar, dependiendo de si el servidor est instalado en Windows, Linux o Mac OS X. Esta ruta depender de cmo y dnde haya instalado MySQL. Por lo general, se tratar de la carpeta data, dentro de la ruta de instalacin de MySQL. El nombre del archivo se compone del nombre del ordenador con la extensin err (linux.err si el nombre del equipo fuese linux), aunque tambin puede ser mysql.err . La ubicacin del archivo de registro de errores se puede cambiar si le pasa al servidor el siguiente parmetro al arrancar:
--log-error [= ruta]

Fjese en que la ruta del archivo es opcional. Si pasa el parmetro sin ella estar indicando que quiere activar el registro de errores pero deja la decisin del nombre del archivo a MySQL. La figura 9.11 muestra el contenido tpico del archivo de registro de errores de un servidor MySQL instalado en Mac OS X.

Figura 9.11. Contenido del registro de errores

Cada lnea del archivo de registro comienza con un nmero de seis dgitos que representa la fecha con el formato AAMMDD (ao, mes y da). A continuacin la hora en la que se produjo en mensaje y, por ltimo, el mensaje. En cuanto al registro de consultas, puede seleccionar su ubicacin si, en el momento de arrancar, le pasa al servidor el parmetro:
--log [= ruta]

Este archivo de registro es especialmente til si conoce la existencia de algn problema, por ejemplo durante la conexin de algn programa con el servidor de bases de datos, pero no dispone de suficiente informacin para solucionarlo. El tercer archivo de registro que puede resultarle interesante es el binario. ste se diferencia del resto en que no es posible su examen directo, con un editor de texto, al contrario que los dos anteriores. Para activar este archivo de registro pase el siguiente parmetro al servidor durante el arranque:
--log-bin [= ruta]

Para examinar un archivo de registro binario debe hacer uso de la utilidad mysqlbinlog.exe, que se encuentra en la carpeta bin, dentro de la carpeta en la que MySQL est instalado. Para que le muestre el contenido de un archivo de registro binario debe pasarle su ruta como argumento. La figura 9.12 muestra el resultado de intentar leer directamente el contenido de un archivo de registro binario

recin creado, en lugar de leerlo utilizando mysqlbinlog.exe.

Figura 9.12. Archivo de registro binario

Si el nmero de operaciones realizadas en su servidor de bases de datos es muy grande, el tamao de los archivos de registro puede llegar a ser excesivo. Adems de suponer un posible problema para el mismo servidor, que puede quedarse sin espacio en disco, su tarea como administrador se ver dificultada: trabajar con archivos demasiado extensos puede ser un problema. Puede obligar a MySQL a crear nuevos archivos de registro utilizando la siguiente instruccin, como si estuviese ejecutando instrucciones SQL:
FLUSH LOGS;

Los archivos de registro binario utilizan una extensin compuesta de varios dgitos: mayor nmero, archivo ms reciente.
Not a: Le recomendamos que realice esta operacin de forma peridica y haga una copia de seguridad de los archivos de registro, por lo que pueda pasar.

Archivos de registro en tablas


MySQL permite guardar las entradas del registro en tablas, en lugar de en archivos. Se trata de algo muy interesante por varias razones. Tras el repaso a los archivos de registro que hicimos en el apartado anterior, la ms evidente salta a la vista: resulta mucho ms sencillo buscar informacin en la tabla de una base de datos que en un archivo de texto. Los datos de cada lnea del archivo de registro se desgajan, yendo cada uno a una columna de la tabla correspondiente. Ya dispone de dos tablas de registro en su servidor MySQL, dentro de la base de datos mysql: general_log y slow_log. Por defecto, estas tablas no se estn utilizando, as que estarn vacas, como puede ver en la figura 9.13.

Figura 9.13. Tablas de registro, vacas

La tabla general_log se utiliza para guardar las entradas del registro de consultas, o registro general. En la tabla slow_log se guardan las entradas del registro lento. Antes de nada tenemos que saber dnde guarda MySQL los datos de registro, en archivos o en tablas. Para ello ejecute la siguiente consulta:
SHOW VARIABLES LIKE 'log_output';

La figura 9.14 muestra el resultado de realizar esta operacin en un servidor MySQL con la configuracin por defecto: la informacin de registro se guarda en archivos.

Figura 9.14. Registro en archivos

La opcin de configuracin log_output , que se pasa como parmetro durante el arranque del servidor (--logoutput ), puede tomar tres valores: FILE , TABLE o NONE . Con el primero (--log-output=FILE ) se utilizarn archivos para el registro, mientras que con el segundo se utilizarn tablas. El tercero desactiva la generacin de informacin de registro. Si lo desea, esta informacin se puede guardar simultneamente en archivos y tablas utilizando el parmetro --log-output=FILE,TABLE . Ahora bien, no es necesario reiniciar el servidor para empezar a utilizar el registro en tablas, nos basta con utilizar la siguiente sentencia:
SET GLOBAL log_output='TABLE';

El valor de la opcin de configuracin cambiar y MySQL la tendr en cuenta de inmediato. En la figura 9.15 puede ver cmo hemos cambiado el valor de esta opcin y la posterior consulta que demuestra que el cambio ha tenido lugar.

Figura 9.15. El registro, ahora en tablas

Aunque hayamos configurado MySQL para que guarde el registro en tablas, recordemos que slo dos de ellos se ven afectados: el general y lento. Como vimos anteriormente, estos registros se activan a travs de parmetros de inicio de MySQL. Pero, como ya sospecha, es posible activarlos utilizando la misma tcnica que acaba de ver. As que comencemos comprobando si el registro general est activo:

SHOW VARIABLES LIKE 'general_log';

Si el valor de esta opcin de configuracin es OFF significar que est desactivado. Utilice la siguiente sentencia para activarlo:
SET GLOBAL general_log='ON';

La figura 9.16 muestra el resultado de llevar a cabo estas dos operaciones.

Figura 9.16. Activacin del registro general

A partir de este momento, con el registro en tablas activo y el registro general en funcionamiento, la tabla general_log comenzar a recibir datos de MySQL. Para comprobarlo, realice la siguiente consulta:
USE mysql;

SELECT * FROM general_log\G

El resultado, en la figura 9.17, muestra, precisamente, las consultas que hemos estado realizando: en la fila 7 pedimos que se nos mostrase el valor de la variable general_log, en la 8 seleccionamos la base de datos que aparece en la fila 9 (mysql) y, en la 10, realizamos la consulta de los datos de la tabla en cuestin.

Figura 9.17. Contenido de la tabla de registro

Cada registro tiene 6 columnas: event_time: Cundo tuvo lugar el evento registrado?

user_host: Quin gener el evento en cuestin? thread_id: Identificador del subproceso. server_id: Identificador del servidor. command_type: Tipo de orden. Por ejemplo, una consulta (Query) o la seleccin de una base de datos (Init DB). argument: Parmetros pasados a la orden. En el caso de una consulta ser la consulta en s. Al guardar la informacin de registro en tablas resulta sencillo obtener la lista de operaciones realizadas a lo largo de un da, o desde cierto equipo conocida su IP, o la lista de todas las consultas, por citar slo algunos ejemplos. Una de las ventajas de mantener los registros en tablas es que podemos guardar informacin de diferentes servidores en la misma ubicacin. Configure los servidores a su cargo para que guarden sus registros en las tablas de uno de ellos. As slo tendr que consultar esa tabla, filtrando los registros por servidor. Otra ventaja: podramos utilizar desencadenadores para que MySQL realizase ciertas tareas en caso de que se insertasen ciertos valores en la tabla de registro. Si se produce un error, ya sabe dnde encontrar la descripcin del mismo. No le gustara, adems, poder entender esos mensajes de error, en caso de que no sepa ingls?

Idioma de los errores


En este apartado describiremos la solucin a un problema que seguramente habr notado desde que comenz a trabajar con MySQL: los mensajes de error no aparecen, por defecto, en espaol. Puede comprobarlo si intenta conectarse con el servidor de MySQL proporcionando una contrasea incorrecta o ejecutando una consulta de seleccin sin especificar una base de datos, por ejemplo. La figura 9.18 es una buena muestra de ello.

Figura 9.18. Mensaje de error en ingls

Para cambiarlo, slo tiene que utilizar un parmetro en el arranque del servidor:
--language=spanish

Para pasar dicho parmetro durante el inicio del servicio debe recordar lo aprendido durante el captulo dedicado a la administracin de MySQL. En concreto, la figura 9.19 muestra el aspecto de las propiedades del servicio al incluir dicho parmetro.

Figura 9.19. Para obtener mensajes en espaol

Una vez reinicie el servicio podr comprobar que los mensajes de error del servidor aparecen en espaol. Prueba de ello es la figura 9.20, en la que puede ver el resultado de ejecutar la misma consulta con la que obtuvimos el mensaje de error de la figura 9.18, una consulta de seleccin sin indicar sobre qu base de datos.

Figura 9.20. Mensaje de error en espaol

Como puede comprobar si compara la figura 9.18 con la 9.20, independientemente del idioma en el que se muestren los mensajes de error el cdigo es el mismo (en este caso, el 1046). Gracias a ello le ser ms sencillo responder a estos errores en sus programas de forma sistemtica en caso de que se produzcan.

MySQLi y los errores


La gestin de los errores en MySQLi sigue unas pautas muy sencillas. Si est utilizando la versin orientada a objetos de la misma, cada objeto con el que est trabajando dispondr de una pareja de propiedades que, en caso de error, expondrn el cdigo del mismo y su descripcin. Se trata de errno y error , respectivamente. Como ya sabe, existe una excepcin a esta regla. En el caso de que el error se produzca al intentar establecer una conexin con un servidor de bases de datos, no podr utilizar las propiedades errno y error de la clase, puesto que no se habr podido crear. Para esta eventualidad dispone de otras dos funciones, mysqli_connect_errno() y mysqli_connect_error(), que devuelven el cdigo del error y su descripcin, respectivamente.

respectivamente. En caso de que est trabajando con la versin funcional de esta biblioteca, podr utilizar las funciones mysqli_errno() y mysqli_error(). Estas dos funciones necesitan una referencia a la variable con la que se realiz la operacin que gener el error. Por ejemplo, un gestor de conexin, el valor obtenido tras establecer una conexin con una base de datos de MySQL. De cmo utilizar estas funciones poco podemos contar, puesto que ya las hemos utilizado en numerosas ocasiones a lo largo del libro. Sin embargo, para sacar el mayor partido de ellas utilcelas conjuntamente con todas las herramientas de gestin de errores que haya visto a lo largo de este captulo.

10

Plantillas
Si la calidad de un lenguaje de programacin tuviese que medirse por la utilidad de las herramientas desarrolladas con l, la nota de PHP sera de las ms altas. Las aplicaciones que hemos desarrollado hasta ahora, por su sencillez, slo dejaban entrever uno de los problemas que entraa la programacin con PHP: la mezcla de la lgica con la representacin. Suponga que est desarrollando una aplicacin para una empresa. En este proyecto, usted est al cargo de la parte de la programacin (lo que se conoce como la lgica de la aplicacin) pero no del diseo de las pginas (la representacin). El proceso de unir las dos partes del trabajo no resulta demasiado complejo: copiamos un poco de cdigo PHP en una pgina HTML, un bucle all, unas variables ac, y cambiamos la extensin de las pginas HTML por PHP. El verdadero problema viene cuando hemos de hacer un cambio, ya sea en la parte del diseo o en la parte de la programacin. Por lo general, los diseadores no tienen nocin alguna sobre PHP, as que siguen trabajando con su diseo. Somos nosotros los que tenemos que volver a modificar sus pginas HTML para incluir el cdigo PHP en ellas, tras los cambios que hayan realizado. As una y otra vez. Aunque existen herramientas que le permiten localizar diferencias entre archivos y mezclar slo aquellas partes que le interesen, tiene otra opcin mucho ms interesante y til: las plantillas de Smarty.

Qu es Smarty?
Smarty es una capa ms dentro de nuestra particular torre de Babel. Hasta ahora hemos apilado un buen montn de tecnologas: un servidor de bases de datos MySQL, un servidor de pginas Web, PHP, HTML y JavaScript. Como puede ver en la figura 10.1, Smarty podra situarse entre PHP y HTML.

Figura 10.1. Dnde est Smarty?

La principal misin de Smarty es aislar la lgica de la representacin de las pginas. El resultado: no hay cdigo PHP en las pginas HTML, ni cdigo HTML en las pginas PHP. Esto permite que el equipo de desarrollo pueda trabajar de forma independiente al equipo de diseo. Lo mejor para entender lo que estamos diciendo es verlo en funcionamiento.

Un pequeo ejemplo
Este ejemplo le mostrar de qu es capaz Smarty. An no lo hemos instalado (lo haremos en el siguiente apartado), as que an queda un poco para que pueda poner en funcionamiento lo que vamos a ver. Sin embargo, es interesante que sepa, antes de nada, lo que se puede conseguir con Smarty. Se trata de algo muy sencillo. De hecho, vamos a retomar el primer ejemplo que vimos en el captulo 2, aquel que mostraba la hora. El cdigo de esa pgina era el siguiente:
La hora es: <?= date("H:i:s") ?>.

Una sola lnea de cdigo cuyo resultado variaba en funcin de la hora a la que la pgina se cargase. El resultado de cargar esa pgina puede verse en la figura 10.2.

Figura 10.2. Qu hora es?

HTML y PHP entremezclados en la misma lnea. Poco diseo hay en esta pgina, pero podemos dejarlo libre de cdigo PHP. Con Smarty, tendramos dos archivos: el PHP y una plantilla con el diseo correspondiente, un archivo que, por lo general, tiene la extensin TPL (template, plantilla). Para nuestro ejemplo, podra ser el siguiente:

La hora es: {$hora}.

Si guardase ese archivo con el nombre smarty.tpl y lo intentase cargar en un cliente Web podra ver algo parecido a lo que muestra la figura 10.3.

Figura 10.3. Plantilla sin aplicar

Un diseador podra trabajar con este archivo, aadiendo lo que le plazca, con tal de que cumpla una condicin: incluir {$hora} donde deba ir la hora. Y ahora, le toca al programador. El cdigo de la pgina PHP sera el siguiente:
<?php

include('Smarty.class.php');

$smarty = new Smarty; $smarty->assign('hora', date("H:i:s")); $smarty->display('smarty.tpl');

?>

El primer requisito: tener acceso al archivo Smarty.class.php. En este archivo est la descripcin de la clase Smarty, que utilizaremos para llevar a cabo la magia. Slo tiene que crear un ejemplar de dicha clase y utilizar el mtodo assign() para crear la variable $hora que la plantilla utiliza para mostrar la hora. El mtodo display() se encarga de localizar la ubicacin de dicha variable en la plantilla y mostrar el resultado de la sustitucin. El resultado ser idntico al que vimos en la figura 10.2. Seguro que est impaciente por empezar a utilizar esta herramienta en sus pginas. No es extrao. Adems de la ventaja que supone separar el diseo de la lgica en sus programas, existen muchas otras. Una de las ms importantes es que podr cambiar el aspecto de las pginas sin que cambie la lgica del programa. Hablando claro: una vez tenga el programa que recupera la lista de gneros, podr disponer de varios diseos diferentes para la pgina nicamente cambiando el nombre de la plantilla que quiera utilizar.

Instalacin
El primer paso para instalar Smarty es descargarlo desde su pgina Web:

http://smarty.net/ Localice la pgina de descarga en la Web de Smarty. Debido a la naturaleza de la Web, no es seguro que ste sea enlace del que descargar Smarty cuando lea estas lneas pero, por si acaso: http://smarty.net/download.php Descargue la ltima versin estable. Por lo general, se trata de un archivo con la extensin tar.gz, aunque tambin est disponible una versin en formato zip. Herramientas como 7-Zip (http://7-zip.org/), tar y gunzip (disponibles casi con total seguridad en su distribucin de Linux) o Stuffit (http://my.smithmicro.com/mac/stuffit/) le ayudarn a extraer el contenido del archivo en una carpeta temporal.
Not a: Esto es para aquellos que utilicen Windows. La extensin t ar.gz es muy frecuente en sistemas Unix. La parte final, gz , indica que el archivo ha sido comprimido con gzip, mientras que t ar indica que se trata de un paquete de archivos.

El contenido de esa carpeta temporal ser otra con el nombre de la versin actual de Smarty dentro de la que podr ver una serie de archivos y carpetas, como en la figura 10.4.

Figura 10.4. Los archivos de Smarty

El proceso de instalacin es tan sencillo como colocar esta carpeta donde desee. En este caso vamos a copiarla dentro de la carpeta en la que XAMPP se haya instalado. Esta ruta ser diferente dependiendo del sistema operativo que utilice. Obviamente, si no utiliza XAMPP tendr que guardar la carpeta de Smarty en otra ubicacin. Posteriormente, modifique la configuracin de PHP para que sepa dnde encontrar a Smarty. Existe una variable de configuracin llamada include_path. Como ya sabe por captulos anteriores, estas opciones de configuracin pueden incluirse en el archivo php.ini, para que estn disponibles de forma global, o en Apache, limitando su mbito a una carpeta en particular.

Vamos a optar por la segunda opcin. Como ya hicimos en el captulo anterior y en el 7, vamos a crear una nueva carpeta dentro de la predeterminada de Apache, la carpeta htdocs. El nombre de esta carpeta ser plantillas. Modifique entonces la configuracin de Apache para que las pginas PHP que estn en esa carpeta sepan dnde encontrar a Smarty. Para ello, incluya una directiva php_admin_value con la que asignar un valor a la opcin de configuracin include_path. En esa variable debe incluir dos carpetas. La primera, aquella en la que haya instalado Smarty. La segunda, la carpeta en la que vaya a poner las plantillas. La configuracin de Apache para la carpeta plantillas podra ser algo as:
...

<Directory "C:/xampp/htdocs/plantillas"> Options Indexes FollowSymlinks AllowOverride None Order allow,deny Allow from all php_admin_value include_path \ "C:/xampp/smarty/libs;C:/xampp/htdocs/plantillas" </Directory>

...

Al reiniciar Apache podr ver las opciones de configuracin de PHP en la carpeta plantillas utilizando la funcin phpinfo() dentro de un archivo PHP con un contenido como ste, que ya vimos en anteriores captulos:
<?php

phpinfo();

?>

El valor de la variable include_path puede verse en la figura 10.5.

Figura 10.5. La ruta de Smarty

Not a: En Windows, las rutas a incluir se separan con punto y coma (; ). En el resto de sistemas operativos, con dos puntos (: ).

La prueba ms sencilla para saber si Smarty est correctamente instalado es crear una pgina PHP dentro de la carpeta plantillas, que se encuentra en el interior de htdocs, con el siguiente cdigo:
<?php

require('Smarty.class.php');

require('Smarty.class.php');

$smarty = new Smarty;

?>

Si al cargar esta pgina no se produce ningn error, todo ha ido bien. En caso contrario, lo ms seguro es que PHP no haya sido capaz de encontrar los archivos necesarios. Revise la configuracin y vuelva a cargar la pgina. Una posible solucin, si no localiza el problema, es indicar la ruta completa del archivo requerido:
<?php

require( 'C:/xampp/smarty/libs/Smarty.class.php' );

$smarty = new Smarty;

?>

Y ahora que tiene Smarty en su sistema, vamos a retomar la pgina que muestra el listado de gneros.

Lista de gneros
En el captulo 7 vimos cmo cargar la lista de gneros existentes en nuestra base de datos. Tras lo visto en los captulos siguientes a ese, el cdigo de dicha pgina es el siguiente:
<?php

$videoteca = new mysqli( '', '', '', 'videoteca');

if (mysqli_connect_errno() != 0){ echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query( 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

while ($fila = $resultado->fetch_row()){ printf( "(%u) %s - %s<br/>", $fila[0], $fila[1], $fila[2] );

); }

$resultado->close(); $videoteca->close();

?>

Analice el cdigo PHP anterior. Olvidando los mensajes que enve en caso de error en la conexin o la consulta, el punto que tendramos que modificar para cambiar el aspecto de los datos mostrados ser el bucle while, encargado de representar la informacin de los gneros. Es ah donde tendremos que utilizar Smarty. Guarde el cdigo anterior en un archivo llamado generos.php, dentro de la carpeta plantillas que cre anteriormente. En esa misma carpeta necesitar otras dos: templates y templates_c. En la primera guarde los archivos con la extensin TPL , la segunda es para uso interno de Smarty. Vamos a comenzar haciendo algo sencillo: lograr que el aspecto de la pgina sea el mismo que tena sin utilizar Smarty.

La plantilla
De golpe, no hay dolor, esta es la plantilla:
<html>

<head> <title>Smarty - gneros</title> </head>

<body> {section name=i loop=$generos} ({$generos[i].id}) {$generos[i].nombre} {$generos[i].descripcion}<br/> {/section} </body>

</html>

Debe guardarla en la carpeta templates, dentro de la carpeta plantillas, con el nombre generos.tpl. Y qu es lo que hace esta plantilla? Primero fjese en los elementos {section}. Gracias a ellos puede realizar iteraciones. Smarty permite definir secciones de cdigo en las que iterar por algunas de las variables que pase a travs del mtodo assign(). En este caso, el nombre de la variable es $generos. Se trata de una matriz que contendr la lista de gneros disponible, y en cada iteracin se referir a cada elemento de la matriz con el nombre i.

Dentro del bucle se accede al identificador del gnero as:


$genero[i].id

El atributo loop de la seccin determina sobre qu variable va a iterar, mientras que el atributo name le da el ndice del elemento actual. Esto en cuanto a la plantilla pero, cmo queda la pgina PHP?

La pgina PHP
El siguiente es el cdigo PHP de la pgina que muestra la lista de gneros, pero utilizando Smarty para ello:
<?php

include('Smarty.class.php');

$videoteca = new mysqli( '', '', '', 'videoteca');

if (mysqli_connect_errno() != 0) { echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query( 'SELECT * FROM genero' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

$generos = array();

while ($fila = $resultado->fetch_assoc()){ array_push($generos, $fila); }

$resultado->close(); $videoteca->close();

$smarty = new Smarty; $smarty->assign('generos', $generos); $smarty->display('generos.tpl');

?>

Hasta que llegamos al bucle while, todo es ms o menos igual que antes de utilizar Smarty, salvo por el uso de la instruccin include. La primera diferencia la encontramos en este bucle, que en lugar de mostrar los detalles de cada gnero, se dedica a guardarlos todos en una matriz.

Tras este bucle, se cierra tanto el resultado de la consulta como la conexin con la base de datos. Ah empieza la diferencia. Creamos un ejemplar de la clase Smarty, le pasamos la lista de gneros, que tenemos en una matriz y llamamos al mtodo display() para que la magia tenga lugar. El resultado es indistinguible del obtenido sin Smarty, como puede verse en la figura 10.6.

Figura 10.6. Gneros, con Smarty

Pero s que hay una importante diferencia. Veamos lo sencillo que resulta cambiar el aspecto de una pgina.

Otra plantilla
Haga un pequeo cambio en la pgina PHP que muestra los gneros utilizando Smarty. Va a recibir el nombre de la plantilla a travs de la URL. Si no recibe ningn nombre se utilizar uno predeterminado. Entonces, pase ese nombre de plantilla al mtodo display(). Algo as:
...

include('Smarty.class.php');

$plantilla = $_GET['plantilla']; if($plantilla == ''){ $plantilla = 'generos.tpl'; }

$videoteca = new mysqli( '', '', '', 'videoteca');

...

$smarty->display($plantilla);

...

Si carga la pgina tal y cual, como antes, todo seguir funcionando correctamente. Ahora, vamos a crear una nueva plantilla, basada en la anterior. En lugar de mostrar la lista de gneros tal cual, como texto, lo har dentro de una tabla. Esta plantilla tendra el siguiente cdigo:
<html>

<html>

<head> <title>Smarty - gneros</title> </head>

<body>

<table border="1">

<tr> <th>Id</th> <th>Nombre</th> <th>Descripcin</th> </tr>

{section name=i loop=$generos} <tr> <td>{$generos[i].id}</td> <td>{$generos[i].nombre}</td> <td>{$generos[i].descripcion}</td> </tr> {/section} </table>

</body>

</html>

Guarde esta plantilla con el nombre tabla.tpl dentro de la carpeta templates que cre anteriormente. La magia vuelve a ocurrir cuando carga la pgina pasando un valor para el nombre de la plantilla, como puede verse en la figura 10.7. Un mundo de posibilidades, abierto ante nosotros.

Figura 10.7. Mismo PHP, varias plantillas

11

Procedimientos almacenados
La posibilidad de utilizar procedimientos almacenados en MySQL es, quiz, una de las caractersticas ms esperadas. La ausencia de los mismos en versiones anteriores a la 5 supona una traba para el desarrollo de algunas aplicaciones, razn por la que muchos decidan utilizar otros sistemas gestores de bases de datos. Por fortuna, esto ha dejado de ser una excusa. Los procedimientos almacenados facilitan la ejecucin de conjuntos de instrucciones SQL, permitiendo agruparlos bajo un nombre comn. Adems, gracias a su empleo se puede lograr cierto nivel de independencia entre la base de datos y las aplicaciones que hacen uso de ella. Este captulo sirve como presentacin de los procedimientos almacenados. Para que pueda leerse independientemente del resto del libro utilizaremos un subconjunto de la base de datos de ejemplo desarrollada en captulos anteriores, aunque tambin podr utilizar la base de datos completa, si lo desea. Empezaremos creando una base de datos con una sola tabla, que utilizaremos para probar el funcionamiento de un sencillo procedimiento almacenado de ejemplo. La sintaxis ser explicada en apartados posteriores. A partir de ese momento veremos procedimientos almacenados ms complejos. Tambin veremos cmo crear funciones almacenadas, consideradas por muchos como una variedad de procedimientos almacenados. Como comprobar, las diferencias existentes entre ambos no son demasiadas.

Introduccin
A lo largo de los captulos que preceden a ste ha podido comprobar cmo evoluciona una base de datos, partiendo de una sencilla idea que se va complicando a medida que se convierte en realidad. Quiz algunos lectores de este libro hayan acudido directamente a los captulos finales (como ste), en los que se tratan en detalle las ms importantes caractersticas de MySQL. Aunque no es recomendable, para hacerlo posible es necesario que dichos captulos sean independientes, de alguna manera, del resto del libro. Supondremos que el lector tiene ciertas nociones bsicas tanto sobre el funcionamiento del servidor de bases de datos MySQL como sobre las herramientas necesarias para trabajar con l. Adems, deber conocer el lenguaje SQL.

Base de datos reducida

Seguramente ya est familiarizado con la base de datos que hemos creado a lo largo de este libro. Puede ver un diagrama de la misma en la figura 11.1. En lo que a este captulo respecta, vamos a trabajar con una versin muy reducida de la misma. De hecho, la base de datos que utilizaremos slo contendr la tabla actor .

Figura 11.1. Diagrama de la videoteca

En la nica tabla de esta base de datos insertaremos los mnimos registros necesarios para poder obtener resultados interesantes con los procedimientos almacenados que crearemos en este captulo. En los siguientes dos apartados crearemos la base de datos de prueba e insertaremos algunos registros en su nica tabla.

Creacin
Para crear la base de datos con la que trabajaremos en este captulo slo es necesario dar las siguientes rdenes a MySQL:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca;

Advert encia: Tenga cuidado: si ya dispone de una base de datos con ese nombre, las instrucciones anteriores la borrarn junto con su contenido.

Una vez disponga de la base de datos es necesario crear la tabla que contendr los detalles de los actores. Las siguientes instrucciones cumplen tal misin:
USE videoteca;

DROP TABLE IF EXISTS actor; CREATE TABLE actor ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL,

nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, imdb VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY(id) ) ENGINE = InnoDB;

La figura 11.2 muestra un diagrama de la tabla que acaba de crear. Est realizado con MySQL Workbench.

Figura 11.2. Subconjunto de la videoteca

Insercin
El ltimo paso consiste en insertar algunos registros en la tabla actor de la base de datos que acabamos de crear para poder trabajar con ellos. Utilice las siguientes instrucciones:
USE videoteca;

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Harrison', 'Ford', 'nm0000148');

INSERT INTO actor(nombre, apellidos, imdb) VALUES('Russell', 'Crowe', 'nm0000128');

Tras crear esta versin reducida de la base de datos desarrollada durante los captulos anteriores estamos en disposicin de comenzar a trabajar con procedimientos almacenados.

Un sencillo ejemplo
Una de las tareas ms simples que se pueden realizar utilizando procedimientos almacenados es recuperar informacin. Por ejemplo, la lista de actores almacenados en la tabla actor . El siguiente cdigo crea un procedimiento almacenado de tales caractersticas:
USE videoteca;

CREATE PROCEDURE pa_actores_lista()

SELECT * FROM actor;

Fjese en cmo est construido el nombre del procedimiento almacenado. Como separador de palabras hemos utilizado el guin bajo (_), lo ms parecido a un espacio que nos permiten las normas de MySQL para los

nombres. El nombre comienza con pa, las iniciales de procedimiento almacenado. As es posible diferenciarlo claramente de una tabla. El resto del nombre intenta definir claramente la finalidad del procedimiento almacenado. Se trata de una eleccin personal que depende de las preferencias de cada uno. Posteriormente nos centraremos en la sintaxis necesaria para crear procedimientos almacenados. Ya conoce la misin de la primera lnea del listado anterior: indicar la base de datos con la que queremos trabajar. La siguiente, que comienza con la instruccin CREATE PROCEDURE , le ser desconocida, pero no as el resto. De hecho, se trata de una simple consulta de seleccin. Lo que diferencia las instrucciones anteriores de una consulta de seleccin es, precisamente, la instruccin CREATE PROCEDURE . Se podra decir que dicha lnea le da al servidor de bases de datos la siguiente orden: "Ahora te voy a mostrar una serie de instrucciones SQL, gurdalas con el nombre pa_actores_lista porque luego las voy a necesitar". Para crear el procedimiento almacenado, ejecute las instrucciones anteriores como si estuviese ejecutando cualquier otro conjunto de instrucciones. La figura 11.3 muestra la respuesta que MySQL debera dar.

Figura 11.3. Creacin del primer ejemplo

Ha llegado el momento de obtener los frutos del trabajo realizado hasta ahora. Ejecute el procedimiento almacenado utilizando las siguientes instrucciones:
USE videoteca;

CALL pa_actores_lista();

La figura 11.4 muestra el resultado devuelto por el procedimiento almacenado que acabamos de crear.

Figura 11.4. Lista de actores

Como puede comprobar si lo desea, ejecutar el procedimiento almacenado devuelve el mismo resultado

que esta consulta:


USE videoteca;

SELECT * FROM actor;

Entonces, por qu utilizar procedimientos almacenados? Aunque existen muchas otras ventajas, existe una muy obvia: quien ejecute este procedimiento almacenado no necesita saber nada en absoluto sobre la estructura de la base de datos. Se podra decir que hemos divido la base de datos en dos partes: una estructural y otra lgica. La parte estructural estara compuesta tanto por el diseo de la base de datos como por los registros almacenados en las tablas. El conjunto de procedimientos almacenados creados para recuperar informacin de esa base de datos sera la parte lgica. Y por qu supone esta divisin una ventaja? Porque ofrece la posibilidad de trabajar con dos equipos. Suponga que esta base de datos va a ser el ncleo de un sitio Web dedicada al cine y que sus pginas estarn escritas usando el lenguaje PHP. Esas pginas sern el cliente de la base de datos. Como ya hemos visto, este lenguaje dispone de las herramientas necesarias para comunicarse con MySQL. As que podra existir un equipo dedicado al mantenimiento de la base de datos, diseando tablas, definiendo sus campos y creando los procedimientos almacenados que devuelvan informacin a partir de los datos contenidos en la base de datos. Y, por otro lado, el equipo dedicado a la creacin de las pginas PHP. Para incorporar la informacin obtenida a partir de la base de datos, este equipo nunca utilizara consultas, slo procedimientos almacenados. Por lo tanto, no sera necesario que conociesen la estructura de la base de datos, slo tendran que llamar a un determinado procedimiento almacenado para obtener la lista de actores, otro les proporcionara todos los detalles del mismo, un tercero les mostrara la lista de pelculas protagonizadas por dicho actor, y as para cada caso.
Not a: Esta independencia entre equipos tiene ventajas aadidas. Por ejemplo, la posibilidad de modificar el diseo de la base de datos sin por ello tener que modificar las pginas PHP, siempre y cuando los procedimientos almacenados sigan devolviendo los mismos datos.

Sintaxis
Las posibilidades ofrecidas por el uso de los procedimientos almacenados van mucho ms all de lo visto en el ejemplo anterior. Para poder sacarles todo su

visto en el ejemplo anterior. Para poder sacarles todo su jugo es necesario conocer cmo construirlos correctamente, precisamente lo que veremos a partir de ahora.

Creacin
La sintaxis de la instruccin para la creacin de procedimientos almacenados en MySQL es la siguiente:
CREATE PROCEDURE nombre_pa ([parmetro, [...]) instrucciones

Tras las palabras reservadas CREATE PROCEDURE se incluye el nombre del procedimiento almacenado. Si fuese necesario, puede recibir una serie de parmetros (ms al respecto en el apartado Funciones almacenadas, ms adelante). El procedimiento almacenado estar completo cuando se incluyan las instrucciones asociadas al mismo. La primera lnea que se puede ver en la definicin de la sintaxis del procedimiento almacenado se conoce como cabecera, mientras que la segunda es el cuerpo del procedimiento. El siguiente ejemplo calcula y muestra el nmero de registros de la tabla actor :
USE videoteca;

CREATE PROCEDURE pa_actores_cantidad()

SELECT COUNT(*) FROM actor;

El resultado de ejecutar este procedimiento almacenado puede verse en la figura 11.5.

Figura 11.5. Nmero de actores

Variables
Los datos no son etreos y, en ocasiones, necesitar almacenarlos en algn lugar. Una variable es ese lugar. En ellas se guardarn aquellos valores que haya que consultar o modificar posteriormente. El lenguaje SQL es un lenguaje de programacin. En la jerga de los programadores, reservar el espacio necesario para guardar dichos valores se conoce como declarar una variable. Este espacio se encuentra en la memoria

principal del ordenador, es decir, en la RAM. Para declarar una variable es necesario seguir la siguiente sintaxis:
DECLARE nombre_variable[, ...] tipo [DEFAULT valor_predeterminado]

La palabra reservada DECLARE va seguida del nombre de la variable que se quiera declarar. Incluya a continuacin el tipo de datos de dicha variable, es decir, la naturaleza de los datos que contendr. Por ejemplo, la siguiente instruccin sirve para crear una variable de tipo entero llamada actores:
... DECLARE actores INT; ...

Consejo: Si quiere refrescar sus conocimientos sobre los tipos de datos, acuda a la seccin 6 del captulo 3, Tipos de datos. En ella se hace un repaso de los ms importantes ofrecidos por MySQL.

Inicialmente, el valor almacenado en una variable es NULL . El primer paso consiste en asignar un valor inicial a las variables que cree, algo que se logra gracias a la palabra reservada DEFAULT , que se incluye en la sintaxis de DECLARE . As, es posible declarar la variable actores para que su valor inicial sea 0:
... DECLARE actores INT DEFAULT 0; ...

Existen dos formas de asignar un valor a una variable tras su creacin: Directamente: Utilizando la palabra reservada SET . As, podra asignarse el valor 0 a la variable tras declararla:
... DECLARE actores INT;

SET actores = 0; ...

Tomando su valor de una consulta: Utilizando la pal abra INTO en una consulta de seleccin. Por ejemplo, la siguiente consulta recupera el nmero de registros en la tabla actor y guarda el valor en la variable actores:
... DECLARE actores INT;

SELECT

SELECT COUNT(*) INTO actores FROM actor; ...

En lo que resta de captulo podr encontrar varios ejemplos del uso de variables en procedimientos almacenados. El cuerpo de los procedimientos almacenados que hemos visto hasta ahora est compuesto de una sola sentencia SQL. Sin embargo, es posible incluir tantas instrucciones como sea necesario.

Delimitadores
Ya sabe que cuando se escribe una sentencia SQL es necesario utilizar punto y coma (;) para indicar dnde acaba. La sentencia de creacin de un procedimiento almacenado tambin es SQL y, como tal, necesita el empleo de dicho delimitador. Puede comprobar que los dos procedimientos almacenados creados hasta ahora cumplen dicha norma. Por otra parte, la misma norma ha de seguirse en el cuerpo del procedimiento almacenado si ste est compuesto por ms de una sentencia SQL, caso que hasta ahora no se ha dado. Aparece aqu un problema: cmo diferenciar entre el punto y coma que finaliza una sentencia perteneciente al cuerpo del procedimiento almacenado y el que marca el final del mismo? Por ejemplo, fjese en esta versin del procedimiento almacenado visto anteriormente, cuya misin era devolver el nmero de registros en la tabla actor :
USE videoteca;

CREATE PROCEDURE pa_actores_cantidad2() BEGIN

DECLARE actores INT DEFAULT 0;

SELECT COUNT(*) INTO actores FROM actor; SELECT actores;

END;

En lugar de ejecutar directamente la consulta, se utiliza una variable en la que se almacena el resultado de la consulta. A continuacin, se devuelve dicho valor. Es la posibilidad de realizar las mismas tareas de diferentes

formas lo que hace tan interesante utilizar este tipo de tecnologas. Si intenta crear el procedimiento almacenado anterior MySQL le mostrar varios mensajes de error, ya que no es capaz de diferenciar entre el punto y coma que termina una sentencia SQL interior y el que termina el procedimiento almacenado. La solucin a este conflicto es relativamente simple: definir un delimitador diferente para los procedimientos almacenados. Para ello se utiliza la palabra clave DELIMITER, seguida de la secuencia de caracteres marcar el final del procedimiento almacenado. Aunque existe la posibilidad de utilizar prcticamente cualquier delimitador en la documentacin de MySQL se utilizan dos barras inclinadas (//). El siguiente es el cdigo del procedimiento almacenado anterior, corregido para que sea correcto:
USE videoteca;

DELIMITER //

CREATE PROCEDURE pa_actores_cantidad2() BEGIN

DECLARE actores INT;

SELECT COUNT(*) FROM actor INTO actores; SELECT actores;

END

// DELIMITER ;

Antes de comenzar la creacin del procedimiento almacenado se declara el nuevo delimitador. A continuacin, se crea el procedimiento almacenado y, tras la instruccin END, se utiliza el delimitador declarado anteriormente. Para terminar, se deja todo como estaba, estableciendo como delimitador el punto y coma. La figura 11.6 muestra la respuesta del cliente de MySQL al ejecutar las instrucciones de creacin del procedimiento almacenado y una posterior llamada al mismo.

Figura 11.6. Uso de delimitadores

Fjese en la diferente respuesta obtenida al utilizar los procedimientos almacenados que devuelven el nmero de registros en la tabla actor . El primero de ellos, en la figura 11.5, encabeza el resultado con COUNT(*). Efectivamente, el nmero mostrado bajo dicho texto es el resultado de esa instruccin. Sin embargo, en la figura 11.6, el encabezado es actores, puesto que lo que se est seleccionando es el valor de la variable as llamada.

Parmetros
Como pudo verse en la descripcin de la sintaxis de los procedimientos almacenados, existe la posibilidad de declarar una serie de parmetros asociados. A su vez, es necesario describir la sintaxis de estos parmetros:
[ IN | OUT ] nombre_parmetro tipo

El significado de las palabras reservadas IN y OUT es el siguiente: IN : El parmetro es de entrada, es decir, se est pasando un valor desde la instruccin de llamada. Ese valor slo se utilizar para proporcionar informacin al procedimiento almacenado. OUT : Se trata de un parmetro de salida, es decir, para comunicarse con el exterior, para informar de un valor obtenido al ejecutar el procedimiento almacenado.
Not a: Como ya sabe, los corchetes indican una opcin, por lo que no es obligatorio incluir los valores IN o OUT . De forma predeterminada, si no se indica nada, el parmetro ser de tipo IN.

Como el movimiento se demuestra andando, nada mejor que un ejemplo sobre la utilizacin de cada tipo de parmetro para comprender su funcionamiento. En primer lugar, los parmetros de entrada, es decir, el tipo de

parmetro predeterminado. El siguiente cdigo sirve para crear un procedimiento almacenado que muestra la lista de actores cuyo nombre comienza con una determinada letra:
USE videoteca;

CREATE PROCEDURE pa_actores_buscar(letra CHAR(2))

SELECT * FROM actor WHERE nombre LIKE letra;

Si quisiese localizar todos los actores cuyo nombre comienza con la letra h debera ejecutar este procedimiento almacenado as:
CALL pa_actores_buscar('h%');

La figura 11.7 muestra el resultado de ejecutar esta consulta.

Figura 11.7. Bsqueda de actores

Suponga que, adems de la lista de actores, necesita guardar en una variable de salida el nmero de actores localizados. Es decir, ha de utilizarse una variable de tipo OUT :
USE videoteca;

DELIMITER //

CREATE PROCEDURE pa_actores_buscar2( IN letra CHAR(2), OUT actores INT ) BEGIN

SELECT * FROM actor WHERE nombre LIKE letra;

SELECT COUNT(*) INTO

actores FROM actor WHERE nombre LIKE letra;

END

// DELIMITER ;

La llamada a este procedimiento almacenado es como sigue:


USE videoteca; CALL pa_actores_buscar2('h%', @cantidad);

Tambin se buscan aquellos actores cuyo nombre comience con la letra h, como se indica en el primer parmetro. Sin embargo, fjese en que el segundo comienza con el carcter @ (arroba), conocido por su presencia en las direcciones de correo electrnico. Utilice este smbolo para crear variables de sesin, cuya existencia se limita al tiempo que permanezca conectado con MySQL. As, tras la llamada al procedimiento almacenado de bsqueda es posible obtener el nmero de resultados obtenidos de la siguiente forma:
SELECT @cantidad;

En la figura 11.8 puede ver la respuesta de MySQL tanto a la llamada al procedimiento almacenado como al acceso al valor de @cantidad.

Figura 11.8. Valor de la variable de salida

Not a: Existe un tercer tipo de parmetro, INOUT , que queda fuera de los objetivos de este captulo. Para ms informacin consulte la documentacin de MySQL.

MySQL tambin dispone de lo que podramos llamar un pariente muy cercano de los procedimientos almacenados (prcticamente un hermano): las funciones almacenadas.

Funciones almacenadas
La sintaxis de las funciones almacenadas es

prcticamente la misma que la de los procedimientos almacenados:


CREATE FUNCTION nombre_fa ([parmetro, [...]) RETURNS tipo instrucciones

A diferencia de los procedimientos, las funciones slo pueden utilizar un tipo de parmetros, los de entrada (IN ). Al encabezado de la funcin se aade la palabra clave RETURNS seguida del tipo de datos del valor devuelto. Las funciones almacenadas proporcionan una forma diferente de realizar una misma tarea. Considere esta versin modificada del procedimiento almacenado que mostraba el nmero de registros presentes en la tabla de actores:
USE videoteca;

DELIMITER //

CREATE FUNCTION fa_actores_cantidad() RETURNS INT BEGIN

DECLARE actores INT;

SELECT COUNT(*) INTO actores FROM actor; RETURN actores;

END

// DELIMITER ;

Es posible utilizar las funciones dentro de consultas SQL, como puede ver en la siguiente:
USE videoteca;

SELECT fa_actores_cantidad();

El resultado de ejecutar la anterior consulta puede verse en la figura 11.9.

Figura 11.9. Funcin almacenada

Not a: Fjese en que, a diferencia de los procedimientos almacenados, el prefijo seleccionado para los nombres de las funciones almacenadas es fa . De nuevo, una eleccin personal.

A pesar de las diferencias existentes entre los procedimientos y las funciones almacenadas, en los siguientes apartados nos referiremos a ambos como procedimientos almacenados. As, cuando la definicin de la sintaxis de una determinada operacin incluya la palabra reservada PROCEDURE , recuerde que debe cambiarla por FUNCTION si va a trabajar con una funcin en lugar de con un procedimiento.

Eliminacin
Es posible que, tras crear un procedimiento almacenado, se localice algn error en el cdigo del mismo o se quiera modificar su funcionamiento. En esas ocasiones puede eliminar el procedimiento almacenado utilizando orden DROP . Para evitar un error en caso de que el procedimiento almacenado no exista puede aadir las palabras reservadas IF EXISTS. A continuacin, vuelva a crear el procedimiento almacenado aadiendo las modificaciones que considere necesarias. Por ejemplo, suponga que quiere cambiar el procedimiento almacenado que devuelve la lista de actores, de manera que ahora el resultado se ordene alfabticamente, primero por apellidos y luego por nombre. Deber ejecutar las siguientes instrucciones:
USE videoteca;

DROP PROCEDURE IF EXISTS pa_actores_lista;

CREATE PROCEDURE pa_actores_lista()

SELECT * FROM actor ORDER BY apellidos, nombre;

Utilizacin desde PHP


La forma en la que puede utilizar procedimientos almacenados en sus pginas PHP es prcticamente idntica a la que ya conoce para la ejecucin de consultas. Vamos a aprovechar el procedimiento almacenado con el que termin el apartado anterior para mostrar la lista de intrpretes de la base de datos. ste es el cdigo necesario:
<?php

$videoteca = new mysqli( 'localhost', 'root', '', 'videoteca' );

if ($videoteca->errno != 0) { echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query( 'CALL pa_actores_lista()' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

while ($fila = $resultado->fetch_row()){ printf( "(%u) %s %s: %s<br/>", $fila[0], $fila[1], $fila[2], $fila[3] ); }

$resultado->close(); $videoteca->close();

?>

Como puede comprobar, slo debe pasar la instruccin CALL pa_actores_lista() al mtodo query() y trabajar con el resultado como si de una consulta normal y corriente se tratase. La figura 11.10 muestra el resultado del programa anterior.

Figura 11.10. Procedimientos almacenados y PHP

A lo largo de este captulo hemos visto los conceptos bsicos necesarios para trabajar con procedimientos almacenados. Gracias a ellos es posible agrupar varias sentencias SQL bajo un mismo nombre, simplificando la ejecucin de tareas frecuentes como el acceso o la modificacin del contenido de las tablas de una base de datos.

Ahora sabe cmo crear, modificar y eliminar procedimientos almacenados. Obviamente, tambin cmo utilizarlos. Incluso ha visto, sin entrar en detalles, que estos procedimientos almacenados pueden utilizarse desde lenguajes de programacin como PHP. Sin embargo, este captulo es slo el comienzo. Si desea ampliar sus conocimientos sobre procedimientos almacenados, le recomendamos que visite la pgina de la documentacin de MySQL dedicada a los mismos: http://dev.mysql.com/doc/mysql/en/create-procedure.html Quiz encuentre interesante el siguiente artculo, tambin publicado en la Web de MySQL: http://dev.mysql.com/tech-resources/articles/mysqlstoredprocedures.html

12

Desencadenadores
Este captulo est dedicado a otra de las importantes caractersticas de MySQL: los desencadenadores. Tambin conocidos por su nombre en ingls (triggers), los desencadenadores permiten realizar tareas de forma automtica cuando una determinada circunstancia tiene lugar. Se pueden crear desencadenadores que se activen antes o despus de una insercin, una actualizacin o un borrado. As, con los desencadenadores se puede verificar que los valores que se intenta insertar en una tabla cumplen unas determinadas condiciones, deteniendo la operacin en caso de que se detecte alguna incongruencia. Tambin es posible asociar un desencadenador a una operacin de actualizacin, de manera que una modificacin de los datos de una determinada tabla active de forma automtica una actualizacin en otra tabla, manteniendo sincronizados los datos que se requieran. Si lo desea, puede utilizar desencadenadores para realizar borrados en cascada: el borrado de un determinado registro en una tabla tiene como consecuencia el borrado de otros registros en otras tablas. Como se reconoce en la documentacin de MySQL, las caractersticas ofrecidas por los desencadenadores son limitadas, algo que no disminuye la utilidad de los mismos. El simple hecho de que sea posible utilizarlos deja prever que, poco a poco, las capacidades de los desencadenadores irn aumentando. Y slo se han enumerado algunas de las posibilidades que ofrece esta interesante caracterstica de MySQL.

Introduccin
Al igual que en el captulo anterior, dedicado a los procedimientos almacenados, este captulo trata una de las ms importantes caractersticas de MySQL. Por lo tanto, es posible que muchos lectores tengan la tentacin de leer estas pginas sin pasar por los captulos anteriores. Para facilitarles las cosas, este captulo pretende ser lo ms independiente del resto del libro que sea posible. De nuevo, supondremos que el lector tiene ciertas nociones bsicas tanto sobre el funcionamiento del servidor de bases de datos MySQL como de las herramientas necesarias para trabajar con l. Adems, deber conocer el lenguaje SQL. Si no cumple alguno de estos requisitos lo ms razonable es que lea este libro como debe, desde el principio.

Base de datos reducida


Durante este captulo trabajaremos con una versin reducida y ligeramente modificada de la base de datos creada a lo largo de los captulos anteriores de este libro. La seccin homnima del captulo anterior muestra ms detalles sobre la misma, le recomendamos que acuda a ella si quiere saber ms al respecto. En lo que respecta a este captulo, dicha base de datos est compuesta por dos tablas. La primera de ellas, llamada actor, contiene un identificador numrico nico para cada actor , su nombre y sus apellidos. Aqu comienza un pequeo cambio. Anteriormente, esta tabla tambin contena un campo llamado imdb: el identificador que IMDb (http://imdb.com/) asigna a cada actor, para proporcionar una forma de acceder a la informacin de dicha Web desde los programas que desarrolle. Imagine que un nuevo diseador de bases de datos, con ms experiencia, se ha hecho cargo de videoteca. Se trata de una persona con las ideas muy claras y ha encontrado lo que cree que es una incongruencia en el diseo de la tabla actor. A su modo de ver, esta tabla slo debe contener datos sobre el actor y el campo imdb no est relacionado con l, sino con una fuente de informacin externa. Adems, existe un nuevo requisito solicitado por la empresa que est pagando el desarrollo de la base de datos: se debe crear un nuevo campo, compuesto por el nombre y los apellidos del actor, en minsculas y separados por un guin bajo (_). Por lo visto, quieren que ese nombre se utilice en las direcciones Web de su propia pgina dedicada al cine: una por cada actor. As, los detalles de Harrison Ford estaran en la direccin: http://www.example.com/harrison_ford/
Aviso: En esa direccin no va a encontrar nada relacionado con el cine, se trata de un simple ejemplo. Slo por si acaso.

El diseador ha considerado que el nuevo campo y el campo imdb tienen aspectos en comn, as que ha decidido crear una nueva tabla en la que guardar ambos. Esta tabla estar relacionada con la tabla actor gracias al identificador numrico. El nombre de la tabla ser actor_ext . Por lo visto ext viene de externo y hace referencia a que los datos que la tabla contiene son externos al actor. La figura 12.1 muestra el aspecto de las dos tablas que contendrn los datos de cada actor.

Figura 12.1. Diseo de la base de datos

Creacin
A continuacin veremos qu instrucciones son necesarias para crear tanto la base de datos reducida como las tablas que contiene. Adems, insertaremos algunos registros de ejemplo para que la base de datos disponga de contenido con el que trabajar. En primer lugar, es necesario crear la base de datos:
DROP DATABASE IF EXISTS videoteca; CREATE DATABASE videoteca;

Advert encia: Sea cauto, si ha seguido los ejemplos de todo el libro ya tendr una base de datos con ese nombre. Para conservarla slo tiene que cambiar el nombre de la base de datos videot eca en las lneas anteriores por otro que sea de su agrado y acordarse de seguir utilizndolo durante el resto del captulo.

A continuacin, cree las tablas de la base de datos utilizando las siguientes instrucciones:
USE videoteca;

CREATE TABLE actor ( id INT NOT NULL AUTO_INCREMENT, nombre VARCHAR(64) NOT NULL, apellidos VARCHAR(64) NOT NULL, PRIMARY KEY(id) ) ENGINE = InnoDB;

CREATE TABLE actor_ext ( idactor INT NOT NULL, imdb VARCHAR(32) NOT NULL, carpeta VARCHAR(255) NOT NULL, PRIMARY KEY(idactor), INDEX ae_FK(idactor), FOREIGN KEY(idactor) REFERENCES actor(id) ) ENGINE = InnoDB;

Insercin
Por ltimo, inserte algunos valores en las tablas. En este caso, como hay dos, ser necesario realizar una insercin por cada tabla:
USE videoteca;

INSERT INTO actor(nombre, apellidos) VALUES('Harrison', 'Ford');

INSERT INTO actor(nombre, apellidos) VALUES('Russell', 'Crowe');

INSERT INTO actor_ext(idactor, imdb, carpeta)

INSERT INTO actor_ext(idactor, imdb, carpeta) VALUES(1, 'nm0000148', 'harrison_ford');

INSERT INTO actor_ext(idactor, imdb, carpeta) VALUES(2, 'nm0000128', 'russell_crowe');

Lgicamente, los valores necesarios para realizar las inserciones en la tabla actor_ext han sido tomados de la tabla actor . El valor de idactor es el del campo id de la tabla actor tras guardar el registro. Al tratarse de un campo de incremento automtico no es posible conocer su antes de realizar la insercin.

Sintaxis
Siguiendo la costumbre, antes de los ejemplos veremos la sintaxis de las instrucciones relacionadas con los desencadenadores.

Creacin
Para crear desencadenadores es necesario seguir la siguiente sintaxis:
CREATE TRIGGER nombre momento evento ON tabla FOR EACH ROW instrucciones;

Las palabras que estn en minsculas son las que necesitan explicacin: nombre: Es el nombre que recibe el desencadenador, aquel por el que nos referiremos a l cuando queramos utilizarlo. momento: Puede tomar los valores BEFORE (antes) o AFTER (despus). Se utiliza para determinar si las instrucciones asociadas al desencadenador se ejecutarn antes o despus de la operacin que lo activ. evento: Indique aqu el tipo de instruccin que activar el desencadenador. Se puede tratar de INSERT , UPDATE o DELETE . tabla: Nombre de la tabla con la que estar asociado el desencadenador. instrucciones: Utilice BEGIN y END, como en los procedimientos almacenados, si desea que el desencadenador tenga asociada ms de una orden.

Eliminacin
Para eliminar un desencadenador debe seguir la siguiente sintaxis:
DROP TRIGGER nombre;

Como es lgico, nombre se refiere al nombre del desencadenador que desea eliminar.

Ejemplos

Por fin, tras no pocas pginas introductorias, nos vamos a poner manos a la obra. En los siguientes apartados comprobaremos lo tiles que pueden llegar a ser los desencadenadores, tanto en las tareas de insercin y actualizacin como en las de borrado.

Insercin
Recuerda que, anteriormente, insertamos algunos registros en la tabla actor ? Despus, para realizar la insercin de los registros correspondientes en la tabla actor_ext , fue necesario comprobar qu identificador se asign al registro de cada actor para as mantener la integridad referencial. Ahora crearemos un desencadenador que, automticamente, tras la insercin de un nuevo actor en su tabla, crear el registro correspondiente en la tabla actor_ext , insertando el valor adecuado en el campo carpeta. En primer lugar hemos de seleccionar el nombre del desencadenador. Pregntese a qu tabla debe estar asociado el desencadenador. Las instrucciones asociadas se ejecutarn cuando se inserte un nuevo registro en la tabla actor . Incluya el nombre de esa tabla como parte del nombre del desencadenador. Ahora, qu operacin activa el desencadenador? Una insercin. Incluya tambin el nombre de esa operacin como parte del nombre del desencadenador. Por ltimo, para diferenciar un desencadenador de cualquier otro objeto de la base de datos aadiremos el prefijo dc a su nombre. Por lo tanto, podramos llamar dc_actor_insertar a este desencadenador. Obviamente, se trata de una de las infinitas posibilidades existentes; seleccione la que ms apropiada considere. La nica ventaja de este sistema es que permite diferenciar de un vistazo entre un desencadenador y otros objetos de la base de datos, as como saber qu tarea realiza. Tras seleccionar el nombre del desencadenador y saber a qu tabla y operacin est asociado debemos determinar si las instrucciones asociadas al mismo se ejecutarn antes o despus del evento que activ el desencadenador. En el caso que nos ocupa, es necesario conocer el valor que toma el identificador del actor recin insertado; por lo tanto, las instrucciones debern ejecutarse despus, cuando dicho identificador ya exista. El siguiente sera el encabezado del desencadenador que estamos creando, a falta de las instrucciones asociadas:
... CREATE TRIGGER dc_actor_insertar AFTER INSERT ON actor ...

Slo resta escribir las instrucciones asociadas al

desencadenador. En primer lugar, es necesario obtener el identificador del actor recin insertado. Puede acceder a todos los valores de la operacin que provoc la activacin del desencadenador gracias al alias NEW. Por lo tanto, es posible acceder a dicho valor escribiendo NEW.id. En segundo lugar, hay que concatenar el nombre y los apellidos del actor. De nuevo, es posible utilizar el alias NEW para tal fin. El cuerpo del desencadenador sera el siguiente:
... DECLARE nuevo_carpeta VARCHAR(255);

SET nuevo_carpeta = CONCAT( LOWER(NEW.nombre), '_', LOWER(NEW.apellidos) );

INSERT INTO actor_ext(idactor, imdb, carpeta) VALUES(NEW.id, '', nuevo_carpeta); ...

La declaracin de la variable nuevo_carpeta es la primera accin que lleva a cabo el desencadenador. En ella se almacenar el nombre de la carpeta asociada al actor, fruto de la concatenacin del nombre y los apellidos, en minsculas, con un guin bajo como separador. La insercin se realiza utilizando dicha variable. Fjese en que, como no se dispone del identificador imdb, se inserta una cadena vaca en el campo correspondiente. El cdigo completo de este desencadenador es el siguiente:
USE videoteca;

DELIMITER //

CREATE TRIGGER dc_actor_insertar AFTER INSERT ON actor FOR EACH ROW BEGIN

DECLARE nuevo_carpeta VARCHAR(255);

SET nuevo_carpeta = CONCAT( LOWER(NEW.nombre), '_', LOWER(NEW.apellidos) );

INSERT INTO actor_ext(idactor, imdb, carpeta) VALUES(NEW.id, '', nuevo_carpeta);

END

// DELIMITER ;

Not a: Ms sobre variables y delimitadores en el captulo 11, dedicado a procedimientos almacenados.

Inserte ahora un nuevo actor en la tabla actor :


USE videoteca;

INSERT INTO actor(nombre, apellidos) VALUES('Tim','Robins');

La figura 12.2 muestra el resultado de realizar la insercin de un nuevo actor en la tabla actor y una posterior consulta a la tabla actor_ext .

Figura 12.2. Desencadenador en accin

Not a: Como ejercicio para el lector se deja la creacin de un procedimiento almacenado que reciba como parmetros el nombre y los apellidos del actor, as como su identificador imdb. Este procedimiento almacenado realizar la insercin del nombre y el apellido en la tabla actor. Como consecuencia, el desencadenador asociado crear el registro correspondiente en la tabla act or_ext . Slo quedara actualizar esta ltima tabla, insertando el identificador imdb donde corresponda.

Actualizacin
Como puede que ya haya notado, exista un error en el nombre del actor que se insert en la seccin anterior: su apellido se escribe Robbins y no Robins. Es un error cometido a propsito para aprovechar las posibilidades de los desencadenadores en operaciones de actualizacin. Suponga que se ha dado cuenta del error y lo intenta subsanar. Para ello, tendra que utilizar las siguientes instrucciones (no lo haga todava):
USE videoteca;

UPDATE actor SET

SET apellidos = 'Robbins' WHERE id = 3;

Pero claro, esto slo subsanara el error en la tabla actor , no en actor_ext , as que sera necesario realizar otra actualizacin (tampoco la haga ahora):
USE videoteca;

UPDATE actor_ext SET carpeta = 'tim_robbins' WHERE idactor = 3;

No sera mejor que esta segunda actualizacin se realizase de forma automtica? A fin de cuentas, ya sabe las operaciones que debe realizar porque las utiliza en el desencadenador de insercin. El siguiente es el cdigo del desencadenador asociado con las actualizaciones de la tabla actor . Se han seguido los mismos razonamientos que con el desencadenador de insercin para seleccionar su nombre:
USE videoteca;

DELIMITER //

CREATE TRIGGER dc_actor_actualizar AFTER UPDATE ON actor FOR EACH ROW BEGIN

DECLARE nuevo_carpeta VARCHAR(255);

SET nuevo_carpeta = CONCAT( LOWER(NEW.nombre), '_', LOWER(NEW.apellidos) );

UPDATE actor_ext SET carpeta = nuevo_carpeta WHERE idactor = NEW.id;

END

// DELIMITER ;

Ahora s, realice la operacin de modificacin en la tabla actor . Podr comprobar que, de forma automtica, el valor

del campo carpeta de la tabla actor_ext ha cambiado y su valor tambin es el correcto.

Borrado
Hasta ahora, todos los desencadenadores que hemos visto se ejecutaban tras la accin que los activaba. El ejemplo que veremos en este apartado ejecuta las instrucciones asociadas antes, no despus. Supongamos que queremos eliminar a uno de los actores de la base de datos, por ejemplo, el que se insert en el apartado anterior. Para eliminarlo es necesario borrar tanto el registro asociado en la tabla actor_ext como el de la tabla actor . Pero, como ya sabe utilizar desencadenadores, puede que prefiera automatizar el trabajo. Vamos a crear un desencadenador que se active al intentar un borrado en la tabla de actores y, antes de realizarlo, elimine el registro correspondiente en la tabla actor_ext . Por qu antes y no despus? Porque la tabla actor_ext tiene un campo, idactor , que est relacionado con el campo id de la tabla actor . No es posible eliminar el registro de la tabla actor sin antes eliminar el asociado de la tabla actor_ext . Intntelo si quiere:
USE videoteca;

DELETE FROM actor WHERE id = 3;

Obtendr un error como el que se puede ver en la figura 12.3.

Figura 12.3. Error al borrar

El siguiente es el cdigo de un desencadenador que se activa cuando se intenta eliminar un registro de la tabla actor :
USE videoteca;

DELIMITER //

CREATE TRIGGER dc_actor_eliminar BEFORE DELETE ON actor FOR EACH ROW BEGIN

DELETE FROM actor_ext WHERE idactor = OLD.id;

END

// DELIMITER ;

Puede acceder a los campos de la tabla a la que est asociado el desencadenador mediante el alias OLD. As, el identificador del registro que se est intentado eliminar es OLD.id. Tras crear el desencadenador podr comprobar que la operacin de borrado ya no provoca error alguno. En este captulo ha aprendido a utilizar desencadenadores, una de las interesantes caractersticas de MySQL que le permitir automatizar tareas tediosas, como inserciones dependientes de claves de incremento automtico, actualizaciones y borrados. Sin embargo, tenga cuidado. Utilizar desencadenadores en exceso puede complicar las operaciones de mantenimiento de la base de datos si su funcionamiento o existencia no est completamente documentado. Contrariamente a lo que se piensa, los desencadenadores no ralentizan el funcionamiento global de la base de datos. Lgicamente, aaden ciclos de proceso cuando estn en funcionamiento pero, si las operaciones que realiza no los activan, su base de datos ser tan rpida como si no estuviesen presentes. En resumen: sus operaciones de seleccin tendrn el mismo rendimiento con y sin desencadenadores.

13

Vistas
Como su propio nombre deja al descubierto, las vistas permiten modificar la forma en la que los datos son presentados. Se trata de una caracterstica de MySQL que, dada su importancia, se presenta en su propio captulo. En los dos captulos anteriores se presentaron los conceptos bsicos necesarios para poder trabajar con procedimientos almacenados y desencadenadores. Las vistas le permitirn aadir una nueva capa a esas dos, aumentando el valor de su base de datos. Dejando tecnicismos a un lado, se puede decir que las vistas proporcionan control sobre los datos que desea recuperar y sobre la forma en la que los mismos se presentan. Puede pensar en las vistas como en tablas ficticias que toman sus datos de las tablas existentes. En este captulo aprenderemos la sintaxis necesaria para crear, modificar y eliminar vistas. Utilizando la base de datos de ejemplo que vimos en el captulo anterior, dedicado a los desencadenadores, crearemos una vista que permitir simular que la tabla que contiene los datos de los actores no fue dividida en ningn momento. A todos los efectos, el usuario no apreciar que haya habido cambio alguno en el diseo de la base de datos. Cuando este captulo termine tendr en su poder el conocimiento necesario para utilizar tres de las tcnicas ms interesantes que MySQL pone en su poder. Estar en su mano sacar el mximo partido de ellas en su trabajo.

Introduccin
Para trabajar en este captulo aprovecharemos parte del trabajo realizado en el anterior. Todo lo necesario para disponer de una base de datos con la que poder hacer pruebas est en la seccin 1 del captulo 12. Refresquemos la memoria de aquellos que ya hayan pasado por l con la figura 13.1. En ella puede ver las dos nicas tablas que componen la base de datos.

Figura 13.1. Base de datos de trabajo

As pues, siga todos los pasos de dicho apartado si an no lo ha hecho. Cuando termine, vuelva aqu y contine leyendo.

Sintaxis

Antes de comenzar a trabajar con vistas veremos la sintaxis de las diferentes operaciones que se pueden realizar con ellas: creacin, modificacin y borrado.

Creacin
Para crear vistas en sus bases de datos debe seguir la siguiente sintaxis:
CREATE [OR REPLACE] VIEW nombre AS consulta;

Entre corchetes, OR REPLACE . Si, al crear la vista, utiliza esas palabras reservadas y ya existe una con el mismo nombre, sta ser reemplazada con la nueva. Indique el nombre por el que desea referirse a la vista en nombre. El resto de la vista estar compuesto por una consulta de seleccin. En la seccin 3 de este mismo captulo veremos algunos ejemplos.

Modificacin
Si desea realizar algn cambio en una vista ya existente tiene dos opciones: utilizar CREATE OR REPLACE VIEW (como acabamos de ver) o ALTER VIEW. La sintaxis de esta ltima es:
ALTER VIEW nombre AS consulta;

Eliminacin
Cuando no necesite seguir utilizando una determinada vista puede eliminarla utilizando DROP VIEW:
DROP VIEW [IF EXISTS] nombre;

Para evitar que el intento de borrado provoque un error si no existiese ninguna vista con ese nombre, incluya IF EXISTS. De esa forma, la instruccin de borrado slo se ejecutar si la vista existe.

Ejemplos
La base de datos con la que trabajaremos durante este captulo est compuesta por dos tablas. Como ya sabr, son el resultado de dividir la tabla actor original, dejando en una de ellas los datos pertenecientes al actor y moviendo a la otra los datos externos al mismo: el identificador de IMDb y el nombre de la carpeta de la Web en la que estar su pgina. Este ltimo campo es de nueva aparicin y fue creado en el captulo anterior.

Creacin
Es posible que alguno de los usuarios de la base de datos necesite obtener la misma informacin que antes de la divisin de la tabla actor . Como ya sabe, eso puede lograrse con la siguiente consulta:

USE videoteca;

SELECT a.id, a.nombre, a.apellidos, ae.imdb FROM actor a JOIN actor_ext ae ON a.id = ae.idactor;

El resultado de ejecutar la consulta anterior puede verse en la figura 13.2.

Figura 13.2. Datos de actores

No le parece interesante poder ocultar a algunos usuarios los detalles de la estructura de la base de datos? Por ejemplo, a aquellos con menos conocimientos de SQL. Para estos usuarios podra crear una vista en la que los datos de las tablas actor y actor_ext se combinasen, comportndose como una sola tabla. Al igual que con los procedimientos almacenados y los desencadenadores, utilizaremos un prefijo que permita diferenciar las vistas del resto de objetos de la base de datos. En este caso, dicho prefijo ser v. El cdigo necesario para crear dicha vista es el siguiente:
USE videoteca;

CREATE VIEW v_actor AS

SELECT a.id, a.nombre, a.apellidos, ae.imdb FROM actor a JOIN actor_ext ae ON a.id = ae.idactor;

Las vistas se comportan a todos los efectos como si fuesen tablas. Por lo tanto, es posible realizar consultas de seleccin sobre ellas:
USE videoteca;

SELECT * FROM v_actor;

En la figura 13.3 puede ver el resultado de crear la vista y realizar una consulta sobre ella.

Figura 13.3. Creacin y uso de una vista

Not a: No es posible asignar a una vista el nombre de un objeto ya existente en la base de datos. Pruebe a utilizar el nombre act or en la vista que acaba de crear. MySQL le avisar de que ya existe una tabla con ese nombre, como puede ver en la figura 13.4.

Figura 13.4. Conflicto en el nombre

Modificacin
Hasta tal punto las vistas se comportan como si de tablas se tratase que es posible incluir modificadores, como los de ordenacin, en las consultas que sobre ella se realicen. Por ejemplo:
USE videoteca;

SELECT * FROM v_actor ORDER BY apellidos, nombre;

Fjese en el resultado de ejecutar esta consulta, que se muestra en la figura 13.5, y comprelo con el obtenido en la figura 13.2. Podr comprobar que el orden en el que se devuelven los registros ha cambiado.

Figura 13.5. Orden en las vistas

Pero tambin es posible modificar el orden en el que los registros son devueltos, directamente, por la vista. Para ello, slo hay que modificar la consulta. Como vimos en el apartado dedicado a la sintaxis de las operaciones relacionadas con la gestin de las vistas, disponemos de dos opciones: CREATE OR REPLACE VIEW y ALTER VIEW. El cdigo necesario para modificar la vista utilizando la primera de las opciones es el siguiente:
USE videoteca;

CREATE OR REPLACE VIEW v_actor AS

SELECT a.id, a.nombre, a.apellidos, ae.imdb FROM actor a JOIN actor_ext ae ON a.id = ae.idactor ORDER BY apellidos, nombre;

Aunque tambin puede obtener el mismo resultado con las siguientes instrucciones:
USE videoteca;

ALTER VIEW v_actor AS

SELECT a.id, a.nombre, a.apellidos, ae.imdb FROM actor a JOIN actor_ext ae ON a.id = ae.idactor ORDER BY apellidos, nombre;

En la figura 13.6 puede comprobar que ahora la vista devuelve los datos de los actores ordenados.

Figura 13.6. La vista ordena los datos

Eliminacin
Cuando decida que no necesita una determinada vista puede eliminarla utilizando la instruccin DROP VIEW. Por ejemplo, las siguientes instrucciones eliminan la vista v_actor de la base de datos videoteca:
USE videoteca;

DROP VIEW v_actor;

La eliminacin de una vista no supone la eliminacin de las tablas de las que obtena los datos.

Utilizacin desde PHP


La forma en la que puede utilizar vistas en sus pginas PHP es prcticamente idntica a la que ya conoce para la ejecucin de consultas. ste es el cdigo necesario para utilizar la vista que devuelve la lista de intrpretes ordenados por nombre que creamos en la seccin anterior:
<?php

$videoteca = new mysqli( 'localhost', 'root', '', 'videoteca' );

if ($videoteca->errno != 0) { echo('Error en la conexin.'); exit(); }

$resultado = $videoteca->query( 'CALL pa_actores_lista()' );

if ($resultado == FALSE){ echo('Error en la consulta.'); }

while ($fila = $resultado->fetch_row()){ printf( "(%u) %s %s: %s<br/>", $fila[0], $fila[1], $fila[2], $fila[3] ); }

$resultado->close(); $videoteca->close();

?>

Como puede comprobar, slo debe pasar la instruccin CALL pa_actores_lista() al mtodo query() y trabajar con el resultado como si de una consulta normal y corriente se tratase. La figura 13.7 muestra el resultado del programa anterior.

Figura 13.7. Vistas y PHP

Durante este captulo ha aprendido a gestionar una de las caractersticas ms interesantes de MySQL, las vistas. Gracias a ellas puede ocultar la verdadera estructura de la base de datos a algunos de los usuarios de la misma. Esto puede suponer una gran ventaja en aquellas ocasiones en las que sea necesario modificar la distribucin de los campos dentro de las diferentes tablas. Si el usuario utiliza las vistas que se le proporcionan slo ser necesario cambiar la forma en la que la vista trabaja para seguir proporcionando al usuario lo que espera. Sin embargo, el uso de vistas tambin presenta inconvenientes. Entre ellos, la sobrecarga de trabajo que la gestin de las vistas puede suponer a los administradores de la base de datos. Si, adems, la base de datos tambin tiene procedimientos almacenados y desencadenadores, debe tener especial cuidado en mantener completamente documentados todos los aspectos de la base de datos. As, administradores y usuarios sabrn qu resultados pueden esperar de sus operaciones.

14

XML
De un tiempo a esta parte las siglas XML se han hecho omnipresentes en el mbito de la informtica. Como antes con muchos otros estndares, su adopcin se anuncia como la solucin de los problemas a los que se enfrentan a diario los profesionales del mundo de la informtica. Ests siglas, que tanto han dado que hablar, proceden del ingls eXtensible Markup Language (lenguaje extensible de marcas). La pareja formada por las aplicaciones Web (desarrolladas con MySQL y PHP) y XML resulta especialmente interesante. Por una parte, hace ms fcil la posibilidad de que en la base de datos slo haya datos puros, sin formato, cuya apariencia pueda ser modificada posteriormente. Por otra, permite almacenar en bruto grandes cantidades de datos en un nico campo y, luego, extraer o modificar nicamente un fragmento. MySQL nos ofrece dos formas de combinar datos y XML. En primer lugar, utilizando herramientas como mysql o mysqldump. En segundo lugar, mediante dos funciones que permiten manipular cadenas de texto con formato XML que se encuentren almacenadas en algn campo. Aunque dista mucho de ser el soporte completo que a todos nos gustara tener, s que se trata de un punto de partida. Por su parte, PHP dispone de multitud de herramientas para tratar con XML. En este captulo encontrar una introduccin al formato XML. Veremos cmo obtener valores en formato XML desde la lnea de rdenes, aprenderemos trabajar directamente con XML, desde consultas SQL y, por ltimo, utilizaremos PHP junto con XML.

Qu es XML?
Al hablar de XML y MySQL nos debatimos entre la sencillez de unas siglas y la panacea universal. Ni una cosa ni otra: no son slo unas siglas, y lo que es seguro es que, por s sola, la utilizacin de XML con MySQL y PHP no resolver todos nuestros problemas. Aunque tambin es seguro que har ms sencillo encontrar soluciones a los mismos. Pero, qu aspecto tiene un documento XML? En realidad, no se trata de nada extrao, son sencillos caracteres de texto puestos uno tras otro. El siguiente contiene detalles sobre el reparto de Blade Runner:
<?xml version="1.0"?> <reparto> <papel protagonista="si"> <personaje>Rick Deckard</personaje>

<actor>Harrison Ford</actor> </papel> <papel protagonista="no"> <personaje>Roy Batty</personaje> <actor>Rutger Hauer</actor> </papel> <papel protagonista="no"> <personaje>Rachael</personaje> <actor>Sean Young</actor> </papel> </reparto>

Si conoce HTML seguro que encuentra similitudes. La figura 14.1 muestra cmo se ve el anterior documento XML en un cliente Web. Es interesante comprobar que, desde el principio, aplicaciones que pensbamos que tenan una nica misin (visitar pginas Web, en este caso) estn listas para desempear muchas otras funciones. Aunque, si lo piensa un poco, tampoco es tan sorprendente: XML est pensado con Internet como uno de sus objetivos.

Figura 14.1. XML en un cliente Web

Lo que s queda claro es que, aunque los que mejor van a entender XML son las mquinas y los procesos, dada su naturaleza estructurada, nosotros tambin somos capaces de sacar conclusiones a partir de un documento XML, de un vistazo. Todo lenguaje tiene unas reglas ms o menos estrictas que deben ser cumplidas para que pueda ser entendido. En el caso de XML, esto es an ms cierto. XML es un lenguaje en el que prima la sencillez y la portabilidad. Mientras ms estricto sea, ms fcil ser crear programas capaces de leerlo de forma eficaz. Parafraseando a Jack el destripador, vayamos por partes.

Partes de un documento XML


Antes de describir con ms detalle cada parte de un documento XML recordemos que es un lenguaje de

marcas, pensado para la descripcin de datos. En l, las marcas estn delimitadas por los smbolos "menor que" (<) y "mayor que" (>). Todo lo que se encuentre entre esos dos smbolos es una marca o etiqueta. Por ejemplo, <personaje> y <actor> son etiquetas. Dicho lo cual, un documento XML puede presentar tres partes diferentes: el prlogo, el cuerpo y el eplogo. Prlogo Todo documento XML debe comenzar con un prlogo que se encargue de presentar el tipo del documento, la versin de la norma a la que se adhiere y muchas otras caractersticas. En el ejemplo que nos ocupa el prlogo es el siguiente:
<?xml version="1.0"?>

La etiqueta de esta lnea est compuesta de forma diferente al resto de las que aparecen en el documento: en lugar de estar entre los smbolos "menor que" (<) y "mayor que" (>), a stos se aade un smbolo de cierre de interrogacin, lo que resulta en (<?) y (?>). Eso quiere decir que se trata de una instruccin que contiene informacin sobre el documento, lo que se conoce como instruccin de proceso. A continuacin del prlogo nos encontramos con el contenido del documento. Cuerpo Los datos que un documento XML nos ofrece estn en lo que se conoce como cuerpo. En el caso de nuestro ejemplo, se tratara de todo lo que est entre <reparto> y </reparto>, incluidas estas dos etiquetas. Este elemento se conoce como la raz del documento. Eplogo Situado a continuacin del cuerpo del documento, puede estar compuesto de instrucciones de proceso como las del prlogo, a excepcin de declaraciones XML o de tipo de documento.

Etiquetas
Para diferenciar entre los distintos elementos que componen un documento XML hemos de utilizar etiquetas. Las etiquetas estn compuestas por un nombre y unos atributos, debe existir una de apertura y otra de cierre y deben estar correctamente situadas. Nombres Es ms que recomendable ceirse a un determinado patrn al dar nombre a las etiquetas: todo minsculas, todo maysculas, o una combinacin de ambas, pero siempre con el mismo patrn. Seguir esta recomendacin le evitar muchos quebraderos de cabeza en el futuro.

Cada etiqueta de apertura debe tener una de correspondiente de cierre. Por ejemplo:
<actor>Harrison Ford</actor>

Las etiquetas de cierre son como las de apertura, pero con una barra inclinada antes del nombre de la misma. Obviamente, los nombres de las etiquetas de apertura y cierre deben coincidir. Atributos Las etiquetas pueden aprovecharse para incluir otros datos, utilizando atributos. Si conoce HTML ya habr tenido su primer contacto con los atributos. Por ejemplo, la etiqueta HTML para crear un enlace a otra pgina podra ser la siguiente:
... <A HREF=http://enreas.com/mysql> Gua de MySQL </A> ...

En este caso, la etiqueta A se refiere a un enlace y HREF es un atributo. Los atributos seran las propiedades que tiene ese elemento: ese enlace lleva a una determinada direccin que se indica en el atributo A. El caso de XML no es diferente: la etiqueta denota el nombre del elemento, y el atributo, sus propiedades. Los atributos slo pueden indicarse en las etiquetas de apertura, no en las de cierre. Un atributo est formado por el nombre del mismo y el valor que toma, separados ambos por un signo de igualdad (=). El valor del atributo debe estar obligatoriamente entre comillas. Estas comillas pueden ser simples o dobles, pero si la apertura de comillas es simple, el cierre tambin debe serlo, e igual si son dobles. Uniendo etiquetas, atributos y valores, qu tenemos? Nodos Un nodo est compuesto por una etiqueta, sus atributos y su contenido. El contenido es todo lo que est entre la etiqueta de apertura y la de cierre, lo que puede incluir a otros nodos. Si en el contenido de un nodo hay otros nodos, nos referiremos a ellos como nodos descendientes. En el primer nivel de descendencia estn los nodos hijos. Si estos nodos tienen a su vez otros nodos en su interior, sern hijos del inmediatamente anterior, y nietos del otro. Esta estructura de padres e hijos tambin es conocida como estructura arbrea o jerarqua. La jerarqua en nuestro ejemplo est muy clara: el primer nodo del rbol es <reparto>. Este nodo tiene como descendientes nodos <papel> que, a su vez, tienen como descendientes a los nodos <personaje> y <actor>.

Con esta breve introduccin ya estamos listos para trabajar con XML.

XML desde la lnea de rdenes


La forma ms sencilla de que el resultado de nuestras consultas SQL est en formato XML es utilizar las herramientas para la lnea de rdenes como, por ejemplo, mysql, de la que tanto partido hemos sacado durante este libro. Slo tenemos que aadir un parmetro ms, xml. As, por ejemplo, para iniciar una sesin con el usuario root utilizaramos la siguiente orden:
mysql -u root -p --xml

Cuando introduzca la contrasea le parecer que nada ha cambiado, pero basta con que realice una consulta para darse cuenta de que no es as. Por ejemplo, vamos a seleccionar todos los soportes guardados en la base de datos:
USE videoteca;

SELECT * FROM soporte;

La figura 14.2 muestra el resultado de ejecutar esta consulta tras utilizar ese parmetro.

Figura 14.2. Resultado de una consulta en XML

En el documento XML obtenido podemos examinar los diferentes elementos que describimos al principio del captulo: hay un prlogo y un cuerpo, pero no hay eplogo. Dentro del cuerpo podemos ver el nodo raz, resultset (conjunto de resultados, en ingls.). El valor de uno de sus atributos, statement , es la consulta que dio como resultado el documento XML que estamos examinando. Los descendientes de resulset son nodos row, uno por fila obtenida como resultado de la consulta. A su vez, los descendientes de este nodo son nodos field, uno por cada campo solicitado en la consulta. En este caso son todos los campos de cada fila de la tabla soporte. El atributo name contiene el nombre del atributo. El valor de cada campo se encuentra entre las etiquetas de apertura y

cierre de los nodos field. El documento XML obtenido responde fielmente a las caractersticas de la consulta SQL realizada. Por ejemplo, supongamos que no nos interesan ni los identificadores ni las siglas. La figura 14.3 muestra el resultado de ejecutar esta consulta:
USE videoteca;

SELECT nombre FROM soporte;

Figura 14.3. Consulta SQL con un nico campo

Como puede comprobar, ahora cada elemento row slo tiene un descendiente, un elemento field correspondiente con el campo nombre. El documento XML tambin puede modificarse desde la consulta SQL para que el valor del atributo name sea el que queramos. Por ejemplo, gracias a esta consulta su valor ser soporte en lugar de nombre:
USE videoteca;

SELECT nombre AS soporte FROM soporte;

Puede ver el resultado en la figura 14.4.

Figura 14.4. Cambio en el nombre del campo

Obtener el resultado en formato XML es muy interesante, pero quiz lo fuese ms si pudisemos guardarlo en un archivo para poder utilizarlo desde otras aplicaciones. S, puede copiar el resultado obtenido y pegarlo en un editor de textos, pero tambin puede ejecutar esta orden:
mysql -u root -p --xml -e "SELECT * FROM soporte" videoteca > soportes.xml

Tras el parmetro xml aparece el parmetro e, que necesita el texto de la consulta a realizar (la de seleccin de soportes, en este caso). A continuacin, indicamos el nombre de la base de datos con la que queremos trabajar y, por ltimo, redirigimos el resultado a un archivo. En la figura 14.5 puede ver el archivo resultante, abierto con Internet Explorer.

Figura 14.5. Resultado XML en Internet Explorer

Ya sabemos cmo obtener el resultado de nuestras consultas en formato XML. A continuacin veremos que es posible guardar documentos XML en los campos de una tabla, as como extraer valores de ellos y modificarlos.

Funciones XML
MySQL proporciona dos funciones para trabajar con documentos XML: ExtractValue y UpdateXML . En realidad, siendo precisos, estas dos funciones trabajan con fragmentos de cadenas en formato XML, ya que no incluiremos el prlogo. Pero, de qu puede servir guardar fragmentos de documentos XML en los campos de una tabla? Volvamos a la base de datos de ejemplo que hemos utilizado en esta gua y supongamos que queremos almacenar nuevos datos en ella. En este caso, el reparto de cada pelcula. Dnde encajara dentro del modelo que puede ver en la figura 14.6?

Figura 14.6. La base de datos de la videoteca

Podramos aadir una pareja de campos nuevos: reparto_personaje y reparto_actor . No parece demasiado lgico, verdad? Slo podramos almacenar uno de los personajes del reparto. Si aadisemos ms parejas reparto_personaje y reparto_actor , con un nmero al final para diferenciarlas, podramos tener tantas como quisisemos. Pero eso no soluciona otro problema: estamos aadiendo datos duplicados. A fin de cuentas, tenemos una tabla para los actores. Est claro que se trata de informacin relacionada con cada pelcula, pero tambin con cada actor. Deberamos crear una tabla de personajes relacionada con la tabla de actores y con la de pelculas. Estas relaciones deberan ser muchos a muchos: un mismo personaje puede aparecer en varias pelculas (como Peter Parker en la serie de pelculas de Spiderman) y, adems, un mismo actor puede interpretar varios personajes en la misma pelcula (en este caso, Tobey Maguire se encarga tanto de Peter Parker como de Spiderman). Merece la pena que aadamos la tabla de personajes y las dos tablas auxiliares necesarias para mantener la integridad referencial de las relaciones correspondientes? En la figura 14.7 puede ver el reparto de la primera parte de Spiderman. Fjese en que se trata slo de parte de ella, si hace clic en el enlace more (el puntero del ratn se encuentra sobre l) podr ver el reparto completo de esta pelcula.

Figura 14.7. Reparto de Spiderman

Supongamos que no nos interesa para nada mantener la tabla de personajes, slo queremos disponer del reparto como simple referencia. Tampoco queremos que el reparto mantenga relacin con la tabla de actores. En definitiva, slo necesitamos guardar una lista. Las funciones ExtractValue y UpdateXML nos permitirn hacer esto, precisamente. Aunque se trata slo de una de las mltiples aplicaciones que se le pueden dar. Pero antes de ver estas dos funciones hablemos un poquito de XPath.

XPath
La clave de utilizar XML es doble: guardar y extraer. Primero, hay que saber cmo almacenar los datos, y debe hacerse de forma homognea. Segundo, hay que saber extraer informacin a partir de los datos. XPath no es ms que un conjunto de reglas sintcticas que definen un sistema de consulta para documentos XML. Igual que ocurre dentro de un sistema de archivos, una consulta XPath puede ser absoluta o relativa. Se dice que es absoluta si parte del nodo raz, es decir, el primer carcter de la consulta es /. Recordemos el documento XML con el que comenz el captulo:

<?xml version="1.0"?> <reparto> <papel protagonista="si"> <personaje>Rick Deckard</personaje> <actor>Harrison Ford</actor> </papel> <papel protagonista="no"> <personaje>Roy Batty</personaje> <actor>Rutger Hauer</actor> </papel> <papel protagonista="no"> <personaje>Rachael</personaje> <actor>Sean Young</actor> </papel> </reparto>

Gracias a XPath podemos llegar a los nombres de cada personaje utilizando: Una ruta absoluta: /reparto/papel/personaje. Una ruta relativa: papel/personaje, a partir de /reparto. XPath tambin permite acceder al valor de los atributos. Por ejemplo, para obtener los valores del atributo protagonista tendramos que utilizar la ruta: /reparto/papel/personaje@protagonista.

Datos de ejemplo
Para probar el funcionamiento de las dos funciones que permiten trabajar con datos en formato XML vamos a modificar la tabla de pelculas. Crearemos un nuevo campo que contendr fragmentos de XML con el reparto. Ejecute la siguiente consulta para aadir este nuevo campo:
USE videoteca;

ALTER TABLE pelicula ADD reparto TEXT NOT NULL;

Ahora vamos a insertar en ese nuevo campo el fragmento XML con el reparto de Blade Runner. Si el identificador de esta pelcula es el 1, la consulta de actualizacin sera:
USE videoteca;

UPDATE pelicula SET reparto = '<reparto> <papel protagonista="si"> <personaje>Rick Deckard</personaje> <actor>Harrisond Ford</actor> </papel>

</papel> <papel protagonista="no"> <personaje>Roy Batty</personaje> <actor>Rutger Hauer</actor> </papel> <papel protagonista="no"> <personaje>Rachael</personaje> <actor>Sean Young</actor> </papel> </reparto>' WHERE id = 1;

La figura 14.8 muestra el resultado de realizar una consulta de seleccin sobre la tabla de pelculas para ver los campos de Blade Runner.

Figura 14.8. Datos de la pelcula Blade Runner

Y ahora, qu hacemos con todo esto?

ExtractValue
La funcin ExtractValue permite recuperar valores de un fragmento de un documento XML. Recibe dos parmetros: el fragmento en cuestin y una expresin XPath que determina qu valores debe devolver. El siguiente es un sencillo ejemplo del funcionamiento de esta funcin:
SELECT ExtractValue( '<papel> <personaje>Roy Batty</personaje> <actor>Rutger Hauer</actor> </papel>', '/papel/personaje' ) AS personaje;

Como acaba de ver, no es necesario que el fragmento se tome de una tabla. El resultado de ejecutar esta consulta aparece en la figura 14.9.

Figura 14.9. Ejemplo de utilizacin de ExtractValue

Truco: Las cosas seran mucho ms feas sin esa ltima clusula AS personaje. Haga la prueba.

El valor del segundo parmetro es /papel/personaje. Si interpreta ese valor como una ruta slo tiene que seguir los nodos para obtener el resultado mostrado en la figura 14.9. Primero el nodo raz, papel y luego el nodo personaje. Obtendramos un resultado distinto si utilizsemos como segundo parmetro la expresin XPath /papel/actor . Pero, cul ser el resultado de utilizar esta funcin con un valor almacenado en un campo de una tabla? Qu ocurrir si ms de un registro coincide con la expresin XPath? Ejecute la siguiente consulta para averiguarlo:
USE videoteca;

SELECT ExtractValue( reparto, '/reparto/papel/personaje' ) AS personajes FROM pelicula WHERE id = 1;

Como muestra la figura 14.10, el resultado es la lista de personajes contenidos en el fragmento XML del campo.

Figura 14.10. Lista de personajes

Igual de sencillo es obtener la lista de intrpretes. Tambin podemos acceder a los atributos utilizando la expresin XPath /reparto/papel/@protagonista. La figura

14.11 muestra el resultado utilizarla en una consulta.

Figura 14.11. Atributos de cada papel

Sin embargo, de poco nos sirven los resultados que acabamos de obtener. En este ltimo ejemplo s es fcil diferenciar entre cada uno de los elementos devueltos pero, en el caso de los nombres de los personajes (Rick Deckard Roy Batty Rachael) resulta un poco ms complicado. Podemos solucionarlo si combinamos varias de las tcnicas aprendidas a lo largo de este libro. Vamos a utilizar el siguiente cdigo para crear un procedimiento almacenado que recupere, uno por uno, los nombres de los personajes y los devuelva separados por comas. De esa forma, si llama al procedimiento almacenado desde un lenguaje de programacin, podr acceder fcilmente a cada uno de ellos.
Not a: Encontrar ms informacin sobre los procedimientos almacenados en el captulo 11.

El cdigo del procedimiento almacenado es el siguiente:


DELIMITER //

DROP PROCEDURE IF EXISTS pa_personajes_obtener;

CREATE PROCEDURE pa_personajes_obtener ( idpelicula INT ) BEGIN

DECLARE i INT DEFAULT 1; DECLARE j INT DEFAULT 0;

DECLARE personajes TEXT DEFAULT ''; DECLARE personaje TEXT DEFAULT '';

SELECT ExtractValue( reparto, 'count(/reparto/papel)') INTO j FROM

FROM pelicula WHERE id = idpelicula;

WHILE i <= j DO

SELECT ExtractValue( reparto, '/reparto/papel[$i]/personaje') INTO personaje FROM pelicula WHERE id = idpelicula;

SELECT IF( i <> j, CONCAT(personaje, ', '), personaje) INTO personaje;

SET personajes = CONCAT( personajes, personaje);

SET i = i + 1;

END WHILE;

SELECT personajes;

END //

DELIMITER ;

Para obtener la lista de personajes de la pelcula con identificador 1 (Blade Runner) tendra que ejecutar la siguiente consulta:
USE videoteca;

CALL pa_personajes_obtener(1);

El resultado, en la figura 14.12.

Figura 14.12. Personajes, separados por comas

En este procedimiento almacenado se utilizan varias tcnicas avanzadas. Para empezar, contamos el nmero de papeles de que disponemos en el fragmento XML. El resultado de esa consulta se guarda en la variable j. A continuacin, obtenemos uno por uno los nombres de los personajes y los guardamos en otra variable, separados por comas. El ltimo nombre no incluye una coma al final. Para poder acceder a ellos de uno en uno utilizamos la expresin XPath /reparto/papel[$i]/personaje, donde $i toma los valores desde 1 hasta el nmero de papeles existentes: /reparto/papel[1] representa al primer nodo papel, /reparto/papel[2] al segundo y as sucesivamente. Terminamos devolviendo el valor guardado en la variable personajes.
Not a: En el procedimiento almacenado anterior utilizamos la instruccin de control de flujo WHILE y la funcin IF, tcnicas avanzadas que no han tenido su hueco en este libro. Si desea ms informacin sobre ellas consulte la documentacin de MySQL.

UpdateXML
La funcin UpdateXML es la contrapartida necesaria de ExtractValue. Recordemos que sta ltima permite extraer datos de fragmentos de documentos XML almacenados en campos de una tabla. No tendra mucho sentido que para modificar los valores de esos campos tuvisemos que guardar una nueva versin de dichos fragmentos. UpdateXML recibe tres parmetros: el fragmento XML con el que trabajar, la expresin XPath que determina qu valores se quieren modificar y, por ltimo, el nuevo valor que queremos guardar. Volvamos a utilizar los datos de ejemplo. Para empezar, eche un vistazo a la lista de actores presentes en el campo reparto. Pudimos verla en la figura 14.8. Si se fija, hemos metido la pata: el actor principal de Blade Runner no es Harrisond Ford sino Harrison Ford. Ejecute la siguiente consulta para corregirlo:
USE videoteca;

UPDATE pelicula SET reparto = UpdateXML( reparto, '/reparto/papel[1]/actor', '<actor>Harrison Ford</actor>' ) WHERE

id = 1;

Tras papel, entre corchetes, la posicin en la que se encuentra el elemento papel que queremos modificar. En este caso se trata del primero de ellos, el correspondiente al papel de Rick Deckard. Ha tenido xito el cambio? Comprubelo con la siguiente consulta:
USE videoteca;

SELECT ExtractValue( reparto, '/reparto/papel[1]/actor' ) AS actor FROM pelicula WHERE id = 1;

La figura 14.13 muestra el resultado de ejecutar tanto la modificacin como la consulta de datos.

Figura 14.13. Modificacin con UpdateXML

SimpleXML
Su nombre no poda ser ms claro: SimpleXML es la forma ms sencilla de manipular documentos XML desde PHP, con diferencia. Existen otras alternativas, cada una con sus ventajas y sus inconvenientes si las comparamos entre s. Por ejemplo, DOM (o DOM XML si utiliza PHP 4) o la pareja XMLReader y XMLWriter.

Apertura
Segn vimos en los apartados anteriores, la siguiente orden devuelve la lista de gneros contenidos en la tabla correspondiente de la base de datos.

mysql -u root -p --xml -e "SELECT * FROM soporte" videoteca > soportes.xml

La anterior figura 14.5 mostraba el resultado de ejecutar dicha orden. Se trata del siguiente documento XML:
<?xml version="1.0"?>

<resultset statement="SELECT * FROM soporte" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" > <row> <field name="id">1</field> <field name="nombre">DVD</field> <field name="descripcion"> Digital Versatile Disc </field> </row>

<row> <field name="id">2</field> <field name="nombre">VHS</field> <field name="descripcion"> Video Home System </field> </row> </resultset>

Cargar un documento XML desde un archivo de texto utilizando SimpleXML es, pues eso, simple:
<?php

$xml = new SimpleXMLElement( 'C:\soportes.xml', NULL, TRUE );

echo $xml->asXML();

?>

La figura 14.14 muestra el resultado de este breve programa.

Figura 14.14. Carga de un documento XML

Truco: Efectivamente, no parece un documento XML en absoluto, pero eso es porque el cliente Web est interpretando el cdigo XML y slo muestra la parte

interesante para nosotros, meros seres humanos. Si quiere ver el cdigo XML completo haga clic con el botn derecho del ratn sobre la pgina y seleccione la opcin Ver cdigo fuente del men desplegable que aparecer.

Para cargar el documento XML utilizamos el constructor de la clase SimpleXMLElement . El primer parmetro es el contenido XML que deseamos cargar. Puede ser tanto una cadena de texto con contenido XML como un URL (que apunte a una direccin Web o a contenido dentro del sistema de archivos), dependiendo del valor del tercer parmetro. Si su valor es TRUE , el primer parmetro se interpretar como URL, si es FALSE como texto XML.
Not a: El segundo parmetro se puede utilizar para pasar opciones al intrprete XML, libxml, que quedan fuera del alcance de esta gua.

El mtodo asXML de la clase SimpleXMLElement se utiliza para obtener el contenido XML cargado desde el recurso externo o desde la cadena de texto pasada como primer parmetro. Aunque poder mostrar el contenido de un documento XML est muy bien, lo que resulta realmente interesante es poder acceder a sus elementos.

Recorrido de nodos
El nodo raz del documento XML que estamos utilizando en este apartado es resultset . Sus descendientes son los nodos row que, a su vez, contienen nodos field. Resulta sencillo recorrer cada nodo row del documento:
<?php

$xml = new SimpleXMLElement( 'C:\soportes.xml', NULL, TRUE );

$rows = $xml->xpath('/resultset/row');

foreach($rows as $row){ echo $row->asXML() . '<br/>'; }

?>

La apertura del documento es exactamente igual que antes. Ahora, en lugar de mostrar el contenido del documento utilizamos el mtodo xpath para acceder a los nodos que nos interesan. En este caso se trata de los nodos row que contiene el nodo resultset . Por lo tanto, el parmetro de que debemos pasar a xpath es /resultset/row. Como resultado se devolvern todos los nodos del documento que cumplan ese criterio. Para acceder a cada nodo slo tenemos que iterar por $rows y mostrar su contenido utilizando asXML. La figura

14.15 muestra lo que se vera al ejecutar el anterior programa.

Figura 14.15. Acceso a nodos

Acceso a atributos
Para acceder a los atributos de un nodo debemos utilizar el mtodo attributes del nodo que nos interese. As, podra utilizar un bucle foreach para obtener todos los nodos row, otro bucle para obtener todos los nodos field y, una vez all, obtener todos los atributos con otro bucle foreach. Dependiendo del valor del atributo name de cada nodo field contenido en su interior mostraremos la informacin de una forma o de otra. Por ejemplo, el identificador ir entre parntesis, al principio, el nombre en negrita y, a continuacin, tras dos puntos, la descripcin, terminada en punto. El cdigo resultante sera el siguiente:
<?php

$xml = new SimpleXMLElement( 'C:\soportes.xml', NULL, TRUE );

$rows = $xml->xpath('/resultset/row');

foreach($rows as $row){

$fields = $row->xpath('field');

foreach($fields as $field){

$attributes = $field->attributes();

foreach($attributes as $attribute){

switch($attribute){

case 'id': echo('(' . $field->asXML() . ') '); break;

case 'nombre': echo('<b>' . $field->asXML() . '</b>: '); break;

break;

case 'descripcion': echo($field->asXML() . '.<br/>'); break;

?>

El resultado, en la figura 14.16.

Figura 14.16. Acceso a los atributos

Not a: SimpleXML tambin permite modificar el contenido de los documentos XML, incluso construirlos desde cero. Consulte la documentacin de SimpleXML si desea ms informacin al respecto.

Tras lo visto en este captulo ya sabe cmo obtener en resultado de sus consultas SQL en formato XML, algo que puede serle til si quiere utilizar esos datos en otros programas. Adems, hemos aprendido cmo funcionan tanto ExtractValue como UpdateXML , que permiten extraer y modificar valores de campos que contengan fragmentos de documentos en formato XML. Para terminar, hemos aprendido a tratar esos datos XML desde PHP. Aunque las capacidades de MySQL en lo que a este formato se refiere son bastante rudimentarias, se trata slo de la punta del iceberg. La mayora de los lenguajes de programacin modernos permiten trabajar directamente con XML. Es ms, le garantizo que MySQL seguir incorporando nuevas caractersticas para facilitar el trabajo con XML, as que todo el tiempo que invierta en aprender sobre l ser una buena inversin. No podemos decir lo mismo de PHP. Este lenguaje de programacin ofrece diferentes interfaces de acceso a XML adems de SimpleXML como, por ejemplo, DOM o la pareja XMLReader y XMLWriter. Cada una de ellas tiene sus virtudes y sus defectos. La eleccin depender de las necesidades de sus programas.

Eplogo
Durante este libro hemos recorrido una gran cantidad de tecnologas de diferente naturaleza: servidores Web, servidores de bases de datos, diferentes lenguajes de programacin. Y de todas estas herramientas diferentes hemos sido capaces de lograr lo impensable, gracias a que son capaces de colaborar entre ellas. El espacio del que disponemos en una gua de estas caractersticas es limitado y sin embargo, hemos trabado contacto con una gran cantidad de productos diferentes. Espero que, al menos, todo esto haya servido para que pierda el miedo y sepa que tiene frente a s una gran cantidad de posibilidades si dispone de las herramientas adecuadas. Recuerde: an queda mucho que aprender.

Table of Contents
Dedicatoria Agradecimientos Introduccin Cmo usar este libro Prlogo 1. MySQL y PHP 1.1. La primera aplicacin 1.2. XAMPP 1.2.1. Puesta en marcha de XAMPP 1.3. Trabajando con MySQL 1.3.1. Creacin de la base de datos 1.3.2. Creacin de la tabla 1.3.3. Inserciones 1.4. Trabajando con PHP 2. PHP 2.1. Introduccin 2.2. Editores 2.3. Estructura de un archivo PHP 2.3.1. Escapar de HTML 2.3.2. Funciones de salida 2.3.3. Comentarios 2.4. Variables 2.4.1. Tipos de datos 2.5. Operadores 2.5.1. Operador bsico de asignacin 2.5.2. Operadores aritmticos 2.5.3. Operadores de comparacin 2.5.4. Operadores lgicos 2.5.5. Operadores de incremento 2.5.6. Concatenacin de cadenas 2.5.7. Precedencia de operadores 2.5.8. Cambios de tipo 2.6. Instrucciones de control 2.6.1. Instrucciones condicionales 2.6.2. Instrucciones iterativas 2.6.3. Salida de bucles 3. MySQL 3.1. Bases de datos 3.2. Qu es una tabla? 3.3. Base de datos de ejemplo 3.3.1. Herramientas de consulta 3.3.2. Creacin de la base de datos 3.4. Operaciones sobre tablas 3.4.1. Creacin 3.4.2. Modificacin 3.4.3. Borrado 3.5. Tipos de tabla 3.5.1. MyISAM 3.5.2. InnoDB 3.6. Tipos de datos 3.6.1. Tipos de texto

3.6.2. Tipos numricos 3.6.3. Fechas y horas 4. PHP orientado a objetos 4.1. Funciones 4.1.1. Parmetros 4.1.2. Devolucin de valores 4.1.3. Trabajando con funciones 4.2. Inclusin de archivos 4.3. Orientacin a objetos 4.3.1. Clases 4.3.2. Ms all de las clases 5. Diseo de bases de datos 5.1. El ejemplo 5.1.1. Limitaciones 5.1.2. Objetivos 5.2. MySQL Workbench 5.2.1. Instalacin 5.3. Conceptos varios 5.3.1. El valor NULL 5.3.2. Claves primarias 5.3.3. ndices 5.3.4. Columnas de incremento automtico 5.3.5. El modelo relacional 5.4. Divide y vencers 5.4.1. Creacin de tablas con MySQL Workbench 5.4.2. Divisin de tablas 5.4.3. Relacionar tablas 5.4.4. Relaciones muchos a muchos 5.4.5. El ejemplo finalizado 6. SQL 6.1. La base de datos de ejemplo 6.1.1. Creacin de la base de datos 6.1.2. Insercin de datos 6.2. Operadores 6.2.1. Operadores aritmticos 6.2.2. Operadores de comparacin 6.2.3. Operadores lgicos 6.2.4. Cambiando la precedencia 6.3. Manipulacin de bases de datos 6.3.1. Creacin 6.3.2. Borrado 6.4. Consultas de seleccin 6.4.1. Listados de una tabla 6.4.2. Listados de varias tablas 6.5. Actualizaciones 6.6. Inserciones 6.7. Borrados 7. PHP y MySQL 7.1. Acceso mejorado a MySQL 7.2. El ciclo de la vida 7.2.1. Conexin 7.2.2. Operacin 7.2.3. Desconexin 7.3. Conjuntos de registros

7.4. Otras consultas 7.5. Consultas escapadas 7.6. Configuracin 7.6.1. Valores de configuracin 7.6.2. Modificacin de la configuracin 7.6.3. Ventajas 7.6.4. Inconvenientes 7.6.5. Opciones de PHP en Apache 8. Formularios 8.1. Cmo funcionan los formularios 8.2. Formularios HTML 8.2.1. Creacin de formularios 8.2.2. Elementos de un formulario 8.3. Envo de informacin 8.4. Recuperacin de informacin 8.5. Insercin de registros 8.6. Control en el lado del cliente 9. Gestin de errores 9.1. PHP y los errores 9.1.1. Configuracin 9.1.2. Funciones 9.1.3. Excepciones 9.2. MySQL y los errores 9.2.1. Archivos de registro 9.2.2. Archivos de registro en tablas 9.2.3. Idioma de los errores 9.3. MySQLi y los errores 10. Plantillas 10.1. Qu es Smarty? 10.1.1. Un pequeo ejemplo 10.2. Instalacin 10.3. Lista de gneros 10.3.1. La plantilla 10.3.2. La pgina PHP 10.3.3. Otra plantilla 11. Procedimientos almacenados 11.1. Introduccin 11.1.1. Base de datos reducida 11.1.2. Creacin 11.1.3. Insercin 11.2. Un sencillo ejemplo 11.3. Sintaxis 11.3.1. Creacin 11.3.2. Variables 11.3.3. Delimitadores 11.3.4. Parmetros 11.3.5. Funciones almacenadas 11.3.6. Eliminacin 11.4. Utilizacin desde PHP 12. Desencadenadores 12.1. Introduccin 12.1.1. Base de datos reducida 12.1.2. Creacin 12.1.3. Insercin 12.2. Sintaxis 12.2.1. Creacin

12.2.2. Eliminacin 12.3. Ejemplos 12.3.1. Insercin 12.3.2. Actualizacin 12.3.3. Borrado 13. Vistas 13.1. Introduccin 13.2. Sintaxis 13.2.1. Creacin 13.2.2. Modificacin 13.2.3. Eliminacin 13.3. Ejemplos 13.3.1. Creacin 13.3.2. Modificacin 13.3.3. Eliminacin 13.4. Utilizacin desde PHP 14. XML 14.1. Qu es XML? 14.1.1. Partes de un documento XML 14.1.2. Etiquetas 14.2. XML desde la lnea de rdenes 14.3. Funciones XML 14.3.1. XPath 14.3.2. Datos de ejemplo 14.3.3. ExtractValue 14.3.4. UpdateXML 14.4. SimpleXML 14.4.1. Apertura 14.4.2. Recorrido de nodos 14.4.3. Acceso a atributos Eplogo

Anda mungkin juga menyukai