Calendario de eventos - Otras variantes en la aplicación

Haremos una serie de modificaciones a nuestra aplicación del calendario de eventos luego de haber visto la estructura fundamental en los conceptos anteriores, ésto nos servirá para identificar que partes de la aplicación se deben modificar.

Algoritmos a implementar.

  1. Modificar el acceso a datos utilizando la librería PDO.

    Hay que hacer cambios en los archivos "conexion.php", "index.php", "datoseventos.php" y "datoseventospredefinidos.php".

    conexion.php
    <?php
    
    function retornarConexion() {
        $server="localhost";
        $usuario="root";
        $clave="";
        $base="base1";
        return new PDO("mysql:dbname=$base;host=$server", "$usuario","$clave", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); 
    }
    
    ?>
    
    datoseventos.php
    <?php
    header('Content-Type: application/json');
    
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select codigo as id,
                                         titulo as title,
                                         descripcion,
                                         inicio as start,
                                         fin as end,
                                         colortexto as textColor,
                                         colorfondo as backgroundColor 
                                    from eventos");
            $sql->execute();
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $sql = $pdo->prepare("insert into eventos(titulo,descripcion,inicio,fin,colortexto,colorfondo) values 
                                  (:titulo,:descripcion,:inicio,:fin,:colortexto,:colorfondo)
            ");
            $resultado = $sql->execute(array(
                "titulo" => $_POST['titulo'],
                "descripcion" => $_POST['descripcion'],
                "inicio" => $_POST['inicio'],
                "fin" => $_POST['fin'],
                "colortexto" => $_POST['colortexto'],
                "colorfondo" => $_POST['colorfondo'],
            ));
            echo json_encode($resultado);
            break;
    
        case 'modificar':
            $sql = $pdo->prepare("update eventos set titulo=:titulo,
                                                         descripcion=:descripcion,
                                                         inicio=:inicio,
                                                         fin=:fin,
                                                         colortexto=:colortexto,
                                                         colorfondo=:colorfondo
                                                     where codigo=:codigo");
            $resultado = $sql->execute(array(
                "titulo" => $_POST['titulo'],
                "descripcion" => $_POST['descripcion'],
                "inicio" => $_POST['inicio'],
                "fin" => $_POST['fin'],
                "colortexto" => $_POST['colortexto'],
                "colorfondo" => $_POST['colorfondo'],
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($resultado);
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from eventos where codigo=:codigo");
            $resultado = $sql->execute(array(
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($resultado);
            break;
    }
    
    datoseventospredefinidos.php
    <?php
    header('Content-Type: application/json');
    
    require("conexion.php");
    
    $pdo = retornarConexion();
    
    switch ($_GET['accion']) {
        case 'listar':
            $sql = $pdo->prepare("select codigo,titulo,horainicio,horafin,colortexto,colorfondo from eventospredefinidos");
            $sql->execute();
            $resultado = $sql->fetchAll(PDO::FETCH_ASSOC);
            echo json_encode($resultado);
            break;
    
        case 'agregar':
            $sql = $pdo->prepare("insert into eventospredefinidos(titulo,horainicio,horafin,colortexto,colorfondo) values 
                                              (:titulo,:horainicio,:horafin,:colortexto,:colorfondo)");
            $resultado = $sql->execute(array(
                "titulo" => $_POST['titulo'],
                "horainicio" => $_POST['horainicio'],
                "horafin" => $_POST['horafin'],
                "colortexto" => $_POST['colortexto'],
                "colorfondo" => $_POST['colorfondo']
            ));
            echo json_encode($resultado);
            break;
    
        case 'borrar':
            $sql = $pdo->prepare("delete from eventospredefinidos where codigo=:codigo");
            $resultado = $sql->execute(array(
                "codigo" => $_POST['codigo']
            ));
            echo json_encode($resultado);
            break;
    
    }
    

    El último archivo que requiere modificar el acceso a datos con la librería PDO es:

    index.php
    <!DOCTYPE html>
    <html lang="es">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Calendario de Eventos</title>
    
      <link href="bootstrap-4.3.1/css/bootstrap.min.css" rel="stylesheet">
      <link href="datatables/datatables.min.css" rel="stylesheet">
      <link href="clockpicker/bootstrap-clockpicker.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/core/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/daygrid/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/timegrid/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/list/main.css" rel="stylesheet">
      <link href="fullcalendar-4.3.1/packages/bootstrap/main.css" rel="stylesheet">
    
    
      <script src="js/jquery-3.4.1.js"></script>
      <script src="js/popper.min.js"></script>
      <script src="bootstrap-4.3.1/js/bootstrap.min.js"></script>
      <script src="datatables/datatables.min.js"></script>
      <script src="clockpicker/bootstrap-clockpicker.js"></script>
      <script src='js/moment-with-locales.js'></script>
      <script src='fullcalendar-4.3.1/packages/core/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/daygrid/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/timegrid/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/interaction/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/list/main.js'></script>
      <script src='fullcalendar-4.3.1/packages/core/locales/es.js'></script>
      <script src='fullcalendar-4.3.1/packages/bootstrap/main.js'></script>
    </head>
    
    <body>
      <div class="container-fluid">
        <section class="content-header">
          <h1>
            Calendario
            <small>Panel de control</small>
          </h1>
        </section>
    
        <div class="row">
    
          <div class="col-10">
            <div id="Calendario1" style="border: 1px solid #000;padding:2px"></div>
          </div>
    
          <div class="col-2">
            <div id='external-events' style="margin-bottom:1em; height: 350px; border: 1px solid #000; overflow: auto;padding:1em">
              <h4 class="text-center">Eventos predefinidos</h4>
              <div id='listaeventospredefinidos'>
    
                <?php
                require("conexion.php");
                $pdo = retornarConexion();
                $sql = $pdo->prepare("SELECT codigo,titulo,horainicio,horafin,colortexto,colorfondo FROM eventospredefinidos");
                $sql->execute();
                $ep = $sql->fetchAll(PDO::FETCH_ASSOC);
                foreach ($ep as $fila)
                  echo "<div class='fc-event' data-titulo='$fila[titulo]' data-horafin='$fila[horafin]' data-horainicio='$fila[horainicio]' 
                        data-colorfondo='$fila[colorfondo]' data-colortexto='$fila[colortexto]' data-codigo='$fila[codigo]'
                        style='border-color:$fila[colorfondo];color:$fila[colortexto];background-color:$fila[colorfondo];margin:10px'>
                        $fila[titulo]  [" . substr($fila['horainicio'], 0, 5) . " a " . substr($fila['horafin'], 0, 5) . "]</div>";
    
                ?>
              </div>
            </div>
            <hr>
            <div style="text-align:center"><button type="button" id="BotonEventosPredefinidos" class="btn btn-success">Administrar eventos predefinidos</button>
            </div>
          </div>
    
        </div>
      </div>
    
    
      <!-- FormularioEventos -->
      <div class="modal fade" id="FormularioEventos" tabindex="-1" role="dialog">
        <div class="modal-dialog" role="document">
          <div class="modal-content">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">×</span>
              </button>
            </div>
            <div class="modal-body">
              <input type="hidden" id="Codigo">
              <div class="form-row">
                <div class="form-group col-md-12">
                  <label>Título del evento:</label>
                  <input type="text" id="Titulo" class="form-control" placeholder="">
                </div>
              </div>
    
              <div class="form-row">
                <div class="form-group col-md-6">
                  <label>Fecha de inicio:</label>
    
                  <div class="input-group" data-autoclose="true">
                    <input type="date" id="FechaInicio" value="" class="form-control" />
                  </div>
                </div>
                <div class="form-group col-md-6" id="TituloHoraInicio">
                  <label>Hora de inicio:</label>
    
                  <div class="input-group clockpicker" data-autoclose="true">
                    <input type="text" id="HoraInicio" value="" class="form-control" autocomplete="off" />
                  </div>
                </div>
              </div>
    
              <div class="form-row">
                <div class="form-group col-md-6">
                  <label>Fecha de fin:</label>
    
                  <div class="input-group" data-autoclose="true">
                    <input type="date" id="FechaFin" value="" class="form-control" />
                  </div>
                </div>
                <div class="form-group col-md-6" id="TituloHoraFin">
                  <label>Hora de fin:</label>
    
                  <div class="input-group clockpicker" data-autoclose="true">
                    <input type="text" id="HoraFin" value="" class="form-control" autocomplete="off" />
                  </div>
                </div>
              </div>
    
              <div class="form-group">
                <label>Descripción:</label>
                <textarea id="Descripcion" rows="3" class="form-control"></textarea>
              </div>
              <div class="form-group">
                <label>Color de fondo:</label>
                <input type="color" value="#3788D8" id="ColorFondo" class="form-control" style="height:36px;">
              </div>
              <div class="form-group">
                <label>Color de texto:</label>
                <input type="color" value="#ffffff" id="ColorTexto" class="form-control" style="height:36px;">
              </div>
    
            </div>
            <div class="modal-footer">
    
              <button type="button" id="BotonAgregar" class="btn btn-success">Agregar</button>
              <button type="button" id="BotonModificar" class="btn btn-success">Modificar</button>
              <button type="button" id="BotonBorrar" class="btn btn-success">Borrar</button>
              <button type="button" class="btn btn-success" data-dismiss="modal">Cancelar</button>
    
            </div>
          </div>
        </div>
      </div>
    
    
      <script>
        document.addEventListener("DOMContentLoaded", function() {
    
          $('.clockpicker').clockpicker();
    
          let calendario1 = new FullCalendar.Calendar(document.getElementById('Calendario1'), {
            plugins: ['dayGrid', 'timeGrid', 'interaction'],
            height: 800,
            droppable: true,
            locale: 'es',
            showNonCurrentDates: false,
            header: {
              left: 'today,prev,next',
              center: 'title',
              right: 'dayGridMonth,timeGridWeek,timeGridDay'
            },
            editable: true,
            events: 'datoseventos.php?accion=listar',
            dateClick: function(info) {
              limpiarFormulario();
              $('#BotonAgregar').show();
              $('#BotonModificar').hide();
              $('#BotonBorrar').hide();
              if (info.allDay) {
                $('#FechaInicio').val(info.dateStr);
                $('#FechaFin').val(info.dateStr);
              } else {
                let fechaHora = info.dateStr.split("T");
                $('#FechaInicio').val(fechaHora[0]);
                $('#FechaFin').val(fechaHora[0]);
                $('#HoraInicio').val(fechaHora[1].substring(0, 5));
              }
              $("#FormularioEventos").modal();
            },
            eventClick: function(info) {
              $('#BotonModificar').show();
              $('#BotonBorrar').show();
              $('#BotonAgregar').hide();
              $('#Codigo').val(info.event.id);
              $('#Titulo').val(info.event.title);
              $('#Descripcion').val(info.event.extendedProps.descripcion);
              $('#FechaInicio').val(moment(info.event.start).format("YYYY-MM-DD"));
              $('#FechaFin').val(moment(info.event.end).format("YYYY-MM-DD"));
              $('#HoraInicio').val(moment(info.event.start).format("HH:mm"));
              $('#HoraFin').val(moment(info.event.end).format("HH:mm"));
              $('#ColorFondo').val(info.event.backgroundColor);
              $('#ColorTexto').val(info.event.textColor);
              $("#FormularioEventos").modal();
            },
            eventResize: function(info) {
              $('#Codigo').val(info.event.id);
              $('#Titulo').val(info.event.title);
              $('#FechaInicio').val(moment(info.event.start).format("YYYY-MM-DD"));
              $('#FechaFin').val(moment(info.event.end).format("YYYY-MM-DD"));
              $('#HoraInicio').val(moment(info.event.start).format("HH:mm"));
              $('#HoraFin').val(moment(info.event.end).format("HH:mm"));
              $('#ColorFondo').val(info.event.backgroundColor);
              $('#ColorTexto').val(info.event.textColor);
              $('#Descripcion').val(info.event.extendedProps.descripcion);          
              let registro = recuperarDatosFormulario();
              modificarRegistro(registro);
            },
            eventDrop: function(info) {
              $('#Codigo').val(info.event.id);
              $('#Titulo').val(info.event.title);
              $('#FechaInicio').val(moment(info.event.start).format("YYYY-MM-DD"));
              $('#FechaFin').val(moment(info.event.end).format("YYYY-MM-DD"));
              $('#HoraInicio').val(moment(info.event.start).format("HH:mm"));
              $('#HoraFin').val(moment(info.event.end).format("HH:mm"));
              $('#ColorFondo').val(info.event.backgroundColor);
              $('#ColorTexto').val(info.event.textColor);
              $('#Descripcion').val(info.event.extendedProps.descripcion);
              let registro = recuperarDatosFormulario();
              modificarRegistro(registro);
            },
            drop: function(info) {
              limpiarFormulario();
              $('#ColorFondo').val(info.draggedEl.dataset.colorfondo);
              $('#ColorTexto').val(info.draggedEl.dataset.colortexto);
              $('#Titulo').val(info.draggedEl.dataset.titulo);
              let fechaHora = info.dateStr.split("T");
              $('#FechaInicio').val(fechaHora[0]);
              $('#FechaFin').val(fechaHora[0]);
              if (info.allDay) { //verdadero si el calendario esta en vista de mes
                $('#HoraInicio').val(info.draggedEl.dataset.horainicio);
                $('#HoraFin').val(info.draggedEl.dataset.horafin);
              } else {
                $('#HoraInicio').val(fechaHora[1].substring(0, 5));
                $('#HoraFin').val(moment(fechaHora[1].substring(0, 5)).add(1, 'hours'));
              }
              let registro = recuperarDatosFormulario();
              agregarEventoPredefinido(registro);
            }
          });
    
          calendario1.render();
    
    
          new FullCalendarInteraction.Draggable(document.getElementById('listaeventospredefinidos'), {
            itemSelector: '.fc-event',
            eventData: function(eventEl) {
              return {
                title: eventEl.innerText.trim()
              }
            }
          });
    
          //Eventos de botones de la aplicación
          $('#BotonAgregar').click(function() {
            let registro = recuperarDatosFormulario();
            agregarRegistro(registro);
            $("#FormularioEventos").modal('hide');
          });
    
          $('#BotonModificar').click(function() {
            let registro = recuperarDatosFormulario();
            modificarRegistro(registro);
            $("#FormularioEventos").modal('hide');
          });
    
          $('#BotonBorrar').click(function() {
            let registro = recuperarDatosFormulario();
            borrarRegistro(registro);
            $("#FormularioEventos").modal('hide');
          });
    
          $('#BotonEventosPredefinidos').click(function() {
            window.location = "eventospredefinidos.html";
          });
    
    
          // funciones para comunicarse con el servidor via ajax
          function agregarRegistro(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=agregar',
              data: registro,
              success: function(msg) {
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function modificarRegistro(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=modificar',
              data: registro,
              success: function(msg) {
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function borrarRegistro(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=borrar',
              data: registro,
              success: function(msg) {
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          function agregarEventoPredefinido(registro) {
            $.ajax({
              type: 'POST',
              url: 'datoseventos.php?accion=agregar',
              data: registro,
              success: function(msg) {
                calendario1.removeAllEvents();
                calendario1.refetchEvents();
              },
              error: function(error) {
                alert("Hay un problema:" + error);
              }
            });
          }
    
          // funciones que interactuan con el formulario de entrada de datos
          function limpiarFormulario() {
            $('#Codigo').val('');
            $('#Titulo').val('');
            $('#Descripcion').val('');
            $('#FechaInicio').val('');
            $('#FechaFin').val('');
            $('#HoraInicio').val('');
            $('#HoraFin').val('');
            $('#ColorFondo').val('#3788D8');
            $('#ColorTexto').val('#ffffff');
          }
    
          function recuperarDatosFormulario() {
            let registro = {
              codigo: $('#Codigo').val(),
              titulo: $('#Titulo').val(),
              descripcion: $('#Descripcion').val(),
              inicio: $('#FechaInicio').val() + ' ' + $('#HoraInicio').val(),
              fin: $('#FechaFin').val() + ' ' + $('#HoraFin').val(),
              colorfondo: $('#ColorFondo').val(),
              colortexto: $('#ColorTexto').val()
            };
            return registro;
          }
    
        });
      </script>
    
    </body>
    
    </html>
    

    El resultado de ejecutar la aplicación es la misma, solo hemos cambiado la librería para acceder a nuestra base de datos MySQL.