El objetivo de estos ejercicios es obtener una aplicación web capaz de gestionar una tabla de una base de datos. En este caso, la tabla es una mínima agenda. En cada ejercicio se añade una funcionalidad a la aplicación como refleja el título de cada ejercicio.
Estos ejercicios van encadenados. Cada ejercicio se debe hacer a partir del ejercicio anterior, añadiendo las páginas necesarias.
En estos ejercicios la única comprobación que se realiza sobre los datos introducidos por el usuario es que su longitud se adapta al tamaño de los campos en la base de datos.
En cada ejercicio, se encuentran unos comentarios que incluyen un dibujo que indica las relaciones entre las diferentes páginas:
Para facilitar la realización de los ejercicios, se proporcionan unas plantillas de los ejercicios Bases de datos (1) (Bases de datos) que incluyen parte de las páginas (los fragmentos HTML y las bibliotecas específicas de bases de datos). También puede descargar otras plantillas de los ejercicios Bases de datos (1) (Bases de datos) que incluyen únicamente el ejercicio 6, pero con más código ya incluido en las plantillas.
Para facilitar la verificación de los ejercicios, se proporcionan ficheros .side que permiten la comprobación con Selenium IDE 4 del funcionamiento de la aplicación de ejemplo y de los ejercicios.
Puede descargar unas posibles soluciones completas de estos ejercicios.
Escriba un programa que permita crear una base de datos.
// Base de datos utilizada por la aplicación
$cfg["dbMotor"] = SQLITE; // Valores posibles: MYSQL o SQLITE
// Configuración para SQLite
$cfg["sqliteDatabase"] = "/tmp/mclibre-base-datos-1-1.sqlite"; // Ubicación de la base de datos
// Configuración para MySQL
$cfg["mysqlHost"] = "localhost"; // Nombre de host
$cfg["mysqlUser"] = "mclibre_base_datos_1_1"; // Nombre de usuario
$cfg["mysqlPassword"] = ""; // Contraseña de usuario
$cfg["mysqlDatabase"] = "mclibre_base_datos_1_1"; // Nombre de la base de datos
// Tamaño de los campos en la tabla Personas
$cfg["tablaPersonasTamNombre"] = 40; // Tamaño de la columna Personas > Nombre
$cfg["tablaPersonasTamApellidos"] = 60; // Tamaño de la columna Personas > Apellidos
// SQLITE: Borrado y creación de tablas
$consulta = "DROP TABLE IF EXISTS $cfg[tablaPersonas]";
$consulta = "CREATE TABLE $cfg[tablaPersonas] (
id INTEGER PRIMARY KEY,
nombre VARCHAR($cfg[tablaPersonasTamNombre]) COLLATE NOCASE,
apellidos VARCHAR($cfg[tablaPersonasTamApellidos]) COLLATE NOCASE
)";
// MYSQL: Borrado y creación de base de datos y tablas
$consulta = "DROP DATABASE IF EXISTS $cfg[mysqlDatabase]";
$consulta = "CREATE DATABASE $cfg[mysqlDatabase]
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci";
$consulta = "USE $cfg[mysqlDatabase]";
$consulta = "CREATE TABLE $cfg[tablaPersonas] (
id INTEGER UNSIGNED AUTO_INCREMENT,
nombre VARCHAR($cfg[tablaPersonasTamNombre]),
apellidos VARCHAR($cfg[tablaPersonasTamApellidos]),
PRIMARY KEY(id)
)";
Amplíe el ejercicio anterior de manera que permita incluir registros en la base de datos.
// Controles en el formulario
print " <td><input type=\"text\" name=\"nombre\" size=\"$cfg[formPersonasTamNombre]\" maxlength=\"$cfg[formPersonasMaxNombre]\" autofocus></td>\n";
...
print " <td><input type=\"text\" name=\"apellidos\" size=\"$cfg[formPersonasTamApellidos]\" maxlength=\"$cfg[formPersonasMaxApellidos]\"></td>\n";
Estas constantes se pueden definir en config.php y en este caso hacerlas coincidir con el tamaño de los campos en la base de datos:
// Tamaño de los campos en la tabla Personas
$cfg["tablaPersonasTamNombre"] = 40; // Tamaño de la columna Personas > Nombre
$cfg["tablaPersonasTamApellidos"] = 60; // Tamaño de la columna Personas > Apellidos
// Tamaño de los controles en los formularios
$cfg["formPersonasTamNombre"] = $cfg["tablaPersonasTamNombre"]; // Tamaño de la caja de texto Personas > Nombre
$cfg["formPersonasTamApellidos"] = $cfg["tablaPersonasTamApellidos"]; // Tamaño de la caja de texto Personas > Apellidos
// Tamaño máximo admitido por los controles en los formularios
$cfg["formPersonasMaxNombre"] = $cfg["tablaPersonasTamNombre"]; // Tamaño máximo admitido por la caja de texto Personas > Nombre
$cfg["formPersonasMaxApellidos"] = $cfg["tablaPersonasTamApellidos"]; // Tamaño máximo admitido por la caja de texto Personas > Apellidos
// Comprueba la longitud del dato recibido
$nombre = recoge("nombre");
$nombreOk = false;
if (mb_strlen($nombre, "UTF-8") > $cfg["formPersonasMaxNombre"]) {
print " <p class=\"aviso\">El nombre no puede tener más de $cfg[formPersonasMaxNombre] caracteres.</p>\n";
print "\n";
} else {
$nombreOk = true;
}
// Añade un registro
$consulta = "INSERT INTO $cfg[tablaPersonas]
(nombre, apellidos)
VALUES (:nombre, :apellidos)";
$resultado = $pdo->prepare($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} elseif (!$resultado->execute([":nombre" => $nombre, ":apellidos" => $apellidos])) {
print " <p class=\"aviso\">Error al ejecutar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
print " <p>Registro creado correctamente.</p>\n";
}
Amplíe el ejercicio anterior de manera que permita listar los registros de la base de datos.
// Selecciona y muestra todos los registros
$consulta = "SELECT * FROM $cfg[tablaPersonas]";
$resultado = $pdo->query($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error en la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
print " <p>Listado completo de registros:</p>\n";
...
foreach ($resultado as $registro) {
print " <tr>\n";
print " <td>$registro[nombre]</td>\n";
print " <td>$registro[apellidos]</td>\n";
print " </tr>\n";
}
...
Amplíe el ejercicio anterior de manera que permita borrar individualmente los registros de la base de datos.
// Imprime casillas de verificación
$consulta = "SELECT * FROM $cfg[tablaPersonas]";
$resultado = $pdo->query($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error en la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
print " <form action=\"borrar-2.php\" method=\"$cfg[formMethod]\">\n";
print " <p>Marque los registros que quiera borrar:</p>\n";
...
foreach ($resultado as $registro) {
print " <tr>\n";
print " <td class=\"centrado\"><input type=\"checkbox\" name=\"id[$registro[id]]\"></td>\n";
print " <td>$registro[nombre]</td>\n";
print " <td>$registro[apellidos]</td>\n";
print " </tr>\n";
}
...
// Recoge y borra los registros seleccionados
$id = recoge("id", []);
// Comprobamos el dato recibido
$idOk = false;
if ($id == []) {
print " <p class=\"aviso\">No se ha seleccionado ningún registro.</p>\n";
} else {
$idOk = true;
}
if ($idOk) {
foreach ($id as $indice => $valor) {
$consulta = "DELETE FROM $cfg[tablaPersonas]
WHERE id = :indice";
$resultado = $pdo->prepare($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} elseif (!$resultado->execute([":indice" => $indice])) {
print " <p class=\"aviso\">Error al ejecutar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
print " <p>Registro borrado correctamente (si existía).</p>\n";
}
}
}
Amplíe el ejercicio anterior de manera que permita buscar registros de la base de datos.
// Busca registros
$nombre = recoge("nombre");
$apellidos = recoge("apellidos");
// Comprobamos los datos recibidos procedentes de un formulario
$nombreOk = false;
$apellidosOk = false;
...
if ($nombreOk && $apellidosOk) {
$consulta = "SELECT * FROM $cfg[tablaPersonas]
WHERE nombre LIKE :nombre
AND apellidos LIKE :apellidos";
$resultado = $pdo->prepare($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} elseif (!$resultado->execute([":nombre" => "%$nombre%", ":apellidos" => "%$apellidos%"])) {
print " <p class=\"aviso\">Error al ejecutar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
print " <p>Registros encontrados:</p>\n";
...
foreach ($resultado as $registro) {
print " <tr>\n";
print " <td>$registro[nombre]</td>\n";
print " <td>$registro[apellidos]</td>\n";
print " </tr>\n";
}
...
los comodines (%) deben incluirse al ejecutar la consulta, no se podrían incluir en la definición de $consulta.
Amplíe el ejercicio anterior de manera que permita modificar registros de la base de datos.
// Imprime botones radio
$consulta = "SELECT * FROM $cfg[tablaPersonas]";
$resultado = $pdo->query($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error en la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
print " <form action=\"modificar-2.php\" method=\"$cfg[formMethod]\">\n";
print " <p>Indique el registro que quiera modificar:</p>\n";
...
foreach ($resultado as $registro) {
print " <tr>\n";
print " <td class=\"centrado\"><input type=\"radio\" name=\"id\" value=\"$registro[id]\"></td>\n";
print " <td>$registro[nombre]</td>\n";
print " <td>$registro[apellidos]</td>\n";
print " </tr>\n";
}
...
// Recoge el id del registro y selecciona el registro
$id = recoge("id");
if ($id == "") {
print " <p class=\"aviso\">No se ha seleccionado ningún registro.</p>\n";
} else {
$consulta = "SELECT * FROM $cfg[tablaPersonas]
WHERE id = :id";
$resultado = $pdo->prepare($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} elseif (!$resultado->execute([":id" => $id])) {
print " <p class=\"aviso\">Error al ejecutar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
$registro = $resultado->fetch();
...
// Muestra los valores del registro en el formulario
print " <td><input type=\"text\" name=\"nombre\" size=\"$cfg[formPersonasTamNombre]\" maxlength=\"$cfg[formPersonasMaxNombre]\" value=\"$registro[nombre]\" autofocus></td>\n";
...
print " <td><input type=\"text\" name=\"apellidos\" size=\"$cfg[formPersonasTamApellidos]\" maxlength=\"$cfg[formPersonasMaxApellidos]\" value=\"$registro[apellidos]\"></td>\n";
// Control oculto con el id del registro modificado
print " <input type=\"hidden\" name=\"id\" value=\"$id\">\n";
// Actualiza el registro
$consulta = "UPDATE $cfg[tablaPersonas]
SET nombre = :nombre, apellidos = :apellidos
WHERE id = :id";
$resultado = $pdo->prepare($consulta);
if (!$resultado) {
print " <p class=\"aviso\">Error al preparar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} elseif (!$resultado->execute([":nombre" => $nombre, ":apellidos" => $apellidos, ":id" => $id])) {
print " <p class=\"aviso\">Error al ejecutar la consulta. SQLSTATE[{$pdo->errorCode()}]: {$pdo->errorInfo()[2]}</p>\n";
} else {
print " <p>Registro modificado correctamente.</p>\n";
}