Skip to content

Unidad 3.7: CRUD básico, table simple

3.7.1 Introducción a CRUD

¿Qué es CRUD?

CRUD es un acrónimo que representa las cuatro operaciones básicas que se realizan en las bases de datos:

  • Create (Crear): Insertar nuevos registros en una tabla.
  • Read (Leer): Consultar y recuperar datos de la base de datos.
  • Update (Actualizar): Modificar registros existentes en la base de datos.
  • Delete (Eliminar): Eliminar registros de la base de datos.

Estas operaciones son fundamentales en las aplicaciones web, ya que permiten interactuar con los datos de manera eficiente. La mayoría de las aplicaciones web, como sistemas de gestión, tiendas en línea o redes sociales, realizan operaciones CRUD para gestionar sus datos.


Casos de uso de una página de administración CRUD

Imaginemos una página de administración de empleados, que es el caso de uso en el que nos centraremos en este tema. Esta página permitirá a los administradores:

  1. Ver la lista de empleados: Una tabla que muestre los empleados actuales.
  2. Añadir nuevos empleados: Un formulario que permita ingresar nuevos datos de empleados.
  3. Editar datos de los empleados: Un formulario que permita modificar los datos de los empleados existentes.
  4. Eliminar empleados: Opción para eliminar empleados de la base de datos.

En la siguiente imagen, mostramos cómo se podría representar este flujo de operaciones en un diagrama de casos de uso.

Diagrama de Casos de Uso en Mermaid

Diagrama de Casos de Uso

Este diagrama ilustra las operaciones CRUD en la página de administración de empleados.

%%{init: {"themeVariables": {"primaryColor": "#4E8AF4", "edgeLabelBackground":"#ffffff", "tertiaryColor": "#f9f9f9"}}}%%
graph TB
    A[Administrar Empleados] --> B[Ver lista de empleados]
    A[Administrar Empleados] --> C[Añadir nuevo empleado]
    A[Administrar Empleados] --> D[Editar datos de empleado]
    A[Administrar Empleados] --> E[Eliminar empleado]

    B --> F[Consultar empleados]
    C --> G[Formulario para crear]
    D --> H[Formulario para editar]
    E --> I[Confirmación de eliminación]

Este diagrama visualiza cómo las operaciones CRUD se traducen en funcionalidades en la interfaz de usuario de una aplicación web.


Estructura de la página de administración

Para empezar, necesitamos tener una visión clara de cómo se verá la página de administración. El diseño debe permitir que los administradores interactúen fácilmente con los empleados, ya sea para agregar nuevos, ver los existentes, actualizarlos o eliminarlos.

Vamos a estructurar la página en los siguientes pasos:

  1. Vista de los empleados: Esta es la página principal donde se mostrarán todos los empleados en una tabla.
  2. Formulario de creación de nuevo empleado: Un formulario donde el administrador pueda ingresar los datos del nuevo empleado.
  3. Formulario de edición de empleado: Similar al formulario de creación, pero con los datos del empleado que se desean modificar.
  4. Confirmación de eliminación: Un mecanismo para pedir confirmación antes de eliminar un registro.

Objetivos de la página CRUD

  • Interactividad: La página permitirá al usuario interactuar de forma intuitiva, sin recargar la página.
  • Validación de entradas: Tanto en el lado del cliente (HTML) como en el servidor (PHP), para asegurarnos de que los datos introducidos son correctos y seguros.
  • Facilidad de uso: Usaremos tablas para visualizar los datos, y formularios para editar y agregar empleados.

Resumen de la introducción

En este punto, hemos definido qué es CRUD y cómo se aplica en la página de administración de empleados. Hemos visto cómo estructuraremos la página y qué funcionalidades debemos implementar, desde la visualización de los empleados hasta la adición, edición y eliminación de registros.

Ahora, avanzaremos con el siguiente punto, que es la vista HTML donde crearemos la estructura básica de la página y organizaremos los datos.


3.7.2 Vista HTML - Estructura de la página

Estructura básica de la página

La estructura de nuestra página de administración CRUD de empleados tendrá:

  1. Una tabla para mostrar los empleados.
  2. Filtros para buscar y ordenar los empleados por nombre, apellido, etc.
  3. Botones de acción para editar, eliminar o añadir nuevos empleados.

1. Crear la tabla para visualizar empleados

La tabla será el centro de nuestra vista. Aquí se mostrarán todos los empleados de la base de datos. La estructura básica de la tabla incluirá columnas como: ID, Nombre, Apellido, fecha nacimiento, fecha de contratación y género etc. Además, proporcionaremos botones de acción en cada fila para editar o eliminar a cada empleado. los campos que necesitamos incluir son:

  • emp_no: ID del empleado
  • first_name: Nombre
  • last_name: Apellido
  • birth_date: Fecha de nacimiento
  • hire_date: Fecha de contratación
  • gender: Género

Ejemplo de código HTML, CSS y JS para la vista:

Vista HTML de la página de empleados

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Administración de Empleados</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <h1>Administración de Empleados</h1>
    <!-- Botón para agregar nuevo empleado -->
    <button>Añadir Nuevo Empleado</button>
    <!-- Tabla de empleados -->
    <table id="empleados">
        <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>
            <!-- Filas de empleados serán generadas aquí -->
        </tbody>
    </table>
    <script src="scripts.js"></script>
</body>
</html>

El archivo CSS definirá el diseño y estilo de la página, incluidos los formularios, la tabla y la ventana modal.

Fichero CSS de ejemplo
        /* Estilos generales */
    body {
        font-family: Arial, sans-serif;
        margin: 20px;
    }

    /* Estilos de la tabla */
    table {
        width: 100%;
        border-collapse: collapse;
        margin-top: 20px;
    }

    table, th, td {
        border: 1px solid #ddd;
    }

    th, td {
        padding: 8px;
        text-align: left;
    }

    th {
        background-color: #f2f2f2;
    }

    tr:hover {
        background-color: #f1f1f1;
    }

    /* Estilos de los botones */
    button {
        padding: 10px 15px;
        margin: 5px;
        cursor: pointer;
    }

    button:hover {
        background-color: #ddd;
    }

El archivo JS manejará la interacción con los elementos de la página, como abrir y cerrar el formulario, realizar la ordenación de la tabla y manejar las acciones de editar y eliminar.

Fichero JavaScript de ejemplo
1
2
3
4
5
6
7
// Función para confirmar la eliminación de un empleado
function confirmarEliminacion(id) {
    if (confirm("¿Estás seguro de que deseas eliminar este empleado?")) {
        // Realizar la eliminación (esto debería ser gestionado por PHP)
        alert("Empleado con ID " + id + " eliminado");
    }
}

Explicación de la estructura HTML:

  1. Tabla de empleados: La tabla ahora incluye las columnas correctas: ID, Nombre, Apellido, Fecha de Nacimiento, Fecha de Contratación, y Género. Además, la columna "Acciones" contendrá los botones para editar o eliminar un empleado.

  2. Filtros y ordenación:

    • Los filtros y campos de ordenación de momento no se muestran. Lo dejamos para más adelante.
  3. Formulario de creación/edición:

    • El formulario de momento no está en la página, lo añadiremos más adelante, en una ventana modal.
    • El formulario permite al administrador agregar o editar empleados.
    • Los campos del formulario son: ID (deshabilitado, se genera automáticamente o se puede ingresar si es necesario), Nombre, Apellido, Fecha de Nacimiento, Fecha de Contratación y Género.
    • El formulario se presentará en una ventana modal cuando el administrador haga clic en el botón "Añadir Nuevo Empleado".

CSS y JS

Este es el primer paso de la página, centrado en la estructura HTML. El siguiente paso sería integrar la lógica de PHP para llenar la tabla con los datos desde la base de datos y manejar las operaciones de CRUD.

A continuación, pasaremos a la parte de llenado de la tabla con los datos de la base de datos, lo que se hará en un paso posterior cuando introduzcamos los scripts de PHP y conectemos la base de datos a la interfaz HTML.


3.7.3 Mostrar los empleados en una tabla

En este punto, vamos a explicar cómo llenar la tabla de empleados con datos desde la base de datos y cómo manejar las interacciones con los botones de acción (editar y eliminar).

Objetivos:

  • Conectar con la base de datos para obtener los empleados.
  • Mostrar los datos en la tabla HTML.
  • Implementar funcionalidades como editar y eliminar usando botones de acción en la tabla.
  • Aplicar seguridad en la consulta para evitar SQL Injection.

1. Conexión a la base de datos y obtener los empleados

Para mostrar los empleados, necesitamos conectarnos a la base de datos, hacer una consulta SELECT a la tabla employees y recuperar los datos. Los resultados de esta consulta se mostrarán en la tabla HTML.

Código PHP para obtener empleados:

MySQLi (orientado a objetos):

Código PHP para obtener empleados con MySQLi

<?php
// Conexión a la base de datos
$conexion = new mysqli("localhost", "root", "", "employees");

if ($conexion->connect_error) {
    die("Conexión fallida: " . $conexion->connect_error);
}

// Consulta para obtener todos los empleados
$query = "SELECT emp_no, first_name, last_name, birth_date, hire_date, gender FROM employees";
$resultado = $conexion->query($query);

if ($resultado->num_rows > 0) {
    while ($empleado = $resultado->fetch_assoc()) {
        echo "<tr>";
        echo "<td>" . $empleado['emp_no'] . "</td>";
        echo "<td>" . $empleado['first_name'] . "</td>";
        echo "<td>" . $empleado['last_name'] . "</td>";
        echo "<td>" . $empleado['birth_date'] . "</td>";
        echo "<td>" . $empleado['hire_date'] . "</td>";
        echo "<td>" . $empleado['gender'] . "</td>";
        echo "<td>
                <button onclick='editarEmpleado(" . $empleado['emp_no'] . ")'>Editar</button>
                <button onclick='eliminarEmpleado(" . $empleado['emp_no'] . ")'>Eliminar</button>
            </td>";
        echo "</tr>";
    }
} else {
    echo "<tr><td colspan='7'>No hay empleados para mostrar.</td></tr>";
}

$conexion->close();
?>
<?php
// Conexión a la base de datos
$conexion = mysqli_connect("localhost", "root", "", "employees");

if (!$conexion) {
    die("Conexión fallida: " . mysqli_connect_error());
}

// Consulta para obtener todos los empleados
$query = "SELECT emp_no, first_name, last_name, birth_date, hire_date, gender FROM employees";
$resultado = mysqli_query($conexion, $query);

if (mysqli_num_rows($resultado) > 0) {
    while ($empleado = mysqli_fetch_assoc($resultado)) {
        echo "<tr>";
        echo "<td>" . $empleado['emp_no'] . "</td>";
        echo "<td>" . $empleado['first_name'] . "</td>";
        echo "<td>" . $empleado['last_name'] . "</td>";
        echo "<td>" . $empleado['birth_date'] . "</td>";
        echo "<td>" . $empleado['hire_date'] . "</td>";
        echo "<td>" . $empleado['gender'] . "</td>";
        echo "<td>
                <button onclick='editarEmpleado(" . $empleado['emp_no'] . ")'>Editar</button>
                <button onclick='eliminarEmpleado(" . $empleado['emp_no'] . ")'>Eliminar</button>
            </td>";
        echo "</tr>";
    }
} else {
    echo "<tr><td colspan='7'>No hay empleados para mostrar.</td></tr>";
}

// Cerrar la conexión
mysqli_close($conexion);
?>

Vamos a analizar el código:

  • Conexión a la base de datos: Se establece una conexión a la base de datos utilizando mysqli_connect() o new mysqli(), lo hemos visto en temas anteriores.

  • Consulta SQL: Se realiza una consulta SELECT para obtener todos los empleados de la tabla employees, en este caso sacamos todos los empleados. Sin filtro.

  • Objeto de resultado: Se verifica si hay resultados y se recorren con un bucle while, generando dinámicamente las filas <tr> para cada empleado. Hay que ver como se crea una fila en la tabla por cada empleado, y una celda por cada campo del empleado.

-- Botones de acción: En cada fila, se incluyen botones Editar y Eliminar que llamarán a las funciones editarEmpleado() y eliminarEmpleado() respectivamente. Estas funciones se implementarán más adelante.

<button onclick='editarEmpleado(" . $empleado['emp_no'] . ")'>Editar</button>
<button onclick='eliminarEmpleado(" . $empleado['emp_no'] . ")'>Eliminar</button>

En este código hay que resaltar como pasamos como parámetro a editarEmpleado y eliminarEmpleado el emp_no, que es el id del empleado. Esto es importante para poder identificar al empleado que queremos editar o eliminar. Por tabto cada fila tendrá una llamada a las funciones pero con el id del empleado correspondiente.

PDO:

Código PHP para obtener empleados con PDO

<?php
try {
    $conexion = new PDO("mysql:host=localhost;dbname=employees", "root", "");
    $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Consulta para obtener todos los empleados
    $query = "SELECT emp_no, first_name, last_name, birth_date, hire_date, gender FROM employees";
    $stmt = $conexion->query($query);

    if ($stmt->rowCount() > 0) {
        while ($empleado = $stmt->fetch(PDO::FETCH_ASSOC)) {
            echo "<tr>";
            echo "<td>" . $empleado['emp_no'] . "</td>";
            echo "<td>" . $empleado['first_name'] . "</td>";
            echo "<td>" . $empleado['last_name'] . "</td>";
            echo "<td>" . $empleado['birth_date'] . "</td>";
            echo "<td>" . $empleado['hire_date'] . "</td>";
            echo "<td>" . $empleado['gender'] . "</td>";
            echo "<td>
                    <button onclick='editarEmpleado(" . $empleado['emp_no'] . ")'>Editar</button>
                    <button onclick='eliminarEmpleado(" . $empleado['emp_no'] . ")'>Eliminar</button>
                </td>";
            echo "</tr>";
        }
    } else {
        echo "<tr><td colspan='7'>No hay empleados para mostrar.</td></tr>";
    }

} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

$conexion = null;
?>

En este ejemplo el análisis es igual que el anterior solo que utilizamos PDO para conectarnos a la base de datos. La diferencia principal es que PDO permite una mejor gestión de errores y es más flexible al trabajar con diferentes bases de datos.


2. Mostrar los datos en la tabla HTML

Los datos que obtenemos de la base de datos deben ser mostrados en el cuerpo de la tabla en el HTML. El código PHP que hemos mostrado anteriormente generará dinámicamente las filas <tr> para cada empleado.

Dentro de cada fila, se mostrarán los datos de cada empleado: ID, Nombre, Apellido, Fecha de Nacimiento, Fecha de Contratación, y Género.

Además, se agregarán botones Editar y Eliminar en cada fila para permitir la modificación o eliminación de los registros. Estos botones llamarán a las funciones editarEmpleado() y eliminarEmpleado() que se implementarán más adelante.


3. Interacción con los botones (Editar y Eliminar)

Cuando el administrador haga clic en el botón Editar, se abrirá el formulario con los datos del empleado para que pueda modificarlos. Para Eliminar, se pedirá confirmación antes de proceder.

Función de Editar:

El botón de Editar pasa el emp_no (ID del empleado) a la función editarEmpleado(). Esto puede abrir el formulario modal con los datos correspondientes del empleado que se desea editar.

Función de Eliminar:

El botón de Eliminar también pasa el emp_no del empleado y ejecuta la función eliminarEmpleado(). Esta función pedirá confirmación antes de eliminar el registro del empleado.

Implementación de las funciones.

De momento vamos a añadir las funciones de editar y eliminar en el fichero JavaScript, aunque no las implementaremos del todo. Más adelante veremos como implementar la lógica de edición y eliminación. Ahora nos conformarmos con que aparezca un alert con la acción que se va a realizar y el id del empleado.

    // Función para editar un empleado
    function editarEmpleado(emp_no) {
        alert("Editando empleado con ID: " + emp_no);
        // Aquí puedes agregar la lógica para llenar el formulario con los datos del empleado
        // y mostrar la ventana modal
    }

    // Función para eliminar un empleado
    function eliminarEmpleado(emp_no) {
        if (confirm("¿Estás seguro de que deseas eliminar el empleado con ID: " + emp_no + "?")) {
            alert("Empleado con ID " + emp_no + " eliminado");
            // Aquí puedes agregar la lógica para eliminar el empleado de la base de datos
        }
    }

Problemas por la cantidad de empleados

Como habrás podido comprobar (puedes mirarlo con select count(*) from employees), la tabla de empleados tiene una gran cantidad de registros. Esto puede hacer que la carga inicial de la página sea lenta.

para evitar esto, podemos implementar paginación o cargar los datos de forma asíncrona (AJAX) para mejorar la experiencia del usuario. Es recomendable que la tabla no cargue todos los empleados de golpe, sino que se carguen por partes. Esto lo veremos más adelante.

Ahora, para hacer más fácil la visualización vamos a limitar la cantidad de empleados que se muestran en la tabla. Para ello, podemos usar la cláusula LIMIT en la consulta SQL. Por ejemplo, si queremos mostrar solo los primeros 100 empleados, podemos modificar la consulta de la siguiente manera:

SELECT emp_no, first_name, last_name, birth_date, hire_date, gender FROM employees LIMIT 100;

Estado del proyecto

Ahora mismo, la página de administración de empleados tiene la siguiente funcionalidad:

  • Conexión a la base de datos: Se conecta a la base de datos y obtiene los empleados.
  • Mostrar empleados: Los empleados se muestran en una tabla HTML generada dinámicamente desde PHP.
  • Botones de acción: Se han agregado botones para editar y eliminar empleados, aunque la lógica de edición y eliminación aún no está implementada.

Nota: Hemos limitado la cantidad de empleados que se muestran en la tabla a 100 para mejorar la carga inicial de la página. Esto es solo un ejemplo y puedes ajustar el límite según tus necesidades.

Esta es la vista que tenemos hasta ahora:

Vista de la tabla de empleados

Vista del formulario modal que utilziaremos para inserciones y modificaciones:

Vista del formulario modal

Vista del mensaje que aparece cuando pulsamos los botones de ordenaar (de momento solo un alert)

Vista del mensaje de ordenación


Resumen

En este punto hemos cubierto:

  • Conexión a la base de datos para obtener los empleados.
  • Mostrar los empleados en una tabla HTML generada dinámicamente desde PHP.
  • Botones de acción: Agregar botones para editar y eliminar empleados.

¡Excelente! Ya está funcionando, la tabla está mostrando los empleados correctamente. La limitación de registros es una excelente práctica, podrémos añadir paginación más adelante para mejorar la eficiencia y la experiencia del usuario.


3.7.4 Mostrar datos del empleado (ventana modal)

Vamos a implementar la ventana modal para mostrar los detalles de un empleado cuando el administrador haga clic en el botón de ver o editar.

La ventana modal es una excelente forma de mostrar la información sin necesidad de recargar la página o navegar a una nueva.

Objetivos:

  • Crear una ventana modal que muestre los detalles del empleado seleccionado.
  • La ventana se abrirá al hacer clic en el botón Ver o Editar.
  • Podremos ver más información detallada del empleado y, en el caso de la edición, modificar esos datos.

Estructura de la ventana modal

1. Mostrar los datos del empleado en la ventana modal

La ventana modal mostrará un formulario con los campos de datos del empleado que se seleccionó. Si es una edición, los campos estarán prellenados con los datos actuales.

2. Código HTML de la ventana modal (ya incluido)

Tenemos que incluir del siguiente código de la ventana modal en el HTML anterior. Tenemos un formulario con los diferentes campos necesarios, todos los campos son obligatorios y el ID del empleado está deshabilitado para evitar que se modifique. Para las fechas hemos utilizado el tipo date, que permite seleccionar la fecha de una manera más amigable.

Código HTML de la ventana modal

<!-- Ventana modal para agregar/editar empleado -->
<div id="modalFormulario" class="modal">
    <div class="modal-content">
        <span class="close" onclick="cerrarFormulario()">&times;</span>
        <h2>Formulario de Empleado</h2>
        <form id="formEmpleado" method="post">
            <label for="emp_id">ID:</label>
            <input type="text" id="emp_id" name="emp_id" disabled>

            <label for="nombre">Nombre:</label>
            <input type="text" id="nombre" name="nombre" required>

            <label for="apellido">Apellido:</label>
            <input type="text" id="apellido" name="apellido" required>

            <label for="fecha_nacimiento">Fecha de Nacimiento:</label>
            <input type="date" id="fecha_nacimiento" name="fecha_nacimiento" required>

            <label for="fecha_contratacion">Fecha de Contratación:</label>
            <input type="date" id="fecha_contratacion" name="fecha_contratacion" required>

            <label for="genero">Género:</label>
            <select id="genero" name="genero" required>
                <option value="M">Masculino</option>
                <option value="F">Femenino</option>
                <option value="O">Otro</option>
            </select>

            <button type="submit">Guardar</button>
            <button type="button" onclick="cerrarFormulario()">Cancelar</button>
        </form>
    </div>
</div>

Este código ya incluye la ventana modal que contiene el formulario para agregar o editar empleados. El funcionamiento de la ventana modal está basado en reglas css. Puedes encontrar los estilos en el fichero css cargado al inicio. Si no lo has trabajado con anterioridad te recomiento que hagas pruebas en una página nueva HTML para comprender su funcionamiento y lo que hacen las reglas.

CSS para la ventana modal
/* Estilos de la ventana modal */
.modal {
    display: none;
    position: fixed;
    z-index: 1;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.4);
}

.modal-content {
    background-color: white;
    margin: 15% auto;
    padding: 20px;
    border: 1px solid #888;
    width: 80%;
}
.close {
    color: #aaa;
    float: right;
    font-size: 28px;
    font-weight: bold;
}

.close:hover,
.close:focus {
    color: black;
    text-decoration: none;
    cursor: pointer;
}

Son dos clases, .modal y .modal-content, que controlan la apariencia de la ventana modal. La clase .modal controla el fondo oscuro y la posición de la ventana, mientras que .modal-content controla el contenido de la ventana modal. La clase .close se utiliza para el botón de cerrar la ventana modal.


3. Función para llenar los datos del empleado en el formulario modal

Cuando el administrador haga clic en el botón de Ver o Editar, se debe llenar el formulario con los datos correspondientes del empleado.

En nuestra aplicación ya tenemos implementado el evento onclik del botón de editar que llama a la función editarEmpleado(id). Ahora vamos a reemplazar la función de que tenemos (ahora solo muestra un alert) por la función siguiente.

Función de JavaScript para mostrar el formulario con los datos del empleado:

Esta función se encargará de llenar el formulario con los datos del empleado seleccionado. Utilizaremos AJAX para obtener los datos del empleado desde el servidor sin recargar la página. Utilizaremos el método GET para pasar el id del empleado al script php. En otras ocasiones utilizaremos POST para poder enviar los datos del formulario al servidor.

Función JavaScript para editar empleado

// Función para llenar el formulario con los datos del empleado
function editarEmpleado(emp_id) {
    // Llamar al servidor para obtener los datos del empleado (esto debe hacerse con una solicitud AJAX)
    // Suponemos que el servidor devuelve los datos en formato JSON

    fetch('getEmpleado.php?id=' + emp_id)
        .then(response => response.json())
        .then(data => {
            // Llenar los campos del formulario modal con los datos
            document.getElementById('emp_id').value = data.emp_no;
            document.getElementById('nombre').value = data.first_name;
            document.getElementById('apellido').value = data.last_name;
            document.getElementById('fecha_nacimiento').value = data.birth_date;
            document.getElementById('fecha_contratacion').value = data.hire_date;
            document.getElementById('genero').value = data.gender;
            // Mostrar la ventana modal
            mostrarFormulario();
        })
        .catch(error => console.error('Error al obtener los datos del empleado:', error));
}

Esta función llama (AJAX utilizando fetch) a un script php al que llamaremos getEmpledo.php y que tenemos implementado en el punto siguiente. De estamanera evitamos tener que recargar toda la página del navegador y solicitamos al servidor los datos del empleado que queremos editar. El script nos devolverà un json con todos los datos del empleado.

Para que funcione la ventana modal tenemos que implementar la función mostrarFormulario() que se encargará de mostrar la ventana modal. Esta función simplemente cambiará el estilo de la ventana modal para que sea visible. Y cerrarFormulario() que se encargará de ocultar la ventana modal.

Función JavaScript para mostrar la ventana modal

1
2
3
4
5
6
7
8
9
// Función para mostrar la ventana modal
function mostrarFormulario() {
    document.getElementById('modalFormulario').style.display = 'block';
}

// Función para cerrar la ventana modal
function cerrarFormulario() {
    document.getElementById('modalFormulario').style.display = 'none';
}

4. PHP para obtener los datos del empleado

El siguiente paso es crear un archivo PHP (por ejemplo, getEmpleado.php) que recibirá un ID de empleado, obtendrá sus datos de la base de datos y devolverá la información en formato JSON. En este caso vamos a utilizar el método GET para obtener el ID del empleado.

Código PHP para obtener un empleado:

Fichero php obtener datos de un empleado

<?php 
// Conexión a la base de datos
$conexion = new mysqli("localhost", "root", "", "employees");

if ($conexion->connect_error) {
    die("Conexión fallida: " . $conexion->connect_error);
}

// Validar si se ha proporcionado el ID del empleado
if (!isset($_GET['id'])) {
    echo json_encode(['error' => 'ID de empleado no proporcionado']);
    exit;
}
// Validar que el ID del empleado es un número entero
if (!filter_var($_GET['id'], FILTER_VALIDATE_INT)) {
    echo json_encode(['error' => 'ID de empleado inválido']);
    exit;
}

// Obtener el ID del empleado
$emp_id = $_GET['id'];

// Consulta para obtener el empleado
$query = "SELECT emp_no, first_name, last_name, birth_date, hire_date, gender FROM employees WHERE emp_no = ?";
$stmt = $conexion->prepare($query);
$stmt->bind_param("i", $emp_id);
$stmt->execute();
$result = $stmt->get_result();

// Devolver los datos en formato JSON
if ($result->num_rows > 0) {
    $empleado = $result->fetch_assoc();
    echo json_encode($empleado);
} else {
    echo json_encode(['error' => 'Empleado no encontrado']);
}

$stmt->close();
$conexion->close();
?>
<?php
// Conexión a la base de datos utilizando PDO
try {
    $conexion = new PDO("mysql:host=localhost;dbname=employees", "root", "");
    $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Validar si se ha proporcionado el ID del empleado
    if (!isset($_GET['id'])) {
        echo json_encode(['error' => 'ID de empleado no proporcionado']);
        exit;
    }
    // Validar que el ID del empleado es un número entero
    if (!filter_var($_GET['id'], FILTER_VALIDATE_INT)) {
        echo json_encode(['error' => 'ID de empleado inválido']);
        exit;
    }

    // Obtener el ID del empleado
    $emp_id = $_GET['id'];

    // Consulta para obtener el empleado
    $query = "SELECT emp_no, first_name, last_name, birth_date, hire_date, gender FROM employees WHERE emp_no = :emp_id";
    $stmt = $conexion->prepare($query);

    // Vincular el parámetro
    $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);

    // Ejecutar la consulta
    $stmt->execute();

    // Verificar si se encontró un resultado
    if ($stmt->rowCount() > 0) {
        $empleado = $stmt->fetch(PDO::FETCH_ASSOC);
        echo json_encode($empleado); // Devolver los datos en formato JSON
    } else {
        echo json_encode(['error' => 'Empleado no encontrado']);
    }

} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}

// Cerrar la conexión
$conexion = null;
?>

Este archivo getEmpleado.php recibe un ID de empleado, realiza una consulta a la base de datos y devuelve los datos del empleado en formato JSON para que el formulario modal se pueda completar.

Ejmplo fichro JSON devuelto

1
2
3
4
5
6
7
8
empleado = {   
    emp_no: 1,
    first_name: "Enrique",
    last_name: "Garcia",
    birth_date: "01/01/1980",
    hire_date: "01/01/1999",
    gender: "M",
}

Resumen del punto 3.7.4: Mostrar datos del empleado (ventana modal)

En este punto hemos cubierto:

  • Mostrar la ventana modal para mostrar los datos del empleado seleccionado.
  • JavaScript para llenar el formulario con los datos del empleado cuando se haga clic en el botón Editar.
  • PHP para obtener los datos del empleado desde la base de datos y devolverlos en formato JSON.

En el siguiente paso, vamos a implementar el proceso para editar los empleados y validar los datos tanto en el cliente (HTML) como en el servidor (PHP).


3.7.5 Editar datos del empleado

En este punto, vamos a permitir que el administrador pueda editar los datos de un empleado desde la misma página de administración, sin recargar la página. Utilizaremos AJAX para realizar la actualización de forma asíncrona y, de esta manera, no perder la vista actual ni recargar la tabla de empleados.

Objetivos:

  1. Formulario de edición: Permitir que el administrador edite los datos de un empleado directamente desde un formulario en la ventana modal.
  2. Validación de los datos: Validar los campos tanto en el cliente (HTML5 y JavaScript) como en el servidor (PHP).
  3. Actualizar los datos: Realizar la actualización de los datos del empleado en la base de datos sin recargar la página.
  4. Actualizar la fila en la tabla: Una vez que los datos se hayan actualizado, se reflejarán en la tabla de empleados sin tener que recargarla.

1. formulario modal

El formulario de edición se ha diseñado en una ventana modal. El objetivo es que, al hacer clic en el botón "Guardar", se envíen los datos del formulario al servidor sin recargar la página.

HTML del formulario:

El formulario para la edición es el mismo que ya tenemos implementado en el código anterior. Aquí lo incluimos nuevamente para referencia:

Formulario de empleado

<!-- Formulario de Empleado (sin cambios) -->
<form id="formEmpleado" method="post" onsubmit="return false;">
    <label for="emp_id">ID:</label>
    <input type="text" id="emp_id" name="emp_id" disabled>

    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre" required>

    <label for="apellido">Apellido:</label>
    <input type="text" id="apellido" name="apellido" required>

    <label for="fecha_nacimiento">Fecha de Nacimiento:</label>
    <input type="date" id="fecha_nacimiento" name="fecha_nacimiento" required>

    <label for="fecha_contratacion">Fecha de Contratación:</label>
    <input type="date" id="fecha_contratacion" name="fecha_contratacion" required>

    <label for="genero">Género:</label>
    <select id="genero" name="genero" required>
        <option value="M">Masculino</option>
        <option value="F">Femenino</option>
        <option value="O">Otro</option>
    </select>

    <button type="submit" onclick="guardarEmpleado()">Guardar</button>
    <button type="button" onclick="cerrarFormulario()">Cancelar</button>
</form>

2. Enviar los datos con AJAX

La función guardarEmpleado() enviará los datos del formulario al servidor utilizando AJAX para que no se recargue la página.

Problema con emp_id

Nota: El campo emp_id está deshabilitado en el formulario, por tanto no se enviará al servidor. Para solucionarlo tenemos que modificar parte del código. En javascripten vez de utilizar FormData para enviar los datos, vamos a crear un objeto JSON con los datos del formulario y lo enviaremos al servidor. De esta manera, el campo emp_id se enviará correctamente. Si utilizamos FormData, el campo emp_id no se enviará porque está deshabilitado, y la acutualización fallará.

JavaScript con AJAX:

Código JavaScript para enviar los datos del formulario

// Función para guardar los datos del empleado
function guardarEmpleado() {
    const form = document.getElementById('formEmpleado');
    const emp_id = document.getElementById('emp_id').value;  // Obtener el ID del empleado
    const nombre = document.getElementById('nombre').value;
    const apellido = document.getElementById('apellido').value;
    const fecha_nacimiento = document.getElementById('fecha_nacimiento').value;
    const fecha_contratacion = document.getElementById('fecha_contratacion').value;
    const genero = document.getElementById('genero').value;

    // Crear un objeto con los datos a enviar
    const data = {
        emp_id: emp_id,
        nombre: nombre,
        apellido: apellido,
        fecha_nacimiento: fecha_nacimiento,
        fecha_contratacion: fecha_contratacion,
        genero: genero
    };

    // const formData = new FormData(form);

    fetch('editarEmpleado.php', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'  // Especificamos que el contenido será JSON
        },
        body: JSON.stringify(data)  // Convertimos el objeto a JSON
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            // Si la actualización fue exitosa, actualizar la tabla sin recargar la página
            actualizarFila(data.empleado);
            cerrarFormulario();
        } else {
            // Si hay un error, mostrar el mensaje de error
            alert(data.error || "Error al actualizar el empleado.");
        }
    })
    .catch(error => {
        console.error('Error:', error);
        alert('Error en la actualización.');
    });
}

En el código podemos ver como obtenemos los datos del formulario y los convertimos a un objeto JSON. Luego, utilizamos fetch para enviar una solicitud POST al archivo editarEmpleado.php. En la cabecera especificamos que el contenido será JSON y en el cuerpo enviamos el objeto convertido a JSON.

3. PHP para actualizar los datos sin recargar la página

En el archivo editarEmpleado.php, recibiremos los datos del formulario enviados por AJAX y actualizaremos la base de datos. Luego, devolveremos una respuesta JSON al cliente.

Código PHP para actualizar los empleados:

Código PHP para editar empleados

<?php
// Conexión a la base de datos con MySQLi OO
$host = getenv('MYSQL_HOST');
$user = getenv('MYSQL_USER');
$pass = getenv('MYSQL_PASSWORD');
$db = 'employees';

$conexion = new mysqli($host, $user, $pass, $db);

// Verificar conexión
if ($conexion->connect_error) {
    echo json_encode(['success' => false, 'error' => "Conexión fallida: " . $conexion->connect_error]);
    exit;
}

// Recibir los datos JSON enviados por AJAX
$data = json_decode(file_get_contents("php://input"));

if ($data) {
    $emp_id = $data->emp_id;
    $nombre = $data->nombre;
    $apellido = $data->apellido;
    $fecha_nacimiento = $data->fecha_nacimiento;
    $fecha_contratacion = $data->fecha_contratacion;
    $genero = $data->genero;

    // Validación de fechas
    $fecha_nacimiento_obj = new DateTime($fecha_nacimiento);
    $fecha_contratacion_obj = new DateTime($fecha_contratacion);
    $fecha_actual = new DateTime();

    $fecha_minima_nacimiento = clone $fecha_contratacion_obj;
    $fecha_minima_nacimiento->sub(new DateInterval('P18Y'));

    if ($fecha_nacimiento_obj > $fecha_minima_nacimiento) {
        echo json_encode(['success' => false, 'error' => "La fecha de nacimiento debe ser al menos 18 años antes de la fecha de contratación."]);
        exit;
    }

    if ($fecha_contratacion_obj > $fecha_actual) {
        echo json_encode(['success' => false, 'error' => "La fecha de contratación no puede ser posterior a la fecha actual."]);
        exit;
    }

    // Consulta preparada con MySQLi OO
    $query = "UPDATE employees 
            SET first_name = ?, 
                last_name = ?, 
                birth_date = ?, 
                hire_date = ?, 
                gender = ? 
            WHERE emp_no = ?";

    $stmt = $conexion->prepare($query);
    if (!$stmt) {
        echo json_encode(['success' => false, 'error' => "Error en la preparación de la consulta: " . $conexion->error]);
        exit;
    }

    $stmt->bind_param("sssssi", $nombre, $apellido, $fecha_nacimiento, $fecha_contratacion, $genero, $emp_id);
    $stmt->execute();

    if ($stmt->affected_rows >= 0) {
        $empleado = [
            'emp_no' => $emp_id,
            'first_name' => $nombre,
            'last_name' => $apellido,
            'birth_date' => $fecha_nacimiento,
            'hire_date' => $fecha_contratacion,
            'gender' => $genero
        ];
        echo json_encode(['success' => true, 'empleado' => $empleado]);
    } else {
        echo json_encode(['success' => false, 'error' => 'No se actualizó ningún registro.']);
    }

    $stmt->close();
}

$conexion->close();
?>
<?php
try {
    // Conexión a la base de datos con PDO
    $host = getenv('MYSQL_HOST');
    $user = getenv('MYSQL_USER');
    $pass = getenv('MYSQL_PASSWORD');

    $conexion = new PDO("mysql:host=$host;dbname=employees", $user, $pass);
    $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Recibir los datos JSON enviados por AJAX
    $data = json_decode(file_get_contents("php://input"));

    if ($data) {
        // Recibir los datos del formulario
        $emp_id = $data->emp_id;
        $nombre = $data->nombre;
        $apellido = $data->apellido;
        $fecha_nacimiento = $data->fecha_nacimiento;
        $fecha_contratacion = $data->fecha_contratacion;
        $genero = $data->genero;

        // Validación de fechas
        $fecha_nacimiento_obj = new DateTime($fecha_nacimiento);
        $fecha_contratacion_obj = new DateTime($fecha_contratacion);
        $fecha_actual = new DateTime();

        // Validar que la fecha de nacimiento sea al menos 18 años antes de la fecha de contratación
        $fecha_minima_nacimiento = $fecha_contratacion_obj->sub(new DateInterval('P18Y'));
        if ($fecha_nacimiento_obj > $fecha_minima_nacimiento) {
            echo json_encode(['success' => false, 'error' => "La fecha de nacimiento debe ser al menos 18 años antes de la fecha de contratación."]);
            exit;
        }

        // Validar que la fecha de contratación no sea mayor que la fecha actual
        if ($fecha_contratacion_obj > $fecha_actual) {
            echo json_encode(['success' => false, 'error' => "La fecha de contratación no puede ser posterior a la fecha actual."]);
            exit;
        }

        // Consulta para actualizar los datos
        $query = "UPDATE employees 
                SET first_name = :nombre, 
                    last_name = :apellido, 
                    birth_date = :fecha_nacimiento, 
                    hire_date = :fecha_contratacion, 
                    gender = :genero 
                WHERE emp_no = :emp_id";

        // Ejecutar la consulta
        $stmt = $conexion->prepare($query);
        $stmt->bindParam(':nombre', $nombre, PDO::PARAM_STR);
        $stmt->bindParam(':apellido', $apellido, PDO::PARAM_STR);
        $stmt->bindParam(':fecha_nacimiento', $fecha_nacimiento, PDO::PARAM_STR);
        $stmt->bindParam(':fecha_contratacion', $fecha_contratacion, PDO::PARAM_STR);
        $stmt->bindParam(':genero', $genero, PDO::PARAM_STR);
        $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);
        $stmt->execute();

        // Devolver éxito y los datos actualizados
        $empleado = [
            'emp_no' => $emp_id,
            'first_name' => $nombre,
            'last_name' => $apellido,
            'birth_date' => $fecha_nacimiento,
            'hire_date' => $fecha_contratacion,
            'gender' => $genero
        ];

        echo json_encode(['success' => true, 'empleado' => $empleado]);

    }
} catch (PDOException $e) {
    echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}

$conexion = null;
?>

En este caso nuestro código PHP recibe los datos del formulario enviados por AJAX, realiza las validaciones necesarias (como la fecha de nacimiento y la fecha de contratación) y actualiza los datos del empleado en la base de datos. Luego, devuelve una respuesta JSON al cliente con el resultado de la operación. Las resuestas pueden ser:

  • success: true si la actualización fue exitosa.
  • empleado: un objeto con los datos actualizados del empleado.
  • error: un mensaje de error si hubo algún problema durante la actualización.
  • success: false si hubo un error en la actualización.
  • error: un mensaje de error si hubo algún problema durante la actualización.

Es importante controlar las respuestas del servidor para que JS pueda actuar en consecuencia. En este caso, si la actualización fue exitosa, se actualizará la fila correspondiente en la tabla de empleados.

4. Actualizar la fila en la tabla

Una vez que el servidor haya respondido con los datos actualizados, debemos actualizar la fila correspondiente en la tabla de empleados.

JavaScript para actualizar la fila:

Código JavaScript para actualizar la fila

// Función para actualizar la fila de la tabla con los nuevos datos
function actualizarFila(empleado) {
    // Encontrar la fila correspondiente en la tabla
    const fila = document.querySelector(`tr[data-id='${empleado.emp_no}']`);
    console.log(fila);
    if (fila) {
        fila.children[1].textContent = empleado.first_name;  // Nombre
        fila.children[2].textContent = empleado.last_name;   // Apellido
        fila.children[3].textContent = empleado.birth_date;   // Fecha de nacimiento
        fila.children[4].textContent = empleado.hire_date;    // Fecha de contratación
        fila.children[5].textContent = empleado.gender;       // Género
    }
    fila.style.display = 'none'; // Ocultar la fila para forzar el re-renderizado
    fila.style.display = ''; // Volver a mostrar la fila con los datos actualizados
}

En esta función el único cambio que hemos realizado es añadir el data-id a las filas de la tabla. De esta manera, podemos identificar la fila que queremos actualizar. Ahora dedemos actualizar nuestra código php que genera la tabla de empleados para que incluya el data-id en cada fila.

<tr  data-id="<?php echo $empleado['emp_no']; ?>">

De esta manera, cada fila tendrá un atributo data-id que contiene el ID del empleado. Esto nos permitirá identificar la fila correcta para actualizarla con los nuevos datos.

Explicación de los pasos realizados:

  1. Formulario Modal: El formulario de edición permanece intacto, con validaciones de HTML5. Al hacer clic en "Guardar", el formulario se envía de manera asíncrona sin recargar la página.

  2. AJAX: Utilizamos JavaScript con AJAX para enviar los datos al servidor sin recargar la página. Cuando el servidor responde con los datos actualizados, se utiliza el DOM para actualizar la fila de la tabla correspondiente.

  3. PHP: El archivo editarEmpleado.php recibe los datos del formulario, realiza las validaciones y ejecuta la consulta UPDATE para actualizar los datos del empleado en la base de datos.

  4. Actualización en la tabla: Al recibir la respuesta del servidor, la fila correspondiente en la tabla de empleados se actualiza automáticamente con los nuevos datos.


Resumen

En este punto, hemos implementado un sistema para editar empleados sin salir de la página. Usamos AJAX para enviar los datos de forma asíncrona, actualizamos la fila de la tabla de empleados utilizando el DOM, y validamos las fechas en el servidor para asegurar que los datos sean correctos.

3.7.6 Eliminar empleados (con validación)

Objetivo: Eliminar un empleado de la base de datos, pero con ciertas restricciones. La eliminación de un empleado implica primero validar si el empleado está relacionado con la tabla de departamentos. Si está relacionado, cerraremos sus periodos (cerrando registros activos), pero no eliminaremos el empleado de la base de datos. Si no está relacionado con ningun departamento, el empleado podrá ser eliminado físicamente.

Flujo de validación:

  1. Comprobar si el empleado es jefe de departamento:
  2. Verificamos si el emp_no del empleado está relacionado con algún departamento como jefe. Si es así, no se puede eliminar.

  3. Cerrar periodos activos:

  4. Si el empleado tiene relación con algún departamento, cerramos estos registros con una fecha anterior a la actual en (departamentos, salarios, títulos).

  5. Eliminar el empleado solo si no tiene relaciones activas:

  6. Si el empleado no tiene relaciones con departamentos, lo eliminamos físicamente de la base de datos.

Pasos a seguir:

  1. Comprobar si el empleado tiene relaciones activas (jefe de departamento, salarios, títulos).
  2. Cerrar periodos: Si el empleado está relacionado, cerramos sus registros.
  3. Eliminar al empleado si no tiene relaciones.

1. Modificación en la función eliminarEmpleado() con validaciones

La función de eliminación ahora debe validar si el empleado puede ser eliminado y cerrar los periodos correspondientes en lugar de eliminarlo físicamente si está relacionado con algún departamento, salario o título.

Función JavaScript actualizada con validación:

Función JavaScript para eliminar empleado

// Función para eliminar un empleado con validaciones
function eliminarEmpleado(emp_id) {
    // Mostrar confirmación al usuario
    const confirmacion = confirm("¿Estás seguro de que deseas eliminar este empleado?");

    if (confirmacion) {
        // Enviar solicitud AJAX para verificar si el empleado puede ser eliminado
        fetch('eliminarEmpleado.php', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ emp_id: emp_id })  // Enviar el ID del empleado
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                if (data.action === "cerrar_periodos") {
                    // Si se cierra el periodo, mostrar mensaje informando de la acción
                    alert("El empleado ha sido desactivado y sus periodos han sido cerrados.");
                } else {
                    // Si se puede eliminar físicamente, eliminar la fila de la tabla
                    eliminarFila(emp_id);
                    alert("Empleado eliminado correctamente.");
                }
            } else {
                alert(data.error || "Error al eliminar el empleado.");
            }
        })
        .catch(error => {
            console.error('Error:', error);
            alert('Error en la eliminación.');
        });
    }
}

La función anterior hace referencia a la función eliminarFila(emp_id) que elimina la fila de la tabla de empleados. Esta función se ejecutará solo si el empleado se elimina físicamente de la base de datos. Debemos añadir esta función en nuestro fichero javascript para eliminar la fila de la tabla.

Función JavaScript para eliminar la fila de la tabla

// Función para eliminar la fila de la tabla después de la eliminación
function eliminarFila(emp_id) {
    // Encontrar la fila correspondiente en la tabla usando el data-id
    const fila = document.querySelector(`tr[data-id='${emp_id}']`);

    if (fila) {
        // Eliminar la fila de la tabla
        fila.remove();
    }
}

2. Creación del escript PHP

El archivo PHP eliminarEmpleado.php ahora debe verificar si el empleado está relacionado con algún departamento, salario o título. Si el empleado es jefe de un departamento, no podrá ser eliminado. Si está relacionado con periodos abiertos, los cerraremos con una fecha anterior a la actual.

Código PHP para validación y eliminación:

script PHP para validar la eliminación del empleado

<?php
try {
    // Conexión a la base de datos con MySQLi orientado a objetos
    $conexion = new mysqli("localhost", "root", "", "employees");

    // Verificar si la conexión fue exitosa
    if ($conexion->connect_error) {
        throw new Exception("Error en la conexión: " . $conexion->connect_error);
    }

    // Recibir los datos JSON enviados por AJAX
    $data = json_decode(file_get_contents("php://input"));

    if ($data) {
        $emp_id = $data->emp_id;
        $fecha_actual = new DateTime();
        $fecha_actual_str = $fecha_actual->format('Y-m-d');

        // **Validación 1: Comprobar si el empleado es jefe de un departamento activo**
        $query_departamento = "SELECT COUNT(*) FROM departments WHERE dept_mgr = ? AND to_date = '9999-01-01'";
        $stmt = $conexion->prepare($query_departamento);
        $stmt->bind_param("i", $emp_id);  // Enlazamos el parámetro (emp_id)
        $stmt->execute();
        $stmt->bind_result($jefe_departamento);
        $stmt->fetch();
        $stmt->close();

        if ($jefe_departamento > 0) {
            // Si el empleado es jefe de un departamento, no lo eliminamos
            echo json_encode(['success' => false, 'error' => 'El empleado es jefe de un departamento y no se puede eliminar.']);
            exit;
        }

        // **Validación 2: Verificar si el empleado está en algún departamento (tiene registros activos)**
        $query_departamentos = "SELECT COUNT(*) FROM dept_emp WHERE emp_no = ? AND to_date = '9999-01-01'";
        $stmt = $conexion->prepare($query_departamentos);
        $stmt->bind_param("i", $emp_id);  // Enlazamos el parámetro (emp_id)
        $stmt->execute();
        $stmt->bind_result($tiene_departamento);
        $stmt->fetch();
        $stmt->close();

        if ($tiene_departamento > 0) {
            // Si el empleado está en un departamento, cerramos sus periodos en departamentos, salarios y títulos

            // Cerrar registros de departamento activos
            $query_departamentos_update = "UPDATE dept_emp SET to_date = ? WHERE emp_no = ? AND to_date = '9999-01-01'";
            $stmt = $conexion->prepare($query_departamentos_update);
            $stmt->bind_param("si", $fecha_actual_str, $emp_id);  // Enlazamos los parámetros
            $stmt->execute();
            $stmt->close();

            // Cerrar registros de salario activos
            $query_salarios_update = "UPDATE salaries SET to_date = ? WHERE emp_no = ? AND to_date = '9999-01-01'";
            $stmt = $conexion->prepare($query_salarios_update);
            $stmt->bind_param("si", $fecha_actual_str, $emp_id);  // Enlazamos los parámetros
            $stmt->execute();
            $stmt->close();

            // Cerrar registros de título activos
            $query_titulos_update = "UPDATE titles SET to_date = ? WHERE emp_no = ? AND to_date = '9999-01-01'";
            $stmt = $conexion->prepare($query_titulos_update);
            $stmt->bind_param("si", $fecha_actual_str, $emp_id);  // Enlazamos los parámetros
            $stmt->execute();
            $stmt->close();

            echo json_encode(['success' => true, 'action' => 'cerrar_periodos']);
        } else {
            // **Validación 3: Si no está en ningún departamento (ni salarios, ni títulos), eliminamos el empleado**
            $query_eliminar = "DELETE FROM employees WHERE emp_no = ?";
            $stmt = $conexion->prepare($query_eliminar);
            $stmt->bind_param("i", $emp_id);  // Enlazamos el parámetro (emp_id)
            $stmt->execute();
            $stmt->close();

            echo json_encode(['success' => true, 'action' => 'eliminar']);
        }
    } else {
        echo json_encode(['success' => false, 'error' => 'ID del empleado no válido.']);
    }

} catch (Exception $e) {
    echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}

$conexion->close();
?>
<?php
try {
    // Conexión a la base de datos con PDO
    $conexion = new PDO("mysql:host=localhost;dbname=employees", "root", "");
    $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Recibir los datos JSON enviados por AJAX
    $data = json_decode(file_get_contents("php://input"));

    if ($data) {
        $emp_id = $data->emp_id;
        $fecha_actual = new DateTime();
        $fecha_actual_str = $fecha_actual->format('Y-m-d'); 

        // **Validación 1: Comprobar si el empleado es jefe de un departamento activo**
        $query_departamento = "SELECT COUNT(*) FROM departments WHERE dept_mgr = :emp_id AND to_date = '9999-01-01'";
        $stmt = $conexion->prepare($query_departamento);
        $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);
        $stmt->execute();
        $jefe_departamento = $stmt->fetchColumn();

        if ($jefe_departamento > 0) {
            // Si el empleado es jefe de un departamento, no lo eliminamos
            echo json_encode(['success' => false, 'error' => 'El empleado es jefe de un departamento y no se puede eliminar.']);
            exit;
        }

        // **Validación 2: Verificar si el empleado está en algún departamento (tiene registros activos)**
        $query_departamentos = "SELECT COUNT(*) FROM dept_emp WHERE emp_no = :emp_id AND to_date = '9999-01-01'";
        $stmt = $conexion->prepare($query_departamentos);
        $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);
        $stmt->execute();
        $tiene_departamento = $stmt->fetchColumn();

        if ($tiene_departamento > 0) {
            // Si el empleado está en un departamento, cerramos sus periodos en departamentos, salarios y títulos

            // Cerrar registros de departamento activos
            $query_departamentos_update = "UPDATE dept_emp SET to_date = :fecha_actual WHERE emp_no = :emp_id AND to_date = '9999-01-01'";
            $stmt = $conexion->prepare($query_departamentos_update);
            $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);
            $stmt->bindParam(':fecha_actual', $fecha_actual_str, PDO::PARAM_STR);
            $stmt->execute();

            // Cerrar registros de salario activos
            $query_salarios_update = "UPDATE salaries SET to_date = :fecha_actual WHERE emp_no = :emp_id AND to_date = '9999-01-01'";
            $stmt = $conexion->prepare($query_salarios_update);
            $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);
            $stmt->bindParam(':fecha_actual', $fecha_actual_str, PDO::PARAM_STR);
            $stmt->execute();

            // Cerrar registros de título activos
            $query_titulos_update = "UPDATE titles SET to_date = :fecha_actual WHERE emp_no = :emp_id AND to_date = '9999-01-01'";
            $stmt = $conexion->prepare($query_titulos_update);
            $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);
            $stmt->bindParam(':fecha_actual', $fecha_actual_str, PDO::PARAM_STR);
            $stmt->execute();

            echo json_encode(['success' => true, 'action' => 'cerrar_periodos']);
        } else {
            // **Validación 3: Si no está en ningún departamento (ni salarios, ni títulos), eliminamos el empleado**
            $query_eliminar = "DELETE FROM employees WHERE emp_no = :emp_id";
            $stmt = $conexion->prepare($query_eliminar);
            $stmt->bindParam(':emp_id', $emp_id, PDO::PARAM_INT);
            $stmt->execute();

            echo json_encode(['success' => true, 'action' => 'eliminar']);
        }
    } else {
        echo json_encode(['success' => false, 'error' => 'ID del empleado no válido.']);
    }
} catch (PDOException $e) {
    echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}

$conexion = null;
?>

Este script PHP se encarga de recibir el ID del empleado a eliminar, verificar si el empleado es jefe de un departamento, y si no lo es, proceder a cerrar los periodos activos o eliminarlo físicamente de la base de datos. Las respuestas pueden ser:

  • success: true si la acción fue exitosa.
  • action: cerrar_periodos si se cerraron los periodos activos.
  • action: eliminar si el empleado fue eliminado físicamente.
  • error: un mensaje de error si hubo algún problema durante la operación.

3. Explicación de los pasos en PHP:

  1. Comprobación si el empleado es jefe de un departamento: Si el empleado tiene el emp_no en la columna dept_mgr de la tabla departments, no puede ser eliminado.
  2. Cierre de periodos activos: Si el empleado tiene registros activos en salarios, títulos o departamentos, se actualizan sus registros con una fecha anterior a la actual (to_date se actualiza).
  3. Eliminación física: Si el empleado no tiene relaciones activas, se elimina físicamente de la base de datos.
  4. Devolución del estado: El servidor responde con success: true y la acción realizada (cerrar periodos o eliminar).

Resumen del flujo de eliminación de empleados:

  1. Comprobamos si el empleado es jefe de departamento.
  2. Si está relacionado con departamentos, salarios o títulos, cerramos esos registros con una fecha anterior a la actual.
  3. Eliminamos físicamente al empleado solo si no tiene relaciones activas.

3.7.7 Alta de empleados

Objetivos:

  1. Generar un nuevo ID automáticamente para los empleados cuando se agreguen.
  2. Fecha de alta por defecto: La fecha de alta debe ser la del día en que el empleado se agrega.
  3. Campos a rellenar por el usuario: Nombre, Apellido, Fecha de nacimiento, Fecha de contratación y Género.
  4. Validaciones tanto en JavaScript como en PHP para asegurar que los datos ingresados son correctos.

Pasos a seguir:

  1. Crear el formulario de alta en la página employees.php.
  2. Enviar el formulario con AJAX para agregar el empleado a la base de datos.
  3. Validar los datos en JavaScript antes de enviarlos al servidor.
  4. Procesar la inserción en el servidor con PHP, asignando un ID automático y la fecha de alta actual.
  5. Mostrar el nuevo empleado en la tabla sin recargar la página.

1. Crear el formulario de alta de empleados en employees.php:

En la página donde muestras la lista de empleados, vamos a utilizar el mismo modal que utilizamos para editar empleados, pero ahora lo usaremos para agregar nuevos empleados.

2. Función JavaScript para manejar la inserción:

Vamos a enviar los datos del formulario a través de AJAX para agregar al empleado sin recargar la página.

Función JavaScript para enviar los datos de alta del empleado:

Vamos a necesitar dos funciones, una para abrir el formulario y otra para guardar el empleado. La función guardarEmpleado() se encargará de enviar los datos al servidor y agregar el nuevo empleado a la tabla, y recoger los errores en caso de que los haya. Por otro lado, hay que añadir la función agregarEmpleadoATabla() que se encargará de agregar el nuevo empleado a la tabla de empleados. Por defecto, lo añadiremos como primer elemento de la tabla.

Código JavaScript para guardar el empleado

// Función para guardar el empleado
function guardarEmpleado() {
    const nombre = document.getElementById('nombre').value;
    const apellido = document.getElementById('apellido').value;
    const fecha_nacimiento = document.getElementById('fecha_nacimiento').value;
    const fecha_contratacion = document.getElementById('fecha_contratacion').value;
    const genero = document.getElementById('genero').value;

    // Validaciones en JavaScript
    if (!nombre || !apellido || !fecha_nacimiento || !fecha_contratacion || !genero) {
        alert("Todos los campos son obligatorios.");
        return;
    }

    // Validación de fechas: Fecha de nacimiento debe ser 18 años antes que la fecha de contratación
    const fechaNacimiento = new Date(fecha_nacimiento);
    const fechaContratacion = new Date(fecha_contratacion);
    const edadMinima = new Date();
    edadMinima.setFullYear(edadMinima.getFullYear() - 18);

    if (fechaNacimiento > edadMinima) {
        alert("La fecha de nacimiento debe ser al menos 18 años antes que la fecha de contratación.");
        return;
    }

    if (fechaContratacion > new Date()) {
        alert("La fecha de contratación no puede ser mayor a la fecha actual.");
        return;
    }

    // Enviar los datos al servidor usando AJAX (fetch)
    fetch('agregarEmpleado.php', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            'nombre': nombre,
            'apellido': apellido,
            'fecha_nacimiento': fecha_nacimiento,
            'fecha_contratacion': fecha_contratacion,
            'genero': genero
        })
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            // Si la inserción fue exitosa, agregar la fila en la tabla sin recargar la página
            agregarEmpleadoATabla(data.empleado);
            cerrarFormulario();
        } else {
            alert("Error al agregar el empleado.");
        }
    })
    .catch(error => {
        console.error('Error:', error);
        alert("Error al agregar el empleado.");
    });
}

// Función para agregar el empleado a la tabla
function agregarEmpleadoATabla(empleado) {
    const tabla = document.getElementById('empleadosTable');
    // insertar la nueva fila al principio de la tabla
    const nuevaFila = tabla.insertRow(0);

    nuevaFila.setAttribute('data-id', empleado.emp_no);
    nuevaFila.innerHTML = `
        <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><button onclick="editarEmpleado(${empleado.emp_no})">Editar</button></td>
        <td><button onclick="eliminarEmpleado(${empleado.emp_no})">Eliminar</button></td>
    `;
}

3. PHP para procesar el alta de empleados (agregarEmpleado.php):

En el servidor, creamos el archivo agregarEmpleado.php para procesar el alta del empleado. Asignamos un ID automático y la fecha de alta actual.

Código PHP para agregar un empleado:

En este archivo, recibimos los datos del formulario enviados por AJAX y los insertamos en la base de datos. Recibiremos un objeto JSON conlos datos del empleado, por ejemplo:

{
    "nombre": "Juan",
    "apellido": "Pérez",
    "fecha_nacimiento": "1990-01-01",
    "fecha_contratacion": "2023-10-01",
    "genero": "M"
}

Nuestro código PHP se encargará de procesar este JSON y agregar el empleado a la base de datos. Crearemos un fichero llamado agregarEmpleado.php que se encargará de recibir los datos del formulario y agregarlos a la base de datos.

Como ves en el ejemplo anterior, falta el campo emp_id porque no lo enviamos desde el formulario. En el código PHP, calcularemos el siguiente ID automáticamente, será un número más que el máximo ID existente en la tabla de empleados. De esta manera es tranasprente para el usuario y no tiene que preocuparse por el ID.

Código PHP para agregar un empleado

<?php
// Conexión a la base de datos con MySQLi OO
$host = getenv('MYSQL_HOST');
$user = getenv('MYSQL_USER');
$pass = getenv('MYSQL_PASSWORD');
$db = 'employees';
$conexion = new mysqli($host, $user, $pass, $db);
// Verificar conexión
if ($conexion->connect_error) {
    echo json_encode(['success' => false, 'error' => "Conexión fallida: " . $conexion->connect_error]);
    exit;
}
// Recibir los datos JSON enviados por AJAX
$data = json_decode(file_get_contents("php://input"));
if ($data) {
    /* Extraer datos del JSON */
    $nombre = $data->nombre;
    $apellido = $data->apellido;
    $fecha_nacimiento = $data->fecha_nacimiento;
    $fecha_contratacion = $data->fecha_contratacion;  // Usamos la fecha de contratación como fecha de alta
    $genero = $data->genero;
    // Convertir las fechas a formato string (Y-m-d)
    $fecha_nacimiento_str = date('Y-m-d', strtotime($fecha_nacimiento)); // Convertir la fecha de nacimiento
    $fecha_contratacion_str = date('Y-m-d', strtotime($fecha_contratacion)); // Convertir la fecha de contratación
    // Calcular el siguiente ID del empleado (MAX(emp_no) + 1)
    $query_max_id = "SELECT MAX(emp_no) FROM employees";
    $stmt = $conexion->prepare($query_max_id);
    $stmt->execute();
    $max_id = $stmt->fetchColumn();
    // Si no hay empleados (es el primer registro), establecer el emp_no como 1
    $nuevo_id = $max_id ? $max_id + 1 : 1;
    // Insertar el nuevo empleado en la base de datos
    $query = "INSERT INTO employees (emp_no, first_name, last_name, birth_date, hire_date, gender)
                VALUES (?, ?, ?, ?, ?, ?)";
    $stmt = $conexion->prepare($query);
    if (!$stmt) {
        echo json_encode(['success' => false, 'error' => "Error en la preparación de la consulta: " . $conexion->error]);
        exit;
    }
    $stmt->bind_param("isssss", $nuevo_id, $nombre, $apellido, $fecha_nacimiento_str, $fecha_contratacion_str, $genero);
    $stmt->execute();   
    /* Devolver el nuevo empleado con su ID generado */
    $empleado = {
        'emp_no' => $nuevo_id,  // Pasamos el ID calculado
        'first_name' => $nombre,
        'last_name' => $apellido,
        'birth_date' => $fecha_nacimiento_str,  
        'hire_date' => $fecha_contratacion_str,
        'gender' => $genero
    }
    echo json_encode(['success' => true, 'empleado' => $empleado]);
    $stmt->close();
    $conexion->close();
} else {
    echo json_encode(['success' => false, 'error' => 'Datos inválidos.']);
    exit;
}
<?php
try {
    // Conexión a la base de datos con PDO
    $conexion = new PDO("mysql:host=localhost;dbname=employees", "root", "");
    $conexion->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Recibir los datos JSON enviados por AJAX
    $data = json_decode(file_get_contents("php://input"));

    if ($data) {
        // Extraer datos del JSON
        $nombre = $data->nombre;
        $apellido = $data->apellido;
        $fecha_nacimiento = $data->fecha_nacimiento;
        $fecha_contratacion = $data->fecha_contratacion;  // Usamos la fecha de contratación como fecha de alta
        $genero = $data->genero;

        // Convertir las fechas a formato string (Y-m-d)
        $fecha_nacimiento_str = date('Y-m-d', strtotime($fecha_nacimiento)); // Convertir la fecha de nacimiento
        $fecha_contratacion_str = date('Y-m-d', strtotime($fecha_contratacion)); // Convertir la fecha de contratación


        // **Calcular el siguiente ID del empleado** (MAX(emp_no) + 1)
        $query_max_id = "SELECT MAX(emp_no) FROM employees";
        $stmt = $conexion->prepare($query_max_id);
        $stmt->execute();
        $max_id = $stmt->fetchColumn();

        // Si no hay empleados (es el primer registro), establecer el emp_no como 1
        $nuevo_id = $max_id ? $max_id + 1 : 1;

        // Insertar el nuevo empleado en la base de datos
        $query = "INSERT INTO employees (emp_no, first_name, last_name, birth_date, hire_date, gender)
                VALUES (:emp_no, :nombre, :apellido, :fecha_nacimiento, :fecha_contratacion, :genero)";

        $stmt = $conexion->prepare($query);
        $stmt->bindParam(':emp_no', $nuevo_id, PDO::PARAM_INT);  // Usar el ID calculado
        $stmt->bindParam(':nombre', $nombre, PDO::PARAM_STR);
        $stmt->bindParam(':apellido', $apellido, PDO::PARAM_STR);
        $stmt->bindParam(':fecha_nacimiento', $fecha_nacimiento_str, PDO::PARAM_STR);
        $stmt->bindParam(':fecha_contratacion', $fecha_contratacion_str, PDO::PARAM_STR);  // Usamos la fecha de contratación
        $stmt->bindParam(':genero', $genero, PDO::PARAM_STR);
        $stmt->execute();

        // Devolver el nuevo empleado con su ID generado
        $empleado = [
            'emp_no' => $nuevo_id,  // Pasamos el ID calculado
            'first_name' => $nombre,
            'last_name' => $apellido,
            'birth_date' => $fecha_nacimiento_str,
            'hire_date' => $fecha_contratacion_str,
            'gender' => $genero
        ];

        echo json_encode(['success' => true, 'empleado' => $empleado]);

    } else {
        echo json_encode(['success' => false, 'error' => 'Datos inválidos.']);
    }

} catch (PDOException $e) {
    echo json_encode(['success' => false, 'error' => 'Error en el servidor: ' . $e->getMessage()]);
}

$conexion = null;
?>

Resumen del flujo para agregar un empleado:

  1. Formulario en HTML: El formulario de alta es mostrado en un modal.
  2. Validación en JavaScript: Se valida la fecha de nacimiento y la fecha de contratación.
  3. Envío de datos con AJAX: Los datos se envían al servidor mediante fetch como un JSON.
  4. Inserción en la base de datos con PHP: El empleado es insertado en la base de datos con un ID automático.
  5. Actualizar la tabla: El nuevo empleado es añadido a la tabla sin recargar la página usando DOM.