Implementar FullCalendar en Symfony

FullCalendar es un plugin jQuery que nos permite implementar de manera sencilla un calendario con una interfaz visual excelente y muy fácil de personalizar. Además, podemos hacer Drag&Drop (arrastrar y soltar) de los eventos agendados para pasarlos de un día a otro.

Hoy vamos a montar en symfony un módulo que nos mostrará un calendario con los eventos almacenados en nuestra base de datos. La parte de administración no la desarrollaré, pero con las completas herramientas que nos ofrece symfony, nos será muy fácil montarlo (si estás dando tus primeros pasos con Symfony, te recomiendo realizar este tutorial donde podrás ver paso a paso como se implementa un projecto con Symfony).

FullCalendar

Generando y configurando el proyecto

Empezaremos desde el principio, creando el proyecto, la aplicación frontend y el módulo calendar:

symfony generate:project calendar
symfony generate:app frontend
symfony generate:module frontend calendar

Ahora conectamos nuestro proyecto con la base de datos modificando el archivo /path/to/project/config/databases.yml

all:
  propel:
    class:        sfPropelDatabase
    param:
      classname:  PropelPDO
      dsn:        mysql:dbname=<strong>[DB-NAME]</strong>;host=localhost
      username:   <strong>[DB-USER]</strong>
      password:   <strong>[DB-PASS]</strong>
      encoding:   utf8
      persistent: true
      pooling:    true

Nuestro siguiente paso será añadir la estructura de base de datos al archivo /path/to/project/config/schema.yml

propel:
  cal:
    id: ~
    description: {type:varchar(50), required: true }
    category: {type: integer, foreignTable: cal_category, foreignReference: id, required: true}
    details: {type:varchar(255), required: true }
    dstart: {type: date, required: true }
    dend: {type: date, required: true }
    created_at: ~
    updated_at: ~
    _indexes:
      intra_cal_I_1: [dstart]
      intra_cal_I_1: [dend]

  cal_category:
    id: ~
    category: {type:varchar(50), required: true, index: unique}
    created_at: ~
    updated_at: ~

y ahora, desde línea de comandos, indicaremos a symfony que genere la base de datos y el modelo de datos, para ello, ejecutamos:

symfony propel:build-all

Con estos pasos ya tenemos preparado nuestro proyecto para integrar FullCalendar… manos a la obra!

Integrando FullCalendar

El primer paso será bajarnos jQuery y FullCalendar de las páginas oficiales. Después guardamos los js jquery.min.js, fullcalendar.min.js, ui.draggable.js y ui.core.js en la carpeta /path/to/project/web/js y el css fullcalendar.css en /path/to/project/web/css.

Suele ser buena práctica definir las rutas antes de empezar a programar.  Dejaremos la ruta por defecto para mostrar el calendario, pero modificaremos la que nos muestra los detalles para indicarle que debe usar la clase sfPropelRoute que nos permitirá obtener el objeto job sin necesidad de generar la consulta SQL. Abrimos el archivo /path/to/project/apps/frontend/config/routing.yml y le añadimos:

cal_show_event:
  url:   /:module/:action/id/:id
  class:   sfPropelRoute
  options: { model: Cal, type: object }
  param:   { module: calendar, action: show }

El siguiente paso será implementar los eventos del mes actual hacia adelante, añadiendo la siguiente función al archivo /path/to/project/lib/model/CalPeer.php

  static public function getCalEvents(){
    // crea el inicio de mes
    $IniMes = date('d-m-Y',mktime(0,0,0,date('m'),1,date('Y')));
    $criteria = new Criteria();
    $criteria->add(self::DSTART, $IniMes, Criteria::GREATER_EQUAL);
    return self::doSelect($criteria);
  }

En el index de nuestro módulo /path/to/project/apps/frontend/modules/calendar/actions/actions.class.php llamámos a esta función:

  public function executeIndex(sfWebRequest $request)
  {
    $this->cal_list = CalPeer::getCalEvents();
  }
  public function executeShow(sfWebRequest $request)
  {
    $this->cal = $this->getRoute()->getObject();
  }

Ahora es el momento de crear la vista /path/to/project/apps/frontend/modules/calendar/templates/indexSuccess.php

<?php use_stylesheet('fullcalendar.css') ?>
<script type='text/javascript'>

$(document).ready(function() {

var d = new Date();
var y = d.getFullYear();
var m = d.getMonth();

$('#calendar').fullCalendar({
draggable: true,
events: [
<?php $total = count($intra_cal_list); $i=0; ?>
<?php foreach ($cal_list as $intra_cal): ?>
{
<?php $i++; ?>
id: <?php echo $intra_cal->getId() ?>,
title: "<?php echo $intra_cal->getDescription() ?>",
<?php
$fecha = strtotime($intra_cal->getDstart());
$anno = date("Y", $fecha);
$mes = date("m", $fecha);
$mes--;
$dia = date("d", $fecha);
?>
start: <?php echo "new Date(".$anno.", ".$mes.", ".$dia.")"; ?>,
<?php
$fecha = strtotime($intra_cal->getDend());
$anno = date("Y", $fecha); $mes = date("m", $fecha);
$mes--;
$dia = date("d", $fecha);
?>
end: <?php echo "new Date(".$anno.", ".$mes.", ".$dia.")"; ?>,
url: "<?php echo url_for('cal/show?id='.$intra_cal->getId()) ?>"
}<?php if ($i != $total) echo "," ?>
<?php endforeach; ?>
]
});

});

</script>

<div id='calendar'></div>

y la vista que nos mostrará el detalle de un evento /path/to/project/apps/frontend/modules/calendar/templates/showSuccess.php

<h1><?php echo $cal->getDescription()?></h1>
<?php echo $cal->getDetails() ?>

Por último, añadimos las siguientes líneas al layout /path/to/project/apps/frontend/templates/layout.php

<?php use_javascript('jquery.min.js') ?>
<?php use_javascript('fullcalendar.min.js') ?>
<?php use_javascript('ui.core.js') ?>
<?php use_javascript('ui.draggable.js') ?>

Hecho esto, si accedemos a nuestra aplicación desde el navegador http://localhost/web/calendar/index veremso nuestro calendario funcionando.

13 thoughts on “Implementar FullCalendar en Symfony

  1. Hola. Te quería preguntar si la consulta a la base de datos carga todos los eventos que devuelva la sql, o se va generando la consulta según se vaya pasando de mes a mes.

    De no ser así, ¿habría alguna manera de que según se vaya pinchando en un mes se genere la consulta?

    Un saludo.

  2. Lo intente hacer, pero no me sale el calendario… estoy usando doctrine, pero igual no creo q sea el problema….

  3. He adaptado supuestamente el “fullcalendar” doctrine, pero tengo problemas con la visualización. Es decir, no veo el index.
    Ayuda?

  4. Con algunas modificaciones ya esta funcionando en mi proyecto; ya solo haría falta marcar fechas en fullCalendar y que estas se graben en la base de datos. ¿como se haría eso con ajax ?

  5. Thank you so much! This example was very helpful, even if I don’t speak Spanish at all! 🙂
    But the tricky part is this one , because the calendar won’t be displayed if you have more than one event and if you have forgotten to insert the commas.

    Anyway, thanks for this!

  6. Hola!

    Manel, no puedo más que agradecerte este tip que me ha ayudado a hacer un módulo completo de la aplicación en un día… cuando yo lo estimaba en una semana 😀

    Yo lo he hecho con Doctrine y la carga de los eventos con AJAX… si cuelgo un post en el blog te enlazo 😉

    Gracias!

  7. gracias por el aporte!!!!
    no me aparecia en pantalla, tuve que hacer algunos arreglos seguramente por los cambios de versiones.
    un error que no me permitia que funcione es en:
    /path/to/project/apps/frontend/modules/calendar/templates/indexSuccess.php
    linea
    ?php $total = count($intra_cal_list); $i=0; ?
    cambiar por:
    ?php $total = count($cal_list); $i=0; ?

    Saludos

  8. Jejeje te quedo infinitamente agradecido, mi problema era de agregar los eventos, pero me diste la solución perfecta.

    Muchas gracias! Saludos desde Colombia

Comments are closed.