Skip to content

Unidad 4: Patrón MVC

4.4 Controlador Frontal (Front Controller)

4.4.1 ¿Qué es el patrón MVC?

El patrón Modelo-Vista-Controlador (MVC) es una arquitectura de software ampliamente utilizada en el desarrollo de aplicaciones web. Separa las responsabilidades de una aplicación en tres componentes distintos:

  • Modelo: Representa los datos y la lógica de negocio de la aplicación. Es responsable de interactuar con la base de datos y devolver los datos procesados.
  • Vista: Se encarga de la presentación, mostrando los datos al usuario de manera estructurada y visual. La Vista recibe los datos del Controlador y los muestra.
  • Controlador: Actúa como intermediario entre el Modelo y la Vista, gestionando las interacciones del usuario. El Controlador recibe las solicitudes del usuario, interactúa con el Modelo para obtener o modificar los datos, y luego actualiza la Vista con los resultados.

4.4.2 ¿Qué es un Controlador Frontal?

El Controlador Frontal es un único punto de entrada para todas las solicitudes de la aplicación. En lugar de permitir que cada archivo PHP maneje directamente una solicitud, el Controlador Frontal se encarga de canalizar todas las solicitudes hacia los controladores específicos correspondientes.

Este patrón es muy útil porque centraliza el manejo de rutas y solicitudes, mejorando tanto la seguridad como la escalabilidad de la aplicación. Todos los accesos a la aplicación deben pasar a través de este controlador, lo que garantiza que la lógica de la aplicación se maneje de manera consistente y ordenada.

4.4.3 Ventajas de implementar un Controlador Frontal

  • Seguridad: Se evita que los usuarios accedan directamente a archivos sensibles (como controladores o vistas) sin pasar por la validación del controlador frontal. Esto aumenta la seguridad de la aplicación.
  • Escalabilidad: Al tener un único punto de entrada, es más fácil escalar la aplicación añadiendo nuevas rutas o controladores sin afectar el flujo general.
  • Mantenimiento: Facilita el mantenimiento de la aplicación, ya que todo el flujo de control está centralizado, lo que hace que la administración de las rutas sea más sencilla.

Diagrama de flujo básico con Controlador Frontal

A continuación, un gráfico que ilustra cómo interactúan el Controlador Frontal, el Modelo, la Vista y el Controlador de Empleados (en este caso, veremos cómo se maneja la acción de ver empleados).

graph TD
    A[Usuario] --> B["Controlador Frontal (index.php)"]
    B --> C[Controlador de Empleados]
    C --> D[Modelo de Empleados]
    D --> E[Base de Datos]
    C --> F[Vista de Empleados]
    F --> A

    C -->|VerEmpleados| C1
    C1 --> C2

    subgraph VerEmpleados
        C1[Obtener lista de empleados]
        C2[Mostrar empleados en tabla]
    end

Explicación del Diagrama (Ver Empleados):

  1. El Usuario realiza una acción, por ejemplo, hacer clic en "Ver empleados".
  2. Controlador Frontal (index.php) recibe la solicitud. Este es el punto de entrada para todas las solicitudes.
  3. El Controlador Frontal pasa la solicitud al Controlador de Empleados (si la solicitud está relacionada con los empleados).
  4. El Controlador de Empleados interactúa con el Modelo de Empleados, que se comunica con la Base de Datos para obtener la información.
  5. Los datos obtenidos son enviados a la Vista de Empleados, que los muestra al Usuario.

Ahora podemos ver un flujo básico de cómo se manejan las solicitudes en una aplicación que sigue el patrón MVC con un Controlador Frontal. Por ejemplo el caso de uso de: Modificar empleado.

graph TD
    A[Usuario] --> B["Controlador Frontal (index.php)"]
    B --> C[Controlador de Empleados]
    C --> D[Modelo de Empleados]
    D --> E[Base de Datos]
    C --> F[Vista de Empleados]
    F --> A

    C -->|"modificarEmpleado"| C1
    C1 --> C2
    C2 --> C3

    subgraph "ModificarEmpleado"
        C1[Obtener datos del empleado]
        C2[Mostrar formulario de edición]
        C3[Actualizar empleado en la base de datos]
    end

Explicación del Diagrama (Modificar Empleado):

  1. El Usuario realiza una acción, por ejemplo, hacer clic en "Modificar empleado".
  2. Controlador Frontal (index.php) recibe la solicitud. Este es el punto de entrada para todas las solicitudes.
  3. El Controlador Frontal pasa la solicitud al Controlador de Empleados (si la solicitud está relacionada con los empleados).
  4. El Controlador de Empleados interactúa con el Modelo de Empleados, que se comunica con la Base de Datos para obtener la información del empleado a modificar.
  5. Los datos obtenidos son enviados a la Vista de Empleados, que muestra un formulario para editar los datos del empleado.
  6. Una vez que el usuario completa el formulario y lo envía, la solicitud vuelve al Controlador Frontal.
  7. El Controlador Frontal pasa la solicitud al Controlador de Empleados, que actualiza los datos del empleado en la Base de Datos.
  8. Finalmente, el Controlador de Empleados redirige al usuario a la Vista de Empleados, que muestra la lista actualizada de empleados.
  9. El flujo se completa y el usuario ve la lista de empleados actualizada.

4.4.4 Modificación de la Estructura de la Aplicación

Objetivo:

Modificar la estructura de la aplicación de acuerdo con el patrón MVC y el Controlador Frontal. Vamos a asegurarnos de que todos los requests de la web pasen por el Controlador Frontal y que no sea posible acceder directamente a los scripts de Modelo, Vista, Controladores o formularios sin pasar por el controlador.

Pasos para Modificar la Estructura de la Aplicación

  1. Crear una estructura de rutas para la aplicación: Configuraremos el Controlador Frontal para redirigir correctamente las solicitudes a sus respectivos controladores y vistas.
  2. Redirigir solicitudes no autorizadas: Asegurarnos de que cualquier intento de acceder a archivos directamente (como el modelo o los controladores) sea redirigido a index.php.
  3. Configurar el controlador principal: Establecer que index.php sea el único punto de entrada, y a partir de ahí dirigir todas las solicitudes.

1. Redirigir todas las solicitudes a index.php

Ahora, vamos a asegurarnos de que no se pueda acceder directamente a los modelos, controladores o vistas sin pasar por index.php, que es el controlador frontal. Este archivo se encargará de gestionar todas las rutas de la aplicación.

Código para redirigir todas las solicitudes a index.php:

En primer lugar, debemos asegurarnos de que los usuarios no puedan acceder directamente a archivos PHP como el modelo, controlador, vistas, etc. Solo se podrá acceder a través de las rutas definidas en index.php.

Para ello, podemos incluir un archivo común que verifique si se está accediendo directamente a un archivo PHP y redirigir al index.php.

Crear un archivo común para validaciones de acceso: verificarAcceso.php

Este archivo será incluido en los archivos PHP que no deberían ser accesibles directamente. Este archivo lo podemos crear en la carpeta lib, donde iremos metiendo aquellos archivos comunes que necesitemos incluir en varios sitios.

Código de verificarAcceso.php:

Verificar acceso a archivos PHP

Este archivo se encargará de verificar si la solicitud proviene directamente de un archivo PHP (es decir, no a través del controlador frontal) y redirigir a index.php.

1
2
3
4
5
6
7
<?php
// Verificar si la solicitud proviene directamente de un archivo PHP (es decir, no a través del controlador frontal)
if (basename($_SERVER['PHP_SELF']) != 'index.php') {
    header('Location: /index.php');  // Redirigir a la página de inicio
    exit;
}
?>

Incluir verificarAcceso.php en el inicio de cada archivo sensible:

Por ejemplo, en el archivo empleados.php, que es una vista que debería ser accesible solo a través del Controlador Frontal, añadimos esta validación:

Incluir verificarAcceso.php en archivos sensibles

Asegúrate de incluir el archivo verificarAcceso.php al inicio de todos los archivos sensibles de la aplicación (modelos, controladores, vistas, etc.) para evitar accesos no autorizados.

1
2
3
4
<?php
// Incluir el archivo de verificación de acceso
include __DIR__ . '../lib/verificarAcceso.php';  // Esto asegura que solo se acceda a este archivo a través de index.php
?>

Nota: Asegúrate de incluir el archivo verificarAcceso.php al inicio de todos los archivos sensibles de la aplicación (modelos, controladores, vistas, etc.) para evitar accesos no autorizados. Esto garantiza que cualquier intento de acceder directamente a estos archivos sea redirigido al Controlador Frontal. Ten en cuenta utilizar la ruta relativa correcta al incluir el archivo, dependiendo de la ubicación de los archivos en tu estructura de directorios.

__ DIR __

Nota

  • __DIR__ es una constante mágica de PHP que devuelve el directorio del archivo actual. Esto es útil para construir rutas relativas de manera segura, sin importar desde dónde se ejecute el script.

Este proceso debe repetirse para todos los archivos sensibles de la aplicación (vistas, controladores, etc.).

2. Redirigir solicitudes a index.php

El archivo index.php será el punto de entrada de nuestra aplicación. Aquí vamos a gestionar todas las solicitudes y dirigirlas a los controladores correspondientes.

Código de index.php:

Código de index.php

Este archivo será el punto de entrada de la aplicación y redirigirá todas las solicitudes al Controlador Principal.

<?php
// Iniciar la sesión si es necesario (para manejar autenticación, si es el caso)
session_start();

// Incluir el controlador principal
include 'controlador/ControladorPrincipal.php';

// Crear una instancia del controlador principal
$controladorPrincipal = new ControladorPrincipal();

// Obtener la acción de la URL (puede ser: ver_empleados, editar_empleado, etc.)
$accion = isset($_GET['accion']) ? $_GET['accion'] : 'inicio';

// Llamar al método que maneja la solicitud según la acción
$controladorPrincipal->manejarSolicitud($accion);
?>

Explicación:

  • index.php ahora es el punto único de entrada para todas las solicitudes.
  • ControladorPrincipal se encarga de canalizar las solicitudes, redirigiendo a los controladores correspondientes (en este caso, empleados, departamentos, etc.).
  • Si el parámetro accion no se pasa en la URL, se redirige a la acción por defecto (por ejemplo, inicio).

3. Controlador Principal (Front Controller)

El Controlador Principal es el responsable de gestionar las solicitudes y redirigirlas a los controladores adecuados. Este controlador puede incluir la lógica de negocio común, como la autenticación y la autorización, y luego delegar las solicitudes específicas a otros controladores.

Código de ControladorPrincipal.php:

Código de ControladorPrincipal.php

Este archivo contiene la lógica del Controlador Principal que redirige las solicitudes a los controladores específicos.

<?php

// Incluir los controladores específicos
include '../controlador/EmpleadoControlador.php';

// Controlador principal que dirige las solicitudes
class ControladorPrincipal {

    // Maneja las solicitudes
    public function manejarSolicitud($accion) {
        switch ($accion) {
            case 'ver_empleados':
                // Mostrar empleados
                $controlador = new EmpleadoControlador();
                $controlador->verEmpleados();
                die();
                break;
            case 'editar_empleado':
                // Editar empleado
                if (isset($_GET['id'])) {
                    $emp_id = $_GET['id'];
                    $controlador = new EmpleadoControlador();
                    $controlador->verEmpleado($emp_id);
                }
                die();
                break;
            case 'agregar_empleado':
                // Agregar empleado
                $controlador = new EmpleadoControlador();
                $controlador->verEmpleado(-1);
                die();
                break;
            case 'eliminar_empleado':
                // Eliminar empleado
                if (isset($_GET['id'])) {
                    $emp_id = $_GET['id'];
                    $controlador = new EmpleadoControlador();
                    $controlador->eliminarEmpleado($emp_id);
                }
                header('Location: index.php?accion=ver_empleados');
                die();
                break;
            case 'inicio':
                break;
            default:
                // Redirigir a la página de inicio si no se encuentra la acción
                header('Location: index.php');
                die();
                exit;
        }
    }
}
?>

Explicación:

  • ControladorPrincipal recibe la acción de la URL y decide qué controlador debe ejecutar.
  • Si la acción no es válida, redirige al index.php para evitar accesos no autorizados.

Resumen de lo realizado en este punto:

  1. Redirigir solicitudes no válidas: Hemos creado un archivo verificarAcceso.php que asegura que todos los accesos sean dirigidos al Controlador Frontal (index.php). De esta forma, cualquier intento de acceder directamente a archivos como modelos, controladores o vistas es redirigido automáticamente a la página de inicio.
  2. Controlador Frontal (index.php): Este archivo es el punto de entrada de la aplicación y redirige todas las solicitudes al ControladorPrincipal, que maneja la lógica de las rutas.
  3. Controlador Principal: El Controlador Principal gestiona todas las solicitudes (acciones del usuario) y las redirige a los controladores específicos según la acción solicitada (ver, agregar, editar, eliminar empleados).

4.4.5 Modificación de los controladores vistas y formularios

Ahora ya no queremos que los usuarios accedan directamente a las vistas, así que tendremos que modificar el controlador de empleados para que se encargue de mostrar la vista correspondiente dependiendo de la accion utilizada por el susuario.

Por ejemplo para ver empleados esta era la función del controlador:

public function verEmpleados($pagina = 1) {
    return $this->modelo->obtenerEmpleados($pagina);
}
En este caso la función devuelve la lista de empleados (según la página selaccionada). Ahora nosotros queremos que esta función se encargue también de mostrar la vista correspondiente, de esta manera el controlador frontal solo tendrá que llamar a esta función cuando el usuario quiera ver la lista de empleados.

1
2
3
4
5
 public function verEmpleados($pagina = 1) {
    $empleados = $this->modelo->obtenerEmpleados($pagina);
    include "./vista/empleados.php";
    return 0;
    }

En este caso la función carga los empleados en una variable $empleados y luego carga el script de la vista. Pero si ahora revisamos el script de la vista veremos que en la vista era cuando cargabamos el controlador de empleados (mal), eso ahora ya no queremos que funcione así. Ahora cuando se carga la vista ya hemos cagado previamente el controlador. La vista debe quedar así:

Vista de empledados

<?php
// Comprobar si el usuario proviene de la página de inicio
include __DIR__ . '/../lib/access.php';
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Empleados</title>
</head>
<body>
    <h1>Lista de Empleados</h1>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Nombre</th>
                <th>Apellido</th>
                <th>Fecha de Nacimiento</th>
                <th>Fecha de Contratación</th>
                <th>Género</th>
                <th>Acciones</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($empleados as $empleado): ?>
            <tr>
                <td><?= $empleado['emp_no'] ?></td>
                <td><?= $empleado['first_name'] ?></td>
                <td><?= $empleado['last_name'] ?></td>
                <td><?= $empleado['birth_date'] ?></td>
                <td><?= $empleado['hire_date'] ?></td>
                <td><?= $empleado['gender'] ?></td>
                <td>
                    <a href="index.php?accion=editar_empleado&id=<?= $empleado['emp_no'] ?>">Editar</a>
                    <button onclick="eliminarEmpleado(<?= $empleado['emp_no']?>);" >Eliminar</button>
                </td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
    <a href="index.php?accion=agregar_empleado">Agregar Nuevo Empleado</a>
    <script>
        function eliminarEmpleado(emp_no) {
            if (confirm('¿Estás seguro de que deseas eliminar este empleado?')) {
                window.location.href = `index.php?accion=eliminar_empleado&id=${emp_no}`;
            }
        }
    </script>
</body>
</html>

En este escrip hay qye ver que ha diferentes modificaciones:

Los botones de accciones se han modificado para que pasen por el controlador frontal.

  • editar:

        <a href="index.php?accion=editar_empleado&id=<?= $empleado['emp_no'] ?>">Editar</a>
    

  • eliminar

    <button onclick="eliminarEmpleado(<?= $empleado['emp_no']?>);" >Eliminar</button>
    ...
    ...
    <script>
        function eliminarEmpleado(emp_no) {
            if (confirm('¿Estás seguro de que deseas eliminar este empleado?')) {
                window.location.href = `index.php?accion=eliminar_empleado&id=${emp_no}`;
            }
           }
    </script>
    

  • crear

        <a href="index.php?accion=agregar_empleado">Agregar Nuevo Empleado</a>
    

Pero claro, estos cambios también obligan a reescribir los formularios ya que estos también serán cargados pasando por el controlador frontal y llamandolos directamente desde las vistas.

Así quedará el formulario de empleados:

Formulario de empleados

?php

include __DIR__ . '/../lib/access.php';

$modo = 'editar';
if (is_null($controlador)) $modo = 'crear';


// Si se recibe un formulario POST, procesar la creación o actualización
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    // Obtener los datos del formulario
    $nombre = $_POST['nombre'];
    $apellido = $_POST['apellido'];
    $fecha_nacimiento = $_POST['fecha_nacimiento'];
    $fecha_contratacion = $_POST['fecha_contratacion'];
    $genero = $_POST['genero'];

    if ($modo == 'editar') {
        // Actualizar el empleado
        $controlador->editarEmpleado($emp_id, $nombre, $apellido, $fecha_nacimiento, $fecha_contratacion, $genero);
    } else if ($modo == 'crear') {
        // Crear un nuevo empleado
        $controlador->agregarEmpleado($nombre, $apellido, $fecha_nacimiento, $fecha_contratacion, $genero);
    } else {
        $controlador->eliminarEmpleado($emp_id);
    }

    // Redirigir a la lista de empleados
    header('Location: index.php?accion=ver_empleados');
    exit;
}
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Formulario Empleado</title>
</head>
<body>
    <h1><?= $modo != 'editar' ? 'Nuevo' : 'Editar' ?> Empleado</h1>
    <form method="POST">
        <label for="nombre">Nombre:</label>
        <input type="text" name="nombre" value="<?= $empleado['first_name'] ?? '' ?>" required><br>

        <label for="apellido">Apellido:</label>
        <input type="text" name="apellido" value="<?= $empleado['last_name'] ?? '' ?>" required><br>

        <label for="fecha_nacimiento">Fecha de Nacimiento:</label>
        <input type="date" name="fecha_nacimiento" value="<?= $empleado['birth_date'] ?? '' ?>" required><br>

        <label for="fecha_contratacion">Fecha de Contratación:</label>
        <input type="date" name="fecha_contratacion" value="<?= $empleado['hire_date'] ?? '' ?>" required><br>

        <label for="genero">Género:</label>
        <select name="genero" required>
            <option value="M" <?= isset($empleado['gender']) && $empleado['gender'] == 'M' ? 'selected' : '' ?>>Masculino</option>
            <option value="F" <?= isset($empleado['gender']) && $empleado['gender'] == 'F' ? 'selected' : '' ?>>Femenino</option>
        </select><br>

        <button type="submit">Guardar</button>
        <a href="index.php?accion=ver_empleados">Cancelar</a>
    </form>
</body>
</html>

Y ya para terminar, y teniendo en cuenta el uso de la superglobal __DIR__ también hemos hecho una modificación en el modelo de empleados, quedando el encabezamiento como sigue:

modificaciones modelo de empleados

<?php
// protección acceso sin pasar por el controlador  frontal

include __DIR__ . "/../lib/access.php";

// Incluir el archivo de conexión a la base de datos

include __DIR__ . "/../lib/bd.php";
...

4.4.6 Plan para la Página de Landing

En este punto, vamos a enfocarnos en crear una página de landing (página de inicio) con un menú básico. Desde esta página, los usuarios podrán acceder a la sección de Empleados y otras áreas (aunque, por ahora, solo funcionarán Inicio y Empleados). Además, se implementará un sistema de redirección para asegurar que todas las solicitudes (acciones CRUD) pasen por el Controlador Principal (Front Controller), garantizando que toda la lógica de la aplicación pase por un único punto de control.

Objetivos de este punto:

  1. Crear una página de landing con un menú de navegación accesible para todos los usuarios.
  2. Asegurarnos de que todas las solicitudes (CRUD) de la aplicación pasen siempre por el Controlador Principal.

Creación de la Página de Landing

Objetivo:

Crear una página de bienvenida o landing que sirva como punto de entrada para el usuario. Esta página incluirá un menú de navegación con enlaces a las secciones de la aplicación, como Empleados, Departamentos, Contacto, etc. De momento, las secciones de Empleados y Inicio serán las únicas activas.

Estructura de la Página de Landing:

La página debe contener lo siguiente:

  • Cabecera con el menú de navegación.
  • Contenido central con un mensaje de bienvenida.
  • Pie de página con información adicional como derechos de autor.

Código de la Página de Landing (index.php)

<?php
// Iniciar la sesión
session_start();

// Incluir el controlador principal
include 'controlador/ControladorPrincipal.php';

// Crear una instancia del controlador principal
$controladorPrincipal = new ControladorPrincipal();

// Obtener la acción de la URL (puede ser: ver_empleados, editar_empleado, etc.)
$accion = isset($_GET['accion']) ? $_GET['accion'] : 'inicio';  // Acción predeterminada: inicio

// Llamar al método que maneja la solicitud según la acción
$controladorPrincipal->manejarSolicitud($accion);
?>


<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Página de Inicio - Sistema de Gestión</title>
    <link rel="stylesheet" href="estilos.css"> <!-- Aquí se incluirán tus estilos -->
</head>
<body>

    <!-- Cabecera -->
    <header>
        <nav>
            <ul>
                <li><a href="index.php?accion=inicio">Inicio</a></li>
                <li><a href="index.php?accion=ver_empleados">Empleados</a></li>
                <li><a href="index.php?accion=ver_departamentos">Departamentos</a></li>
                <li><a href="index.php?accion=contacto">Contacto</a></li>
                <!-- Si el usuario no está logueado, mostramos el enlace al login -->
                <?php if (!isset($_SESSION['usuario'])): ?>
                    <li><a href="login.php">Login</a></li>
                <?php else: ?>
                    <li><a href="logout.php">Cerrar sesión</a></li>
                <?php endif; ?>
            </ul>
        </nav>
    </header>

    <!-- Cuerpo principal de la página -->
    <main>
        <section id="bienvenida">
            <h1>Bienvenido al Sistema de Gestión de Empleados</h1>
            <p>Desde esta página, puedes gestionar empleados, departamentos y más.</p>
            <p>Selecciona una opción del menú para empezar.</p>
        </section>
    </main>

    <!-- Pie de página -->
    <footer>
        <p>&copy; 2025 Sistema de Gestión</p>
    </footer>

</body>
</html>

Explicación:

  1. Menú de navegación: El menú tiene enlaces a las secciones Inicio, Empleados, Departamentos y Contacto. Si el usuario no está autenticado, se muestra un enlace para iniciar sesión.
  2. Contenido central: Contiene un mensaje de bienvenida y una descripción de las funcionalidades de la aplicación.
  3. Pie de página: Información adicional (por ejemplo, derechos de autor).

Canalizar las Solicitudes a través del Controlador Principal

Ahora que tenemos la página de landing creada, debemos asegurarnos de que todas las solicitudes (acciones CRUD) pasen por el Controlador Principal. Esto significa que en lugar de acceder directamente a archivos como crear_editar_empleado.php o eliminar.php, redirigiremos todas las solicitudes a index.php. Este punto ya debe haber sido implmentado en el controlador frontal, pero lo repetimos para asegurarnos de que no se nos olvide.

también es el momento de asegurarnos que no hat llamadas a los controladores desde las vistas, ya que ahora el controlador frontal se encargará de cargar las vistas y los controladores. Por lo tanto, en la vista de empleados no cargaremos el controlador de empleados, sino que lo haremos desde el controlador frontal.


Modificación de ControladorPrincipal.php para Manejar las Solicitudes

El Controlador Principal se encargará de canalizar las solicitudes hacia el Controlador de Empleados o cualquier otro controlador que se necesite.

Lo mismo que hicimos en el punto anterior, esto ya debe estar implementado pero nos aseguramos de que el controlador frontal se encargue de redirigir las solicitudes a los controladores correspondientes.

Explicación:

  • El Controlador Principal maneja las solicitudes y redirige al Controlador de Empleados para realizar las acciones correspondientes.
  • Si la acción no es válida, redirige al index.php.

Resumen:

  1. Página de Landing (index.php): Hemos creado una página de bienvenida con un menú de navegación. La página también incluye enlaces para iniciar sesión y navegar a otras secciones.
  2. Redirección de solicitudes: En lugar de acceder directamente a archivos como crear_editar_empleado.php o eliminar.php, redirigimos todas las solicitudes a index.php para que pasen por el Controlador Frontal.
  3. Controlador Frontal (index.php): Este archivo ahora es el único punto de entrada para todas las solicitudes. Canaliza las acciones a los controladores adecuados.

4.4.7. Pasos para la implementación de la autenticación:

  1. Crear un archivo JSON con usuarios y contraseñas.
  2. Crear una clase de autenticación en PHP que valide los usuarios.
  3. Crear la página de inicio de sesión (login.php) que permita a los usuarios ingresar sus credenciales.
  4. Redirigir a la página de empleados si el usuario se autentica correctamente, y redirigir a login.php si no se autentica.

1. Crear el archivo JSON con usuarios y contraseñas

Empezamos creando un archivo usuarios.json que contendrá las credenciales de los usuarios. Este archivo contendrá los nombres de usuario y las contraseñas cifradas (por ahora usaremos contraseñas en texto claro para simplificar).

Contenido de usuarios.json

Este archivo contendrá un array de objetos, donde cada objeto representa un usuario con su nombre de usuario y contraseña.

{
    "usuarios": [
        {
            "username": "admin",
            "password": "1234"
        },
        {
            "username": "user1",
            "password": "password1"
        }
    ]
}

  • Formato JSON: Almacenamos un array con objetos, donde cada objeto tiene un nombre de usuario (username) y una contraseña (password).

2. Crear la clase de autenticación (Autenticacion.php)

La clase Autenticacion se encargará de validar las credenciales de los usuarios. Recibirá el nombre de usuario y la contraseña, y verificará si coinciden con los datos en el archivo usuarios.json.

Código de Autenticacion.php

Este archivo contiene la clase Autenticacion que valida las credenciales de los usuarios.

<?php
class Autenticacion {

    // Función para validar las credenciales de usuario
    public function validarUsuario($username, $password) {
        // Leer el archivo JSON con los usuarios
        $usuarios = json_decode(file_get_contents('usuarios.json'), true);

        // Buscar el usuario en el archivo JSON
        foreach ($usuarios['usuarios'] as $usuario) {
            if ($usuario['username'] === $username && $usuario['password'] === $password) {
                return true;  // Usuario encontrado y contraseña correcta
            }
        }

        return false;  // Credenciales incorrectas
    }
}
?>

Explicación:

  1. validarUsuario(): Esta función recibe un nombre de usuario y una contraseña, y busca en el archivo usuarios.json si las credenciales coinciden.
  2. json_decode(): Decodifica el contenido del archivo JSON para convertirlo en un array PHP.
  3. Si las credenciales son correctas, devuelve true, de lo contrario devuelve false.

3. Crear la página de inicio de sesión (login.php)

La página de inicio de sesión permitirá a los usuarios ingresar sus credenciales (nombre de usuario y contraseña). Al validar las credenciales, redirigirá al usuario a la página de empleados si es exitoso, o mostrará un mensaje de error si la validación falla.

Código de login.php

Este archivo contiene el formulario de inicio de sesión y la lógica para validar las credenciales.

<?php
session_start();  // Iniciar sesión

// Incluir la clase de autenticación
include 'Autenticacion.php';

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    // Obtener los datos del formulario
    $usuario = $_POST['usuario'];
    $contraseña = $_POST['contraseña'];

    // Crear una instancia de la clase de autenticación
    $autenticacion = new Autenticacion();

    // Validar las credenciales
    if ($autenticacion->validarUsuario($usuario, $contraseña)) {
        // Guardar el usuario en la sesión
        $_SESSION['usuario'] = $usuario;

        // Redirigir al usuario a la página de empleados
        header('Location: empleados.php');
        exit;
    } else {
        $error = "Credenciales incorrectas. Por favor, intente de nuevo.";
    }
}
?>

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Inicio de sesión</title>
</head>
<body>

    <h1>Inicio de sesión</h1>

    <?php if (isset($error)): ?>
        <p style="color: red;"><?= $error ?></p>
    <?php endif; ?>

    <form method="POST">
        <label for="usuario">Usuario:</label>
        <input type="text" name="usuario" required><br>

        <label for="contraseña">Contraseña:</label>
        <input type="password" name="contraseña" required><br>

        <button type="submit">Iniciar sesión</button>
    </form>

</body>
</html>

Explicación:

  1. Formulario de inicio de sesión: El formulario solicita nombre de usuario y contraseña.
  2. Validación: Cuando el formulario se envía, la clase Autenticacion se encarga de validar las credenciales.
  3. Si las credenciales son correctas, el nombre de usuario se guarda en $_SESSION['usuario'], y el usuario es redirigido a la página empleados.php.
  4. Si las credenciales son incorrectas, muestra un mensaje de error.

4. Crear el script de logout

Vamos a crear el script de logout que se encargará de cerrar la sesión del usuario. Este script eliminará la variable de sesión que contiene el nombre de usuario y redirigirá al usuario a la página de inicio de sesión.

Código de logout.php

Este archivo cierra la sesión del usuario y lo redirige a la página de inicio de sesión.

<?php
session_start();  // Iniciar sesión

// Destruir la sesión
session_destroy();

// Redirigir al usuario a la página de inicio
header("Location: index.php?accion=inicio");
exit;
?>

Controlador frontal: Impedir acceso a la páginas sin autenticación.

Para impedir que algún usuario acceda a la página de empleados sin haber iniciado sesión, vamos a incluir un script de verificación al inicio de la página de empleados. Este script verificará si el usuario está autenticado y, si no lo está, lo redirigirá a la página de inicio de sesión. Hay que tener en cuenta que cualquier usuario puede escribir en la barra de direcciones la URL de la página de empleados, por lo que es importante proteger el acceso a esta página. No es suficiente con eliminar el acceso en el menú de navegación.

Para esta vamos a modificar el controlador frontal. Vamos a crear una lista de acciones que no requieren autenticación. Por tanto cuando el usuario acceda sin autenticación se verificará que la acción no esté en la lista de acciones que no requieren autenticación. Si la acción no está en la lista, se redirigirá al usuario a la página de inicio de sesión.

Código de ControladorPrincipal.php modificado

<?php
class ControladorPrincipal {

private $acciones = []; // inicialmente todas la accionee están permitidas

public function __construct() {
    // Aquí puedes inicializar cualquier cosa que necesites
    if (!isset($_SESSION['usuario'])) {
        Si no está logado restringimos las acciones
        $this->acciones = ['login', 'contacto', 'inicio', 'logout'];
    };
}

public function manejarSolicitud($accion) {
    // Verificar si la acción está permitida
    if (sizeof($this->acciones) > 0 && !in_array($accion, $this->acciones)) {
        // Si la acción no está en la lista de acciones permitidas
        $accion = 'inicio';
    }
    switch ($accion) { 
    ...
    ...
    }
}
?>

Explicación:

  1. Autenticación: Verificamos si el usuario está autenticado a través de la sesión. Si no lo está, se le redirige a login.php.

  2. logout: Una vez logado el usuario puede cerrar sesión haciendo clic en el enlace de Cerrar sesión. Esto destruirá la sesión y redirigirá al usuario a la página de inicio de sesión. Una vez cerrada la sesión, el usuario ya no podrá acceder a la página de empleados ni a ninguna otra página protegida.

  3. Protección del controlador frontal: El controlador frontal se encarga de verificar si el usuario está autenticado antes de permitir el acceso a las páginas protegidas. Si el usuario no está autenticado, se le redirige a la página de inicio de sesión.


Resumen de la implementación:

  1. Autenticación con JSON:

    • Creamos un archivo usuarios.json que contiene las credenciales de los usuarios.
    • La clase Autenticacion valida el nombre de usuario y la contraseña comparándolos con el archivo JSON.
  2. Página de inicio de sesión

    • La página login.php permite a los usuarios ingresar sus credenciales.
    • Si la autenticación es exitosa, el usuario es redirigido a la página empleados.php.
  3. Protección de la página de empleados:

    • Solo los usuarios autenticados pueden acceder a la página empleados.php.
    • Si el usuario no está autenticado, se le redirige a login.php.
  • Nota: Podemos ver que solo se controla que el usuario esté logado en la página princial y en el controlador frontal. Con esto debería ser suficiente siempre y cuando cuidemos en la apliación que todas las peticiones pasen por el controlador frontal. De esta manera no es necesario controlar el acceso a cada una de las páginas de la aplicación. Si en algún momento se quiere controlar el acceso a alguna página en concreto, se puede hacer de la misma manera que hemos hecho con el controlador frontal. En este caso, se puede incluir el script de verificación al inicio de la página que queremos proteger.

4.4.8 Desactivar opciones de menú (login)

  1. Mostrar u ocultar las opciones del menú:
    • Si el usuario no está autenticado, las opciones de Empleados y Departamentos serán invisibles o desactivadas.
    • Si el usuario está loggeado, estas opciones se mostrarán y estarán activas.
  2. Usar sesiones de PHP para verificar si el usuario está autenticado.
    • Usaremos la variable de sesión ($_SESSION['usuario']) para determinar si el usuario está logeado o no.

Modificación del código de index.php para ocultar/desactivar las opciones del menú

Aquí tienes cómo se puede modificar el menú de navegación para ocultar las opciones de Empleados y Departamentos si el usuario no está autenticado.

Código de index.php modificado

<?php
    ...
    <!-- Cabecera -->
    <header>
        <nav>
            <ul>
                <li><a href="index.php?accion=inicio">Inicio</a></li>
                <?php if (isset($_SESSION['usuario'])): ?>
                    <!-- Mostrar opciones de Empleados y Departamentos solo si el usuario está logueado -->
                    <li><a href="index.php?accion=ver_empleados">Empleados</a></li>
                    <li><a href="index.php?accion=ver_departamentos">Departamentos</a></li>
                <?php endif; ?>
                <li><a href="index.php?accion=contacto">Contacto</a></li>
                <!-- Si el usuario no está logueado, mostramos el enlace al login -->
                <?php if (!isset($_SESSION['usuario'])): ?>
                    <li><a href="login.php">Login</a></li>
                <?php else: ?>
                    <li><a href="logout.php">Cerrar sesión</a></li>
                <?php endif; ?>
            </ul>
        </nav>
    </header>
    ...

Explicación de los cambios:

  1. Verificación de sesión:

    • Usamos isset($_SESSION['usuario']) para verificar si el usuario está autenticado.
    • Si está logeado, las opciones de Empleados y Departamentos serán visibles y activas.
    • Si no está logeado, las opciones de Empleados y Departamentos no estarán visibles en el menú.
  2. Menú dinámico:

    • El menú se adapta dependiendo del estado de la sesión. Si el usuario está autenticado, tiene acceso a todas las opciones; si no, solo puede ver Inicio y Contacto, y el enlace de Login.

Estilo CSS para desactivar las opciones del menú (Opcional)

Si deseas que las opciones del menú estén visibles pero desactivadas (en lugar de invisibles), puedes aplicar CSS para deshabilitar los enlaces de Empleados y Departamentos cuando el usuario no esté logueado.

Código CSS para desactivar enlaces

/* Ocultar los enlaces si no hay sesión activa */
.navbar li a.disabled {
    pointer-events: none; /* Desactivar el clic */
    color: gray; /* Cambiar el color para indicar que está desactivado */
}

/* Estilo de los enlaces desactivados */
.navbar li a.disabled:hover {
    color: gray; /* Evitar que se cambie el color cuando se pasa el mouse */
}

Código de menú con enlaces desactivados

<nav>
    <ul class="navbar">
        <li><a href="index.php?accion=inicio">Inicio</a></li>
        <?php if (!isset($_SESSION['usuario'])): ?>
            <li><a href="#" class="disabled">Empleados</a></li>
            <li><a href="#" class="disabled">Departamentos</a></li>
        <?php else: ?>
            <li><a href="index.php?accion=ver_empleados">Empleados</a></li>
            <li><a href="index.php?accion=ver_departamentos">Departamentos</a></li>
        <?php endif; ?>
        <li><a href="index.php?accion=contacto">Contacto</a></li>
        <?php if (!isset($_SESSION['usuario'])): ?>
            <li><a href="login.php">Login</a></li>
        <?php else: ?>
            <li><a href="logout.php">Cerrar sesión</a></li>
        <?php endif; ?>
    </ul>
</nav>

Explicación:

  • Si el usuario no está logeado, los enlaces de Empleados y Departamentos estarán visibles pero desactivados.
  • El estilo pointer-events: none previene que el usuario haga clic en estos enlaces desactivados.

Resumen de la implementación:

  1. Menú dinámico: La opción de Empleados y Departamentos solo está disponible si el usuario está autenticado.
  2. Estilo CSS (opcional): Puedes optar por ocultar las opciones de Empleados y Departamentos o desactivarlas (usando CSS).
  3. Redirección a login: Si el usuario no está autenticado, solo podrá ver las opciones de Inicio y Contacto, y podrá iniciar sesión.

Disgrama de la aplicación

---
config:
theme: redux
layout: fixed
---
flowchart TD
subgraph subControllers["subControllers"]
        SC1["Employees"]
        SC2["Departments"]
end
    User(["User"]) --> A["Request"]
    A --> B["Front Controller"]
    B --> subControllers
    subControllers <--> C["Models"] & D["Views"]
    subControllers --> Response["Response"]
    Response --> User
    D <--> n2["HTML"]
    C <--> n1["DB"]
    A@{ shape: rounded}
    Response@{ shape: rounded}
    n2@{ shape: card}
    n1@{ shape: cyl}