Tutorial de FullCalendar con PHP, MySQL, Bootstrap 5 y jQuery/JavaScript

Compartir

[caption id="attachment_2980" align="aligncenter" width="2048"]FullCalendar con PHP FullCalendar con PHP[/caption]

En este tutorial, aprenderás a implementar un calendario interactivo utilizando FullCalendar, un popular plugin de JavaScript que permite gestionar eventos de manera sencilla y efectiva. Utilizaremos PHP y MySQL para manejar los datos del calendario, así como Bootstrap 5 y jQuery para crear una interfaz de usuario atractiva y funcional. A lo largo del tutorial, abordaremos cómo agregar, editar y eliminar eventos en el calendario, garantizando que tengas una comprensión completa del proceso.

Requisitos Previos

Antes de comenzar, asegúrate de tener instalado lo siguiente:

  • Servidor web con PHP (XAMPP, WAMP, etc.)
  • Base de datos MySQL
  • Conocimientos básicos de PHP, MySQL, HTML, CSS y JavaScript.

Estructura del Proyecto

Crea una carpeta para tu proyecto y dentro de ella, crea la siguiente estructura de archivos:

/tu-proyecto
├── index.php
├── fetch_events.php
├── add_event.php
├── update_event.php
├── delete_event.php
├── db_connection.php

Configuración de la Base de Datos

  1. Accede a tu administrador de base de datos (phpMyAdmin, por ejemplo).
  2. Crea una base de datos llamada test_calendario.
  3. Crea una tabla llamada eventos con la siguiente estructura:
CREATE TABLE eventos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    start DATETIME NOT NULL,
    end DATETIME NOT NULL
);

Creación de Archivos PHP

index.php

Este archivo contendrá el código HTML y JavaScript necesario para cargar y manejar el calendario.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Calendario con FullCalendar, PHP y MySQL</title>

<!-- FullCalendar CSS --> <link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css" rel="stylesheet">

<!-- Bootstrap CSS --> <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet"> </head> <body>

<div class="container mt-5"> <h1 class="text-center">Calendario de Eventos</h1> <div id="calendar"></div> </div>

<!-- Modal para Crear/Editar Evento --> <div class="modal fade" id="eventModal" tabindex="-1" aria-labelledby="eventModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <form id="eventForm"> <div class="modal-header"> <h5 class="modal-title" id="eventModalLabel">Agregar Evento</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="mb-3"> <label for="title" class="form-label">Título del Evento</label> <input type="text" class="form-control" id="title" name="title" required> </div> <div class="mb-3"> <label for="start" class="form-label">Fecha de Inicio</label> <input type="date" class="form-control" id="start" name="start" required> </div> <div class="mb-3"> <label for="end" class="form-label">Fecha de Fin</label> <input type="date" class="form-control" id="end" name="end"> </div> <input type="hidden" id="eventId" name="eventId"> </div> <div class="modal-footer"> <button type="submit" class="btn btn-primary">Guardar</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button> <button type="button" id="deleteEventBtn" class="btn btn-danger" style="display: none;">Eliminar Evento</button> </div> </form> </div> </div> </div>

<!-- jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<!-- Bootstrap JS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>

<!-- FullCalendar JS --> <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/locales/es.js"></script>

<script> document.addEventListener("DOMContentLoaded", function() { const calendarEl = document.getElementById('calendar'); const calendar = new FullCalendar.Calendar(calendarEl, { locale: 'es', initialView: 'dayGridMonth', editable: true, events: 'fetch_events.php', eventClick: function(info) { // Editar evento al hacer clic $('#eventModal').modal('show'); $('#title').val(info.event.title); $('#start').val(info.event.startStr); $('#end').val(info.event.endStr); $('#eventId').val(info.event.id); $('#eventModalLabel').text('Editar Evento'); $('#deleteEventBtn').show(); // Mostrar botón de eliminar }, dateClick: function(info) { // Crear nuevo evento al hacer clic en una fecha $('#eventModal').modal('show'); $('#eventForm')[0].reset(); $('#start').val(info.dateStr); $('#end').val(''); $('#eventId').val(''); $('#eventModalLabel').text('Agregar Evento'); $('#deleteEventBtn').hide(); // Ocultar botón de eliminar } });

calendar.render();

// Guardar evento (Agregar o Editar) $('#eventForm').on('submit', function(e) { e.preventDefault(); const eventData = { title: $('#title').val(), start: $('#start').val(), end: $('#end').val(), id: $('#eventId').val() };

$.ajax({ url: eventData.id ? 'update_event.php' : 'add_event.php', type: 'POST', dataType: 'json', data: eventData, success: function(response) { $('#eventModal').modal('hide'); calendar.refetchEvents(); // Recargar eventos if (response && response.message) { alert(response.message); } else { alert("Error: respuesta no válida del servidor"); } }, error: function() { alert("Error al guardar el evento."); } }); });

// Eliminar evento $('#deleteEventBtn').on('click', function() { const eventId = $('#eventId').val();

if (eventId) { $.ajax({ url: 'delete_event.php', type: 'POST', dataType: 'json', data: { id: eventId }, success: function(response) { $('#eventModal').modal('hide'); calendar.refetchEvents(); // Recargar eventos alert(response.message); // Mostrar mensaje de éxito o error }, error: function() { alert("Error al eliminar el evento."); } }); } }); }); </script> </body> </html>

fetch_events.php

Este archivo se encarga de recuperar los eventos de la base de datos y devolverlos en formato JSON.

<?php
// Incluir archivo de conexión
include 'db_connection.php';

$sql = "SELECT id, title, start, end FROM eventos"; $result = $conexion->query($sql);

$events = []; while ($row = $result->fetch_assoc()) { $events[] = $row; }

header('Content-Type: application/json'); echo json_encode($events); ?>

add_event.php

Este archivo permite agregar nuevos eventos a la base de datos.

<?php
// Incluir archivo de conexión
include 'db_connection.php';

$title = $_POST['title']; $start = $_POST['start']; $end = $_POST['end'] ?: $start;

$sql = "INSERT INTO eventos (title, start, end) VALUES (?, ?, ?)"; $stmt = $conexion->prepare($sql); $stmt->bind_param("sss", $title, $start, $end); $stmt->execute();

// Verificar si se insertó el evento if ($stmt->affected_rows > 0) { $response = ['message' => 'Evento agregado exitosamente']; } else { $response = ['message' => 'Error al agregar el evento']; }

// Respuesta en JSON header('Content-Type: application/json'); echo json_encode($response); ?>

update_event.php

Este archivo permite actualizar los eventos existentes.

<?php
// Incluir archivo de conexión
include 'db_connection.php';

$id = $_POST['id']; $title = $_POST['title']; $start = $_POST['start']; $end = $_POST['end'] ?: $start;

$sql = "UPDATE eventos SET title = ?, start = ?, end = ? WHERE id = ?"; $stmt = $conexion->prepare($sql); $stmt->bind_param("sssi", $title, $start, $end, $id); $stmt->execute();

// Verificar si se actualizó el evento if ($stmt->affected_rows > 0) { $response = ['message' => 'Evento actualizado exitosamente']; } else { $response = ['message' => 'Error al actualizar el evento']; }

// Respuesta en JSON header('Content-Type: application/json'); echo json_encode($response); ?>

delete_event.php

Este archivo permite eliminar eventos de la base de datos.

<?php
// Incluir archivo de conexión
include 'db_connection.php';

$id = $_POST['id'];

$sql = "DELETE FROM eventos WHERE id = ?"; $stmt = $conexion->prepare($sql); $stmt->bind_param("i", $id); $stmt->execute();

if ($stmt->affected_rows > 0) { $response = ['message' => 'Evento eliminado exitosamente']; } else { $response = ['message' => 'Error al eliminar el evento']; }

header('Content-Type: application/json'); echo json_encode($response); ?>

db_connection.php

Este archivo maneja la conexión a la base de datos.

<?php
// db_connection.php

$host = "localhost"; $username = "root"; $password = ""; $dbname = "test_calendario";

// Crear la conexión $conexion = new mysqli($host, $username, $password, $dbname);

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

// Establecer la codificación de caracteres a UTF-8 $conexion->set_charset("utf8");

?>

Integración de FullCalendar

En este capítulo, hemos integrado el plugin FullCalendar y lo hemos configurado para cargar eventos desde la base de datos. También hemos creado un modal para agregar y editar eventos.

Agregar Funcionalidad para Editar y Eliminar Eventos

En este capítulo, hemos implementado la lógica para editar y eliminar eventos a través de AJAX, haciendo que nuestra aplicación sea más interactiva y dinámica.

Conclusiones

A lo largo de este tutorial, hemos aprendido a crear un calendario interactivo utilizando FullCalendar, PHP y MySQL. Este conocimiento puede ser extendido y adaptado para desarrollar aplicaciones más complejas que requieran gestión de eventos.

Cabe mencionar que previamente habíamos publicado un tutorial similar en FullCalendar con PHP y MySQL. Sin embargo, ya ha pasado bastante tiempo desde entonces; si gustas, puedes echarle un vistazo. Dado el tiempo transcurrido y la aceptación que tuvo en su momento, decidimos realizar una actualización de ese contenido, adaptándolo a las tecnologías y buenas prácticas actuales.

Obed Alvarado

Sobre el autor

Artículo redactado por Obed Alvarado. Comparto experiencias prácticas sobre PHP, MySQL, aplicaciones web, instalación en hosting y herramientas para negocios.

Comentarios