MVC Master

Módulo 1: Arquitectura Base (BD, Conexión y UI)

Todo software millonario inicia ordenando la casa. Aquí fundaremos la Base de Datos Total, la Conexión Inteligente (POO Singleton) y el Layout (Plantilla UI) Universal con Bootstrap.

1. El Diccionario Relacional (MySQL)

Ve a PHPMyAdmin en tu WAMP local y ejecuta esta estructura maestra completa.

$ MySQL Server
CREATE DATABASE academia_mvc;
USE academia_mvc;

CREATE TABLE usuarios (
    id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100), correo VARCHAR(50) UNIQUE,
    password VARCHAR(255), rol VARCHAR(20) DEFAULT 'ADMINISTRADOR'
);
-- 1. Insertamos Super-Admin (El hash significa "123")
INSERT INTO usuarios (nombre, correo, password) VALUES ('Súper Admin', 'admin@admin.com', '$2y$10$fV8g5Qv5J6O2HhS5aX.UaenM0TIt7D5qE/x1x2k/kP636R5Zk4wz2');

CREATE TABLE estudiantes (
    id INT AUTO_INCREMENT PRIMARY KEY, matricula VARCHAR(20) UNIQUE, nombre VARCHAR(100), correo VARCHAR(50)
);

CREATE TABLE profesores (
    id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100), especialidad VARCHAR(100)
);

CREATE TABLE cursos ( -- Relacion 1:N (1 Profe con Varios Cursos)
    id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100),
    id_profesor INT, FOREIGN KEY (id_profesor) REFERENCES profesores(id) ON DELETE CASCADE
);

CREATE TABLE matriculas ( -- Relacion N:M (El Estudiante puede entrar a Muchos Cursos)
    id_estudiante INT, id_curso INT, PRIMARY KEY (id_estudiante, id_curso),
    FOREIGN KEY (id_estudiante) REFERENCES estudiantes(id) ON DELETE CASCADE,
    FOREIGN KEY (id_curso) REFERENCES cursos(id) ON DELETE CASCADE
);

2. La Conexión Irrompible a la BD (PDO Singleton)

Jamás debes escribir las claves de usuario de la DB en cada archivo mvc. Los profesionales hacen 1 archivo con patrón Singleton para reutilizar la conexión RAM sin saturar al servidor y usando anti-inyecciones `\PDO`.

app/Core/Database.php
<?php
namespace App\Core;

class Database {
    private static $instance = null;
    private $pdo;

    private function __construct() {
        try {
            $this->pdo = new \PDO("mysql:host=localhost;dbname=academia_mvc;charset=utf8", "root", "");
            $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        } catch (\PDOException $e) { die("MySQL Crash: " . $e->getMessage()); }
    }

    public static function getInstance() {
        if (self::$instance === null) { self::$instance = new Database(); }
        return self::$instance->pdo;
    }
}

3. Recursos Locales y el Layout HTML (Bootstrap 5)

En MVC no escribimos 50 veces <!DOCTYPE html>. Programamos el Menú Visual (El Layout) solo 1 vez e inyectamos a PHP en el medio. Para que el proyecto funcione en velocidad máxima (y sin internet), descarga las dependencias y organízalas en tu WAMP.

3.2: Ubicar así en tu Proyecto:
📁 tu_proyecto/
  📁 assets/
    📁 css/
      📄 bootstrap.min.css
      📄 sweetalert2.min.css
    📁 js/
      📄 bootstrap.bundle.min.js
      📄 sweetalert2.all.min.js
Teniendo esos archivos en tus carpetas, crea este HTML en: app/Views/layout/main.php
<!DOCTYPE html>
<html lang="es" data-bs-theme="light">
<head>
    <meta charset="UTF-8"><title><?= $titulo ?? 'Sistema MVC' ?></title>
    <!-- Conectamos las Carpetas Locales de arriba! -->
    <link href="/tu_proyecto/assets/css/bootstrap.min.css" rel="stylesheet">
    <link href="/tu_proyecto/assets/css/sweetalert2.min.css" rel="stylesheet">
</head>
<body class="bg-light text-dark">
    
    <!-- Un simple Nav Bar Master -->
    <nav class="navbar navbar-dark bg-dark mb-4 px-4 shadow">
        <a class="navbar-brand fw-bold" href="/">🚀 Sistema Universitario MVC</a>
        
        <?php if(isset($_SESSION['usuario_rol'])): ?>
            <div class="text-white">👤 <?= $_SESSION['usuario_nombre'] ?> <a href="/logout" class="btn btn-sm btn-danger ms-3">Salir</a></div>
        <?php endif; ?>
    </nav>

    <!-- AQUI OCURRE LA MAGIA DEL CONTENEDOR (Lo que cambian son las Vistas hijas) -->
    <main class="container mb-5">
        <?php 
           // Inyectar los HTMLs hijos si el controlador lo pide
           if(isset($view) && file_exists("app/Views/{$view}.php")) {
               require_once "app/Views/{$view}.php";
           }
        ?>
    </main>

    <!-- Los JS que van siempre al fondo del body! -->
    <script src="/tu_proyecto/assets/js/bootstrap.bundle.min.js"></script>
    <script src="/tu_proyecto/assets/js/sweetalert2.all.min.js"></script>
</body>
</html>