Módulo 7: Proyecto Final del Curso

Proyecto final: Aplicación web de biblioteca en PHP con MVC y MySQL

Lección 33 de 33 del Curso Roadmap Learning Laravel

Duración: 1 semana (aproximadamente 20-30 horas de trabajo, distribuidas según el ritmo del estudiante)
Nivel: Intermedio (requiere conocimientos de HTML, CSS, JavaScript, PHP con POO, MySQL, SQL, protocolo HTTP, patrón MVC, configuración de entornos locales, y seguridad básica en PHP)
Objetivo: Integrar todos los conocimientos del curso en una aplicación web completa para una biblioteca, que gestione libros, autores, y préstamos, aplicando buenas prácticas de desarrollo web.
Materiales necesarios:

  • Computadora con:
    • XAMPP o Laragon instalado (entorno local con Apache, PHP, MySQL, configurado en Módulo 6, Lección 3).
    • Navegador web (Chrome, Firefox, etc.) con herramientas de desarrollo (DevTools, accesible con F12).
    • Editor de texto (recomendado: VS Code, descarga gratuita desde code.visualstudio.com).
    • Papel y lápiz para diagramas o planificación.
  • Acceso a internet (para referencias o investigación).
    Contexto: Este proyecto final es una culminación del curso, combinando:
  • Frontend: HTML/CSS para interfaces (Módulo 2), con JavaScript opcional para validación (Módulo 3).
  • Backend: PHP con POO para lógica (Módulo 4), estructurado en MVC (Módulo 6, Lección 2).
  • Base de datos: MySQL con tablas relacionadas (Módulo 5).
  • Seguridad: Validación de entradas y consultas preparadas (Módulo 6, Lección 4).
  • Entorno: XAMPP o Laragon (Módulo 6, Lección 3).
    La aplicación simula un sistema de biblioteca, un caso práctico común que prepara para proyectos reales o frameworks como Laravel.

Introducción al proyecto final (30 minutos)

Explicación:
El proyecto final consiste en desarrollar una aplicación web para una biblioteca que gestione libros, autores, y préstamos. La aplicación permitirá:

  • Listar libros: Mostrar todos los libros con sus autores (solicitud GET).
  • Listar autores: Mostrar todos los autores (solicitud GET).
  • Listar préstamos: Mostrar los préstamos activos (solicitud GET).
  • Crear libros: Añadir un libro con su autor (formulario, solicitud POST).
  • Crear autores: Añadir un autor (formulario, solicitud POST).
  • Registrar préstamos: Registrar un préstamo de un libro (formulario, solicitud POST).

Requisitos:

  • Frontend:
    • HTML/CSS para formularios y listas (interfaces claras y responsivas).
    • Opcional: JavaScript para validación en el cliente (por ejemplo, verificar campos vacíos).
  • Backend:
    • PHP con clases POO para manejar la lógica (por ejemplo, clases para Libro, Autor, Prestamo).
    • Estructura MVC simple (Modelo, Vista, Controlador).
  • Base de datos:
    • MySQL con tablas relacionadas:
      • autores (autor principal de un libro).
      • libros (relacionados con autores).
      • prestamos (relacionados con libros).
  • Seguridad:
    • Validar entradas (campos obligatorios, formatos correctos).
    • Usar consultas preparadas para prevenir inyección SQL.
  • Entorno: Desplegada en XAMPP o Laragon.

Por qué es importante:

  • Integra todos los módulos del curso en una aplicación completa.
  • Simula un sistema real, preparando para proyectos profesionales.
  • Refuerza MVC, POO, y seguridad, fundamentales para frameworks como Laravel.

Punto clave: El proyecto final demuestra dominio de desarrollo web full-stack con PHP.

Actividad inicial (10 minutos):
Dibuja en papel un esquema de las tres tablas de la base de datos (autores, libros, prestamos) y sus relaciones.

  • Ejemplo:
    autores: id, nombre
    libros: id, titulo, id_autor (FK → autores.id)
    prestamos: id, id_libro (FK → libros.id), fecha_prestamo

Planificación y diseño del proyecto (1 hora)

Explicación:
Antes de codificar, planificaremos la estructura del proyecto, diseñaremos la base de datos, y definiremos las funcionalidades.

Estructura del proyecto:

/biblioteca_app
  /models
    AutorModel.php
    LibroModel.php
    PrestamoModel.php
  /views
    autores_listar.php
    libros_listar.php
    prestamos_listar.php
    autor_crear.php
    libro_crear.php
    prestamo_crear.php
  /controllers
    AutorController.php
    LibroController.php
    PrestamoController.php
  /assets
    css/styles.css
    js/validacion.js (opcional)
  index.php
  config.php
  README.md

Base de datos:

  • Nombre: biblioteca_db.
  • Tablas:
    CREATE DATABASE biblioteca_db;
    USE biblioteca_db;
    
    CREATE TABLE autores (
        id INT AUTO_INCREMENT PRIMARY KEY,
        nombre VARCHAR(100) NOT NULL
    );
    
    CREATE TABLE libros (
        id INT AUTO_INCREMENT PRIMARY KEY,
        titulo VARCHAR(200) NOT NULL,
        id_autor INT NOT NULL,
        FOREIGN KEY (id_autor) REFERENCES autores(id)
    );
    
    CREATE TABLE prestamos (
        id INT AUTO_INCREMENT PRIMARY KEY,
        id_libro INT NOT NULL,
        fecha_prestamo DATE NOT NULL,
        FOREIGN KEY (id_libro) REFERENCES libros(id)
    );
    
    -- Datos de prueba
    INSERT INTO autores (nombre) VALUES 
        ('Gabriel García Márquez'),
        ('Jane Austen');
    INSERT INTO libros (titulo, id_autor) VALUES 
        ('Cien años de soledad', 1),
        ('Orgullo y prejuicio', 2);
    INSERT INTO prestamos (id_libro, fecha_prestamo) VALUES 
        (1, '2025-04-20'),
        (2, '2025-04-21');

Funcionalidades:

  1. Listar autores: Mostrar tabla con nombres de autores (GET /index.php?controlador=autor&accion=listar).
  2. Listar libros: Mostrar tabla con títulos y nombres de autores (GET /index.php?controlador=libro&accion=listar).
  3. Listar préstamos: Mostrar tabla con libros prestados y fechas (GET /index.php?controlador=prestamo&accion=listar).
  4. Crear autor: Formulario para añadir un autor (nombre) (POST /index.php?controlador=autor&accion=guardar).
  5. Crear libro: Formulario para añadir un libro (título, autor) (POST /index.php?controlador=libro&accion=guardar).
  6. Crear préstamo: Formulario para registrar un préstamo (libro, fecha) (POST /index.php?controlador=prestamo&accion=guardar).

Planificación del tiempo:

  • Día 1: Configurar entorno, base de datos, y estructura MVC (2-3 horas).
  • Día 2: Implementar modelos y controladores (4-5 horas).
  • Día 3: Crear vistas y estilos CSS (3-4 horas).
  • Día 4: Añadir validación de entradas y seguridad (2-3 horas).
  • Día 5: Implementar JavaScript opcional y probar (2-3 horas).
  • Día 6: Documentar (README) y depurar (2-3 horas).
  • Día 7: Finalizar pruebas y preparar entrega (1-2 horas).

Punto clave: Una planificación clara asegura un desarrollo organizado y eficiente.

Actividad (15 minutos):
Escribe en papel la estructura de carpetas y las funcionalidades con sus URLs.

  • Ejemplo:
    Estructura:
    /biblioteca_app
      /models
      /views
      /controllers
      /assets
      index.php
      config.php
      README.md
    
    Funcionalidades:
    - Listar autores: GET /index.php?controlador=autor&accion=listar
    - Crear libro: POST /index.php?controlador=libro&accion=guardar

Desarrollo del proyecto: Implementación (15-20 horas, distribuidas)

Explicación:
Implementaremos la aplicación biblioteca con MVC simple, usando PHP con POO, MySQL, HTML/CSS, y seguridad. Opcionalmente, añadiremos JavaScript para validación en el cliente.

Código del proyecto:

  1. Configuración (config.php):

    • Conexión a MySQL.
    <?php
    $host = 'localhost';
    $usuario = 'root';
    $contrasena = ''; // Vacío en XAMPP/Laragon por defecto
    $base_datos = 'biblioteca_db';
    
    $conexion = new mysqli($host, $usuario, $contrasena, $base_datos);
    if ($conexion->connect_error) {
        die("Error de conexión: " . $conexion->connect_error);
    }
    ?>
  2. Modelos:

    • Autor (models/AutorModel.php):
      <?php
      class AutorModel {
          private $conexion;
      
          public function __construct($conexion) {
              $this->conexion = $conexion;
          }
      
          public function listar() {
              $query = "SELECT id, nombre FROM autores ORDER BY nombre";
              $resultado = $this->conexion->query($query);
              return $resultado->fetch_all(MYSQLI_ASSOC);
          }
      
          public function crear($nombre) {
              $stmt = $this->conexion->prepare("INSERT INTO autores (nombre) VALUES (?)");
              $stmt->bind_param("s", $nombre);
              return $stmt->execute();
          }
      }
      ?>
    • Libro (models/LibroModel.php):
      <?php
      class LibroModel {
          private $conexion;
      
          public function __construct($conexion) {
              $this->conexion = $conexion;
          }
      
          public function listar() {
              $query = "SELECT l.id, l.titulo, a.nombre AS autor 
                        FROM libros l 
                        JOIN autores a ON l.id_autor = a.id 
                        ORDER BY l.titulo";
              $resultado = $this->conexion->query($query);
              return $resultado->fetch_all(MYSQLI_ASSOC);
          }
      
          public function crear($titulo, $id_autor) {
              $stmt = $this->conexion->prepare("INSERT INTO libros (titulo, id_autor) VALUES (?, ?)");
              $stmt->bind_param("si", $titulo, $id_autor);
              return $stmt->execute();
          }
      
          public function getAutores() {
              $query = "SELECT id, nombre FROM autores ORDER BY nombre";
              $resultado = $this->conexion->query($query);
              return $resultado->fetch_all(MYSQLI_ASSOC);
          }
      }
      ?>
    • Préstamo (models/PrestamoModel.php):
      <?php
      class PrestamoModel {
          private $conexion;
      
          public function __construct($conexion) {
              $this->conexion = $conexion;
          }
      
          public function listar() {
              $query = "SELECT p.id, l.titulo, p.fecha_prestamo 
                        FROM prestamos p 
                        JOIN libros l ON p.id_libro = l.id 
                        ORDER BY p.fecha_prestamo DESC";
              $resultado = $this->conexion->query($query);
              return $resultado->fetch_all(MYSQLI_ASSOC);
          }
      
          public function crear($id_libro, $fecha_prestamo) {
              $stmt = $this->conexion->prepare("INSERT INTO prestamos (id_libro, fecha_prestamo) VALUES (?, ?)");
              $stmt->bind_param("is", $id_libro, $fecha_prestamo);
              return $stmt->execute();
          }
      
          public function getLibros() {
              $query = "SELECT id, titulo FROM libros ORDER BY titulo";
              $resultado = $this->conexion->query($query);
              return $resultado->fetch_all(MYSQLI_ASSOC);
          }
      }
      ?>
  3. Controladores:

    • Autor (controllers/AutorController.php):
      <?php
      require_once 'models/AutorModel.php';
      
      class AutorController {
          private $modelo;
      
          public function __construct($conexion) {
              $this->modelo = new AutorModel($conexion);
          }
      
          public function listar() {
              $autores = $this->modelo->listar();
              require 'views/autores_listar.php';
          }
      
          public function crear() {
              require 'views/autor_crear.php';
          }
      
          public function guardar() {
              $nombre = trim($_POST['nombre'] ?? '');
              if (empty($nombre) || strlen($nombre) > 100) {
                  die("Error: Nombre obligatorio, máximo 100 caracteres.");
              }
              $nombre = htmlspecialchars($nombre);
              if ($this->modelo->crear($nombre)) {
                  header("Location: index.php?controlador=autor&accion=listar");
                  exit;
              } else {
                  die("Error al crear autor.");
              }
          }
      }
      ?>
    • Libro (controllers/LibroController.php):
      <?php
      require_once 'models/LibroModel.php';
      
      class LibroController {
          private $modelo;
      
          public function __construct($conexion) {
              $this->modelo = new LibroModel($conexion);
          }
      
          public function listar() {
              $libros = $this->modelo->listar();
              require 'views/libros_listar.php';
          }
      
          public function crear() {
              $autores = $this->modelo->getAutores();
              require 'views/libro_crear.php';
          }
      
          public function guardar() {
              $titulo = trim($_POST['titulo'] ?? '');
              $id_autor = intval($_POST['id_autor'] ?? 0);
              if (empty($titulo) || strlen($titulo) > 200) {
                  die("Error: Título obligatorio, máximo 200 caracteres.");
              }
              if ($id_autor <= 0) {
                  die("Error: Autor inválido.");
              }
              $titulo = htmlspecialchars($titulo);
              if ($this->modelo->crear($titulo, $id_autor)) {
                  header("Location: index.php?controlador=libro&accion=listar");
                  exit;
              } else {
                  die("Error al crear libro.");
              }
          }
      }
      ?>
    • Préstamo (controllers/PrestamoController.php):
      <?php
      require_once 'models/PrestamoModel.php';
      
      class PrestamoController {
          private $modelo;
      
          public function __construct($conexion) {
              $this->modelo = new PrestamoModel($conexion);
          }
      
          public function listar() {
              $prestamos = $this->modelo->listar();
              require 'views/prestamos_listar.php';
          }
      
          public function crear() {
              $libros = $this->modelo->getLibros();
              require 'views/prestamo_crear.php';
          }
      
          public function guardar() {
              $id_libro = intval($_POST['id_libro'] ?? 0);
              $fecha_prestamo = $_POST['fecha_prestamo'] ?? '';
              if ($id_libro <= 0) {
                  die("Error: Libro inválido.");
              }
              if (empty($fecha_prestamo) || !preg_match("/^\d{4}-\d{2}-\d{2}$/", $fecha_prestamo)) {
                  die("Error: Fecha de préstamo inválida (YYYY-MM-DD).");
              }
              if ($this->modelo->crear($id_libro, $fecha_prestamo)) {
                  header("Location: index.php?controlador=prestamo&accion=listar");
                  exit;
              } else {
                  die("Error al registrar préstamo.");
              }
          }
      }
      ?>
  4. Vistas:

    • Listar autores (views/autores_listar.php):
      <!DOCTYPE html>
      <html lang="es">
      <head>
          <meta charset="UTF-8">
          <title>Biblioteca - Autores</title>
          <link rel="stylesheet" href="assets/css/styles.css">
      </head>
      <body>
          <h1>Biblioteca</h1>
          <nav>
              <a href="index.php?controlador=autor&accion=listar">Autores</a> |
              <a href="index.php?controlador=libro&accion=listar">Libros</a> |
              <a href="index.php?controlador=prestamo&accion=listar">Préstamos</a>
          </nav>
          <h2>Lista de Autores</h2>
          <a href="index.php?controlador=autor&accion=crear">Añadir autor</a>
          <table>
              <tr><th>ID</th><th>Nombre</th></tr>
              <?php foreach ($autores as $autor): ?>
                  <tr>
                      <td><?php echo htmlspecialchars($autor['id']); ?></td>
                      <td><?php echo htmlspecialchars($autor['nombre']); ?></td>
                  </tr>
              <?php endforeach; ?>
          </table>
      </body>
      </html>
    • Listar libros (views/libros_listar.php):
      <!DOCTYPE html>
      <html lang="es">
      <head>
          <meta charset="UTF-8">
          <title>Biblioteca - Libros</title>
          <link rel="stylesheet" href="assets/css/styles.css">
      </head>
      <body>
          <h1>Biblioteca</h1>
          <nav>
              <a href="index.php?controlador=autor&accion=listar">Autores</a> |
              <a href="index.php?controlador=libro&accion=listar">Libros</a> |
              <a href="index.php?controlador=prestamo&accion=listar">Préstamos</a>
          </nav>
          <h2>Lista de Libros</h2>
          <a href="index.php?controlador=libro&accion=crear">Añadir libro</a>
          <table>
              <tr><th>ID</th><th>Título</th><th>Autor</th></tr>
              <?php foreach ($libros as $libro): ?>
                  <tr>
                      <td><?php echo htmlspecialchars($libro['id']); ?></td>
                      <td><?php echo htmlspecialchars($libro['titulo']); ?></td>
                      <td><?php echo htmlspecialchars($libro['autor']); ?></td>
                  </tr>
              <?php endforeach; ?>
          </table>
      </body>
      </html>
    • Listar préstamos (views/prestamos_listar.php):
      <!DOCTYPE html>
      <html lang="es">
      <head>
          <meta charset="UTF-8">
          <title>Biblioteca - Préstamos</title>
          <link rel="stylesheet" href="assets/css/styles.css">
      </head>
      <body>
          <h1>Biblioteca</h1>
          <nav>
              <a href="index.php?controlador=autor&accion=listar">Autores</a> |
              <a href="index.php?controlador=libro&accion=listar">Libros</a> |
              <a href="index.php?controlador=prestamo&accion=listar">Préstamos</a>
          </nav>
          <h2>Lista de Préstamos</h2>
          <a href="index.php?controlador=prestamo&accion=crear">Registrar préstamo</a>
          <table>
              <tr><th>ID</th><th>Libro</th><th>Fecha de Préstamo</th></tr>
              <?php foreach ($prestamos as $prestamo): ?>
                  <tr>
                      <td><?php echo htmlspecialchars($prestamo['id']); ?></td>
                      <td><?php echo htmlspecialchars($prestamo['titulo']); ?></td>
                      <td><?php echo htmlspecialchars($prestamo['fecha_prestamo']); ?></td>
                  </tr>
              <?php endforeach; ?>
          </table>
      </body>
      </html>
    • Crear autor (views/autor_crear.php):
      <!DOCTYPE html>
      <html lang="es">
      <head>
          <meta charset="UTF-8">
          <title>Biblioteca - Añadir Autor</title>
          <link rel="stylesheet" href="assets/css/styles.css">
          <script src="assets/js/validacion.js"></script>
      </head>
      <body>
          <h1>Biblioteca</h1>
          <nav>
              <a href="index.php?controlador=autor&accion=listar">Autores</a> |
              <a href="index.php?controlador=libro&accion=listar">Libros</a> |
              <a href="index.php?controlador=prestamo&accion=listar">Préstamos</a>
          </nav>
          <h2>Añadir Autor</h2>
          <form action="index.php?controlador=autor&accion=guardar" method="POST" onsubmit="return validarAutor()">
              <label>Nombre: <input type="text" name="nombre" id="nombre" required></label>
              <button type="submit">Guardar</button>
          </form>
      </body>
      </html>
    • Crear libro (views/libro_crear.php):
      <!DOCTYPE html>
      <html lang="es">
      <head>
          <meta charset="UTF-8">
          <title>Biblioteca - Añadir Libro</title>
          <link rel="stylesheet" href="assets/css/styles.css">
          <script src="assets/js/validacion.js"></script>
      </head>
      <body>
          <h1>Biblioteca</h1>
          <nav>
              <a href="index.php?controlador=autor&accion=listar">Autores</a> |
              <a href="index.php?controlador=libro&accion=listar">Libros</a> |
              <a href="index.php?controlador=prestamo&accion=listar">Préstamos</a>
          </nav>
          <h2>Añadir Libro</h2>
          <form action="index.php?controlador=libro&accion=guardar" method="POST" onsubmit="return validarLibro()">
              <label>Título: <input type="text" name="titulo" id="titulo" required></label>
              <label>Autor: 
                  <select name="id_autor" id="id_autor" required>
                      <option value="">Seleccione un autor</option>
                      <?php foreach ($autores as $autor): ?>
                          <option value="<?php echo $autor['id']; ?>">
                              <?php echo htmlspecialchars($autor['nombre']); ?>
                          </option>
                      <?php endforeach; ?>
                  </select>
              </label>
              <button type="submit">Guardar</button>
          </form>
      </body>
      </html>
    • Crear préstamo (views/prestamo_crear.php):
      <!DOCTYPE html>
      <html lang="es">
      <head>
          <meta charset="UTF-8">
          <title>Biblioteca - Registrar Préstamo</title>
          <link rel="stylesheet" href="assets/css/styles.css">
          <script src="assets/js/validacion.js"></script>
      </head>
      <body>
          <h1>Biblioteca</h1>
          <nav>
              <a href="index.php?controlador=autor&accion=listar">Autores</a> |
              <a href="index.php?controlador=libro&accion=listar">Libros</a> |
              <a href="index.php?controlador=prestamo&accion=listar">Préstamos</a>
          </nav>
          <h2>Registrar Préstamo</h2>
          <form action="index.php?controlador=prestamo&accion=guardar" method="POST" onsubmit="return validarPrestamo()">
              <label>Libro: 
                  <select name="id_libro" id="id_libro" required>
                      <option value="">Seleccione un libro</option>
                      <?php foreach ($libros as $libro): ?>
                          <option value="<?php echo $libro['id']; ?>">
                              <?php echo htmlspecialchars($libro['titulo']); ?>
                          </option>
                      <?php endforeach; ?>
                  </select>
              </label>
              <label>Fecha de Préstamo: <input type="date" name="fecha_prestamo" id="fecha_prestamo" required></label>
              <button type="submit">Guardar</button>
          </form>
      </body>
      </html>
  5. Estilos (assets/css/styles.css):

    body {
        font-family: Arial, sans-serif;
        max-width: 900px;
        margin: 0 auto;
        padding: 20px;
    }
    h1 { color: #333; }
    nav { margin-bottom: 20px; }
    nav a { margin-right: 10px; color: #007BFF; text-decoration: none; }
    nav a:hover { text-decoration: underline; }
    table { width: 100%; border-collapse: collapse; margin: 20px 0; }
    th, td { border: 1px solid #ccc; padding: 10px; text-align: left; }
    th { background-color: #f2f2f2; }
    form { margin: 20px 0; }
    label { display: block; margin: 10px 0; }
    input, select, textarea { width: 100%; padding: 8px; margin: 5px 0; }
    button {
        padding: 10px 20px;
        background-color: #007BFF;
        color: white;
        border: none;
        cursor: pointer;
    }
    button:hover { background-color: #0056b3; }
  6. JavaScript (opcional) (assets/js/validacion.js):

    • Validación en el cliente para formularios.
    function validarAutor() {
        const nombre = document.getElementById('nombre').value.trim();
        if (nombre === '') {
            alert('El nombre es obligatorio.');
            return false;
        }
        if (nombre.length > 100) {
            alert('El nombre no puede exceder 100 caracteres.');
            return false;
        }
        return true;
    }
    
    function validarLibro() {
        const titulo = document.getElementById('titulo').value.trim();
        const idAutor = document.getElementById('id_autor').value;
        if (titulo === '') {
            alert('El título es obligatorio.');
            return false;
        }
        if (titulo.length > 200) {
            alert('El título no puede exceder 200 caracteres.');
            return false;
        }
        if (idAutor === '') {
            alert('Seleccione un autor.');
            return false;
        }
        return true;
    }
    
    function validarPrestamo() {
        const idLibro = document.getElementById('id_libro').value;
        const fecha = document.getElementById('fecha_prestamo').value;
        if (idLibro === '') {
            alert('Seleccione un libro.');
            return false;
        }
        if (fecha === '') {
            alert('La fecha de préstamo es obligatoria.');
            return false;
        }
        return true;
    }
  7. Punto de entrada (index.php):

    • Enruta solicitudes a los controladores.
    <?php
    require_once 'config.php';
    require_once 'controllers/AutorController.php';
    require_once 'controllers/LibroController.php';
    require_once 'controllers/PrestamoController.php';
    
    $controladorNombre = $_GET['controlador'] ?? 'autor';
    $accion = $_GET['accion'] ?? 'listar';
    
    switch ($controladorNombre) {
        case 'autor':
            $controlador = new AutorController($conexion);
            break;
        case 'libro':
            $controlador = new LibroController($conexion);
            break;
        case 'prestamo':
            $controlador = new PrestamoController($conexion);
            break;
        default:
            $controlador = new AutorController($conexion);
    }
    
    switch ($accion) {
        case 'listar':
            $controlador->listar();
            break;
        case 'crear':
            $controlador->crear();
            break;
        case 'guardar':
            $controlador->guardar();
            break;
        default:
            $controlador->listar();
    }
    ?>
  8. README (README.md):

    • Instrucciones para ejecutar la aplicación.
    # Biblioteca Web
    
    Aplicación web para gestionar libros, autores y préstamos en una biblioteca, desarrollada con PHP, MySQL, HTML, CSS, y JavaScript (opcional).
    
    ## Requisitos
    - XAMPP o Laragon instalado (Apache, MySQL, PHP).
    - Navegador web (Chrome, Firefox, etc.).
    - Editor de texto (VS Code recomendado).
    
    ## Instalación
    1. Copiar la carpeta `biblioteca_app` a:
       - XAMPP: `C:\xampp\htdocs\biblioteca_app`
       - Laragon: `C:\laragon\www\biblioteca_app`
    2. Iniciar Apache y MySQL en XAMPP o Laragon.
    3. Crear la base de datos en phpMyAdmin (`http://localhost/phpmyadmin`):
       ```sql
       CREATE DATABASE biblioteca_db;
       USE biblioteca_db;
       CREATE TABLE autores (
           id INT AUTO_INCREMENT PRIMARY KEY,
           nombre VARCHAR(100) NOT NULL
       );
       CREATE TABLE libros (
           id INT AUTO_INCREMENT PRIMARY KEY,
           titulo VARCHAR(200) NOT NULL,
           id_autor INT NOT NULL,
           FOREIGN KEY (id_autor) REFERENCES autores(id)
       );
       CREATE TABLE prestamos (
           id INT AUTO_INCREMENT PRIMARY KEY,
           id_libro INT NOT NULL,
           fecha_prestamo DATE NOT NULL,
           FOREIGN KEY (id_libro) REFERENCES libros(id)
       );
       INSERT INTO autores (nombre) VALUES 
           ('Gabriel García Márquez'),
           ('Jane Austen');
       INSERT INTO libros (titulo, id_autor) VALUES 
           ('Cien años de soledad', 1),
           ('Orgullo y prejuicio', 2);
       INSERT INTO prestamos (id_libro, fecha_prestamo) VALUES 
           (1, '2025-04-20'),
           (2, '2025-04-21');
    1. Abrir en el navegador:
      • XAMPP: http://localhost/biblioteca_app
      • Laragon: http://biblioteca_app.test

    Funcionalidades

    • Listar autores, libros y préstamos.
    • Añadir nuevos autores, libros y préstamos mediante formularios.
    • Validación de entradas y prevención de inyección SQL.

    Estructura

    • /models: Clases PHP para lógica de datos (AutorModel.php, LibroModel.php, PrestamoModel.php).
    • /views: Archivos HTML/PHP para la interfaz.
    • /controllers: Clases PHP para manejar solicitudes.
    • /assets: CSS y JavaScript (validación opcional).
    • index.php: Punto de entrada.
    • config.php: Conexión a MySQL.

    Seguridad

    • Validación de entradas: Campos obligatorios, longitud máxima, formatos.
    • Consultas preparadas con mysqli para prevenir inyección SQL.
    • Escaping con htmlspecialchars() para evitar XSS.

    Pruebas

    • Listar: Verifica que se muestren autores, libros y préstamos.
    • Crear: Añade un autor, un libro, y un préstamo. Confirma redirección.
    • Seguridad: Prueba entradas inválidas (vacías, largas) y posibles inyecciones SQL.

    Notas

    • Usa DevTools (F12, pestaña "Red") para verificar solicitudes HTTP.
    • Revisa logs en C:\xampp\apache\logs o C:\laragon\logs si hay errores.

Cómo probarlo:

  1. Configuración:
    • Asegúrate de que XAMPP o Laragon esté corriendo (Apache y MySQL).
    • Crea la base de datos biblioteca_db y las tablas en phpMyAdmin.
    • Inserta los datos de prueba (SQL proporcionado).
    • Guarda los archivos en C:\xampp\htdocs\biblioteca_app (XAMPP) o C:\laragon\www\biblioteca_app (Laragon).
  2. Pruebas:
    • Abre http://localhost/biblioteca_app (XAMPP) o http://biblioteca_app.test (Laragon).
    • Listar:
      • Autores: Verifica que se muestren “Gabriel García Márquez” y “Jane Austen”.
      • Libros: Verifica “Cien años de soledad” y “Orgullo y prejuicio” con sus autores.
      • Préstamos: Verifica los préstamos con fechas.
      • Usa DevTools: Solicitudes GET, código 200 OK.
    • Crear:
      • Añade un autor (por ejemplo, “Mario Vargas Llosa”).
      • Añade un libro (por ejemplo, Título: “La ciudad y los perros”, Autor: “Mario Vargas Llosa”).
      • Registra un préstamo (por ejemplo, Libro: “La ciudad y los perros”, Fecha: “2025-04-22”).
      • Verifica redirección a las listas tras guardar.
      • Usa DevTools: Solicitudes POST, código 200 OK o 302 (redirección).
    • Seguridad:
      • Prueba entradas inválidas: Nombre vacío, título largo, fecha inválida → Mensajes de error.
      • Intenta inyección SQL (por ejemplo, Nombre: '; DROP TABLE autores; --) → Neutralizada por consultas preparadas.
  3. JavaScript (opcional):
    • Verifica que las alertas de validación aparezcan en el cliente si los campos están vacíos o son inválidos.

Flujo MVC:

  • Listar: GET → index.php?controlador=X&accion=listar → XController::listar() → XModel::listar() → X_listar.php.
  • Crear:
    • GET → index.php?controlador=X&accion=crear → XController::crear() → X_crear.php.
    • POST → index.php?controlador=X&accion=guardar → XController::guardar() → XModel::crear() → Redirige a listar.

Por qué es importante:

  • Integra frontend (Módulo 2, 3), backend (Módulo 4), base de datos (Módulo 5), y conceptos avanzados (Módulo 6).
  • Prepara para frameworks como Laravel, que usan MVC, POO, y ORM.

Punto clave: La aplicación biblioteca es una solución full-stack que demuestra habilidades completas de desarrollo web.


Documentación y entrega (2-3 horas)

Explicación:
El entregable es una aplicación funcional con un README claro y una carpeta bien organizada.

Entregable:

  • Carpeta del proyecto: biblioteca_app con todos los archivos (models, views, controllers, assets, index.php, config.php, README.md).
  • Base de datos: biblioteca_db con tablas y datos de prueba.
  • Documento README: Explica cómo instalar y ejecutar la aplicación.
  • Opcional: Capturas de pantalla de la aplicación (listas, formularios, phpMyAdmin).

Instrucciones para la entrega:

  1. Implementar:
    • Copia el código proporcionado en las carpetas correspondientes.
    • Configura la base de datos en phpMyAdmin.
    • Prueba todas las funcionalidades en XAMPP o Laragon.
  2. Documentar:
    • Usa el README.md proporcionado o crea uno propio.
    • Incluye:
      • Descripción del proyecto.
      • Instrucciones de instalación.
      • Funcionalidades implementadas.
      • Notas sobre seguridad y pruebas.
  3. Probar exhaustivamente:
    • Verifica cada funcionalidad (listar y crear para autores, libros, préstamos).
    • Prueba casos límite: Entradas vacías, formatos inválidos, inyecciones SQL.
    • Usa DevTools para confirmar solicitudes HTTP (GET, POST) y códigos de estado (200 OK, 302).
  4. Empaquetar:
    • Comprime la carpeta biblioteca_app (ZIP o RAR).
    • Incluye capturas de pantalla (opcional).
    • Entrega el archivo comprimido y cualquier documentación adicional.

Ejemplo de entrega:

  • Carpeta: biblioteca_app.zip.
  • README.md: Como se mostró arriba.
  • Capturas (opcional): Imágenes de la lista de libros, formulario de préstamo, y phpMyAdmin con las tablas.

Tiempo estimado:

  • Desarrollo: 15-20 horas (distribuidas en la semana).
  • Pruebas: 2-3 horas.
  • Documentación: 2-3 horas.

Consejo:

  • Divide el trabajo por días (ver planificación en la sección 2).
  • Prueba cada componente (modelo, controlador, vista) antes de integrarlos.
  • Usa los logs de XAMPP/Laragon para depurar errores (C:\xampp\apache\logs o C:\laragon\logs).

Punto clave: Un entregable completo y bien documentado refleja profesionalismo y dominio del curso.

© Copyright Cursos Laravel :: 2025 Términos y condiciones