Créer un modèle permettant de calculer l’âge automatiquement

Ceci est une « contribution pédagogique », qui montre par l’exemple comment développer une nouvelle fonctionnalité pour SPIP.

Pouvoir calculer un âge et afficher le résultat automatiquement dans un article, un titre, une brève, etc.
L’âge est mis à jour dynamiquement et automatiquement.
Cet article vous explique pas à pas comment y arriver.

Pré-requis : (conseillé)

  • Connaître un peu de php
  • Connaître un peu de html

Cet article est destiné à : webmestre

Introduction

Nous allons créer, ensemble, un modèle Spip permettant de calculer un âge automatiquement.

Spip, nous permet, facilement, de créer ses propres modèle afin d’ajouter des fonctionnalités.

Qu’est-ce qu’un modèle ?

Je renvoie vers la documentation de Spip qui est, selon moi, la plus appropriée pour l’expliquer : Utiliser les modèles.

Il nous faut savoir deux trois choses sur les modèles avant de faire le nôtre :

  • Les modèles créés ou rajoutés doivent être dans le dossier « modeles » lui-même, dans le dossier « squelettes ».
  • Les modèles sont sous forme de fichier html.
  • Les modèles portent le même nom que la syntaxe correspondante dans Spip
  • S’il doit y avoir des actions en php, le fichier (php) doit avoir le même nom que le fichier html avec _fonctions.php à la fin. Exemple, si notre modèle se nomme modele1.html le fichier contenant les fonctions php aura pour nom : modele1_fonctions.php [1].
  • Pour agir, avec un script php, sur un modèle qui, lui est en html, on utilise un filtre php. Les filtres sont à appliquer sur un champ (exemple : [(#TEXTE|filtre)]).
  • Si le modèle doit faire appel à un code php spécifique, celui ci doit être créé sous la forme de fonctions qui seront appelées comme filtres dans le squelette html du modèle. Cette définition peut se faire dans un fichier du même nom que le fichier html, mais suffixé par « _fonctions.php » et situé dans le même dossier que lui. Exemple, si notre modèle se nomme age.html le fichier contenant les fonctions php aura pour nom : age_fonctions.php [2].

Concrètement :

Note : vous trouverez, à la fin de l’article, le modèle déjà prêt.

Nous allons commencer par créer le répertoire « modeles », s’il n’existe pas déjà, ensuite nous allons partir d’une syntaxe, d’une forme d’écriture que Spip reconnaîtra et qui appellera notre modèle.
Nous partirons sur la syntaxe suivante :

<ages|n=date>

« date » sera, évidemment, à remplacer par la date « d’anniversaire » souhaité, par exemple, si l’on veut dire :

J’utilise Spip depuis ... ans

On écrira :

J'utilise Spip depuis <ages|n=13-02-2011> ans

Le modèle

Maintenant qu’on a notre syntaxe, on peut commencer le modèle, pour cela on va créer un fichier, toujours dans le dossier modeles, nommé ages.html (sans les guillemets). Dans ce fichier il faut écrire les morceaux de html dont vous avez besoin (c’est un mini squelette).
Pour notre modèle nous n’avons pas besoin de balise html, on va juste écrire :

[(#ENV{n}|ages)]

Je vous explique, lorsque, dans Spip, nous avons écrit <ages|n=date> on affecte à la variable, ici, n la valeur date. Afin de récupérer cette valeur, Spip nous propose une syntaxe qui est la suivante :

#ENV{nom_de_la_variable}

Ensuite, sur cette variable nous appliquons un filtre nommé ages (c’est le |ages).

Comment ce filtre fonctionne ?

Spip va appeler une fonction php du même nom, ici ages.

C’est là qu’on créer le fichier php nommé « ages_fonctions.php »

Pourquoi ce fichier doit s’appeler ages_fonctions.php

SPIP permet, par cette dénomination, d’associer un fichier php à un squelette. Notez que si on partage des filtres entre plusieurs squelettes, on utilise mes_fonctions.php.

Dans ce fichier nous allons créer une fonction nommée ages. Notre fichier php commence par <?php et fini par ?>.
Ensuite, on déclare la fonction et on lui met en paramètre une variable qui contiendra la date :

function ages($uneDate) {
	// C'est ici que l'on va écrire le code permettant de calculer l'âge
}

En appliquant le filtre sur #ENV{n}, le paramètre $uneDate va prendre la valeur de #ENV{n} donc de la date stocké dans le paramètre d’environnement n.

Le double slash (//) désigne un commentaire. Un commentaire est un morceaux de code qui n’est pas exécuté, il est souvent utilisé pour aider le développeur dans la compréhension du code.

Dans le cas présent, j’ai décidé de faire une vérification sur la date, afin d’être sûr qu’elle soit au bon format et, ainsi, éviter d’éventuels bogues.
Nous allons commencer par déterminer une chaîne de caractère type (à l’aide des expressions relationnelles : regexp). Je renvoie vers l’article correspondant sur Wikipédia : Expression rationnelle

Voici deux variables, contenant une fonction php permettant de vérifier la présence d’une chaine de caractère (ici notre regexp) :

	// Vérifie la présence d'une chaîne type dans la date (vérifie le format de la date)
	$test1 = preg_match("/(^[0-9]{2})[-\/]([0-9]{2})[-\/]([0-9]{4}$)/", $uneDate);
	$test2 = preg_match("/(^[0-9]{4})[-\/]([0-9]{2})[-\/]([0-9]{2}$)/", $uneDate);

J’utilise la fonction « preg_match », elle fonctionne de la manière suivante :

preg_match("la chaine recherchée", "la chaîne dans laquel on va rechercher la chaîne recherchée", $une_Variable_Contenant_Les_Éventuels_Résultats);

Je vais tenter de vous expliquer une des expressions relationnelles :

/(^[0-9]{2})[-\/]([0-9]{2})[-\/]([0-9]{4}$)/

Les parenthèses désignent un groupe, dans le premier groupe

(^[0-9]{2})

on note la présence d’un accent circonflexe juste avant les crochets [0-9]. L’accent nous indique que l’on peut trouver ce qui suit uniquement en début de ligne, en l’occurrence [0-9] qui désigne n’importe quel chiffre de 0 à 9 (par exemple 4). Après les crochets, il y a des accolades :

{2}

elles indiquent le nombre de fois que l’on doit trouver l’expression juste avant celle-ci (les accolades). Ici

[0-9]{2}

signifie que l’on doit trouver deux chiffres allant de 0 à 9.

Après les premières parenthèses, il y a des crochets ([-\/]) ils signifient qu’il doit y avoir, après les deux chiffres, le caractère « - » ou le caractère « / » [3].

Le dollar « $ », juste avant la dernière parenthèse, signifie que l’expression juste avant doit se situer absolument en fin de ligne, il ne doit rien y avoir derrière).

Maintenant, vous êtes tout à fait capable de comprendre l’expression relationnelle.

Pourquoi avoir fait deux regexp ?

Si vous avez compris et que vous regardez attentivement, vous trouverez facilement la raison. J’aurais très bien pu faire un seul regexp mais j’ai voulu m’assurer que la date donnée soit bien au format Année/Mois/Jour ou Jour/Mois/Année. La première expression cherche : 00-00-0000 (comme en français) et la seconde : 0000-00-00 (comme en SQL). Ici, les zéros désignent n’importe quel chiffre de 0 à 9.

Nous allons, maintenant, pouvoir écrire le test conditionnel qui vérifiera le format de la date, donc :

	if ($test1 or $test2) {
		// Calcule l'âge
	} else {
		// Retourne la phrase : Format de date invalide : "la date en question";
	}

Traduction :
Si (if) le test1 a trouvé une correspondance OU (or) que le test2 a trouvé une correspondance, alors, on calcule l’âge. Sinon (else) on retourne une phrase d’erreur.

Voici le teste conditionnel complet :

	if ($test1 or $test2) {
		// Calcule l'âge
		$age = date('Y') - date('Y', strtotime($uneDate));
		if (date('md') < date('md', strtotime($uneDate))) {
			$age = $age - 1;
		}
	} else {
		return("<b>Format de date invalide : ".$uneDate."</b>");
	}

Explication :
En ligne 3, on a le cœur de la fonction, la base de notre modèle, c’est à dire le calcul de l’âge. Cette ligne veut dire : la variable, du nom de $age, prend la valeur de l’année actuelle moins la valeur de l’année donnée, stocké dans la variable nommée $uneDate.

De la ligne 4 à 6, on voit un autre test conditionnel, permettant de vérifier que la date d’anniversaire n’est pas passée. Dans ce cas, il retire un an à l’âge afin que celui-ci soit juste.

En ligne 8, on a le retour en cas d’erreur. Le mot clef return renvoie la chaîne de caractère donné (notez la présence des balise html <b> et </b> qui permettent de mettre ce qu’elles contiennent en gras) et stoppe l’exécution de la fonction.

J’ai rajouté à la chaîne de caractère la date contenu afin que l’utilisateur puisse se rendre compte de son erreur.

Maintenant, il ne reste plus qu’à retourner l’âge et notre fonction est terminée.
Voici le retour de l’âge :

	// Revoit l'age.
	return($age);

Fini !

Voici la fonction en entier :

<?php
/********************************** age **********************************
*	Cette fonction permet de calculer un âge et de l'afficher dans un
*	article, une rubrique, une brève, etc.
*
*	La syntaxe est la suivante :
*		<ages|n=date>
*
*	Exemples :
*		<ages|n=2000-01-01>
*		<ages|n=01-01-2000>
*
*	Formats de date supportés :
*		AAAA-MM-JJ
*		AAAA/MM/JJ
*		JJ-MM-AAAA
*		JJ/MM/AAAA
*
*	Auteur	: Gaël de Weerdt
*	Version	: 0.0.1
*	Date		: 13 Février 2015
*
*************************************************************************/

	function ages($uneDate) {
		// Vérifie la présence d'une chaîne type dans la date (vérifie le format de la date)
		$test1 = preg_match("/(^[0-9]{2})[-\/]([0-9]{2})[-\/]([0-9]{4}$)/", $uneDate);
		$test2 = preg_match("/(^[0-9]{4})[-\/]([0-9]{2})[-\/]([0-9]{2}$)/", $uneDate);

		if ($test1 or $test2) {
			// Calcule l'âge
			$age = date('Y') - date('Y', strtotime($uneDate));
			if (date('md') < date('md', strtotime($uneDate))) {
				$age = $age - 1;
			}
		} else {
			return("<b>Format de date invalide : ".$uneDate."</b>");
		}

		// Revoit l'age.
		return($age);

	}
?>

Récapitulatif

Nous avons choisi une syntaxe pour Spip, nous avons créé le modèle avec le fichier ages.html, dans lequel nous avons appliqué un filtre (la fonction php ages du fichier ages_fonctions.php) et nous avons écrit la fonction. Et le tout est au bon endroit (dans le dossier modeles" qui est dans le dossier « squelettes »).

Le modèle devrait être fonctionnel, il ne reste plus que l’essayer !

Conclusion

Nous avons créé notre propre modèle qui calcule l’âge automatiquement, le met à jour et il fonctionne très bien !

C’est maintenant à vous de faire vos modèles afin d’améliorer votre Spip :

Téléchargement du modèle

modeles-ages
Version officielle de cette contribution pédagogique.
modeles-ages_v0.0.2
Nouvelle version bien différente permettant de calculer et d’afficher l’âge avec l’année, les mois et les jours ainsi que la gestion des pluriels etc..
Exemple : Âge : 1 an, 20 mois et 2 jours

Notes

[1Si les actions sont partagés entre plusieurs modèles, on utilisera alors mes_fonctions.php

[2Si les actions sont partagés entre plusieurs modèles, il faudra utiliser le fichier généraliste mes_fonctions.php

[3L’antislash « ~ » juste avant le slash « / » permet d’annuler l’effet du slash dans le regexp afin qu’il soit compté comme un caractère lambda.

Discussion

5 discussions

  • 4

    Bonjour,

    Merci pour cette contribution qui semble faire ce que je souhaite. Malheureusement je suis débutant et j’ai un peu du mal à comprendre comment tout ceci fonctionne.

    J’ai suivi les instructions en décompressant l’archive V0.0.2 et en copiant les deux fichiers dans squelettes/modeles (que j’ai créé)

    Je souhaite afficher l’age d’un auteur, dans le fichier « auteur.htlm » de squelettes, j’écris qqpart :
    J’ai <ages|n=#NAISSANCE> ans

    idem si j’écris J’ai <ages|n=01-01-1987> ans

    Je pense que c’est de la que vient mon problème. Je ne comprends pas bien le début du tutoriel :

    « Concrètement :

    Note : vous trouverez, à la fin de l’article, le modèle déjà prêt.

    Nous allons commencer par créer le répertoire « modeles », s’il n’existe pas déjà, ensuite nous allons partir d’une syntaxe, d’une forme d’écriture que Spip reconnaîtra et qui appellera notre modèle.
    Nous partirons sur la syntaxe suivante :

    <ages|n=date>

    « date » sera, évidemment, à remplacer par la date « d’anniversaire » souhaité, par exemple, si l’on veut dire :

    J’utilise Spip depuis ... ans

    On écrira :

    J’utilise Spip depuis <ages|n=13-02-2011> ans
     »

    Je vous remercie bien par avance.

    • Bonjour,

      J’ai écrit cette contribution il y a quelques années. Je ne sais pas si c’est toujours aussi compatible n’ayant pas suivi les évolutions.

      Sinon, si je me souviens bien, la syntaxe <age|n=date> doit être écrite dans un article, un titre ou autre. C’est l’éditeur qui va traduire la syntaxe. La syntaxe ne doit pas être dans le squelette. Dans les squelettes c’est cette syntaxe :

          [(#NAISSANCE|ages)]

      Ça devrait fonctionner.

      La première version est la version qui affiche seulement les années ou quelque chose du genre.

      La deuxième version (v0.0.2) est une version modifiée à la base pour l’association
      « lmcchats » qui affiche l’âge en toute lettre.

    • Merci beaucoup pour cette réponse rapide,

      Effectivement, j’ai crée un article contenant :

      <age|n=date> 

      ça marche parfaitement,

      en revanche, dans mon squelette lorsque je mets

      [(#NAISSANCE|ages)]

      ma page renvoie un message d’erreur :
      Filtre ages non défini dans la boucle principale

      et affiche seulement la valeur #NAISSANCE « 2017-01-01 » sans faire le calcul.

      une idée du problème ?

      merci en tout cas. je vais chercher de mon coté.

    • Bonjour,

      Essaye de retirer le « s » dans le nom du filtre :

          [(#NAISSANCE|age)]

      Si ça ne fonctionne toujours par alors on va reprendre le code du modèle pour en faire un filtre :
      Dans le dossier « squelettes » ajoute le fichier (si ce n’est pas déjà le cas) « mes_fonctions.php » :

      /**
       * Retourne l'age en toute lettres à partir d'une date donnée.
       * 
       * @filtre
       * @link https://contrib.spip.net/Creer-un-modele-permettant-de-calculer-l-age#forum498003
       * @example [(#DATE|ages)]
       * 
       * @param string $uneDate
       * 
       * @return string
       */
      function age($uneDate) {
      	$test1 = preg_match("/(^[0-9]{2})[-\/]([0-9]{2})[-\/]([0-9]{4}$)/", $uneDate);
      	$test2 = preg_match("/(^[0-9]{4})[-\/]([0-9]{2})[-\/]([0-9]{2}$)/", $uneDate);
      	
      	// Si la date donné est bien dans un des formats acceptés
      	if ($test1 or $test2) {
      		// Formatage de la date ("AAA-MM-JJ")
      		$uneDate = date('Y', strtotime($uneDate)) . '-' . date('m', strtotime($uneDate)) . '-' . date('j', strtotime($uneDate));
      		
      		$dateNaissance = new DateTime($uneDate);	// Création d'un objet 'DateTime" avec la date de naissance
      		$dateActuelle  = new DateTime(date('Y-m-d'));	// Création d'un objet 'DateTime" avec la date actuelle
      		
      		$age = $dateNaissance->diff($dateActuelle);	// Calcule de la différence entre les deux dates
      		
      		// Récupère les chiffres
      		$nb_jours  = $age->d;
      		$nb_mois   = $age->m;
      		$nb_annees = $age->y;
      		
      		// Gestion du singlulier et du pluriel
      		($nb_jours > 1)  ? $d = "jours"  : $d = "jour";
      		($nb_annees > 1) ? $y = "ans"    : $y = "an";
      		
      		// Gestion des différent cas d'affichage
      		if ($nb_annees == 0 and $nb_mois == 0) {
      			return("$nb_jours $d");
      		}
      		elseif ($nb_annees == 0 and $nb_jours == 0) {
      			return("$nb_mois mois");
      		}
      		elseif ($nb_mois == 0 and $nb_jours == 0) {
      			return("$nb_annees $y");
      		}
      		elseif ($nb_annees == 0) {
      			return("$nb_mois mois et $nb_jours $d");
      		}
      		elseif ($nb_mois == 0) {
      			return("$nb_annees $y et $nb_jours $d");
      		}
      		elseif ($nb_jours == 0) {
      			return("$nb_annees $y et $nb_mois mois");
      		}
      		
      		return("$nb_annees $y, $nb_mois mois et $nb_jours $d");
      		
      	} else {
      		return("<b>Format de date invalide : " . $uneDate . "</b>");
      	}
      }

      N’oublie pas de mettre la fonction entre les balises PHP : « 

      <?php [...] ?>

       »

      C’est simplement un copier/coller de la fonction du modèle.

      Une fois que c’est fait tu peux ajouter le filtre à tes squelettes :

      [(#NAISSANCE|age)]
    • Merci, ça marche parfaitement

    Répondre à ce message

  • 3

    Bonjour et MERCI !
    Tout marche bien.
    Ce script répond à un besoin pour la publication d’annonces d’adoptions d’animaux (associations de sauvetages).
    Malheureusement, je ne connais pas le php pour l’adapter à cette spécificité : en effet, nous avons des animaux de moins d’un an...
    Pourrais-tu me modifier le script pour qu’il renvoit l’âge en tenant compte des mois ?
    Et si ce n’est ni trop compliqué ni trop de travail, l’idéal serait que le script fasse la différence entre les mois et les années et soit capable de renvoyer une réponse énoncée seulement en mois lorsque le résultat est inférieur à 1 an et « x » ans et « x » mois pour les autres... J’abuse ?
    J’abuse un peu plus : il y a moyen que le script soit capable d’accorder AN en nombre si le sujet à plus d’1 an ?
    Encore merci.
    Bonne journée.

    • Et bah écoutez, pourquoi pas !?

      Donnez-moi quelques exemples d’affichages pour être sûr que cela réponde exactement à vos besoins et je vous fais cela ! Normalement :-)

      L’adresse e-mail que vous avez donné pour poser ce commentaire est-elle réelle ? (toto1074@******.fr)

      Si oui, nous communiquerons par e-mail si cela ne vous gêne pas.

      Bien à vous,

    • Bonjour gdw96.
      Oui, mon adresse courriel est parfaitement valable et correspondre par ce biais me semble en effet plus pratique.
      Je te prépare que quelques exemples d’utilisations très rapidement.
      Merci.
      En attendant, un site personnel où j’ai testé ton modèle (« Date de naissance » dans la description) et qui pourra servir de base aux exemples que je te proposerai : http://lmcchats.free.fr/lmcchats/
      Encore merci et à bientôt.

    • Salut à tous
      Merci gdw pour cette seconde version qui répond parfaitement à mes demandes et marche du tonnerre. (Version PHP minimum 5.2 requise.)
      Merci à tous les autres contributeurs à l’univers du libre : utilisateur final, j’apprécie énormément ce que vous faites.
      MERCI.

    Répondre à ce message

  • 4

    Bonjour,
    Je viens de prendre connaissance de cette contribution et moi aussi je ne réussis pas à décompresser l’archive il est indiqué « Une erreur s’est produite pendant le chargement de l’archive », j’ai essayé plusieurs fois et toujours pareil, dommage j’aimerais tester
    Merci

    • Bonjour mailou,

      J’ai fait une seconde archive (mais j’ai laissé l’ancienne car elle fonctionne pour certaines personnes).

      J’attends les prochains retours.

    • Pour info : sur Mac, les deux archives fonctionnent nickel.

    • @gdw96 : on va éviter de multiplier les archives. Je supprime la première.

    • Merci ;-)

      J’espère qu’elle fonctionnera, c’est étrange tout de même. Je jongle toujours entre plusieurs systèmes et je n’ai jamais eu de problème avant.

      PS :
      Sur Windows, j’utilise surtout le gestionnaire d’archive 7zip.
      Sous GNU/Linux, j’utilise surtout le gestionnaire d’archive Ark.

    Répondre à ce message

  • 5

    Bonjour, et merci pour cet ajout aux possibilités de Spip.
    Tout marche bien, et j’ai effectivement 66 ans comme l’a découvert le programme...
    Ce script répond à la demande d’un participant à la liste de diffusion.
    Bonne journée.

    • Mais ne va pas plus loin que 1902... dommage

    • Bizarrement, chez moi, ça fonctionne jusqu’à l’an 0 !

      (Attention ! Pour les années à moins de 4 chiffres (par exemple pour le 1er janvier 900) il faut écrire « <ages|n=01-01-0900> » ou « <ages|n=0900-01-01> » ou « <ages|n=01/01/0900> » ou « <ages|n=0900/01/01> » : Il ne faut pas oublier de mettre un zéro avant le 900 afin qu’il y ai bien 4 chiffres).

    • Bonjour,
      Si je mets « <ages|n=01/01/1902> » j’ai 113 ans, avec « <ages|n=01/01/1901> » j’obtiens 45 ainsi qu’en mettant des dates antérieures.
      Est ce que le calcul peut dépendre du serveur ou du système ?
      Je suis en local avec easyphp, spip 2 et spip 3 et j’obtiens le même résultat.
      Voir ici :

      http://imagesetpeche.free.fr/?Dates

    • en système 32 bits, les bornes de dates gérés sont 2038-01-19 et 1901-12-13. Une forme de bug de l’an 2000 lié au fait que le point de référence est 1970 et que la date est stockée sur timestamp.

      2 solutions :
      -  la plus simple (mais le plus chère) : avoir un serveur 64 bit.
      -  utiliser la classe datetime : http://php.net/DateTime (il faut du coup faire un php de php...)

    • Ah ! D’accord !

      C’est plus clair comme cela. Il est vrai que je ne comprenais absolument pas d’où venait le problème.

      Après, je suis sous GNU/Linux LinuxMint 17.1 64bits (donc Ubuntu) et je travail d’abords sur ce système.
      Mon serveur virtuel est sous Ubuntu - Apache 2.2.22 64bits
      Mon serveur virtuel local est sous Debian 7 64bits

    Répondre à ce message

  • 1

    Impossible de décompresser le fichier modele spip-ages

    Répondre à ce message

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom