FullCalendar : chargement et mise à jour des évènements dans une base de données

Posté par seiyar81 le 7 août 2013 | Laisser un commentaire (7)

Pour faire suite au précédent article présentant le plugin FullCalendar, nous allons voir comment charger des évènements depuis une base de données pour peupler notre calendrier et ensuite comment les mettre à jour.

Nous allons pour cela mettre en place un calendrier avec affichage simple (mois/semaine/jour) sur notre page web :


<html>
<head>
<link href='fullcalendar/fullcalendar/fullcalendar.css' rel='stylesheet' />
<link href='fullcalendar/fullcalendar/fullcalendar.print.css' rel='stylesheet' media='print' />
<script src='fullcalendar/jquery/jquery.min.js'></script>
<script src='fullcalendar/jquery/jquery-ui.min.js'></script>
<script src='fullcalendar/fullcalendar/fullcalendar.js'></script>

<style>

	body {
		margin-top: 40px;
		text-align: center;
		font-size: 14px;
		font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
		}

	#calendar {
		width: 900px;
		margin: 0 auto;
		}

</style>
</head>
<body>
<div id='calendar'></div>
</body>
</html>

Côté serveur, il va nous falloir une base de données, forcément, avec une table pour stocker les évènements pouvant ressembler à ceci :



--
-- Table structure for table `event`
--

CREATE TABLE IF NOT EXISTS `event` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(55) NOT NULL,
  `start` datetime NOT NULL,
  `end` datetime DEFAULT NULL,
  `allDay` tinyint(1) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

On va ensuite ajouter le code Javascript pour charger et mettre à jour les évènements :


    $(document).ready(function() {
	
        function updateEvent(event,dayDelta,minuteDelta,allDay)
        {
            $.ajax({ 'url': 'ajax.php?action=update', 'type': 'POST', 
                'data': {'id':event.id, 'dayDelta': dayDelta, 'minuteDelta': minuteDelta, 'allDay': allDay},
                success: function(data) {
                    if(data.error)
                        alert(data.error);
                },
                error: function(data) {
                   alert('Une erreur est survenue.'); 
                }
            });
        }
		
				$('#calendar').fullCalendar({
            header: {
    					left: 'prev,next today',
							center: 'title',
							right: 'month,agendaWeek,agendaDay'
						},
            editable: true,
            eventSources: [
                'ajax.php?action=get'
            ],
            eventDrop: function(event,dayDelta,minuteDelta,allDay,revertFunc) {    
                if (!confirm("Valider la modification ?")) {
                    revertFunc();
                } else {
                    updateEvent(event,dayDelta,minuteDelta,allDay);
                }
            },
            eventResize: function(event,dayDelta,minuteDelta,revertFunc) {
                if (!confirm("Valider la modification ?")) {
                    revertFunc();
                } else {
                    updateEvent(event,dayDelta,minuteDelta,0);
                }
            }
		});
		
	});

On note donc que le paramètre d’initialisation eventSources indique au calendrier une (ou plusieurs) url à interroger pour charger les évènements.
Le résultat attendu étant un tableau au format JSON.
Les callbacks eventDrop et eventResize sont appellés dès qu’un évènement est modifié sur le calendrier.
Si l’utilisateur valide l’action, alors on appelle la fonction updateEvent qui enverra la requête d’update au serveur.
Les paramètres dayDelta, minuteDelta et allDay correspondent aux modifications apportées à l’évènement.

Pour fournir ce tableau c’est très simple.
On va créer une page PHP pour recevoir et traiter les requêtes AJAX :


    $dsn = 'mysql:dbname=fullcalendar;host=127.0.0.1';
    $user = 'root';
    $password = 'root';

    if(isset($_GET['action']))
    {
        switch($_GET['action'])
        {
            case 'get':
                try {
                    $db = new PDO($dsn, $user, $password);
                    
                    $sql = 'SELECT * FROM event';
                    $events = array();
                    
                    foreach ($db->query($sql) as $row) {
                        $events[] = $row;
                    }
                    
                    echo json_encode($events);
                    
                } catch (PDOException $e) {
                    echo json_encode(array('error' => 'Connection failed: ' . $e->getMessage()));
                }                
                break;
            default:
                break;
        }
    }
    

Très simple donc, on contrôle l’action reçue en paramètre, si c’est get alors on renvoit un tableau contenant les évènement stockés dans la base de données.
Un simple json_encode des évènements suffit.

Avec ce code on possède donc un calendrier affichant nos évènements.
Pour maintenant mettre à jour nos évènements en base de données, il faut juste ajouter l’action update côté serveur :


case 'update':
  try {
    $db = new PDO($dsn, $user, $password);
    
    $query = $db->query('SELECT * FROM event WHERE id = ' . $_POST['id']);
    $event = $query->fetch(PDO::FETCH_ASSOC);
    
    // Mise a jour de la date
    $diff = calculateDiff($_POST['dayDelta'], $_POST['minuteDelta']);
    
    $newStart = DateTime::createFromFormat('Y-m-d H:i:s', $event['start']);
    $newStart->modify($diff);
    
    $newEnd = DateTime::createFromFormat('Y-m-d H:i:s', $event['end']);
    $newEnd->modify($diff);
    
    $sql = 'UPDATE event SET start = "'.$newStart->format('Y-m-d H:i:s').'",
    end = "'.$newEnd->format('Y-m-d H:i:s').'",
    allDay = "'.$_POST['allDay'].'"
    WHERE id = ' . $_POST['id'];
    $row = $db->query($sql);
    
    echo json_encode(array('updated' => true));
  
  } catch (PDOException $e) {
    echo json_encode(array('error' => 'Db error : ' . $e->getMessage()));
  } catch (Exception $e) {
    echo json_encode(array('error' => $e->getMessage()));
  }       
break;

Le traitement est assez simple, on utilise la classe DateTime pour calculer les changements de dates avec sa méthode modify et deux fonctions que l’on va utiliser pour transformer les dayDelta et minuteDelta en chaîne compréhensible par DateTime :


	function pluralize($string) 
  {
      preg_match("|^([0-9]+)(.*)|",$string,$matched);
      if($matched[1] > 1) {
          return number_format($matched[1]) . $matched[2] . 's';
      }
      return $string;
  }

  function calculateDiff($dayDelta, $minuteDelta)
  {
      if($dayDelta != 'null' && $dayDelta != '0') {
          if($dayDelta < 0)
              $diff = "-".pluralize(abs(intval($dayDelta))." day");
          else if($dayDelta > 0)
              $diff = "+".pluralize(intval($dayDelta)." day");
      }
      else
          $diff = "";

			if($minuteDelta != 'null' && $minuteDelta != '0') {
          if($minuteDelta < 0)
              $diff .= "-".pluralize(abs(intval($minuteDelta))." minute");
          else
              $diff .= "+".pluralize(intval($minuteDelta)." minute");
      }
        
      return $diff;
  }

Ces fonctions vont par exemple transformer dayDelta = +2 : +30 en la chaîne "+2 days"

Et voilà on a maintenant un calendrier affichant nos propres évènements et les enregistrant en base de données.

Catégorie: Développement Web, Javascript | Laisser un commentaire (7)

Créer un calendrier dynamique en Javascript avec FullCalendar

Posté par seiyar81 le 24 octobre 2010 | Laisser un commentaire (4)

Comme on le sait jQuery possède un nombre de plugins tout simplement énorme ! Il y a certes du tri à faire et certains plugins tente de réinventer la roue, en vain…

FullCalendar ne fait pas partie de ceux-là. Vous avez besoin d’ajouter un calendrier permettant une gestion des évènements, un affichage par jour/semaine/mois, et thèmable ? Alors il vous faut FullCalendar !

Le plugin offre plusieurs vues pour afficher les évènements : par jour, semaine, mois avec des versions type agenda ou basique.
Un de ces autres points forts c’est d’être compatible avec jQuery UI et il s’adapte ainsi à votre thème tout seul, plutôt pratique.
Une extension lui permet même de récupérer les évènements de votre Google Calendar !

Voyons voir un peu comment le mettre en place :

	$(document).ready(function() {
	
		var date = new Date();
		var d = date.getDate();
		var m = date.getMonth();
		var y = date.getFullYear();
		
		$('#calendar').fullCalendar({
			header: {
				left: 'prev,next today',
				center: 'title',
				right: 'month,agendaWeek,agendaDay'
			},
			theme: true,
			editable: true,
			events: [
				{
					id: 1
					title: 'Aller sur Yriase.fr',
					start: new Date(y, m, 28),
					end: new Date(y, m, 29),
					url: 'http://www.yriase.fr/',
					allDay: true
				},
				{
					id: 2
					title: 'Nourrir le chat !',
					start: new Date(y, m, 28, 8, 0),
					end: new Date(y, m, 29, 8, 15),
					allDay: false
				}
			]
		});
		
	});

Ce bout de code plutôt simple, inialise votre Calendrier avec 2 évènements et l’adaptation au thème jQuery UI. Le proriété editable indique que les évènements ne peuvent être déplacés (peut être remplacée par la propriété editable de chanque évènement).

Comme vous pouvez le constater les évènements sont en réalité des objets JSON, auxquels on peut donc ajouter des proriétés.
Ainsi on peut par exemple ajouter une propriété type qui pourrait nous permettre de filtrer les évènements par type.
Ce qui serait encore mieux serait de pouvoir ajouter un bouton ou ensemble de boutons pour filtrer, qui soient intégrés au calendrier.
Ca tombe bien, j’avais prévu d’expliquer comme faire !

Le but de la manoeuvre est simple, ajouter des boutons au calendrier simplement en modifiant les valeurs dans la déclaration de la propriété header. Par exemple :

			header: {
				left: 'prev,next today',
				center: 'title',
				right: 'all,mandatory,not_mandatory month,agendaWeek,agendaDay'
			}

On ajoute ici trois boutons donc all,mandatory, not_mandatory pour afficher/cacher les évènements obligatoires ou pas. Pas très original mais c’est bon pour l’exemple !

Maintenant il va nous falloir modifier un petit peu le fichier fullcalendar.js.
Aux alentours de la ligne 80, la déclaration de la propriété buttonText.
Ajouter au tableau les lignes :
all: ‘All’,
mandatory: ‘Mandatory’,
not_mandatory: ‘Not Mandatory’,

Ensuite vers la ligne 710 cherchez :

              if (publicMethods[buttonName]) {
			buttonClick = publicMethods[buttonName];
	      }
	       else if (views[buttonName]) {
			buttonClick = function() {
			  button.removeClass(tm + '-state-hover');
			  changeView(buttonName)
			};
	     }

et ajoutez après :

else {
      buttonClick = function() {
	button.removeClass(tm + '-state-hover');
        button.addClass(tm + '-state-active');
        if(button.hasClass('fc-button-all')) {
              $('.fc-button-mandatory').removeClass(tm + '-state-active');
              $('.fc-button-not_mandatory').removeClass(tm + '-state-active');
        } else if (button.hasClass('fc-button-mandatory')) {
              $('.fc-button-all').removeClass(tm + '-state-active');
              $('.fc-button-not_mandatory').removeClass(tm + '-state-active');
        } else if (button.hasClass('fc-button-not_mandatory')) {
              $('.fc-button-all').removeClass(tm + '-state-active');
              $('.fc-button-mandatory').removeClass(tm + '-state-active');
        }
      };
 }

Cette partie s’occupe de marquer comme actif le bouton cliqué.
Enfin juste après se trouve cette partie :

if (icon) {
	button = $("
"); } else if (text) { ...

Mettez dans le corps du else if(text) :

if(buttonName == 'all') 
  button = $("");
else
  button = $("");

Maintenant il ne vous reste plus qu’a mettre en place les fonctions pour filtrer les évènements selon leur type.
Mais ça ce sera pour une autre fois !

Catégorie: Développement Web, Javascript | Laisser un commentaire (4)