manuel jelix 1.0 draft

232
Guide du développeur Jelix 1.0.6 Ed. brouillon - 17 octobre 2008

Upload: wallman

Post on 24-Jun-2015

776 views

Category:

Documents


7 download

TRANSCRIPT

Page 1: Manuel Jelix 1.0 Draft

Guide du développeur

Jelix 1.0.6

Ed. brouillon - 17 octobre 2008

Page 2: Manuel Jelix 1.0 Draft

Guide du développeurEd. brouillon - 17 octobre 2008

ii

Copyright © 2006, 2007, 2008 Laurent Jouanneau, Les contributeurs au wiki de jelix.org

Ce manuel est distribué selon les termes de la licence Creative Commons by-nc-sa 3.0. Vous pouvez donc repro-duire, modifier, distribuer et communiquer ce manuel au public en respectant les conditions suivantes :– Paternité. Vous devez citer le nom de l’auteur original de la manière indiquée par l’auteur de l’oeuvre ou le

titulaire des droits qui vous confère cette autorisation (mais pas d’une manière qui suggérerait qu’ils vous sou-tiennent ou approuvent votre utilisation de l’oeuvre).

– Pas d’Utilisation Commerciale. Vous n’avez pas le droit d’utiliser ce manuel à des fins commerciales.– Partage des Conditions Initiales à l’Identique. Si vous modifiez, transformez ou adaptez ce manuel, vous

n’avez le droit de distribuer la création qui en résulte que sous un contrat identique à celui-ci.

Page 3: Manuel Jelix 1.0 Draft

Guide du développeurEd. brouillon - 17 octobre 2008

iii

Table des matières

I Installation 1

1 Pré-requis sur le serveur 31.1 Configuration de PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Configuration de PHP-Cli pour MAMP (MacIntosh) . . . . . . . . . . . . . . . . . . . . . . . . . . 31.3 Configuration de PHP-Cli sous windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Installation de l’archive de jelix 5

3 Installation d’une application 63.1 Installation des fichiers de l’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63.2 Configuration du serveur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73.3 Configuration pour les urls "cools" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

4 Installation sur un serveur de production 104.1 Choisir la bonne édition de Jelix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104.2 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

II Fondamentaux 13

5 Principes de fonctionnement 15

5.1 Étapes d’exécution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155.2 Ce que vous avez à manipuler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165.3 Objets en détails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165.4 Les sélecteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165.5 Les objets jRequest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175.6 Le coordinateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185.7 Les objets jResponse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195.8 Appeler une action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

6 Développement d’un module 216.1 Créer un module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216.2 Développer un contrôleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226.3 Utiliser le contrôleur CRUD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256.4 Un contrôleur pour REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

Page 4: Manuel Jelix 1.0 Draft

Guide du développeurEd. brouillon - 17 octobre 2008

iv

7 Les réponses classiques 307.1 Générer une page HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307.2 Faire une redirection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347.3 Générer du texte brut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357.4 Générer du XML quelconque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357.5 Générer un flux de syndication RSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367.6 Générer un flux de syndication Atom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377.7 Générer un PDF à partir d’un contenu LaTeX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397.8 Générer un PDF avec TCPDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407.9 Renvoyer un fichier binaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407.10 Générer un fichier zip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417.11 Générer une interface utilisateur en XUL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417.12 Générer du RDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

8 Services web 478.1 AJAX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478.2 JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488.3 JSON-RPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 488.4 XML-RPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

9 Effectuer des traitements en ligne de commande 539.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539.3 Création d’un controller cmdline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549.4 Création du fichier de configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 549.5 Développement d’actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559.6 Paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559.7 Message d’aide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569.8 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

10 Définir des traitements communs à plusieurs actions 5710.1 Méthodes privées de contrôleurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5710.2 Héritage de contrôleurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5810.3 Personnalisation de réponse commune . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5910.4 Utilisation de zones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

III Composants de jelix 66

11 jTpl : le moteur de templates 6811.1 L’objet jTpl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6811.2 Les fichiers templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6911.3 Les structures de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7211.4 Fonctions jTpl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7311.5 informations meta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7311.6 Informations meta avançées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7311.7 Surcharge de template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7411.8 En coulisse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

Page 5: Manuel Jelix 1.0 Draft

Guide du développeurEd. brouillon - 17 octobre 2008

v

12 jZone : découper vos pages en zones 7512.1 Principes d’une zone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7512.2 Utilisation des zones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7512.3 Appel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7612.4 Utilisation du cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7712.5 Empêcher ponctuellement la mise en cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7912.6 Paramètres automatiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

13 jDao : mapping objet relationnel 8013.1 Fichier DAO de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8013.2 Instanciation et utilisation d’une factory et d’un record DAO . . . . . . . . . . . . . . . . . . . . . . 8313.3 Ajouter des méthodes en XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8613.4 Développer des méthodes en php . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

13.5 Évènements automatiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93

14 Formulaires classiques 9514.1 Les actions à mettre en oeuvre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9514.2 Création d’un formulaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9514.3 Traitement des données en retour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

15 jForms : des formulaires automatiques 9815.1 Format des fichiers jForms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9915.2 Utiliser un formulaire dans un contrôleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10815.3 Affichage d’un formulaire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11415.4 Affichage simple des données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

16 jDb : accéder à une base de données 12116.1 Profils et configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12116.2 Faire des requêtes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12316.3 ResultSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12416.4 Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12516.5 jDbWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

17 jClasses : utiliser des classes métiers 12717.1 Création d’une classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12717.2 Instanciation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12717.3 Installer et Utiliser des classes tierces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

18 jUrl : des URLs automatiques 12918.1 Petit rappel sur les URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12918.2 Configuration générale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12918.3 Configuration des moteur d’URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13118.4 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13118.5 Moteur d’urls ’simple’ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13118.6 Moteur d’urls significatives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132

Page 6: Manuel Jelix 1.0 Draft

Guide du développeurEd. brouillon - 17 octobre 2008

vi

19 jAuth : système d’authentification 13919.1 Mise en oeuvre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13919.2 Utiliser le contrôleur par défaut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14219.3 Utiliser son propre contrôleur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14319.4 classe jAuth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14319.5 Les drivers pour jAuth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

20 jAcl : système de droits 14720.1 Les concepts généraux de jAcl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14720.2 Utiliser jAcl dans ses modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14920.3 Les concepts de jAcl.db . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15120.4 Configurer jAcl.db . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

21 jLocale : internationaliser votre application 15921.1 Principes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15921.2 Fichiers properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15921.3 Récupération d’une chaîne localisée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16121.4 Chaine localisée avec paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16121.5 Changer la langue dynamiquement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16221.6 Détection automatique de la langue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

22 jEvents : communication inter-module 163

22.1 Émettre un évènement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16322.2 Répondre à un évènement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

IV Développement avancé 165

23 Générer un contenu dans un format personnalisé 16723.1 Créer un objet response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167

24 Système de thèmes 17024.1 Les templates d’un thème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17024.2 Les fichiers web d’un thème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17024.3 Déclarer un thème par défaut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17124.4 Déclarer un thème dynamiquement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

25 Surcharge de fichiers de modules 172

26 Développer et utiliser des plugins 17326.1 Déclaration d’un dépôt de plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17326.2 Structure d’un dépôt et création de plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17326.3 Création de plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17426.4 plugins de coordinateur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17426.5 drivers pour jAuth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17526.6 drivers pour jDb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17626.7 plugins de templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17826.8 moteurs de urls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

Page 7: Manuel Jelix 1.0 Draft

Guide du développeurEd. brouillon - 17 octobre 2008

vii

27 La configuration en détails 18227.1 Points d’entrée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18227.2 Organisation de la configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18227.3 Déscriptif des sections de la configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

V Aide au développement 189

28 Configurer le gestionnaire d’erreur 19128.1 Paramétrage des gestionnaires d’erreurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19128.2 Code erreur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

29 Développer des tests unitaires 19329.1 Développer des tests unitaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19329.2 Lancement des tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195

30 Les aides pour debogguer 19730.1 jLog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

VI Les classes utilitaires 198

31 jFilter : vérification et filtrage de données 200

32 jDateTime : manipulation de dates et heures 20132.1 Initialisation à la date/heure courante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20132.2 Conversion à partir d’une chaîne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20132.3 Conversion vers une chaîne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20232.4 Calcul de dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20232.5 Comparaison de dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203

33 jMailer : envoi de mails 20433.1 Classe jMailer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20433.2 Envoi d’un email basique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

34 jWiki : transformation de texte wiki 206

35 jSession : stockage de sessions 20735.1 Classe jSession . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207

VII Les plugins de Jelix 209

36 Plugins de template 21136.1 Modificateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21136.2 Fonctions diverses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21436.3 Médias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21836.4 Meta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

37 Plugins pour le coordinateur 225

Page 8: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

1 / 225

Première partie

Installation

Page 9: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

2 / 225

Les pages de ce chapitre expliquent en détails l’installation de Jelix puis celle d’une application y reposant dessus.Enfin, une dernière section vous explique les points à prendre en compte pour l’installation de votre application surun serveur de production une fois que celle-ci est terminée.

Page 10: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

3 / 225

Chapitre 1

Pré-requis sur le serveur

Vous devez installer au minimum la version 5.2 de PHP. Les extensions dom, simplexml, pcre, session, spl ettokenizer sont requises (elles sont actives en général dans une installation standard de PHP 5.2). Si une de cesextensions n’était pas livrée avec le paquet PHP5, veillez à installer le paquet correspondant.

Note conçernant DOM et XML : vérifiez que c’est bien l’extension DOM et non pas l’extension DOM-XML quiest activée dans php.ini. Certains paquets WAMP active l’extension DOM-XML en même temps que DOM, ce quiconduit à des erreurs PHP.

Vous pouvez installer aussi un connecteur de base de données. Pour le moment Jelix prend en charge MySQL 4.1+,PostgreSQL 8.0+, SQLite et PDO.

Si vous comptez utiliser les scripts en ligne de commande d’aide au développement (jelix-scripts), il vous faut aussiinstaller la version ligne de commande de PHP : PHP-CLI.

1.1 Configuration de PHP

– magic_quotes_gpc et magic_quotes_runtime doivent être à Off. Si ce n’est pas le cas, il faut activer le pluginmagicquotes livré avec jelix.

– session.auto_start doit être à 0– safe_mode doit être à Off (À cause des nombreux fichiers temporaires créés par jelix, il peut être difficile de

configurer une installation avec Jelix avec le safe_mode activé)

Il est également recommandé de mettre ces valeurs :– register_globals = off– asp_tags = off– short_open_tag = offUn phpinfo() peut vous permettre de vérifier votre configuration. Par défaut la configuration se trouve dans un fichier

nommé php.ini.

1.2 Configuration de PHP-Cli pour MAMP (MacIntosh)

Le logiciel MAMP met à votre disposition un programme PHP-Cli. Ce dernier n’est pas le seul PHP-Cli, en effet,Mac OS vous en fournit aussi un en installation standard (à vérifier). Le problème vient du fait que si vous utilisez labase de donnée MySQL de MAMP, le PHP-Cli par défaut n’est pas configuré pour vous permettre de vous connecterà cette dernière.

Voici comment faire pour mettre le PHP-Cli de MAMP par défaut dans le terminal :

Page 11: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

4 / 225

– Ouvrez le fichier /etc/profile.– Assurez-vous de changer les droits d’accès à ce dernier pour pouvoir le modifier.– Ajouter à la fin du fichier les deux lignes suivantes (adaptez le chemin de MAMP si vous n’avez pas utilisé

l’installation par défaut de celui-ci) : <code>export DYLD_LIBRARY_PATH=/Applications/MAMP/Library/lib :${DYLD_LIBRARY_PATH} export PATH=/Applications/MAMP/bin/php5/bin :${PATH}

</code>– Assurez-vous d’avoir laissé un saut de ligne après.– Sauvegardez et remettez les droits d’accès à la normale.Si vous souhaitez mettre de nouveau le PHP-Cli de base par défaut, supprimez juste les deux lignes que vous avez

ajoutées.

1.3 Configuration de PHP-Cli sous windows

– cliquer droit sur l’icône Poste de travail puis Propriétés– dans la fenêtre Propriétés système cliquez sur l’onglet Avancé puis sur le bouton Variables d’environnement– ensuite cliquez sur la Variable Path dans le bloc "Variables utilisateur" si vous êtes le seul utilisateur sur la machine

ou le bloc "Variables système" si il s’agit d’un serveur ou d’une machine avec plusieurs utilisateurs (afin que touspuisse bénéficier de cette configuration).

– Dans la valeur de la variable vous ajoutez le chemin vers le répertoire qui contient PHP. Ex : D :\wamp\bin\php\php5.2.6(n’oubliez pas d’ajouter le ; à la fin si vous avez plusieurs variables path)

– Validez en cliquant sur OK– Fermez le tout et redémarrez.

Avec cette manipulation, vous pourrez executer PHP depuis n’importe quel répertoire notamment pour pouvoir créerdes applications en ligne de commande avec Jelix.

Page 12: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

5 / 225

Chapitre 2

Installation de l’archive de jelix

Jelix est fourni sous forme d’une archive tar.gz ou zip. Cette archive contient un répertoire jelix/lib qui contient tousles fichiers du framework et les bibliothèques dépendantes, ainsi qu’un répertoire jelix/temp.

Décompressez l’archive avec des logiciels comme winzip, unzip ou tar.

tar xvzf jelix-1.0-dev.tar.gz

Vous obtenez les répertoires suivants :

jelix/lib/ sources de Jelix et bibliothèques tiercesjelix/ sources de Jelixjelix-modules/ modules livrés en standard avec Jelixjelix-plugins/ plugins livrés en standard avec Jelixjelix-scripts/ scripts en ligne de commande d’aide pour le développeurjelix-www/ ressources javascript, css, xul... (1.0alpha3)

temp/ fichiers temporaires des applications jelix.

Il y a aussi d’autres répertoires dans jelix/lib/ (non listés ici), qui sont des bibliothèques additionnelles externes auprojet Jelix, et utilisées par Jelix. Il y a par exemple wikirenderer, JSON, difflib etc.

Il est recommandé d’installer ces répertoires en dehors du répertoire de votre site web, pour deux raisons :

1. plus de sécurité

2. permettre de partager une même distribution de Jelix avec plusieurs applications.

Mais ce n’est pas une obligation. Nous admettrons par la suite que vous avez copié ces répertoires dans un répertoiremonsite/.

Vous devez mettre les droits en écriture à l’utilisateur apache (ou tout autre nom d’utilisateur, celui en général quisert à lancer le serveur web) sur le répertoire temp.

Vous pouvez maintenant créer ou installer une application.

Page 13: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

6 / 225

Chapitre 3

Installation d’une application

Nous allons prendre l’installation de testapp en exemple mais les explications sont valables pour n’importe quelleapplication.

Testapp est disponible en téléchargement. C’est une application testant divers composants de Jelix. Elle sert princi-palement aux développeurs de Jelix, mais vous pouvez l’installer pour voir des exemples d’utilisation.

3.1 Installation des fichiers de l’application

3.1.1 Décompression de l’archive

Quand vous décompressez l’archive de testapp, vous obtenez les répertoires suivants :

testapp/ répertoire de l’applicationmodules/ modules de l’applicationplugins/ plugins de l’applicationresponses/ les réponses personnaliséesvar/ répertoire qui contient tout les fichiers créés ou susceptibles d’être modifiés par Jelix, pendant l’exécution

config/ fichiers de configuration de l’applicationlog/ fichiers journaux de l’application et de Jelix

www/ racine du site de l’application (document root)

Copiez ce répertoire dans le repertoire monsite/. Vous avez donc :

monsite/lib/temp/testapp/

Par défaut, l’arborescence des sources est organisée de façon à installer l’application sur un serveur sur lequel vouspouvez spécifier le répertoire racine public du site (document root). Ce répertoire est monsite/testapp/www .

Vous pourrez bien entendu modifier l’emplacement de ces répertoires si par exemple vous ne pouvez pas modifier ledocument root. Nous allons voir comment faire plus loin.

Vous remarquerez que les fichiers propres à l’application et ceux du framework sont séparés. Vous pouvez ainsipartager le répertoire lib avec plusieurs applications.

Page 14: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

7 / 225

3.1.2 Renommer les fichiers de configuration

Dans testapp/var/config vous avez des fichiers *.dist. Renommez-les en enlevant cette particule ’.dist’.

3.1.3 Créer le répertoire temporaire

Dans monsite/temp vous devez créer le dossier testapp

3.1.4 Droits sur les répertoires

Vous devez donner le droit en écriture à l’utilisateur exécutant votre serveur web (apache ou autre) sur les répertoiressuivants :

temp/testapp/testapp/var/config/testapp/var/log/

3.2 Configuration du serveur

Voici ce qu’il faut configurer au niveau du serveur.

3.2.1 Si vous pouvez spécifier le document root

Si vous pouvez spécifier la racine du site en modifiant les fichiers de configuration du serveur web ou via une interfaced’administration comme le proposent certains hébergeurs, indiquez alors le répertoire monsite/testapp/www commeétant la racine du site. Par exemple, avec apache, vous indiquerez dans le fichier httpd.conf, quelque chose comme :

<VirtualHost *>ServerName www.monsite.comDocumentRoot /var/monsite/testapp/www/

</VirtualHost>

Vous devez indiquer aussi un alias vers le répertoire lib/jelix-www, en le nommant jelix :

<VirtualHost *>ServerName www.monsite.comDocumentRoot /var/monsite/testapp/www/Alias /jelix/ "/var/monsite/lib/jelix-www/"

</VirtualHost>

<Directory "/var/monsite/lib/jelix-www/">AllowOverride NoneOrder allow,denyAllow from all

</Directory>

Note : vous pouvez indiquer un autre nom que "jelix" pour l’alias. Vous devez alors l’indiquer dans l’option "je-lixWWWPath" dans le fichier de configuration de l’application, monsite/testapp/var/config/defaultconfig.ini.php sec-tion urlengine.

Et enfin dans ce même fichier vous ajusterez l’option basePath, en indiquant le chemin jusqu’au index.php (ici donc,/) :

Page 15: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

8 / 225

basePath="/"

Ainsi, en tapant http :www.monsite.com vous accédez à votre site, et http :www.monsite.com/jelix/, à jelix-www, quicontient un certain nombre de scripts javascript utiles, des ressources XUL etc..

3.2.2 Si vous ne pouvez pas spécifier le document root

Dans ce cas, il est préférable de déplacer le contenu du répertoire monsite/testapp/www à la racine de votre site, mon-site/. Vous déplacerez donc les fichiers index.php, jsonrpc.php etc, pour obtenir par exemple l’arborescence suivante :

monsite/testapp/lib/temp/index.phpjsonrpc.phpxmlrpc.php

Il faut aussi modifier ces trois fichiers PHP pour changer les chemins relatifs qu’ils contiennent, et faire de mêmepour le fichier testapp/application.init.php. Par exemple le fichier index.php ressemblera à ceci dans notre exemple :

require_once (’lib/jelix/init.php’);require_once (’testapp/application.init.php’);

require_once (JELIX_LIB_CORE_PATH.’request/jClassicRequest.class.php’);$config_file = ’config.classic.ini.php’;$jelix = new jCoordinator($config_file);$jelix->process(new jClassicRequest());

Il faut ensuite déplacer le répertoire lib/jelix-www/ à la racine et le renommer en "jelix". Vous obtiendrez :

monsite/testapp/jelix/lib/temp/index.phpjsonrpc.phpxmlrpc.php

Note : vous pouvez indiquer un autre nom que "jelix" pour ce renommage. Vous devez alors l’indiquer dans l’option"jelixWWWPath" dans le fichier de configuration de l’application, monsite/testapp/var/config/defaultconfig.ini.phpsection urlengine.

Dans le fichier testapp/application.ini.php, vous devez modifier la constante JELIX_APP_WWW_PATH :

define (’JELIX_APP_WWW_PATH’, realpath(JELIX_APP_PATH.’../’).’/’);

Et enfin, dans le fichier monsite/testapp/var/config/defaultconfig.ini.php, vous ajusterez l’option basePath, en indi-quant le chemin jusqu’au index.php (ici donc, /) :

basePath="/"

Vous pouvez alors taper l’adresse de votre site (http :www.monsite.com par exemple, ou http :localhost/)

Page 16: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

9 / 225

3.2.3 Spécifier une extension de fichier autre que .php

Sur certains serveurs, il vous est proposé PHP4 et PHP5 à la fois. En général, les fichiers .php doivent être desfichiers PHP4, et .php5, des fichiers PHP5. Il vous faut donc faire des modifications pour que votre application jelixfonctionne avec PHP5. Deux façons, selon les possibilités.

Par le .htaccess

Dans le répertoire www de votre application rajoutez un fichier .htaccess et mettez y :

AddHandler php5-script .php

Et vous n’avez rien d’autre à faire. Si ça ne fonctionne pas, faites comme suit.

En renommant l’extension

Il faut renommer le fichier index.php en index.php5 (idem pour les autres fichiers php se trouvant dans www :jsonrpc.php, xmlrpc.php, etc...). Par contre, vous n’avez pas besoin de renommer les fichiers php des autres réper-toires !

Dans le fichier de configuration var/config/defaultconfig.ini.php, indiquez l’extension dans la partie urlengine :

entrypointExtension = .php5

3.3 Configuration pour les urls "cools"

Pour pouvoir utiliser des urls significatives avec le système d’url automatique de jelix, il faut activer dans apache (auniveau de la configuration serveur ou dans le .htaccess si cela est permis) :

Options +Multiviews

Et pour Apache 2, rajouter :

AcceptPathInfo on

Pour vérifier que cela fonctionne, créez sur votre site web un fichier test.php qui affiche phpinfo() et essayez l’url :monsite.com/test/foo/bar . Le phpinfo devrait s’afficher, et vous devriez avoir dans $_SERVER[’PATH_INFO’] lachaine "/foo/bar" (voir tout en bas de l’affichage de phpinfo).

Page 17: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

10 / 225

Chapitre 4

Installation sur un serveur de production

On appelle serveur de production, le serveur sur lequel sera installé votre application une fois terminée, donc acces-sible aux utilisateurs finaux. Par opposition, il y a le serveur de développement, celui sur lequel vous développez votreapplication.

Il y a certaines choses différentes à prendre compte dans le cas du serveur de production, afin d’optimiser l’exécutionde votre application basée sur Jelix.

4.1 Choisir la bonne édition de Jelix

Pour développer, vous utilisez bien sûr l’édition "developer" de Jelix. Cette édition comprend les outils de scriptsen ligne de commande et d’autres choses pour le développement.

Cependant, pour l’installation sur un serveur de production, il est préférable d’installer l’édition "optimized" deJelix. Comme son nom l’indique, elle est optimisée, et débarrassée des choses inutiles en production. Notez toutefoisque votre application fonctionnera à l’identique avec l’une ou l’autre des éditions de Jelix, à un détails près : on pourraobserver de légères améliorations de performance avec l’édition "Optimized" ;-).

Si vous choisissez de rester avec l’édition "developer" sur le serveur de production, il n’y a pas de problème à cela.Il est toutefois recommandé de supprimer les scripts en ligne de commande de Jelix.

Note : une édition "Gold" expérimentale est disponible en téléchargement, pour les développeurs qui peuventmodifier la configuration de php, en particulier, installer des extensions PHP. En effet, cette édition repose sur certainesextensions PHP qui ne sont pas disponibles chez tous les hébergeurs, mais aussi sur une extension PHP spécialementdédiée à Jelix, qui prend en charge certains traitements du framework. L’utilisation de l’édition GOLD améliore ainsisensiblement les performances de votre application.

4.2 Configuration

L’installation se passe à l’identique que sur le serveur de développement, y compris pour l’application.

Pour avoir de meilleur performance et plus de sécurité, voici toutefois quelques conseils supplémentaires.

4.2.1 Au niveau du serveur

1. Tous les répertoires autre que le www de votre application devraient être en dehors du "document root" du siteweb.

Page 18: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

11 / 225

2. Bien spécifier les droits sur le répertoire temp, en particulier, que le propriétaire soit l’utilisateur qui exécuteapache (ou celui de votre compte, chez certains hébergeurs) et qu’il ait les droits en écriture. Par exemple, surlinux, il n’est pas recommandé de mettre les droits 0777 sur le répertoire temp ;-)

4.2.2 Au niveau de l’application

Voici quelques conseils au niveau de la configuration de l’application, donc les modifications à faire au niveau dufichier var/config/defaultconfig.ini.php .

section error_handling

Dans la section error_handling, la configuration suivante est vivement conseillée :

[error_handling]messageLogFormat = "%date%\t[%code%]\t%msg%\t%file%\t%line%\n"logFile = error.logemail = root@localhostemailHeaders = "From: [email protected]\nX-Mailer: Jelix\nX-Priority: 1 ( ←↩

Highest)\n"quietMessage="A technical error has occured. Sorry for this trouble."

; mots clés que vous pouvez utiliser : ECHO, ECHOQUIET, EXIT, LOGFILE, SYSLOG, ←↩MAIL, TRACE

default = ECHOQUIET EXIT LOGFILEerror = ECHOQUIET EXIT LOGFILEwarning = ECHOQUIET LOGFILEnotice =strict =; pour les exceptions, il y a implicitement un EXITexception = ECHOQUIET LOGFILE

En clair, il est déconseillé d’utiliser le mot clé ECHO, qui affiche tous les détails des erreurs dans les pages web (in-formations qui pourraient être utiles pour des pirates), mais plutôt ECHOQUIET, qui affiche simplement le messageindiqué dans le paramètre quietMessage.

Toutefois, il est utile d’être informé des erreurs et de leurs détails. Aussi, parallèlement à ECHOQUIET, il estrecommandé d’ajouter l’un de ces mots clés– LOGFILE : les erreurs sont insérées dans le fichier indiqué dans logFile– SYSLOG : les erreurs sont enregistrées au niveau du système– MAIL : les erreurs sont envoyées par Mail.Attention à l’usage de MAIL : ne l’utiliser qu’une fois que vous savez que votre application fonctionne bien sur le

serveur de production. Sinon vous risquez d’être inondé de mails (voire même que votre hébergeur n’appréciasse pasl’usage intensif du mail, pouvant vous prendre pour un spammeur).

Attention aussi à l’usage de SYSLOG : ne mettre cette option que si il s’agit de votre serveur (c’est à dire que vousêtes administrateur de la machine). Sinon le propriétaire de la machine risque de ne pas apprécier.

En conclusion : LOGFILE est plutôt conseillé par rapport à MAIL et à SYSLOG ;-)

Section compilation

Dans la section compilation, vous pouvez désactiver l’option checkCacheFiletime, et encore plus recommandé,l’option force si vous l’avez activé pour le développement.

Page 19: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

12 / 225

[compilation]checkCacheFiletime = offforce = off

L’option checkCacheFiletime évite à Jelix de vérifier tout le temps que le cache (les fichiers générés par Jelix pourles fichiers de configurations, les DAO, templates etc) est bien à jour par rapport aux fichiers de l’application. Àpriori, cette vérification est inutile en production, puisque l’application est rarement modifiée. Bien sûr, si vous ladésactivez, il faudra impérativement vider le répertoire de cache (temp/votre_appli/) à chaque mise à jour de votreapplication , pour que vos modifications soient bien prises en compte ! (surtout quand il s’agit de modification dansla configuration, des daos, locales, templates..)

Section mailer

N’oubliez pas de mettre à jour les paramètres de la section mailer. En effet, les paramètres pour envoyer des mailsne sont pas toujours identiques entre le serveur de développement et le serveur de production.

Page 20: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

13 / 225

Deuxième partie

Fondamentaux

Page 21: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

14 / 225

Comme tout framework, Jelix a des principes de fonctionnement et une série d’objets à connaître, en particulier ceuxqui sont utilisés dans la logique MVC : Modèle, Vue, Controlleur.

Vous allez apprendre dans cette partie à créer un module et à utiliser les contrôleurs et les réponses.

Page 22: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

15 / 225

Chapitre 5

Principes de fonctionnement

Voici quelques explications sur le fonctionnement du framework et sur les principaux objets que vous allez avoir àutiliser.

Le framework se base sur un principe : à chaque URL correspond une action.

5.1 Étapes d’exécution

Page 23: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

16 / 225

1. Le serveur web reçoit une requête HTTP.– Le point d’entrée est exécuté par le serveur lorsqu’une URL l’indique. Par défaut il s’agit de index.php.– Ce script instancie un objet de type jRequest et un coordinateur de type jCoordinator.– L’objet jRequest analyse alors le contenu de la requête HTTP pour en extraire les données. Celles-ci peuvent

être dans l’URL et/ou dans le corps de la requête (méthode POST par exemple).– En particulier jRequest détermine le nom de l’action à exécuter et le nom du module concerné.

2. Le paramètre action contient le nom du contrôleur et la méthode à exécuter. Ce contrôleur est donc instancié etla méthode exécutée. La méthode récupère les paramètres de requête pour déterminer les traitements à suivre.

3. Le contrôleur exécute les traitements métiers et récupère éventuellement des résultats qui seront utilisés pourl’affichage.

4. Le contrôleur instancie un objet de type jResponse auquel il assignera les données à afficher, initialisera lestemplates, etc...

5. Jelix récupère cet objet jResponse, invoque la génération du document en sortie et envoi ce dernier au navigateur.

5.2 Ce que vous avez à manipuler

En général, vous n’aurez pas à utiliser un objet jRequest ou jCoordinator.

Vous aurez par contre à créer un objet de type jController pour y inclure le code d’une action. Cet objet propose desméthodes pour récupérer les paramètres extraits par jRequest, mais aussi pour récupérer un objet jResponse. Vousaurez donc dans le code de l’action, en plus de manipuler vos objets "métier", à manipuler cet objet jResponse pourindiquer les données à renvoyer au navigateur.

5.3 Objets en détails

Voyons maintenant un descriptif de chaque objet présenté ici ainsi que d’autres, à commencer par les sélecteurs.

5.4 Les sélecteurs

5.4.1 L’utilité des sélecteurs

Les sélecteurs sont très utilisés dans Jelix. Ils permettent d’indiquer une ressource, un fichier, sans avoir à connaîtreson chemin. En effet, l’arborescence d’une application Jelix n’est pas figée et peut être modifiée selon les normes envigueurs sur le serveur (le répertoire var de l’application myapp allant dans le répertoire /var/myapp/var par exemple,sur un serveur unix).

De plus les bibliothèques de Jelix peuvent être installées dans une arborescence différente de celle de l’application.

Aussi les sélecteurs permettent de ne pas avoir à modifier son application quand elle est installée différemment.

Et ils permettent aussi d’éviter à devoir taper de long chemins de fichiers...

5.4.2 Comment est défini un sélecteur

Un sélecteur est une chaîne ayant ce format : "unModule~uneRessource" . On peut omettre le module si on se trouveactuellement dans le module en question. Dans ce cas on écrit "uneRessource".

Un sélecteur désigne une ressource d’un type précis. Voici donc les différents types de sélecteurs :

Page 24: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

17 / 225

En règle générale, vous aurez à donner un sélecteur en paramètre de certaines méthodes sans avoir à indiquer sontype. Très souvent en effet ces méthodes savent qu’il s’agira d’un sélecteur sur une ressource d’un type précis.

jDao::create("myModule~myDao");

Ici jDao cherchera un fichier DAO de nom myDAO.dao.xml dans le module myModule.

5.4.3 Définir un sélecteur d’un type précis

Il peut arriver (mais c’est en fait très rare dans l’API de Jelix) que la méthode attende n’importe quel type de sélecteur.Dans ce cas là il faut ajouter un préfixe au sélecteur de manière à indiquer son type. Ce préfixe est indiqué dans letableau du dessus. La notation d’un sélecteur est alors :

"type:unModule~uneRessource"

On appelle cela un "sélecteur complet".

On utilisera alors l’objet jSelectorFactory pour récupérer l’objet sélecteur correspondant (voir la colonne classe dansle tableau) et donc le chemin physique de la ressource indiquée.

$unSelecteur = "tpl:foo~bar";...$selector = jSelectorFactory::create($unSelecteur); // $selector sera un objet ←↩

de type jSelectorTpl$chemin_du_template = $selector->getPath();

5.5 Les objets jRequest

5.5.1 Un objet jRequest pour chaque type de requête

Un objet jRequest prend en charge le traitement des données en entrée afin de les rendre disponibles facilement auframework et plus spécifiquement aux actions. Il permet entre autre de déterminer le module et l’action à exécuter.

Il y a plusieurs types d’objets jRequest qui permettent de traiter différentes données en entrée. En effet, on ne récupèrepas les données en entrée pour une page HTML (situées dans l’URL pour une requête GET ou URL-encodées dansson corps pour une requête POST) de la même manière que celles d’un appel XML-RPC (les données étant situéesdans le corps de la requête HTTP sous forme XML).

À chaque type d’objet jRequest correspond un ou plusieurs formats de sortie autorisés, donc un ou plusieurs objetsjResponse permis.

Les objets jRequest disponibles sont :– classic : pour les requêtes classiques dont le type de réponse est indifférent (HTML, texte, redirection...),– xmlrpc : pour les requêtes XML-RPC. La réponse sera nécessairement en XML-RPC,– jsonrpc : pour les requêtes JSON-RPC. La réponse sera nécessairement en JSON-RPC.D’autres sont possibles (SOAP par exemple).

Page 25: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

18 / 225

5.5.2 Point d’entrée

Il faut un fichier d’entrée PHP pour chaque type de requête que l’on veut utiliser. Pour le classique (a priori, in-dex.php), ça ressemble à ça :

// inclusion du fichier principal de jelixrequire_once (’../../lib/jelix/init.php’);

// inclusion du fichier principal de l’applicationrequire_once (’../../myapp/application.init.php’);

// inclusion d’un objet jRequest de son choixrequire_once (JELIX_LIB_CORE_PATH.’request/jClassicRequest.class.php’);

// on indique le fichier de configuration correspondant au point d’entrée// ici le fichier de config est dans var/config/index/$config_file = ’index/config.ini.php’;

// instanciation du coordinateur et lancement du processus$jelix = new jCoordinator($config_file);$jelix->process(new jClassicRequest());

5.5.3 API

Durant l’exécution de l’action, l’objet jRequest correspondant à la requête est accessible via la propriété requestdu coordinateur. Ce dernier est accessible via une variable globale $gJCoord.

// pour récupérer un paramètre en dehors d’un contrôleur$myfooValue = $GLOBALS[’gJCoord’]->request->getParam(’foo’);

Mais dans un contrôleur, vous avez à votre disposition des méthodes "raccourcis" :

$myfooValue = $this->param(’foo’);

Les autres propriétés de request qui peuvent être utiles :

5.6 Le coordinateur

Le coordinateur est le coeur du framework. C’est en quelque sorte le chef d’orchestre de l’exécution d’une action.

À partir des paramètres donnés par un objet jRequest, le coordinateur en déduit les informations suivantes :– le nom du module et le nom de l’action à exécuter– les données en entrée– la liste des types de réponses possibles et le type de la réponse par défautDes plugins peuvent modifier éventuellement ces informations (ex : plugin qui vérifie l’authentification et redirige

alors vers une autre action, ...).

Avec ces informations il va donc récupérer le contrôleur correspondant et exécuter la méthode qui implémente letraitement correspondant à l’action.

Il récupérera l’objet jResponse fourni par le traitement de l’action pour alors renvoyer au navigateur le contenugénéré par jResponse.

Page 26: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

19 / 225

5.7 Les objets jResponse

5.7.1 jResponse

Un objet jResponse représente la vue dans le modèle MVC. Il est chargé de contrôler et de générer correctement laréponse, c’est à dire les données en sortie. Toute demande d’"affichage" passe par cet objet.

Il existe plusieurs objets qui hérite de la classe jResponse, chacun prenant en charge un format spécifique en sortie :html, texte, fichiers binaires, pdf, XML-RPC etc... Mais aussi des réponses particulières comme la redirection.

Un objet jResponse implémente un certain nombre de méthodes, dont les plus utiles pour vous sont celles-ci :– addHttpHeader () : pour ajouter un entête HTTP, qui sera envoyé au moment opportun.– setHttpStatus () : pour indiquer le code "status" HTTP (200, 404...)Ces méthodes sont disponibles pour tout type de réponse.

Pour connaître les spécificités des différents objets réponses, voir le chapitre sur les réponses.

5.8 Appeler une action

5.8.1 Appeler une action

Une fois que l’on a fait un contrôleur on veut bien sûr pouvoir appeler l’une de ces méthodes, donc indiquer lesinformations nécessaires dans les URLs.

Avec la configuration par défaut de Jelix (donc avec le moteur d’URL simple), il faut indiquer dans l’URL :– le nom du module– le nom de l’action constituée du nom du controleur et du nom de la méthodeOn le fait en indiquant les paramètres module et action.

index.php?module=monmodule&action=moncontroleur:mamethode

Notez que le nom du contrôleur et de la méthode doivent être séparés par le caractère " :".– Si le paramètre action n’est pas présent, Jelix essaiera d’exécuter la méthode index du contrôleur default.– Si le paramètre module est absent, Jelix essaiera d’exécuter l’action indiquée du module indiqué dans le paramètre

startModule dans la configuration de l’application.– Si les deux paramètres sont absents, Jelix exécutera l’action indiquée dans le paramètre startAction, à partir du

module indiqué dans le paramètre startModule dans la configuration de l’application.– Dans le paramètre action, si on indique juste le nom de la méthode, Jelix exécutera la méthode indiquée dans le

contrôleur default

5.8.2 Sélecteurs d’action

Dans vos templates et dans votre code en général, vous n’indiquerez jamais d’URL "en dur". Jelix comporte desmécanismes (la classe jUrl notament) pour générer les URLs correspondantes à des actions. Ceci permet de choisirson moteur d’URL préféré (simple ou significant) et de modifier le "mapping" entre des URLs significatives et desactions. Tout ceci sans toucher ni aux templates, ni aux contrôleurs.

Aussi vous allez devoir la plupart du temps indiquer à divers objets ou méthodes de l’API de Jelix des sélecteursd’action accompagnés d’éventuels paramètres. Voir la page sur les sélecteurs pour en savoir plus sur les sélecteurs engénéral.

Les sélecteurs d’action ont cette syntaxe :

Page 27: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

20 / 225

module~controleur:methode

Vous pouvez omettre l’une de ces parties comme spécifié précédemment :

controleur:methodemethodemodule~controleur:

Vous pouvez aussi indiquer le caractère "#" pour spécifier le module courant ou l’action courante. Dans ces exemples,imaginons que c’est l’action "bar :man" du module "foo" qui a été appelée dans Jelix :– "#~controleur :methode" représente l’action "controleur :methode" du module qui a été appelé. Équivaut donc à

"foo~controleur :methode"– "module~#" représente l’action qui a été appelée mais du module indiqué. Équivaut donc à "module~bar :man"– "#~#" représente le module/l’action qui ont été appelés. Équivaut donc à "foo~bar :man".

5.8.3 Indiquer le point d’entrée

Par défaut quand on indique un sélecteur d’action, il génère l’URL avec le point d’entrée courant : si on a appeléJelix avec index.php, ce sera index.php, si c’est xmlrpc.php, ce sera xmlrpc.php.

Cependant on peut vouloir indiquer des URLs pour d’autres points d’entrées. Par exemple, on est dans une actionqui affiche une page html et on veut indiquer dans la page l’URL du point d’entrée pour les services web jsonrpc.

Dans ce cas on ajoute à la fin du sélecteur d’action, un "@" suivi du nom du type du point d’entrée :

foo~bar:man@css

Ici on demande l’URL de l’action "bar :man" du module "foo", pour les requêtes de type "css".

Pour la plupart des URLs on indiquera certainement "@classic".

Si dans un sélecteur d’action on n’indique juste le type de requête, seront utilisés le module et l’action indiquésrespectivement dans startModule et startAction de la configuration de l’application. Ainsi par exemple le sélecteur"@classic" correspondra à l’URL "index.php".

Pour en savoir plus : configuration et la manipulation des URLs dans Jelix.

Page 28: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

21 / 225

Chapitre 6

Développement d’un module

Les contrôleurs et fonctionnalités de votre application doivent être regroupés en modules.

Un module contient un ensemble de fichiers, entre autre :– Des contrôleurs– Des classes métiers– Des templates– Des fichiers daos– Des formulaires– Des fichiers de languesLes fichiers d’un module sont censés concerner un même domaine fonctionnel. Par exemple, un module "news"

contiendra tous les fichiers qu’il faut pour afficher et/ou gérer les news.

Dans une application, vous devez avoir au moins un module qu’il vous faut créer. Ce sera en général ce qu’on appellele module principal, qui pourrait contenir par exemple ce qu’il faut pour afficher la page d’accueil de votre site.

Notez qu’il y a implicitement un autre module déclaré automatiquement dans votre application : le module "jelix",situé dans lib/jelix/core-modules/jelix.

Dans la suite, nous allons voir comment créer un module et un contrôleur.

6.1 Créer un module

6.1.1 Déclarer les répertoires de modules

Un module est un répertoire dans lequel il y a une arborescence précise. Les modules sont regroupés dans un ouplusieurs répertoires que l’on appelle groupe de modules, ou aussi dépôt de modules.

Configuration générale

Pour avoir accès aux modules, il faut déclarer ces dépôts de modules dans la configuration, par la propriété modu-lesPath. On peut y indiquer plusieurs chemins en les séparant par des virgules. On peut indiquer soit des cheminscomplets, soit des chemins relatifs à un répertoire spécifique de l’arborescence Jelix. Ces chemins relatifs ont unenotation spéciale :

coderepertoire:chemin/relatif/

Page 29: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

22 / 225

coderepertoire est un de ces codes :

Cela évite d’avoir à indiquer un véritable chemin relatif. Et donc d’avoir à changer à la fois le fichier applica-tion.init.php et le fichier de configuration quand on fait une modification dans l’arborescence, quand on migre l’appli-cation d’un serveur à un autre (entre le développement et la production par exemple).

Exemple :

modulesPath = lib:jelix-modules/,app:modules/

On déclare ici qu’il y a deux dépôts de modules : le premier, jelix-modules, se trouvant dans le répertoire lib de jelix ;le deuxième, le répertoire modules de l’application.

Tous les modules se trouvant dans ces deux répertoires seront utilisables et les actions qu’ils déclarent pourront êtreappelées depuis un navigateur.

Restrictions

Il se peut que parmi les modules présents dans un dépôt, on veuille en désactiver certains : cela peut arriver si cegroupe de module est partagé par plusieurs applications et que pour l’application courante, on ne veuille pas utilisercertains de ces modules. Ou encore que pour plus de sécurité, on interdisent l’accès à certains modules pour certainspoints d’entrée.

On dispose alors de deux paramètres de configuration :

checkTrustedModules = ontrustedModules = foo,bar,baz

On active la restriction d’accès via le paramètre checkTrustedModules, et on indique les modules autorisés danstrustedModules. Les autres modules ne seront pas accessibles de l’extérieur. Par contre, les modules autorisés peuventaccéder aux ressources des modules non autorisés (classes, zones, dao...).

6.1.2 Créer un module

Le principe : il suffit de créer un répertoire dans un dépôt, avec un nom précis, et d’y mettre les contrôleurs, les daoset tout ce qu’il faut dans leurs sous-répertoires respectifs.

Le plus simple est encore d’utiliser le script jelix et la commande createmodule :

php jelix.php createmodule monmodule

Cela vous créé un module de nom "monmodule" dans le répertoire modules/ de l’application, des sous répertoiresainsi qu’un contrôleur par défaut.

6.2 Développer un contrôleur

Les contrôleurs sont les objets qui vont effectuer les actions correspondantes à chacune des urls de votre application.

Un contrôleur possède une ou plusieurs méthodes correspondant à des actions, qui vont effectuer des traitements etpréparer une réponse (html, redirection, ...) pour le navigateur.

Un contrôleur est toujours dédié à un type de requête particulier.

Page 30: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

23 / 225

6.2.1 Convention de nommage

Fichier

Les contrôleurs doivent être stockés dans le répertoire controllers des modules. Ils ont chacun un nom qui va servirde suffixe ou préfixe.

Le fichier d’un contrôleur a un nom bien précis :

cccc.tttt.php

où– cccc est le nom du contrôleur– tttt est le type de requête auquel il est dédié.Par exemple, si vous l’appelez "foo", et qu’il est dédié au type de requête "classic" (ce qui sera le plus souvent le

cas), le nom du fichier sera foo.classic.php.

Classe

La classe d’un contrôleur doit toujours avoir le suffixe "Ctrl". Dans le cas d’un contrôleur nommé "foo", sa classedevra être nommée "fooCtrl".

6.2.2 Création d’un contrôleur

Chaque module a en principe un contrôleur principal, que l’on appelle généralement "default". On va prendre ce nompour l’exemple de création de contrôleur.

En suivant les conventions de nommage, on créé donc une classe de nom "defaultCtrl" dans un fichier controllers/-default.classic.php.

Voici le code source minimal :

class defaultCtrl extends jController {

}

Une classe de contrôleur doit toujours hériter de la classe jController.

Ensuite, il faut ajouter au moins autant de méthodes que d’actions prises en charge par le contrôleur. Ces méthodessont publiques, n’ont pas d’arguments, et doivent renvoyer un objet de type jResponse.

Voici un exemple de méthode pour une action "index" :

class defaultCtrl extends jController {

public function index(){$rep = $this->getResponse(’html’);$rep->addContent(’<p>Test</p>’);return $rep;

}

}

Page 31: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

24 / 225

Note : quand le nom d’une action est absent, ou incomplet (il n’y a que le nom de la méthode ou que le nom ducontrôleur), alors Jelix complètera le nom de l’action avec "default" pour le contrôleur et "index" pour le nom de laméthode. Il est donc recommandé d’avoir toujours un contrôleur "default" dans un module et une méthode "index"dans chaque contrôleur.

Utilisation d’un constructeur de classe

Pour utiliser un constructeur de classe dans un contrôleur, il est nécessaire de mentionner le constructeur parent ainsique d’y lier l’argument $request. Exemple :

class defaultCtrl extends jController {function __construct($request) {

parent::__construct($request);/* Reste du code du contrôleur ici */

}}

6.2.3 Services fournis par jController

Dans une action, vous avez un certains nombre de méthodes à votre disposition.

Récupérer un objet jResponse

Vous devez toujours renvoyer un objet dérivant de jResponse, qui est en fait le "view" du modèle MVC. Il y a uncertains nombres d’objet jResponse fournies par Jelix, permettant de générer du XHTML, du JSON, du text, du css,du xml, du zip ou même faire des redirections. Chaque type d’objet jResponse est déclaré dans jelix par un mot clé.

Aussi, pour récupérer un objet "réponse" précis, vous appelez la méthode getResponse en indiquant le mot clécorrespondant au type de réponse que vous voulez.

$rep = $this->getResponse(’html’);

$rep contient ici une réponse qui va générer du html. l’objet $rep est du type jResponseHtml.

Sachez que vous pouvez définir vos propres types de réponses, voir même plusieurs type de réponse issue d’un mêmetype, afin d’avoir d’éviter de dupliquer du code, ou de prendre en charge un format que ne connait pas jelix. Voyezpour cela l’article sur la création des réponses personnalisées.

Récupérer les paramètres de requête

Comme vous le savez, les paramètres de la requête http sont stockés dans un objet jRequest, qui lui même est stockédans l’objet jCoordinator. On peut ainsi récupérer un paramètre de cette façon :

$id = $GLOBALS[’gJCoord’]->request->getParam(’id’);

Mais il y a plus pratique : la méthode param() disponible dans les contrôleurs, au résultat équivalent.

$id = $this->param(’id’);

Si il n’y a pas de paramètre de nom id, le résultat sera la valeur null. Vous pouvez aussi indiquer en deuxièmeargument une valeur qui sera prise si le paramètre indiqué n’existe pas.

Page 32: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

25 / 225

$titre = $this->param(’title’,’un titre’);

Il y a d’autres méthodes similaires, comme intParam(), floatParam() et boolParam(), prenant les mêmes argu-ments, mais transformant le paramètre récupéré dans le type de donnée correspondant. Avec intParam(), vous ob-tiendrez un nombre entier ; avec floatParam(), un décimal. Cela permet ainsi de "filtrer" les données. Et pour bool-Param(), vous obtiendrez true si le paramètre vaut "true", "1", "on" ou "yes", et false dans le cas contraire.

Si vous voulez un filtrage pour d’autres types de données, utilisez la classe jFilter.

6.3 Utiliser le contrôleur CRUD

6.3.1 Introduction

Un contrôleur (jControllerDaoCrud) est fourni avec jelix pour faire du CRUD. CRUD veut dire Create, Read, Update,Delete. En substance, c’est un contrôleur qui contient toutes les actions pour créer, lire, mettre à jour et effacer unenregistrement d’une table, et lister les enregistrements de cette table. Il lui faut en gros pour fonctionner, le nom d’unfichier DAO et d’un fichier jForms. Il s’occupe du reste.

C’est donc un contrôleur permettant de mettre en place rapidement une gestion d’un enregistrement de table.

6.3.2 Création d’un CRUD

Pour l’utiliser, il faut créer un contrôleur dans votre module, qui hérite non pas de jController, mais de jController-DaoCrud. Exemple, dans un fichier samplecrud.classic.php

class sampleCrudCtrl extends jControllerDaoCrud {

}

Il faut ensuite lui indiquer un DAO qui utilise la table que l’on veut gérer, et un fichier jforms, qui permettra d’afficherle formulaire d’édition d’un enregistrement. Cela se fait au travers des propriétés $dao et $form :

class sampleCrudCtrl extends jControllerDaoCrud {

protected $dao = ’testapp~products’;

protected $form = ’testapp~products’;

}

Et c’est tout ! En imaginant que ce contrôleur se trouve dans le module main, affichez alors la page

index.php?module=main&action=samplecrud:index

Vous avez alors toutes les pages qu’il faut pour gérer les enregistrements de la table.

Important : par défaut, le controleur récupère la réponse HTML définit dans jelix, c’est à dire qu’il vous faut faireune réponse HTML personnalisée. Si vous n’en avez pas, rien ne s’affichera. Si vous ne voulez pas faire de réponsepersonnalisée (ce qui est dommage), il faudra configurer le contrôleur.

Page 33: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

26 / 225

6.3.3 Personnalisation

Il se peut que le comportement par défaut du controleur et des affichages des pages ne correspondent pas à ce quevous voulez, et qu’il faille faire des choses au niveau du formulaire (préremplir à la main des listbox par exemple).Voici donc ce qui est possible de faire.

Indiquer le profil jDb

Si il faut utiliser un profil de connexion spécifique, indiquez le dans la propriété $dbProfil :

protected $dbProfil = ’admin’;

Configurer la réponse

Par défaut, comme il a été dit plus haut, le controleur récupère la réponse HTML par défaut. Cela se fait dans laméthode _getResponse() du contrôleur :

protected function _getResponse(){return $this->getResponse(’html’);

}

L’objet réponse renvoyé par cette méthode est alors utilisé par toutes les actions du contrôleur CRUD.

Comme vous le voyez, rien n’est fait au niveau de la réponse : pas de déclaration de template principal (bodyTpl),pas de feuille de style ou autre. Le contrôleur s’attend en effet à ce que l’objet renvoyé par getResponse soit un objetréponse crée par vos soins et communs à tous vos contrôleurs.

Si vous voulez donc changer ça, surchargez donc ces méthodes en y ajoutant ce que vous voulez. Exemple :

protected function _getResponse(){$rep = $this->getResponse(’html’);$rep->addCSSLink(’admin.css’);$rep->body->assignZone(’menu’, ’adminmenu’);return $rep;

}

Ainsi la page de liste des enregistrement, de vue et d’édition d’un enregistrement etc auront une feuille de styleadmin.css et un menu qui est généré par la zone adminmenu.

Intégration des templates dans la réponse

Chaque action d’affichage du contrôleur CRUD utilise un template, dont le contenu sera assigné au template principalde la réponse dans la variable de template MAIN. En d’autres termes, chaque action fait l’équivalent de :

$rep->body->assign(’MAIN’, $resultatTemplateAction);

Si vous voulez que ce soit dans une variable de template autre que MAIN, vous pouvez changer la propriété $tem-plateAssign :

class sampleCrudCtrl extends jControllerDaoCrud {//...protected $templateAssign = ’AUTRE’;

//...}

Page 34: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

27 / 225

6.3.4 Liste des enregistrements

Elle est affichée par l’action index.

Configuration simple

Des propriétés du contrôleur CRUD permettent de configurer l’affichage de la liste.

Nombre d’enregistrements par page

Il est défini par la propriété $listPageSize :

protected $listPageSize = 20;

Liste des propriétés

Par défaut, toutes les propriétés du DAO sont affichées. Si vous voulez restreindre, indiquez la liste des propriétés àafficher dans propertiesForList :

protected $propertiesForList = array(’titre’,’date_creation’,’auteur’);

Ordre d’affichage

Il n’y a pas d’ordre spécifique pour afficher les enregistrements. Pour forcer un ordre précis, indiquée la liste despropriétés du dao qui serviront d’ordre, et le sens :

protected $propertiesForRecordsOrder = array(’date’=>’desc’, ’title’=>’asc’);

Template

Le template par défaut utilisé pour lister les enregistrement est ’jelix~crud_list’.

protected $listTemplate = ’jelix~crud_list’;

Vous pouvez bien sûr soit le surcharger dans un thème, soit en indiquer un autre.

Le template recevra les variables de templates suivantes :– list : liste des résultats (renvoyé par le dao)– primarykey : le nom de la clé primaire– properties : la liste des propriétés à afficher– controls : la liste des contrôles du formulaire jforms, permettant donc d’obtenir le libellé de chaque entête de

colonne de chaque propriété.– editAction : le nom de l’action pour le lien d’édition d’un enregistrement– editAction : le nom de l’action pour le lien d’édition d’un enregistrement– createAction : le nom de l’action pour le lien de création d’un enregistrement– deleteAction : le nom de l’action pour le lien de suppression d’un enregistrement– viewAction : le nom de l’action pour le lien de visualisation d’un enregistrement– listAction : le nom de l’action pour le lien de la liste des enregistrements (donc l’action présente)– listPageSize : la valeur de $listPageSize– page : la valeur du paramètre url "offset", indiquant le numéro d’ordre du premier enregistrement à afficher dans

la liste.– recordCount– offsetParameterName

Page 35: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

28 / 225

6.3.5 Configuration avancée de la liste

6.3.6 Détails d’un enregistrement

6.3.7 Création d’un enregistrement

6.3.8 Mise à jour d’un enregistrement

6.3.9 Destruction d’un enregistrement

6.4 Un contrôleur pour REST

La technique REST consiste à utiliser les fonctionnalités du protocole HTTP pour manipuler une ressource. Eneffet, il existe les méthodes POST et GET que vous connaissez, mais il existe aussi les méthodes PUT et DELETE.Ainsi, pour effectuer une création, un affichage, un effacement d’une ressource, plutôt que d’avoir plusieurs URLsspécifiques pour faire cela, il y a une seule URL, et on utilise le champ "method" de HTTP pour indiquer l’action àeffectuer.

Pour en savoir plus sur les principes de REST, il existe pas mal d’explications sur le web. N’hésitez pas à googler !

Voyons maintenant comment faire du REST dans Jelix.

6.4.1 Le contrôleur

Nous avons vu qu’il existe 4 methodes GET, POST, DELETE, PUT dans le protocole HTTP. Il faut implémenterdonc 4 méthodes pour chacune d’elles dans un contrôleur.

Vous devez réaliser un contrôleur qui va implémenter l’interface jIRestController. Ce contrôleur ne pourra être utiliserque pour faire du REST. Vous ne pourrez donc pas réaliser des méthodes pour des actions supplémentaires, autres queles quatres imposées par l’interface jIRestController :

class exempleCtrl extends jController implements jIRestController {

function get(){

}

function post(){

}

function put(){

}

function delete(){

}}

Dans ces méthodes, vous développez vos actions comme à l’accoutumée, en respectant la signification de ces mé-thodes. En général, GET doit correspondre à un affichage d’une ressource, POST à sa création, PUT à sa modification,et DELETE à sa suppression.

Page 36: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

29 / 225

Note : il est indispensable de déclarer que vous implémentez l’interface jIRestController. C’est en effet en analysantle contrôleur que Jelix sait si vous faites du REST ou pas, ce qui change son comportement interne.

6.4.2 Appel

Comme la nature de l’action est indiquée dans la méthode HTTP, de l’extérieur vous n’avez en fait qu’une seule url,donc qu’une seule action. C’est le type de la méthode HTTP indiquée dans la requête HTTP qui indiquera à Jelixd’appeler l’une des 4 méthodes du contrôleur.

Aussi, quand vous voulez récupérer avec jUrl l’url de l’action qui correspond à votre contrôleur REST, vous ne devezindiquer que le module et le nom du contrôleur, et ne pas mettre donc le nom d’une méthode.

Ainsi, l’action qui permet d’appeler les methodes contrôleur de l’exemple, est "leModule~exemple :" (si le moduleest "leModule"). Notez qu’il faut mettre un " :" pour indiquer que l’on indique bien le nom du contrôleur, et non lenom d’une méthode.

Avec l’url obtenu par jUrl : :get("leModule~exemple :"), vous pouvez alors appeler dans vos scripts javascripts, viaxmlHttpRequest par exemple, l’une des quatres méthodes du contrôleur, simplement en indiquant à xmlHttpRequestque vous voulez utiliser GET, POST, DELETE ou PUT.

Note

Vous pouvez bien sûr faire du REST avec un contrôleur classique, en testant dans votre action, la valeur de $_SER-VER[’REQUEST_METHOD’] qui indique le type de la méthode HTTP. Mais c’est peut être moins "sexy" que d’uti-liser le procédé indiqué dans cette page pour implémenter du REST ;-)

Page 37: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

30 / 225

Chapitre 7

Les réponses classiques

Jelix fournit en standard un certain nombre d’objet de réponses pour renvoyer aux navigateurs des contenus dans desformats courants. Ce chapitre les décrits.

7.1 Générer une page HTML

Pour récupérer une réponse xhtml/html, vous indiquez l’alias "html" à la méthode getResponse(). Vous récupérezainsi la réponse comme ceci :

$rep = $this->getResponse(’html’);

Vous avez alors dans $rep une instance de l’objet JResponseHtml.

7.1.1 Xhtml ou html

jResponseHtml est utilisé pour renvoyer par défaut une réponse au format XHTML. Mais le HTML est possible, enl’indiquant via la méthode setXhtmlOutput :

$rep->setXhtmlOutput(true); // Réponse au format xhtml$rep->setXhtmlOutput(false); // Réponse au format html

Par la suite, vous pouvez savoir si la réponse renverra du html ou du xhtml en appelant la méthode isXhtml().

7.1.2 Génération du contenu

L’objet jResponseHtml implémente des méthodes et propriétés pour manipuler le contenu (X)HTML.

Le source HTML d’une page est découpé en deux parties : la partie <head>, et la partie <body> :

Page 38: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

31 / 225

jResponseHTML s’occupe de générer le contenu de la balise <head>, à partir des informations données au travers deses méthodes. Par contre la génération du contenu de la partie <body> est de votre ressort, avec l’aide éventuellementd’un template. Voyons tout ça en détails.

7.1.3 Modification de l’entête HTML

Pour modifier le contenu de la balise <head>, vous avez plusieurs méthodes et propriétés. Vous pouvez ainsi modifierle titre du document, le "favicon", les urls des feuilles de styles et des scripts javascripts à lier au document, du CSS

Page 39: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

32 / 225

ou du javascript à inclure directement dans le <head>, ou encore les mots clés associés, la description de la page, etautres metas. Voyons un exemple qui montre l’ensemble de ces possibilités :

$rep->title = "Le titre de mon document";

// génère une balise <script src="lib.js"....>$rep->addJSLink(’lib.js’);

// génère une balise <script>alert....</script> qui sera incluse dans <head>$rep->addJSCode(’alert("essai");’);

// génère une balise <link>$rep->addCSSLink(’maFeuille.css’);

// génère une balise <style>$rep->addStyle(’span’, ’font-weight:bold;’);

// ajoute une balise meta pour la description$rep->addMetaDescription(’description’);

// ajoute une balise meta pour les mots clés$rep->addMetaKeywords(’motclé motclé motclé’);

Notez que pour la méthode addCSSLink et addJSLink, vous pouvez indiquer un paramètre supplémentaire qui doitêtre un tableau associatif, décrivant les attributs supplémentaires à mettre.

$rep->addCSSLink(’maFeuille.css’, array(’title’=>’design bleu’, rel=>’alternate ←↩stylesheet’));

Si vous voulez injecter du contenu spécifique dans la balise <head>, vous pouvez le faire via la méthode addHead-Content()

$rep->addHeadContent(’<link rel="alternate" type="application/rss+xml" title=" ←↩Recent Changes" href="/feed.php" />’)

Si à un moment ou à un autre, vous voulez annuler les modification faites dans le head (par exemple, vous êtes dansune zone qui est appelée par un module tierce que vous ne voulez pas/pouvez pas modifier), vous pouvez appeler laméthode clearHtmlHeader(). Cette fonction vous permet d’effacer une partie du header de votre document html, enindiquant quoi effacer : ’CSSLink’, ’Styles’, ’JSLink’, ’JSCode’ et/ou ’Others’.

$rep->clearHtmlHeader(array(’CSSLink’, ’Styles’));

Cela effacera les liens CSS (addCSSLink) et les balises <style> (addStyle).

7.1.4 Générer le contenu de la page HTML

jResponseHtml génère la balise <body>, mais c’est vous qui en contrôlez ses attributs et son contenu.

Pour définir les attributs de la balise <body>, vous pouvez utiliser la propriété bodyTagAttributes.

$rep->bodyTagAttributes = array(’onload’=>’bodyonload()’, ’class’=>’maincontent’);

Pour générer le contenu même de la balise body, vous avez deux choix : soit utiliser un template, soit utiliser laméthode addContent().

Page 40: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

33 / 225

Générer avec un template

Pour utiliser un template, jResponseHtml propose deux propriétés :– bodyTpl, qui doit contenir le sélecteur du template à utiliser– body qui contient un objet jTpl permettant de "paramétrer" le template.Exemple :

$rep->bodyTpl = ’myapp~main’;

$rep->body->assign(’person’,’Laurent’);

Le contenu généré par le moteur de template sera intégré entre les balises <body> et </body>.

Pour en savoir plus sur l’utilisation des templates, consultez le chapitre sur les templates.

Il se peut que vous ayez besoin d’ajouter du contenu en plus de celui produit par le template. Pour cela vous utiliserezla méthode addContent(). Elle prend en paramètre une chaine pour lecontenu, et un booléen (facultatif) pour indiquersi on veut que le contenu soit ajouté avant (true) ou après (false, valeur par défaut) le contenu du template.

$rep->addContent(’Mon contenu HTML après le template’);$rep->addContent(’Mon contenu HTML avant le template’, true);

Notez que le contenu à ajouter peut être aussi le contenu de zones

$rep->addContent(jZone::get(’monmodule~uneZone’));

Générer avec un template principal et des "sous-templates"

Bien souvent, les pages d’un site ont un gabarit commun, et seules certaines zones changent (notament le contenuprincipal) en fonction de l’action. Il y aura donc un template principal , définit comme on l’a vu précédemment, quine contiendra que le contenu commun à toutes les pages, et dans chaque action on utilisera un autre template (un"sous-template") pour générer le contenu spécifique, dont on injectera le résultat dans le template principal. Ce travailpeut être fait avec un template directement, ou au moyen d’une zone.

Et pour éviter que dans chaque action on définisse à chaque fois le template principal, les élements communs (feuillesde style etc), on créera un objet réponse HTML qui héritera de jResponseHtml.

Pour savoir comment faire, lire la section sur la personnalisation de réponse commune.

générer sans template

Si vous ne voulez pas utiliser de template pour le body, alors il faut laisser la propriété bodyTpl à vide, et utiliserseulement la méthode addContent() :

$rep->addContent(’contenu pour mon body’);

7.1.5 Autres paramètres de la réponses

Comme jResponseHtml est dérivé de jReponse, vous pouvez aussi influer sur les entêtes HTTP : le code "status" etajouter d’autres en-têtes.

$rep->setHttpStatus ("404", "Not Found");$rep->addHttpHeader ("Date-modified", "....");

Page 41: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

34 / 225

Il y a aussi une autre propriété, propre à jResponseHtml : xhtmlContentType. Cette propriété défini si le contenuxHTML doit être envoyé avec une entête HTTP Content-Type spécifique : application/xhtml+xml. Bien sûr, unevérification des capacités du navigateur à recevoir du xhtml est faites, et si le navigateur ne peut pas recevoir duxHTML, la réponse sera envoyée avec le Content-Type text/html comme pour le HTML classique.

$rep->xhtmlContentType = true ;

7.2 Faire une redirection

Il existe deux types d’objets de redirection possible :– jResponseRedirect : redirige vers une action de l’application avec la possibilité de passer des paramètres– jResponseRedirectUrl : redirige vers une URL quelconque, en particulier une URL externe à votre application

jelix

7.2.1 jResponseRedirect

Pour spécifier une redirection vers une action, vous indiquez le type ’redirect’. Vous récupérez la réponse commececi :

$rep = $this->getResponse(’redirect’);

Vous avez alors dans $rep une instance de l’objet jResponseRedirect.

Vous avez ensuite trois propriétés sur cet objet :– action pour indiquer l’action vers laquelle rediriger– params pour indiquer les paramètre d’une action (tableau associatif)– anchor pour indiquer la partie "ref" de l’url (#anchor)Exemple :

$rep->action = "module~controleur:action";$rep->params = array(’foo’ => ’bar’);$rep->anchor = ’yo’;

Définir ces propriétés est facultatif. Ainsi, si on n’indique pas l’action, ce sera l’action actuelle.

Et ensuite il n’y a plus qu’à renvoyer la réponse.

return $rep;

7.2.2 jResponseRedirectUrl

Pour spécifier une redirection vers une URL quelconque, vous indiquez le type ’redirectUrl’. Vous récupérez laréponse comme ceci :

$rep = $this->getResponse(’redirectUrl’);

Vous avez alors dans $rep une instance de l’objet jResponseRedirectUrl. Cet objet possède une unique propriété,url qui doit contenir une chaine, l’url de la page vers laquelle rediriger (en général, il s’agira d’une url externe àl’application jelix, jResponseRedirect étant plus approprié pour les urls vers l’application jelix).

$rep->url = "http://jelix.org";return $rep;

Page 42: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

35 / 225

7.3 Générer du texte brut

Il faut utiliser jResponseText qui est récupérable via l’alias "text". Cet objet possède une propriété "content" danslaquelle vous mettez le texte voulu.

function myaction(){$rep = $this->getResponse(’text’);$rep->content = ’my text’;return $rep;

}

Par défaut, jResponseText renvoi le type mime text/plain et avec le charset indiqué dans la config de jelix.

Toutefois, comme jResponseText dérive de jResponse, vous pouvez modifier les en-tête http, donc le type mime etle charset.

D’ailleurs, jResponseText peut-être utilisé comme base pour d’autres formats à contenu textuels (json ou autre ré-ponse pour ajax par ex).

7.4 Générer du XML quelconque

jResponseXML permet de renvoyer au navigateur du XML. Son alias est "xml"

$rep = $this->getResponse(’xml’);

Pour indiquer le contenu xml, vous avez deux possibilités.– *Attention** : dans les deux cas, le XML doit être bien formé. Si ce n’est pas le cas, la réponse sera une erreur.

7.4.1 Générer à partir d’un template

Par défaut, la propriété $content contient un objet jTpl. Vous devez indiquer le sélecteur de template dans la propriété$contentTpl.

$rep->contentTpl = ’monMOdule~monxml’;$rep->content->assign(’foo’,’bla bla bla’);

jResponseXml s’occupe de générer la balise "< ?xml ?>" donc vous n’avez pas à vous en occuper dans le template.Cependant, si le template comporte déjà cette balise, il faudra alors faire un

$rep->sendXMLHeader = false;

7.4.2 Génération sans template

Si vous ne voulez pas utiliser un template, vous mettez le contenu xml, sous forme de chaine, dans la propriété$content.

$rep->content = ’<mondoc> <title>jelix</title> </mondoc>’;

jResponseXml s’occupe de générer la balise "< ?xml ?>" donc vous n’avez pas à vous en occuper. Cependant, si letemplate comporte déjà cette balise, il faudra alors faire un

$rep->sendXMLHeader = false;

Page 43: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

36 / 225

7.4.3 Indiquer des feuilles de styles.

Vous pouvez attachez des feuilles de styles CSS ou XSLT au document XML produit. Pour cela, vous devez utili-sez les méthodes addCSSStyleSheet() ou addXSLStyleSheet(). Elles prennent toutes deux en premier argument l’urldu fichier, et en deuxième argument optionnel un tableau associatif définissant les pseudo attributs à mettre sur laprocessing instruction générée.

$rep->addCSSStyleSheet(’my.css’, array(’title’=>’super jolie’));$rep->addXSLStyleSheet(’my.xsl’);

7.5 Générer un flux de syndication RSS

Jelix permet de générer un fil RSS assez facilement grâce à jResponseRss20. Cet objet prend en charge totalement laspécification RSS 2.0. Comme tout type de réponse, la première chose à faire est de récupérer l’objet jResponseRss20(alias "rss2.0").

$rep = $this->getResponse(’rss2.0’);

7.5.1 Informations sur le fil rss

jReponseRss20 possède tout d’abord une propriété infos, qui est un objet permettant de spécifier les propriétés du filRSS : son titre, l’url du site, le copyright, la description etc. Exemple :

$rep->infos->title = ’Actualité de Jelix’;$rep->infos->webSiteUrl= ’http://jelix.org/fr/’;$rep->infos->copyright = ’Copyright 2006-2008 jelix.org’;$rep->infos->description = ’Actualité sur le framework PHP5 Jelix’;$rep->infos->updated = ’2007-06-08 12:00:00’;$rep->infos->published = ’2007-06-08 12:00:00’;$rep->infos->ttl=60;

Les champs updated et published sont des dates qui indiquent respectivement la date de dernière mise à jour du filRSS, et la date de publication du channel RSS. On peut mettre la même date. Ces dates sont en générale déterminéespar la date de publication de l’item le plus récent qui sera présenté dans le fil. Par exemple, pour un fil RSS d’un blog,ce sera la date du dernier billet.

La propriété ttl indique à l’aggrégateur de l’utilisateur, la durée (en minute) pendant laquelle il peut mettre le contenuen cache avant de redemander le fil RSS.

Par défaut, la description doit être du texte normal. Cependant vous pouvez indiquer du HTML ou XHTML. Dansce cas vous devez l’indiquer dans la propriété descriptionType, qui peut prendre la valeur "html", "xhtml" ou "text".

7.5.2 Informations sur les items

Il faut ensuite remplir le channel avec les items que vous voulez publier. Pour un blog par exemple, les items serontles descriptifs des derniers billets publiés.

Pour chaque item, vous devez appeler la méthode createItem() de jResponseRss20 pour récupérer un objet quicontiendra les informations de l’item. Vous remplissez alors cet objet et vous le stockez dans l’objet jResponseRss20avec la méthode addItem()

Voici un exemple avec une dao de news :

Page 44: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

37 / 225

$newsdao = jDao::get(’news’);$first = true;

// ici on récupère la liste des 10 dernières news// on suppose que la liste est classé de la plus récente à la moins récente// (méthode définie dans la dao)$list = $newsdao->findTenFirstNews();

foreach($list as $news){

if($first){// le premier enregistrement permet de connaitre// la date du channel$rep->infos->updated = $news->date_create;$rep->infos->published = $news->date_create;$first=false;

}

// on récupère l’url de l’article de news$url = jUrl::get(’news~default:article’, array(’newsid’=>$news->id));

// on crée un item RSS, en donnant un titre, une url, une date au format [yyyy ←↩-mm-jj hh-mm-ss]

$item = $rep->createItem($news->title, $url, $news->date_create);

// auteur de la news$item->authorName = $news->author;

// contenu HTML de la news$item->content = $news->content;$item->contentType=’html’;

//dans notre exemple, on dit que l’url de la news est considéré// comme étant l’id de la news// dans le cas contraire, on aurait pu mettre $item->id =$news->id$item->idIsPermalink = true;

// on ajoute l’item dans le fil RSS$rep->addItem($item);

}

7.5.3 Autres informations

Il est possible d’indiquer plus d’informations sur le fil rss ou sur chaque item. Consultez la documentation de refe-rence sur les objets jRSS20Info et jRSSItem.

7.6 Générer un flux de syndication Atom

Jelix permet, en plus de RSS, de pouvoir générer un fil Atom 1.0. Pour cela il faut utiliser l’objet jResponseAtom10,qui prend en charge quasiement la totalité de la spécification Atom 1.0. Son alias est "atom1.0".

$rep = $this->getResponse(’atom1.0’);

Page 45: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

38 / 225

La manipulation de jResponseAtom10 est identique à jResponseRss20. La difference se situe sur quelques propriétésdans les informations du fil ou des items.

7.6.1 Informations sur le fil atom

jResponseAtom10, comme jresponseRss20, possède une propriété infos, qui est un objet permettant de spécifier lespropriétés du fil Atom. Exemple :

$rep->infos->title = ’Actualité de Jelix’;$rep->infos->webSiteUrl= ’http://jelix.org/fr/’;$rep->infos->copyright = ’Copyright 2006-2007 jelix.org’;$rep->infos->description = ’Actualité sur le framework PHP5 Jelix’;$rep->infos->updated = ’2007-06-08 12:00:00’;$rep->infos->selfLink=jUrl::get();

Le champs updated est la date de dernière mise à jour du fil Atom. Elle est en générale déterminée par la date depublication de l’item le plus récent qui sera présenté dans le fil. Par exemple, pour un fil Atom d’un blog, ce sera ladate du dernier billet.

La propriété selfLink est l’url de ce fils Atom.

Par défaut, la description doit être du texte normal. Cependant vous pouvez indiquer du HTML ou XHTML. Dansce cas vous devez l’indiquer dans la propriété descriptionType, qui peut prendre la valeur "html", "xhtml" ou "text".

7.6.2 Informations sur les items

Il faut ensuite remplir le channel avec les items que vous voulez publier. Pour un blog par exemple, les items serontles descriptifs des derniers billets publiés.

Pour chaque item, vous devez appeler la méthode createItem() de jResponseAtom10 pour récupérer un objet quicontiendra les informations de l’item. Vous remplissez alors cet objet et vous le stockez dans l’objet jResponseAtom10avec la méthode addItem()

Voici un exemple avec une dao de news :

$newsdao = jDao::get(’news’);$first = true;

// ici on récupère la liste des 10 dernières news// on suppose que la liste est classé de la plus récente à la moins récente// (méthode définie dans la dao)$list = $newsdao->findTenFirstNews();

foreach($list as $news){

if($first){// le premier enregistrement permet de connaitre// la date du channel$rep->infos->updated = $news->date_create;$first=false;

}

// on récupère l’url de l’article de news$url = jUrl::get(’news~default:article’, array(’newsid’=>$news->id));

// on crée un item ATOM, en donnant un titre, une url, une date

Page 46: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

39 / 225

$item = $rep->createItem($news->title, $url, $news->date_create);

// auteur de la news$item->authorName = $news->author;

// résumé de la news en HTML$item->summary = $news->summary;$item->summaryType=’html’;

// contenu HTML de la news$item->content = $news->content;$item->contentType=’html’;

// on ajoute l’item dans le fil ATOM$rep->addItem($item);

}

7.6.3 Autres informations

Il est possible d’indiquer plus d’informations sur le fil atom ou sur chaque item. Consultez la documentation dereference sur les objets jAtom10Info et jAtom10Item.

7.7 Générer un PDF à partir d’un contenu LaTeX

Jelix propose un objet jResponseLatexToPdf qui permet de générer un document PDF à partir d’un document écriten LaTeX. Son alias est "ltx2pdf".

$rep = $this->getResponse("ltx2pdf");

– *Note : L’utilisation de jResponseLatexToPdf nécessite la présence du programme pdflatex sur le serveur !**

Si ce programme n’est pas situé dans les chemins reconnus par le système (définis par la variable d’environnementPATH sous Linux par exemple), il faut indiquer son chemin complet dans la propriété $pdflatexPath. Exemple :

$rep->pdflatexPath = ’/usr/bin/pdflatex’;

jResponseLatexToPdf s’occupe de générer un entête LaTeX comprenant le titre du documents et les auteurs, le resteest à définir (en LaTeX) dans un template que vous indiquerez dans la propriété $bodyTpl. Et vous accédez au moteurde template via la propriété $body.

Il y a aussi la méthode addCommand qui permet d’ajouter des commandes LaTeX au début du document.

Exemple :

$rep = $this->getResponse("ltx2pdf");

$rep->title = ’titre du document’;$rep->authors[] = ’Michel Dupont’;$rep->bodyTpl = ’monModule~doclatex’;

$rep->addCommand(’documentclass’, ’article’, array(’a4’, ’14pt’));$this->addCommand(’geometry’, ’hmargin=1cm, vmargin=2cm’);

$rep->body->assign(’texte’, $unTexte);

return $rep;

Page 47: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

40 / 225

7.8 Générer un PDF avec TCPDF

Un objet jResponseTcpdf est fourni depuis la version 1.0, permettant de générer un PDF à partir de la classe TCPDF(qui est une version améliorée de la célèbre FPDF).

Pour l’utiliser, vous devez d’abord télécharger les fontes disponibles sur le site de Jelix (Elles ne sont pas fourniesavec Jelix à cause de leur poids), et les installer dans lib/pdf-fonts/.

Ensuite dans une action :

$rep = $this->getResponse(’tcpdf’);

$rep->outputFileName = ’article.pdf’;$rep->doDownload = true;

// initialise l’objet tcpdf$rep->initPdf();$rep->tcpdf->AddPage();$rep->tcpdf->SetTitle(’un titre’);$rep->tcpdf->Text(10,10,’un texte’);...return $rep;

L’objet dans la propriété tcpdf est tout simplement un objet TCPDF. Voir la documentation de TCPDF pour savoirl’utiliser et connaître son API.

Pour utiliser son propre objet tcpdf (parce que l’on veut surcharger par exemple certaines méthodes de TCPDF :

$rep = $this->getResponse(’tcpdf’);

$rep->outputFileName = ’article.pdf’;$rep->doDownload = true;

// initialize l’objet tcpdf$rep->tcpdf = new MyTcPdf();$rep->tcpdf->AddPage();$rep->tcpdf->SetTitle(’un titre’);$rep->tcpdf->Text(10,10,’un texte’);...return $rep;

MyTcPdf étant l’objet qui hérite de TCPDF.

7.9 Renvoyer un fichier binaire

Pour renvoyer un fichier binaire (un exécutable, une image, une video, une archive ou autre), il faut utiliser jRepon-seBinary dont l’alias est "binary"

$rep = $this->getResponse(’binary’);

En premier lieu, ill vous faut indiquer dans la propriété $outputFileName le nom de fichier sous lequel apparaitra lecontenu, à l’utilisateur.

$rep->outputFileName = ’truc.gif’;

Vous pouvez aussi définir le type mime du contenu :

Page 48: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

41 / 225

$rep->mimeType = ’image/gif’;

Et vous devez aussi spécifier si le fichier doit être proposé à l’utilisateur pour l’enregistrement ou non. Pour desfichiers couramment pris en charge par les navigateur (les images par exemple), on mettra false :

$rep->doDownload = false;

Ensuite pour le contenu, vous pouvez indiquer soit un fichier existant, soit du contenu que vous générez vous même.

Pour renvoyer un fichier existant :

$rep->fileName = JELIX_APP_VAR_PATH.’fichier_a_renvoyer.gif’;

Et sinon, si vous générez vous même, mettez le contenu dans une chaîne et mettez le dans $content :

$rep->content = ’...’;

7.10 Générer un fichier zip

Jelix propose jResponseZip qui permet de générer un fichier zip à la volée, et le proposer en téléchargement àl’utilisateur. L’alias est "zip" :

$rep = $this->getResponse(’zip’);

Vous devez ensuite indiquer un nom de fichier. C’est sous ce nom que le contenu zip sera proposé à l’utilisateur. Cenom de fichier n’est pas forcément celui d’un fichier existant sur le serveur.

$rep->zipFilename=’myCrazyPackage.zip’;

Ensuite, il faut créer le zip. La propriété $content est un objet jZipCreator, dont vous utiliserez les méthodes pourajouter du contenu dans le zip. (Voyez la documentation de référence sur jZipCreator).

// ajoute le contenu du fichier datas/truc.txt stocké sur le serveur,// et le réference dans le zip sous le nom machin.txt$rep->content->addFile(JELIX_VAR_PATH.’datas/truc.txt’, ’machin.txt’);

// ajoute tout le contenu d’un répertoire "exemples" stocké sur le serveur$rep->content->addDir(JELIX_VAR_PATH.’exemples/’, ’exemples’, true);

// créer un fichier dans le zip, avec le nom et le contenu donné$rep->content->addContentFile(’dynamic.txt’, ’contenu généré comme on veut’);

Et c’est tout :-) L’utilisateur se verra proposer d’enregistrer sur son disque un fichier myCrazyPackage.zip, quicontiendra un fichier machin.txt, un répertoire exemples, et un fichier dynamic.txt.

7.11 Générer une interface utilisateur en XUL

7.11.1 Qu’est ce que XUL ?

XUL est un langage de description d’interface utilisateur. Il peut être très utile pour réaliser des applications webayant l’ergonomie d’une application desktop, sans avoir à inclure des scripts JS et de faire du DHTML partout.Voir http ://xulfr.org. XUL est utilisé dans Firefox pour son interface utilisateur. Notez qu’il faut obligatoirement unnavigateur basé sur le moteur Gecko de Mozilla (dont Firefox) pour pouvoir afficher du XUL.

Page 49: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

42 / 225

7.11.2 jResponseXul et cie

L’objet jResponseXul permet de générer une fenêtre XUL (<window>). Il y a aussi jResponseXulDialog pour lesboîtes de dialogue (<dialog>), jResponseXulOverlay pour les overlays XUL (<overlay>), et jResponseXulPage pourles pages XUL incluses via une balise <iframe> dans une fenêtre XUL. Chacun de ces objets ont la même API (tousbasés sur jResponseXul), il y a seulement quelques différences minimes, au niveau notamment de la balise principalegénérée.

jResponseXul permet de générer, comme jResponseHtml, les liens vers les feuilles de styles et les scripts javascript,la balise principale, et les liens des overlays, qu’ils soient statiques ou dynamiques (voir plus loin).

7.11.3 Utilisation de jResponseXUL

Voici les alias pour récupérer les différentes réponses XUL :

$window = $this->getResponse("xul");$dialog = $this->getResponse("xuldialog");$overlay = $this->getResponse("xuloverlay");$page = $this->getResponse("xulpage");

Dans la suite, on utilisera $window mais les exemples fonctionnent aussi avec les autres objets (sauf indicationcontraire).

Vous pouvez indiquer des attributs à mettre sur la balise principale (<window>, <overlay>, <dialog> ou <page>) :

$window->rootAttributes = array("width"=>"300");

Pour lier la page XUL avec des feuilles de styles, des scripts et des overlays, il suffit d’utiliser les méthodes addCss-Link(), addJsLink() et addOverlay() :

$window->addCssLink(’style.css’);$window->addJsLink(’scripts.js’);$window->addOverlay(’overlay.xul’);

Générer sans template

Si vous ne voulez pas utiliser de template, vous pouvez tout simplement utiliser la methode addContent pour ajouterdu XUL dans la page :

$rep->addContent(’contenu xul’);

Générer avec un template

Dans la propriété $body vous avez un objet jTpl, et vous devez indiquer dans la propriété $bodyTpl le sélecteur dutemplate à utiliser. Et $title permet d’indiquer le titre de la fenêtre :

$window->title = "ma fenêtre";$window->bodyTpl = "monmodule~listexul";$window->body->assign("liste", $liste);

Comme pour jResponseHtml, vous pouvez inclure du contenu avant ou après celui du template. Pour cela vousutiliserez la méthode addContent(). Elle prend en paramètre une chaine pour le contenu, et un booléen (facultatif)pour indiquer si on veut que le contenu soit ajouté avant (true) ou après (false, valeur par défaut) le contenu dutemplate.

Page 50: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

43 / 225

$rep->addContent(’Mon contenu XUL après le template’);$rep->addContent(’Mon contenu XUL avant le template’, true);

Notez que le contenu à ajouter peut être aussi le contenu de zones

7.11.4 Réaliser des overlays

Un overlay est un fichier XUL qui permet d’ajouter des modifications à une autre page XUL sans toucher à son codesource. C’est très utilisé dans Firefox par les extensions. Cela peut être aussi utilisé dans une application web, et enparticulier dans Jelix : un module peut déclarer un overlay pour une page XUL générée par un autre module.

principe

La façon dont ça fonctionne est assez simple et repose sur le système d’évènement de Jelix. En fait un objet jRes-ponseXul, avant de générer le contenu final, envoi un évènement pour se signaler. En réponse, les modules peuventlui renvoyer l’url d’un overlay. Une balise < ?xul-overlay ?> sera ajoutée alors dans la page.

Une condition pour que ça fonctionne vraiment : il faut que l’action qui génère la page xul mette la propriété $fet-chOverlays à true :

$window->fetchOverlays = true;

Dans le cas contraire (et c’est le comportement par défaut), aucun évènement ne sera envoyé et donc aucun overlay"étranger" ne pourra être indiqué.

mise en oeuvre

Tout d’abord, il faut faire une action qui génère une réponse "xuloverlay", comme vous l’avez vu plus haut. Imaginonsqu’il s’agisse de l’action "testa~xul :overlay1" et que l’action qui affiche la page xul sur laquelle s’applique l’overlaysoit "testb~xul :index".

Dans le module "testa", il faut ensuite faire un "listener" pour pouvoir répondre à l’évènement "FetchXulOverlay"qu’envoie jResponseXul quand il demande les overlays à lier. Dans un fichier classes/testa.listener.php, vous aurezalors :

class testaListener extends jEventListener{

function onFetchXulOverlay($event){

}}

L’évènement a un paramètre, "tpl", qui indique le sélecteur de template utilisé pour la page principal générée parl’action "testb~xul :index". Admettons qu’il s’agisse de "testb~mainxul". On va tester si le paramètre est bien letemplate que l’on attend, et en retour, on va indiquer l’url de l’overlay.

class testaListener extends jEventListener{

function onFetchXulOverlay($event){if($event->getParam(’tpl’) == ’testb~mainxul’){

$event->Add(’testa~xul:overlay1’);}

}}

Page 51: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

44 / 225

N’oublions pas de déclarer ce listener dans le fichier events.xml du module test a :

<events xmlns="http://jelix.org/ns/events/1.0"><listener name="testa">

<event name="FetchXulOverlay" /></listener>

</events>

Voilà, vous pouvez de cette manière modifier l’écran XUL du module testb sans toucher à son template xul.

7.12 Générer du RDF

jResponseRdf permet de générer un document au format RDF. Cela est utile entre autre lors de la réalisation d’ap-plication en XUL, pour les templates XUL. Son alias est "rdf".

Vous avez deux moyens d’utiliser jResponseRdf :– soit vous fournissez une liste de données et la classe s’occupe de générer du RDF– soit vous écrivez vous même le code RDF dans un template, ce qui est nécessaire pour les graphes RDF complexes.

7.12.1 Génération automatique de RDF

Cela ne fonctionne que pour les RDF qui representent qu’une liste simple de données (pas de sous arbres parexemple).

Vous indiquez la liste des données au niveau de la propriété $datas : cela peut être une liste de tableaux associatifs,un objet jResultSet (iterateur) que retourne jDb : :query ou les méthodes de type "select" des daos.

$rep = $this->getResponse("rdf");

$dao = jDao::get(’users’);$rep->datas = $dao->findAll();

Ou encore

$rep->datas = array(array(’nom’=>’dupont’, ’prenom’=>’georges’),array(’nom’=>’durant’, ’prenom’=>’paul’),array(’nom’=>’duchemin’, ’prenom’=>’jacques’),

);

Ce dernier exemple va générer le RDF suivant :

<RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"xmlns:row="http://dummy/rdf#">

<Bag RDF:about="urn:data:row"><li><Description>

<row:nom>dupont</row:nom><row:prenom>georges</row:prenom>

</Description></li><li><Description>

<row:nom>durant</row:nom><row:prenom>paul</row:prenom>

</Description></li><li><Description>

Page 52: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

45 / 225

<row:nom>duchemin</row:nom><row:prenom>jacques</row:prenom>

</Description></li></Bag>

</RDF>

jResponseRdf donne par défaut le namespace "http :dummy/rdf#" aux éléments contenant les données, namespacedéclaré avec le préfixe "row". Vous pouvez changer cela via respectivement les propriétés $resNs et $resNsPrefix//.

$rep->resNs = ’http://monsite.com/ns/users/’;$rep->resNsPrefix = ’user’;

Vous pouvez aussi changer l’identifiant de la liste qui est par défaut "urn :data :row" :

$rep->resUriRoot = ’urn:monsite:users’;

Enfin, pour diverses raisons, vous voudriez peut être mettre certaines informations en tant qu’attributs, et d’autres entant qu’elements. Il faut alors l’indiquer via les propriétés $asElement et $asAttribute.

$rep->asAttribute = array(’prenom’);$rep->asElement = array(’nom’);

Note : à partir du moment où vous changez l’une de ces deux propriétés, il faut alors indiquer tous les noms desdonnées que vous voulez voir apparaitre dans le RDF.

Cela donne alors :

<RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"xmlns:user="http://monsite.com/ns/users/">

<Bag RDF:about="urn:monsite:users"><li><Description user:prenom="georges">

<user:nom>dupont</user:nom></Description></li>

<li><Description user:prenom="paul"><user:nom>durant</user:nom>

</Description></li><li><Description user:prenom="jacques">

<user:nom>duchemin</user:nom></Description></li>

</Bag></RDF>

7.12.2 Génération à partir d’un template

L’autre façon d’utiliser jResponseRdf est de passer par un template pour générer le contenu RDF. Vous devez indiquerles données pour le template via la propriété $datas, elles seront ainsi disponible via la variable de template "datas".Et vous devez indiquez le sélecteur du template dans la propriété $template.

$rep = $this->getResponse("rdf");

$rep->datas = array(array(’nom’=>’dupont’, ’prenom’=>’georges’),array(’nom’=>’durant’, ’prenom’=>’paul’),array(’nom’=>’duchemin’, ’prenom’=>’jacques’),

);$rep->template = ’monmodule~datasrdf’;

Page 53: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

46 / 225

Et dans datasrdf.tpl :

<RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"xmlns:user="http://monsite.com/ns/users/">

<Bag RDF:about="urn:monsite:users">

{foreach $datas as $dt}<li><Description user:prenom="{$data[’prenom’]|escxml}">

<user:nom>{$data[’nom’]|escxml}</user:nom></Description></li>

{/foreach}

</Bag></RDF>

Note : vous n’avez pas à mettre le prologue xml (< ?xml... )

Note : les propriétés $resNs, $resNsPrefix, $resUriRoot, $asElement et $asAttribute sont inutiles dans le cas del’utilisation d’un template.

Page 54: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

47 / 225

Chapitre 8

Services web

Outre les contenus classiques que l’on peut fournir aux navigateurs (HTML, XML etc), Jelix permet égalementd’implémenter des services web, que ce soit pour de l’Ajax, en JSON, ou pour fournir des services plus évolués enXML-RPC ou SOAP (SOAP est prévu pour Jelix 1.1).

Une des particularités de développer des services web dans Jelix, est que le principe de développement reste le mêmeque pour les contenus classiques : vous récupérez un objet réponse, vous lui donnez des paramètres, et Jelix s’occupedu reste. Vous n’avez pas à connaître le format précis du protocole du services web utilisé, à gérer les entête HTTPetc.

La seule différence est que pour certains type de services web, vous devez avoir un point d’entrée spécifique au typede services web (donc, autre que index.php).

8.1 AJAX

Bien que le terme AJAX précise qu’une réponse doit être en XML (d’où le X dans AJAX), AJAX est souvent utiliséavec d’autres types de format.

Selon ce que vous attendez côté client, soit dans la propriété responseText, soit dans la propriété responseXml del’objet xmlHttpRequest, vous utiliserez un objet jResponse différent.– Pour tout ce qui est contenu XML quelconque, vous utiliserez jResponseXml– Pour des réponses en JSON, vous utiliserez jResponseJson– Pour renvoyer des fragments de code HTML, il ne faut pas utiliser jResponseHtml, mais jResponseText (voir

exemple ci-dessous).– En règle générale, vous utiliserez jResponseText.

8.1.1 Renvoyer des fragments de code HTML

Il ne faut pas utiliser jResponseHtml, car cet objet génère tout ce qu’il faut pour une page HTML : le <head>, le<body> etc... Bien souvent, dans une requête AJAX, on ne veut récupérer qu’un fragment de code HTML.

jResponseText est plus adapté pour cela (dans la version 1.1, il y aura jResponseHtmlFragment) :

$rep = $this->getResponse(’text’);$rep->content = ’<p>nouvelle donnée</p>’;return $rep;

Page 55: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

48 / 225

Note à propos de l’utilisation de jforms dans des réponses Ajax

Il y a un souci connu quand on utilise un formulaire jforms dans un template pour une réponse autre que html pourfaire une réponse ajax : il peut y avoir une erreur PHP qui dit que l’objet response n’a pas la méthode addJsLink.

En effet, pour fonctionner correctement, un formulaire jforms a besoin de la présence du fichier lib/jelix-www/js/jforms.jsdans la page qui appelle la requête ajax. Ce fichier est inclus automatiquement par le plugin form, en appelant la me-thode addJsLink de la réponse. Malheureusement, il manque un test d’existance de cette méthode. Ce bug sera corrigédans la version 1.0.4.

Autre chose, même si ce bug n’existait pas, il reste un problème : comme les fragments HTML renvoyé par lesreponses ajax n’ont pas d’entête HTML <head>, le script n’est pas inclus dans la page html final, ce qui causera deserreurs javascript. Pour le moment, il n’y a pas d’autres solutions que d’inclure ce script jforms.js "à la main" lors dela génération de la page hôte (celle qui fait donc la requête ajax).

8.2 JSON

JSON est un format de données qui réutilise des éléments syntaxique de Javascript. Cela facilite alors grandementl’utilisation de contenu en JSON dans une page HTML. C’est de plus en plus utilisé pour la technique AJAX.

Pour envoyer un contenu en JSON au navigateur, vous pouvez employer la réponse jResponseJson dont l’alias est"json". Vous n’avez ensuite qu’à mettre n’importe quelles données dans la propriété $datas.

$rep = $this->getResponse(’json’);$rep->datas = array( ’nom’=>’dupont’, ’prenom’=>’jean’);

Vous recevrez alors coté client, ceci :

{ nom: ’dupont’, prenom:’jean’}

– *Exemple d’utilisation avec une DAO**

$countryDao = jDao::get(’common~country’);$countries = $countryDao->findAll();$response = $this->getResponse(’json’);$response->datas = array();foreach($countries as $country) {

$response->datas[] = array(’id’ => $country->id , ’name’ => $country->name);}

On récupére coté client des objets en notation JSON comme celui-ci :

{ id: ’1’, name:’Europe’}

8.3 JSON-RPC

Jelix propose la prise en charge du protocole json-rpc. Ce protocole d’échange est similaire à XML-RPC dans lefonctionnement, mais utilise JSON comme format de donnée au lieu de XML (RPC = Remote Procedure Call).

Page 56: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

49 / 225

8.3.1 Point d’entrée spécifique

Une requête JSON-RPC est spécifique, et pour y répondre, on ne peut pas utiliser l’objet request "classic". Il vousfaut créer un point d’entrée spécifique dans le répertoire www, jsonrpc.php par exemple, qui utilise jJsonRpcRequestplutôt que jClassicRequest. Le type de requête et du point d’entrée est donc "jsonrpc".

Le point d’entrée devra contenir ceci :

require_once (’../../lib/jelix/init.php’);require_once (’../../VOTRE APPLI/application.init.php’);

$config_file = ’jsonrpc/config.ini.php’;

require_once (JELIX_LIB_CORE_PATH.’request/jJsonRpcRequest.class.php’);

$jelix = new jCoordinator($config_file);$jelix->process(new jJsonRpcRequest());

Il ne faut pas oublier de déclarer ce point d’entrée au niveau de la configuration des moteurs d’urls simple ousignificant. Si vous utilisez le moteur d’url simple, vous devez mettre dans la section simple_urlengine_entrypointsde la configuration de jelix la déclaration suivante :

jsonrpc = "@jsonrpc"

jsonrpc étant le nom du point d’entrée, et @jsonrpc indiquant le type de point d’entrée.

Si vous utilisez le moteur d’url significant, vous devez ajouter la balise suivante :

<jsonrpcentrypoint name="jsonrpc" default="true" />

Dans un cas comme dans l’autre, vous pouvez alors récupérer l’url d’une action pour jsonrpc comme ceci :

$url = jUrl::get("module~action@jsonrpc");

8.3.2 Contrôleur

Comme on a affaire à un type de requête particulier, le nom du fichier du contrôleur doit avoir le suffixe ".jsonrpc.php".Par exemple, un contrôleur "default" : "default.jsonrpc.php". (Vous pouvez bien sûr avoir un autre contrôleur "default"pour d’autres types de requêtes, "default.classic.php" par exemple).

Ensuite, le contenu du contrôleur est similaire à ce que vous avez l’habitude de faire, à la seule différence que vousutiliserez jResponseJsonRpc, qui a pour alias "jsonrpc", pour répondre aux requêtes JsonRpc :

class defaultCtrl extends jController {

function index(){

$rep = $this->getResponse(’jsonrpc’);

// n’importe quelles types de données : entier, chaine, array, objets...$donnees_php = ... ;

$rep->response = $donnees_php;

return $rep;

}}

Page 57: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

50 / 225

8.3.3 Appel depuis le client

Qui dit JsonRpc, dit une partie cliente qui envoi une requête jsonrpc. Comme vous pouvez le lire dans la spécificationde jsonrpc, il faut envoyer une chaine de ce type :

{ method : "",id:"",params: {}

}

Dans method, vous indiquerez, dans le cas d’un appel à une application jelix, le sélecteur de l’action à appeler :

method:"monModule~default:index"

Les données que vous mettrez dans params seront mise dans le paramètre "params" dans la réponse. Ainsi, pour lesrécupérer dans l’action vous ferez :

$parametres = $this->param(’params’);

Bien entendu, ce que vous avez dans $parametres sera des données "php" (chaine, array ou autre), la transformationde la chaine json étant réalisée par jJsonRpcRequest..

Notez qu’un script javascript est fourni dans lib/jelix-www/json.js. Il vous permet, dans vos pages HTML de trans-former vos données javascript en chaine json. Pour cela, sur les objets, tableaux et autre type de donnée javascript, ilsuffit d’appeler la méthode javascript toJSONString() qui renvoi une chaine. Il suffit ensuite de passer cette chaine àxmlHttpRequest pour envoyer la requête JSONRPC à jelix. Exemple, dans votre page HTML :

var jsonrpc = { method : "monModule~default:index",id:"1",params: null

};

var toSend = jsonrpc.toJSONString();var p = new XMLHttpRequest();p.onload = null;p.open("POST", "http://monsite.tld/jsonrpc.php", false);p.send(toSend);

var reponse = p.responseText.parseJSON();var resultat = reponse.result;

Enfin si dans l’action jelix, vous avez fait un

$rep->response = "hello";

Vous aurez alors dans la variable resultat de l’exemple javascript, une chaine "hello".

8.4 XML-RPC

Jelix propose la prise en charge de xml-rpc. C’est un protocole d’échange de données en XML : un client envoie uncontenu XML indiquant une fonction à exécuter et des paramètres. Le serveur renvoie un résultat, toujours sous formede XML (RPC = Remote Procedure Call).

Page 58: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

51 / 225

8.4.1 Point d’entrée spécifique

Une requête XML-RPC est spécifique, et pour y répondre, on ne peut pas utiliser l’objet request "classic". Il vousfaut créer un point d’entrée spécifique dans le répertoire www, xmlrpc.php par exemple, qui utilise jXmlRpcRequestplutôt que jClassicRequest. Le type de requête et du point d’entrée est donc "xmlrpc".

Le point d’entrée devra contenir ceci :

require_once (’../../lib/jelix/init.php’);require_once (’../../VOTRE APPLI/application.init.php’);

$config_file = ’xmlrpc/config.ini.php’;

require_once (JELIX_LIB_CORE_PATH.’request/jXmlRpcRequest.class.php’);

$jelix = new jCoordinator($config_file);$jelix->process(new jXmlRpcRequest());

Il ne faut oublier de déclarer ce point d’entrée au niveau de la configuration des moteurs d’urls simple ou signifi-cant. Si vous utilisez le moteur d’url simple, vous devez mettre dans la section simple_urlengine_entrypoints de laconfiguration de jelix la déclaration suivante :

xmlrpc = "@xmlrpc"

xmlrpc étant le nom du point d’entrée, et @xmlrpc indiquant le type de point d’entrée.

Si vous utilisez le moteur d’url significant, vous devez ajouter la balise suivante :

<xmlrpcentrypoint name="xmlrpc" default="true" />

Dans un cas comme dans l’autre, vous pouvez alors récupérer l’url d’une action pour xmlrpc comme ceci :

$url = jUrl::get("module~action@xmlrpc");

8.4.2 Contrôleur

Comme on a affaire à un type de requête particulier, le nom du fichier du contrôleur doit avoir le suffixe ".xmlrpc.php".Par exemple, un contrôleur "default" : "default.xmlrpc.php". (Vous pouvez bien sûr avoir un autre contrôleur "default"pour d’autres types de requêtes, "default.classic.php" par exemple).

Ensuite, le contenu du contrôleur est similaire à ce que vous avez l’habitude de faire, à la seule différence que vousutiliserez jResponseXmlRpc, qui a pour alias "xmlrpc", pour répondre aux requêtes JsonRpc :

class defaultCtrl extends jController {

function index(){

$rep = $this->getResponse(’xmlrpc’);

// n’importe quelles types de données : entier, chaine, array, objets...$donnees_php = ... ;

$rep->response = $donnees_php;

return $rep;

}}

Page 59: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

52 / 225

8.4.3 Appel depuis le client

Qui dit XmlRpc, dit une partie cliente qui envoi une requête xmlrpc. Comme vous pouvez le lire dans la spécificationde xml-rpc, il faut envoyer du contenu XML de ce type :

<?xml version="1.0" ?><methodCall>

<methodName>module:default:index</methodName><params>

<param><string>Allo ?</string></param></params>

</methodCall>

Dans methodName, vous indiquerez, dans le cas d’un appel à une application jelix, le sélecteur de l’action à appeler,comme ici "module :default :index".

Notez qu’il faut indiquer le caractère " :" plutôt que "~" comme séparateur du nom du module et du nom de l’action.En effet, le caractère tilde "~" est interdit dans le nom de la méthode en xmlrpc. De ce fait, il faut obligatoirementindiquer le module, le controleur et la méthode.

Les données que vous mettrez dans params seront mises dans le paramètre "params" dans la réponse jelix. Ainsi,dans l’action, pour les récupérer dans l’action, vous ferez :

$parametres = $this->param(’params’);

Bien entendu, ce que vous avez dans $parametres sera des données "php" (chaine, array ou autre), la transformationdu contenu de la balise <params> étant réalisée par jXmlRpcRequest..

Exemple d’appel XMLRPC à partir d’un page HTML : à faire...

Page 60: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

53 / 225

Chapitre 9

Effectuer des traitements en ligne de commande

9.1 Introduction

Jelix vous permet de lancer des actions spécialement en ligne de commande. Ceci est très pratique pour effectuer destraitements sur un serveur et de les planifier.

9.2 Installation

Pour lancer des actions en ligne de commande, il faut 3 éléments :– un point d’entrée spécifique– un controller cmdline– un fichier de configuration pour la ligne de commandeLes jelix-scripts vont vous permettre de créer ces éléments facilement.

9.2.1 Création du point d’entrée

À l’aide des jelix-scripts

Il se créé au moment de la création de l’application :

$ php jelix.php createapp -withcmdline

Avec cette commande, vous allez créer la structure d’une nouvelle application qui contiendra en plus un répertoirescripts contenant alors le point d’entrée cmdline : cmdline.php

Manuellement

Si vous avez déjà créé votre application vous pouvez créer le point d’entrée votre application/scripts/cmdline.php àla main. Voici son contenu :

<?php

require_once (’../../lib/jelix/init.php’);

require_once (’.././application.init.php’);

Page 61: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

54 / 225

require_once (JELIX_LIB_CORE_PATH.’request/jCmdLineRequest.class.php’);

$config_file = ’cmdline/config.ini.php’;

$jelix = new jCoordinator($config_file);$jelix->process(new jCmdLineRequest());

?>

9.3 Création d’un controller cmdline

Pour pouvoir travailler en mode cmdline, vous allez devoir créer un controller spécifique à la ligne de commande.

9.3.1 À l’aide des jelix-scripts

Vous pouvez créer votre controller en utilisant les jelix-scripts :

$ php jelix.php createmodule -cmdline foo // création du module foo avec un ←↩controller cmdline

ou

$ php jelix.php -cmdline foo bar // création du controller bar dans le module foo

9.3.2 Manuellement

Pour créer le controller manuellement, celui-ci ne devra pas hériter de jController comme habituellement, mais ildevra hériter de jControllerCmdline.

<?php

class defaultCtrl extends jControllerCmdLine {

function index() {$rep = $this->getResponse(); // response text$rep->content = "Hello, it works !";return $rep;

}}

?>

9.4 Création du fichier de configuration

Si vous avez créé l’application avec l’option -withcmdline le fichier de configuration aura été généré pour vous.

Voici son emplacement : app/var/config/cmdline/config.ini.php

Si le fichier n’existe pas, vous pouvez très simplement le créer à la main en prenant modèle sur le fichier de configu-ration classic (app/var/config/index/config.ini.php)

Page 62: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

55 / 225

9.5 Développement d’actions

Pour lancer vos actions, vous allez certainement vouloir lui passer des paramètres et des options.

9.5.1 Options

Déclaration

Pour déclarer les options que l’on pourra passer à l’action en ligne de commande, il faut utiliser la variable de classe$allowed_options qui est un tableau.

protected $allowed_options = array(’nom_action’ => array(’-nom_option’ => true/false));

Si le nom de l’option vaut true cela signifie qu’une valeur est attendue après l’option.

Récupération

Dans les actions de votre controller cmdline vous allez vouloir récupérer les options passées au script. Pour cela ilfaut utiliser la méthode option(’-nom_option’)

Exemple :

public function myscript() {$myoption = $this->option(’-nom_option’);

}

9.6 Paramètres

9.6.1 Déclaration

Le mécanisme est le même pour les paramètres :

protected $allowed_parameters = array(’nom_action’ => array(’nom_parametre’ => true/false));

Ici si le nom du paramètre vaut true c’est qu’il est obligatoire, false sinon.

9.6.2 Récupération

Dans les actions de votre controller cmdline vous allez vouloir récupérer les paramètres passés au script. Pour cela ilfaut utiliser la méthode param(’-nom_option’)

Exemple :

public function myscript() {$myparam = $this->param(’nom_parametre’);

}

Page 63: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

56 / 225

9.7 Message d’aide

Vous pouvez aussi gérer le message d’aide sur les commandes. Ceux-ci se déclare dans la variable de classe $help :

public $help = array(’nom_action’ => ’message’

);

Nous allons dans la partie suivante comment se servir de ce message d’aide

9.8 Utilisation

Pour utiliser vos scripts, c’est à dire vos actions de vos controllers cmdline, rendez vous en ligne de commande dansle répertoire app/scripts

Il suffit alors de lancer le script cmdline.php suivi de l’action à lancer (en utilisant le sélecteur d’action) et suividu/des options et du/des paramètres voulu

Exemple :

$ php cmdline.php module~controller:action -nom_option optionval nom_param

Pour afficher l’aide, il suffit de faire :

$ php cmdline.php jelix~help:index module~controller:action

Page 64: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

57 / 225

Chapitre 10

Définir des traitements communs à plusieurs ac-tions

Il y a plusieurs types de traitements : les traitements métiers, et ceux dédiés à la génération de la page web. Pour lestraitements métiers, vous utiliserez des classes métiers, des classes services, des daos. Celles-ci pouvant être utilisablepar tous les modules, c’est un premier moyen de réaliser des traitements métiers qui puissent être réutilisables. Voirclasses-metiers.

Pour ce qui concerne la génération d’une page, c’est un peu plus complexe que ça car il y a plusieurs façons de faire.Nous sommes donc devant le cas suivant : nous avons plusieurs pages qui ont des parties communes. Cela peut êtrepar exemple un bandeau, un pied de page, un menu sur le coté etc.. Il peut y avoir aussi quelques pages qui ont un peuplus que ça en commun. Voici diverses solutions selon le contexte.– Utilisation de méthodes privées de contrôleurs– Héritage de contrôleurs– Utilisation d’une réponse commune– Utilisation de zones

10.1 Méthodes privées de contrôleurs

Si la similitude des pages se résume à quelques actions qui sont dans un même contrôleur, alors vous pouvez utiliserune méthode privée/protégée, qui va faire le travail commun à toutes ces actions.

class defaultCtrl extends jController {

protected function common(){$rep = $this->getResponse(’html’);$rep->title = ’Même titre pour tout le monde’;$rep->body->assign(’menu’, ’<ul><li>item 1</li><li>item 2</li></ul>’);return $rep;

}

function index(){$rep = $this->common();$rep->body->assign(’MAIN’,’<p>Bienvenue sur cette application de test</p>’);return $rep;

}

Page 65: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

58 / 225

function liste(){$rep = $this->common();$rep->body->assign(’MAIN’,’<ul><li>une</li><li>liste</li></ul>’);return $rep;

}

}

Dans cette exemple, les deux actions index et liste font appel à une méthode commune qui va réaliser le travailcommun.

10.2 Héritage de contrôleurs

Si plusieurs actions de plusieurs contrôleurs ont des traitements en commun, alors vous pouvez utiliser le mécanismed’héritage objet. C’est à dire réaliser un contrôleur de base, qui ne sera pas utilisé directement, mais dont hériterontles contrôleurs concernés.

Voici un exemple de contrôleur de base, dans le fichier controllers/myBaseController.php :

class myBaseController extends jController {

protected function common(){$rep = $this->getResponse(’html’);$rep->title = ’Même titre pour tout le monde’;$rep->body->assign(’menu’, ’<ul><li>item 1</li><li>item 2</li></ul>’);return $rep;

}

}

Et dans vos contrôleurs :

global $gJCoord;include $gJCoord->getModulePath(’monModule’).’controllers/myBaseController.php’;

class defaultCtrl extends myBaseController {

function index(){$rep = $this->common();$rep->body->assign(’MAIN’,’<p>Bienvenue sur cette application de test</p>’);return $rep;

}

function liste(){$rep = $this->common();$rep->body->assign(’MAIN’,’<ul><li>une</li><li>liste</li></ul>’);return $rep;

}

}

Page 66: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

59 / 225

Notez l’include et le extends myBaseController ;

Bien sûr, le contrôleur de base peut contenir des propriétés, d’autres méthodes, voir même des méthodes d’actions.C’est à dire que vous pouvez ainsi avoir plusieurs contrôleurs qui possèdent au final des actions communes (quipeuvent elle-même tenir compte de propriétés ou d’autres méthodes pour gérer des différences).

Vous pouvez faire par exemple un contrôleur de base, qui définit une série d’actions : liste, creation, modification,suppression. Ces actions se basant sur des propriétés pour savoir les daos et les templates à utiliser. Ainsi, il est aiséde réaliser plusieurs contrôleurs, héritant de ce contrôleur de base, et n’ayant plus qu’à indiquer dans des propriétésles daos et les templates. De quoi ainsi se faire une administration basique assez rapidement.

10.3 Personnalisation de réponse commune

Les deux solutions précédentes sont intéressantes pour des cas peu courants, ou du moins, pas généraux à l’applica-tion. Si vous avez des choses en commun pour la majorité des actions, il est préférable de faire autrement : surchargerun objet réponse.

Vous créerez cet objet response de façon à ce que ce soit lui qui fasse le travail commun à toutes les actions. Imaginonspar exemple que toutes les pages HTML de votre site ait le même menu dynamique, la même feuille de style etc..Vous créerez donc une classe response comme il est indiqué dans générer un contenu personnalisé, et qui effectuerace travail.

Si vous voulez réaliser des modules réutilisables, cette façon de faire est d’autant plus intéressante puisqu’alors toutce qui ne concerne pas le module est réalisé à l’extérieur de ce module. Il est donc plus indépendant de l’application,contrairement au cas où il gère lui même dans ses actions les parties communes des pages du site (bandeau etc...).

Vos propres classes de réponses peuvent hériter de jResponseHtml par exemple. Dans cette classe, vous pouvezalors :– surcharger le constructeur pour réaliser des choses qui seront fait lorsque vous ferez le getResponse dans votre

contrôleur– surcharger la méthode _commonProcess. Notez que cette méthode n’existe que pour jResponseHtml. Elle sera

appelée aprés votre action, et juste avant l’affichage définitif.Voyons plus précisément comment ça se gère globalement. Vous avez donc vos pages HTML, qui contiennent la

partie <head> et la partie <body> :

Page 67: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

60 / 225

Vous aurez un template principal qui s’occupe de générer l’ensemble du contenu de <body>, et ce template va être dé-claré au niveau de votre propre objet response. Voici par exemple votre objet responses/myHtmlResponse.class.php :

require_once (JELIX_LIB_RESPONSE_PATH.’jResponseHtml.class.php’);

class myHtmlResponse extends jResponseHtml {

public $bodyTpl = ’myapp~main’;

protected function _commonProcess(){

Page 68: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

61 / 225

}}

Votre page est en général découpé en zone :

Ainsi le template pourrait ressembler à ceci

<div id="header"> ... {$date} </div><div id="sidebar-left"> {$A} {$B} {$C} </div><div id="sidebar-right"> {$D} </div>

Page 69: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

62 / 225

<div id="main-content"> {$MAIN} </div>

<div id="footer"> ...</div>

Ces zones A, B, C, D et MAIN peuvent être générées par des sous-templates ou des objets jZone, materialisés ici pardes parties distinctes :

En particulier, la partie MAIN sera générée par un template que les actions fourniront.

Ainsi l’objet réponse pourra s’occuper par exemple de la partie A (si celle-ci est commune à toutes les pages), et lesautres zones seront remplies à loisir par les actions. Dans l’objet réponse on aura donc :

Page 70: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

63 / 225

require_once (JELIX_LIB_RESPONSE_PATH.’jResponseHtml.class.php’);

class myHtmlResponse extends jResponseHtml {

public $bodyTpl = ’myapp~main’;

protected function _commonProcess(){// toutes les pages auront une zone de login affichée$this->body->assignZone("A", "auth~login");

// et au cas où rien n’est défini pour B,C,D et MAIN, on met du contenu// par défaut$this->body->assignIfNone(’B’,’’);$this->body->assignIfNone(’C’,’’);$this->body->assignIfNone(’D’,’’);$this->body->assignIfNone(’MAIN’,’<p>No content</p>’);

// on indique les autres variables$this->body->assign(’date’, date(’Y-m-d’));

}}

Dans les actions (contrôleurs), on fera donc des choses comme :

function mon_action() {$rep = $this->getResponse(’html’);// on indique du contenu pour B$rep->assign(’B’,’<h2>Hello !</h2>’);

// on indique du contenu pour D$rep->assignZone(’D’, ’ma_sidebar’);

// Pas de contenu pour C, donc on ne fait rien pour C

// on s’occupe maintenant de la partie principal// qui a son propre template$tplMain = new jtpl();$tplMain->assign(...);$rep->assign(’MAIN’, $tplMain->fetch(’monmodule~montpl’));

return $rep;}

Bien sûr, la réponse peut définir aussi autre chose que le template : feuille de styles et cie. Ce qui évite de le fairedans les actions. Exemple, en surchargeant le constructeur :

class myHtmlResponse extends jResponseHtml {

public $bodyTpl = ’myapp~main’;

// traitement executé AVANT les actionspublic function __construct() {

parent::__construct();$this->addCSSLink(’design/screen.css’);

}

// traitement executé APRES les actions

Page 71: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

64 / 225

protected function doAfterActions(){

$this->title .= ($this->title !=’’?’ - ’:’’).’ My App’;

// toutes les pages auront une zone de login affichée$this->body->assignZone("A", "auth~login");

// et au cas où rien n’est défini pour B,C,D et MAIN, on met du contenu// par défaut$this->body->assignIfNone(’B’,’’);$this->body->assignIfNone(’C’,’’);$this->body->assignIfNone(’D’,’’);$this->body->assignIfNone(’MAIN’,’<p>No content</p>’);

// on indique les autres variables$this->body->assign(’date’, date(’Y-m-d’));

}}

10.3.1 Déclaration de l’objet response

Cet objet response est déclaré comme ceci dans la configuration :

[responses]html=myHtmlResponse

Toutes les actions qui feront alors appel à la réponse "html", fourniront un objet myHtmlResponse, et donc une pageavec un formulaire de login généré par la zone ’auth~login’, un contenu par défaut pour les variables de templatesMAIN, A, B etc (si elles n’ont pas été définies par l’action).

10.3.2 Astuces utiles

Lorsque vous définissez une réponse personnalisée, il peut être utile de récupérer certaines valeurs de votre applica-tion, comme– le theme : $GLOBALS[’gJConfig’]->theme– les paramètres de la requête : $GLOBALS[’gJCoord’]->request->getParam(..)Ci-dessous un exemple

public function __construct() {parent::__construct();$theme = $GLOBALS[’gJConfig’]->urlengine[’basePath’].’themes/’.$GLOBALS[’ ←↩

gJConfig’]->theme.’/’ ;$this->addCSSLink($theme.’css/screen.css’);

}

protected function _commonProcess(){

$this->title .= ($this->title !=’’?’ - ’:’’).’ My App’;

$param = $GLOBALS[’gJCoord’]->request->getParam(’paramSommaire’)

// toutes les pages auront une zone de login affichée$this->body->assignZone("A", "auth~login", array( ’paramSommaire’ => ←↩

$param ) );

Page 72: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

65 / 225

// et au cas où rien n’est défini pour B,C,D et MAIN, on met du contenu// par défaut$this->body->assignIfNone(’B’,’’);$this->body->assignIfNone(’C’,’’);$this->body->assignIfNone(’D’,’’);$this->body->assignIfNone(’MAIN’,’<p>No content</p>’);

// on indique les autres variables$this->body->assign(’date’, date(’Y-m-d’));

}

10.3.3 Définir plusieurs réponses

Notez que vous pouvez définir plusieurs réponses html, dans le cas où votre site comporte plusieurs pages type. Parexemple :

[responses]html=myHtmlResponsehtml2=myOtherHtmlResponseadm=adminHtmlresponse

Il suffira alors dans les actions d’indiquer le bon code pour indiquer le type de réponse :

$rep = $this->getResponse(’html’);// ou$rep = $this->getResponse(’html2’);// ou$rep = $this->getResponse(’adm’);

10.3.4 Utiliser ponctuellement une réponse d’origine

Si dans une action, vous voulez absolument utiliser la classe d’origine fourni par Jelix, et non celle qui redéfinit untype de réponse, vous pouvez alors l’indiquer en indiquant true en deuxième paramètre de getResponse :

$rep = $this->getResponse(’html’, true);

$rep contiendra un objet de type jResponseHtml, et non myHtmlResponse.

10.4 Utilisation de zones

Il se peut qu’un ensemble de page possède une ou plusieurs zones identiques, sans que cela soit général à tout le site.Vous pouvez alors créer des zones.

Page 73: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

66 / 225

Troisième partie

Composants de jelix

Page 74: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

67 / 225

Cette partie vous permet de découvrir tout les composants que Jelix vous offre, en dehors des objets spécifiques à lastructure d’un projet et au modèle MVC.

Voici donc comment utiliser les templates, accéder aux bases de données, réaliser des formulaires, internationaliservotre application etc.

Page 75: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

68 / 225

Chapitre 11

jTpl : le moteur de templates

Jelix inclu son propre moteur de template jTpl. Les templates sont des fichiers portant l’extension ".tpl" et se trouvantdans le répertoire "templates" des modules.

11.1 L’objet jTpl

L’objet jTpl sert à générer le contenu indiqué dans un fichier template, à partir des données que vous lui fournissez,et en suivant les instructions contenues dans le template.

Les objets jResponse ou jZone instancie pour vous un objet jTpl. Par exemple, la propriété body de l’objet jRespon-seHtml est un objet jTpl, de même que la propriété _tpl de jZone.

Dans d’autres circonstances, vous aurez à faire :

$tpl = new jTpl();

Voici les méthodes les plus importantes à connaître.

11.1.1 assign

$tpl->assign($nom, $valeur);

Cette méthode vous permet de créer une variable de template. Une variable de template n’est accessible qu’au niveaudu template. C’est avec cette méthode que vous pouvez donc passer des données (valeurs statiques, objets, itérateurs,etc..) au template pour vous en servir à générer du contenu.

Vous pouvez également créer ou modifier une variable directement dans le fichier tpl en utilisant.

{assign $nom = $valeur}

– *important** : le nom d’une variable de template doit respecter les conventions de nommage des noms de variablesPHP. Par exemple, le nom ne doit pas contenir de tiret ou d’autres signes de ponctuations. Il ne doit contenir quedes lettres avec éventuellement des chiffres et le caractère souligné (_).

11.1.2 assignIfNone

Idem que assign, mais la valeur est assignée à la variable uniquement si celle-ci n’existe pas.

Page 76: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

69 / 225

11.1.3 assignZone

$tpl->assignZone($name, $zoneSelector, $params);

Le paramètre params est facultatif. Cette méthode est un raccourci de :

$tpl->assign($name, jZone::get($zoneSelector, $params));

11.1.4 assignZoneIfNone

Idem que assignZone, mais la valeur est assignée à la variable uniquement si celle-ci n’existe pas.

11.1.5 get

Si vous voulez récupérer la valeur d’une variable de template déjà initialisée, vous pouvez utiliser cette méthode.

$value = $tpl->get(’foo’);

11.1.6 Récupération du contenu

Une fois que les variables sont initialisées, vous pouvez appeler la méthode fetch pour générer le contenu du templateet le récupérer. Vous donnerez à cette méthode le selecteur du fichier de template.

$contenu = $tpl->fetch(’mymodule~mytemplate’);

L’appel de cette méthode n’est indispensable que dans le cas où vous avez instancier vous même l’objet jTpl.

Il existe une autre méthode, mais que vous n’appelerez jamais puisque les objets jResponse le font à votre place :display.

$tpl->display(’mymodule~mytemplate’);

Le contenu du template est évalué et affiché directement.

11.2 Les fichiers templates

Un fichier de template contient du HTML, du XUL ou ce que vous voulez qui soit en rapport avec le type de laréponse. Il contient aussi des instructions pour incorporer des valeurs que vous aurez fournies, des instructions pourgénérer répétitivement des portions de HTML, XUL etc.

La syntaxe utilisée dans jTpl est à mi chemin entre celle utilisée dans le moteur de template Smarty, et la syntaxePHP. Le but étant d’avoir des templates suffisamment lisibles, facile à modifier en n’imposant pas une syntaxe tropéloignée de PHP, tout en proposant des facilités que ne possède pas PHP et propres à Jelix.

Il faut avoir en tête que la plupart des templates que vous ferez ne doivent pas contenir de fichiers entiers. Enparticulier, pour les réponses HTML, vos templates ne doivent contenir que ce qui se trouve entre les balises <body>et </body> de votre page, le reste étant généré automatiquement par jResponseHtml.

Page 77: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

70 / 225

11.2.1 Syntaxe des instructions

Les instructions jTpl sont spécifiées entre accolade : {instruction....}.

Si vous voulez inclure des accolades dans le source, sans que ce soit interprété par jTpl, vous pouvez utiliser {ldelim}pour {, et {rdelim} pour }. Si vous avez un bloc contenant plusieurs accolades (comme du code javascript), vouspouvez aussi utiliser l’alternative avec {literal} :

<script type="text/javascript">{literal}

for(i=0;i<max;i++) {if(foo){ ...}

}{/literal}

</script>

Si vous voulez mettre des commentaires qui ne seront pas inclus dans le contenu généré, utilisez {*...*}

<p>bla bla</p>{* ceci est un commentaire *}

11.2.2 Expressions

Une expression jTpl est identique à une expression PHP et renvoie, comme dans PHP, une valeur. Vous pouvezutiliser les opérateurs PHP classiques, les objets, etc...

On peut utiliser les variables de templates qu’on a passées à jTpl, comme des variables classiques en PHP :

$nom_variable_de_template

Une expression peut contenir aussi des sélecteurs de locale, en utilisant une syntaxe spécifique à jTpl. Ce type desélecteur doit être placé entre @. jTpl ira chercher la chaîne correspondante dans la langue courante :

@mon_module~cle.chaine.localisee@."fooo bar"

La chaîne correspondant à mon_module~cle.chaine.localisee sera récupérée et concaténée à "fooobar".

À l’intérieur du nom de la clé, on peut indiquer un nom de variable de template. Cela permet ainsi de construire unnom de clé dynamiquement.

@mon_module~cle.chaine.$nom_variable_template.autre@

si $nom_variable_template vaut "foo", alors la clé sera "mon_module~cle.chaine.foo.autre".

11.2.3 Affichage d’une expression, d’une variable

Il faut mettre l’expression entre accolade. Elle doit commencer par un nom de variable ou par un sélecteur de locale :

{$mavariable}{$mavariable * 3}{$mavariable." - ".@mod~message.ok@}{@modul~une.cle.de.locale@."-".$uneAutreVariable}{@modul~une.cle.$dynamique@."-".$uneAutreVariable}

Ceci est équivalent en php à

Page 78: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

71 / 225

<?php echo $mavariable; ?><?php echo $mavariable * 3; ?><?php echo $mavariable." - ".jLocale::get("mod~message.ok"); ?><?php echo jLocale::get("modul~une.cle.de.locale")."-".$uneAutreVariable; ?><?php echo jLocale::get("modul~une.cle.".$dynamique)."-".$uneAutreVariable; ?>

11.2.4 Constantes prédéfinies

Pour apporter une certaine facilité, des variables de templates prédéfinies ont été ajoutées :– $j_basepath : contient le chemin url du répertoire de l’application (paramètre de configuration basePath)– $j_jelixwww : contient le chemin url vers le contenu du répertoire jelix-www (paramètre de configuration je-

lixWWWPath)– $j_themepath : contient le chemin url vers le répertoire du thème courant– $j_datenow : date courante (aaaa-mm-jj)– $j_timenow : heure courante (hh :mm :ss)

11.2.5 Modificateurs

Un modificateur est en fait une fonction qui va modifier le contenu qui va être affiché. Cela fonctionne comme danssmarty. On peut mettre plusieurs modificateurs à la suite :

{$unevariable|upper}{$unevariable|upper|escxml}{$uneUrl|escurl}

Ceci est en fait équivalent à :

<?php echo strtoupper($unevariable);?><?php echo htmlspecialchars(strtoupper($unevariable));?><?php echo rawurlencode($uneUrl);?>

Les modificateurs indiqués en exemple sont de simples alias à des fonctions existantes, mais vous pouvez créer vospropres modificateurs, pouvant accepter plusieurs arguments.

Les modificateurs existants et leur équivalent php :– upper (strtoupper)– lower (strtolower)– escxml (htmlspecialchars)– strip_tags (strip_tags)– escurl (rawurlencode)– capitalize (ucwords)D’autres sont fournis. Voir la liste sur la référence API.

modificateur avec paramètres

Il peut y avoir des modificateurs qui acceptent des paramètres. Vous devez mettre ceux-ci, séparés par des virgules(,) , après le nom du modificateur et deux-points ( :).

Exemple : ici le modificateur jdatetime, prenant deux paramètres de type chaîne :

<p>la date est {$myDate|jdatetime:’db_date’,’timestamp’}.</p>

Page 79: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

72 / 225

11.3 Les structures de contrôle

Elles sont équivalentes à celle en PHP. Voici celles qui sont pour le moment implémentées :

11.3.1 if, else, elseif

{if condition_1}// code ici

{elseif condition_2}// code ici

{else}// code ici

{/if}

Note : les parenthèses encadrant la condition ne sont pas obligatoires.

11.3.2 while

{while condition}// code ici

{/while}

Note : les parenthèses encadrant la condition ne sont pas obligatoires.

11.3.3 foreach

{foreach expression}// code ici

{/foreach}

Note : il ne faut pas entourer l’expression par des parenthèses.

11.3.4 for

{for expression}// code ici

{/for}

L’expression est bien sûr semblable à celle du "for" en PHP. Cependant, il ne faut pas entourer l’expression par desparenthèses.

Page 80: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

73 / 225

11.4 Fonctions jTpl

Ce sont des fonctions classiques mais appelables uniquement dans un template. Certaines sont disponibles en stan-dard et vous pouvez en réaliser en créant un plugin de template. Leur syntaxe est :

{nom_fonction paramètres}

Les paramètres sont des expressions jTpl, donc similaires aux expressions PHP. Cependant, contrairement en PHP,il ne faut pas entourer les paramètres par des parenthèses.

Sachez que les fonctions, et en général la plupart des plugins de templates, sont attribués à un type de réponseparticulier. Donc il existe des fonctions utilisables dans des templates pour les réponses HTML, mais pas dans lestemplates pour les réponses Text par exemple.

11.5 informations meta

Il existe une balise assez spéciale : {meta}. Elle n’influence pas l’interprétation du template, ne génère aucun contenu,mais permet de fournir des informations sur le template qui pourraient être réutilisées par un programme utilisant letemplate.

{meta nom expression}

Exemple :

{meta auteur ’laurent’}

On peut en mettre plusieurs bien sûr. Ces informations sont récupérables via la méthode meta() de l’objet jTpl :

$tpl = new jTpl();

$metas = $tpl->meta(’le_fichier_template’);

echo $metas[’auteur’]; // affiche ’laurent’

11.6 Informations meta avançées

Des informations meta peuvent être traitées automatiquement via un plugin de template. Par exemple, il existe unplugin de meta permettant d’indiquer des informations pour une réponse HTML (feuille de style CSS, script JS, etc...).Leur syntaxe est :

{meta_nom_plugin nom expression}

Exemple :

{meta_html css ’/styles/my.css’}{meta_html js ’fooscript.js’}{meta_html bodyattr array(’onload’=>’alert("charge")’)}

Un plugin similaire existe pour XUL, et bien sûr vous pouvez réaliser le votre.

Page 81: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

74 / 225

11.7 Surcharge de template

Chaque module défini des templates qui lui sont propres, mais pour éviter d’avoir à retravailler sur les templatesoriginaux du module lorsque ce dernier est réutilisé dans une autre application, il est possible d’appliquer d’autrestemplates afin de produire un nouvel affichage, sans toucher au contrôleur.

Pour cela Jelix utilise un système de thème, le thème par défaut étant stocké dans /var/themes/default, il est possibled’ajouter d’autres thèmes en ajoutant simplement des répertoires dans /var/themes, par exemple /var/themes/mon_theme.

Ainsi /var/themes/mon_theme/mon_module/mon_template.tpl redéfini le template mon_template du module mon_modulepour le thème mon_theme.

Pour plus de détails, voir la page sur les thèmes.

11.8 En coulisse

Les templates jTpl sont "compilés" sous forme de fichiers purs PHP, et stockés dans un cache pour améliorer les per-formances. Vous pouvez donc voir l’équivalence d’un de vos fichiers templates dans temp/votre_application/compiled/templates/modules/nom_module~nom_template.phpou pour les templates redefinis dans les themes : temp/votre_application/compiled/templates/themes/nom_theme/nom_module~nom_template.php

Vous pouvez créer aussi des plugins de templates, pour ajouter vos propres "tags" dans la syntaxe jtpl. Voir tpl.

Page 82: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

75 / 225

Chapitre 12

jZone : découper vos pages en zones

12.1 Principes d’une zone

Les zones dans Jelix représentent des morceaux de la réponse finale. En d’autre termes, elles sont destinées à géreret générer le contenu d’une portion de l’écran, de la page web. Une page web est donc composée essentiellement dezones.

L’intérêt d’utiliser les zones est de :– pouvoir réutiliser une zone dans des pages différentes : une zone est en théorie indépendante du contexte : elle fait

elle même appel aux classes métiers et possède son propre template.– avoir une génération de contenu paramétrable : les zones acceptent des paramètres.– pouvoir générer plus rapidement les pages, en activant la mise en cache des zones : seules les zones dont les

paramètres changent (la zone principale en général) sont régénérées (ou celles dont on aura effacé le cache).– au passage, alléger le code des contrôleurs.

12.2 Utilisation des zones

12.2.1 Création

Une zone est déclarée via une classe héritant de jZone. Le nom de cette classe est le nom de la zone suivit du mot"Zone"

class testZone extends jZone {

}

Elle doit être stockée dans un fichier nom_de_la_zone.zone.php, dans le répertoire zones du module. Ici donc, ils’agit du fichier zones/test.zone.php.

Par défaut, un objet jZone instancie un moteur de template.

Utilisation sans template

Si vous ne voulez pas utiliser de template pour votre zone, vous devez surcharger la méthode _createContent, quidoit renvoyer le contenu de la zone sous forme de chaine. Vous ne devez pas faire d’echo ou de print !

Page 83: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

76 / 225

class testZone extends jZone {

protected function _createContent(){return "<p>Ceci est le contenu d’une zone</p>";

}}

Utilisation avec template

La plupart du temps, vous utiliserez toutefois un template. Vous devez indiquer dans la propriété $_tplname letemplate que vous utilisez (c’est un sélecteur), et surcharger la méthode _prepareTpl(). Cette méthode est, comme sonnom l’indique, chargée d’initialiser l’objet jTpl instancié automatiquement par jZone et stocké dans la propriété _tpl.

class testZone extends jZone {

protected $_tplname=’template_test’;

protected function _prepareTpl(){$this->_tpl->assign(’foo’,’bar’);

}}

Et le template (stocké dans templates/template_test.tpl) :

<p>Ceci est un template. Et foo vaut {$foo}.</p>

12.3 Appel

Il y a plusieurs façons de récupérer le contenu d’une zone en fonction de ce que l’on veut faire.

Si on veut récupérer simplement son contenu (dans un contrôleur) on fait :

$contenu = jZone::get(’test’); // ou ’leModule~test’...

Cependant, il arrive très souvent qu’il s’agisse d’affecter le contenu de la zone à une variable du template principal,lorsque la réponse possède un template principal (ce qui est le cas des réponses HTML qui possèdent un objet jTpldans sa propriété body). Dans le contrôleur, on pourra donc utiliser la méthode assignZone de jTpl :

$rep = $this->getResponse(’html’);$rep->title = ’page de test’;$rep->bodyTpl = ’testapp~main’;$rep->body->assignZone(’MAIN’, ’test’);

test correspondant au nom du fichier test.zone.php MAIN correspondant à la variable de template {$MAIN}

Autre solution, on peut avoir dans un template, un appel de zone direct :

<div id="menu"> {zone ’leModule~test’} </div>

Page 84: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

77 / 225

12.3.1 Appel avec des paramètres

Il est possible de faire passer des paramètres à une zone. Pour cela, on procède de la manière suivante :

Appel depuis un contrôleur :

$rep = $this->getResponse(’html’);$rep->title = ’page de test’;$rep->bodyTpl = ’testapp~main’;$rep->body->assignZone(’MAIN’, ’test’, array(’foo’=>’bar’));

Et pour récupérer la variable dans la zone, on utilise la méthode getParam() :

class testZone extends jZone {

protected $_tplname=’template_test’;

protected function _prepareTpl(){$foo = $this->getParam(’foo’);$foo = strtoupper($foo);$this->_tpl->assign(’foo’, $foo);

}}

Dans cet exemple on a fait passer la variable ’foo’ avec pour valeur ’bar’ en paramètre de la zone. On a récupéréla variable ’foo’ dans la zone pour effectuer un traitement dessus (ici, mise en majuscule) et on a affecté ’foo’ autemplate de la zone.

À noter que Jelix affecte automatiquement les variables passées en paramètres de la zone au template de zone si ilexiste. Vous pouvez vous passer d’écrire :

protected function _prepareTpl(){$this->_tpl->assign(’foo’, $this->getParam(’foo’));

}

Si vous utilisez le plugin de template zone, le passage des paramètres à la zone s’effectue de cette manière :

<div id="menu"> {zone ’leModule~test’, array(’foo’=>’bar’)} </div>

12.4 Utilisation du cache

Il est possible de mettre le contenu généré dans un cache. Et il peut y avoir un cache pour chaque valeur des para-mètres de la zone.

12.4.1 Activation du cache

Par défaut, une zone ne gère pas de cache : il faut donc l’activer dans votre classe, via la propriété _useCache enla mettant à true :

class testZone extends jZone {

protected $_useCache = true;

}

Page 85: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

78 / 225

Le contenu de la zone sera ainsi mis dans un fichier de cache. Si la zone a des paramètres, un cache sera crée pourà chaque valeur différente des paramètres. Ainsi, si vous avez un paramètre ’id_article’, un cache sera crée à chaquefois que la zone sera appelée avec une valeur de id_article différente.– *ATTENTION** : un cache se matérialise par un fichier dans le répertoire temporaire de l’application. Si vous

avez des milliers d’articles, cela peut engendrer autant de fichiers dans votre répertoire temporaire. Il faut doncéviter dans un cas comme celui-là, d’activer le cache si votre hébergeur vous limite en nombre de fichiers parexemple.

Utilisez donc le cache à bon escient. Par exemple, pour une application fréquentée moyennement (un même articlelu seulement quelque fois par jour), il n’est pas forcément nécessaire d’activer le cache. À vous de juger...

(note : il était documenté auparavant l’utilisation d’une propriété _cacheParams. Cette propriété n’a en fait jamaisété utilisé dans jZone, donc n’a jamais servi à rien...)

12.4.2 Rafraîchissement du cache

Il est nécessaire de régénérer le cache quand les informations contenues sont obsolètes. Cette régénération peut sefaire automatiquement régulièrement (toutes les n secondes), ou alors être forcée manuellement.

Vous utiliserez l’une ou l’autre des méthodes selon les cas. La deuxième méthode est moins gourmande en ressourcepuisque le cache ne se régénère uniquement en temps voulu. L’inconvénient c’est qu’il faut explicitement effacer lecache dans vos classes métier. La première méthode évite ce travail, mais consomme plus de ressources, et le contenude la zone n’est pas à jour pendant le délai indiqué. À réserver donc pour afficher des informations non vitales, dontla "fraîcheur" n’a pas vraiment d’importance.

Automatique

Pour un rafraîchissement automatique, il suffit d’indiquer dans la propriété _cacheTimeout le délai d’invaliditédu cache, en secondes :class testZone extends jZone {

protected $_useCache = true;

protected $_cacheTimeout = 60;}

Ici le cache sera régénéré toutes les 60 secondes. Si vous mettez 0, il n’y aura pas de rafraîchissement automatique.

Forcé

La suppression "manuelle" du cache se fait via les méthodes statiques clear et clearAll.

Par exemple, dans la classe métier de votre article, au moment de modifier l’article (en base de données par exemple)ou de le supprimer, vous allez appeler jZone pour qu’il supprime le cache correspondant, afin qu’il soit régénéré auprochain affichage. Bien sûr, il faut indiquer les valeurs des paramètres qui identifient le cache. Dans notre exempledonc, id_article.

jZone::clear(’mymodule~article’, array(’id_article’=>546));

Si vous voulez effacer tous les caches d’une même zone, vous pouvez appeler clearAll :jZone::clearAll(’mymodule~article’);

Et si vous voulez effacer tous les caches de toutes les zones :jZone::clearAll();

Page 86: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

79 / 225

12.5 Empêcher ponctuellement la mise en cache

Il faut noter que les méthodes _createContent et _prepareTpl (que vous pouvez surcharger), ne sont appelées quelorsque le cache doit être régénéré.

Il se peut que pour une raison ou pour une autre (en fonction de la valeur d’un certain paramètre par exemple), vousne vouliez pas que parfois le résultat de la zone soit mis en cache.

Il suffit alors, dans _createContent ou _prepareTpl, de mettre la propriété _cancelCache à true

protected function _prepareTpl(// ....$this->_cancelCache=true;//...

}

12.6 Paramètres automatiques

L’affichage d’une zone peut dépendre de paramètres donnés explicitement, mais aussi de paramètres "externe" im-plicites. C’est le cas par exemple pour une zone qui affiche la version d’un article en fonction de la langue configuréedans l’appli. On peut bien sûr passer à chaque appel de zone le code langue, mais ce n’est pas forcément pratique.On pourrait ne pas avoir à l’indiquer dans les paramètres, et le récupérer soit même dans _prepareTpl/_createContent,mais alors il n’est pas possible que cela devienne un critère discriminant pour le système de cache si vous l’utilisez.

La solution est de surcharger le constructeur, et d’initialiser ce paramètre :

class articleZone extends jZone {

protected $_useCache = true;

public function __construct($params=array()){$params[’lang’] = $GLOBALS[’gJConfig’]->locale;parent::__construct($params);

}

}

Page 87: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

80 / 225

Chapitre 13

jDao : mapping objet relationnel

jDao permet de générer des objets PHP qui opèrent sur des tables précises de base de données. La génération de cesobjets inclus la génération des requêtes SQL qui correspondent à ces opérations.

Pour ce faire, jDao se base sur un fichier XML que vous devez fournir. Ce fichier permet de s’affranchir de l’écriturefastidieuse des requêtes SQL, permet de tenir compte des problématiques du genre SQL injection : les objets généréss’occupent de tout. Le fichier XML peut être généré par un outil de développement, comme par exemple l’une descommandes fournies avec le script Jelix.

À partir d’un fichier XML de ce type, jDAO fourni donc deux objets, un objet "record" et un objet "factory", selonle pattern DAO.

Un objet record représente un enregistrement : ses propriétés correspondent avec les champs d’une ou plusieurstables.

Un objet factory fourni un certain nombre de méthodes permettant de créer un record, de le sauvegarder, de le détruireou de récupérer des ensembles d’objets record.

13.1 Fichier DAO de base

Pour utiliser jDao, il faut d’abord décrire dans un fichier XML le mapping objet-relationnel, c’est à dire indiquerdans ce fichier la correspondance entre les propriétés de l’objet DAO et les champs d’une ou plusieurs tables

13.1.1 Création automatique

Le fichier d’un DAO peut être généré par le script jelix en ligne de commande, à partir d’une table de base de donnéeexistante.

php jelix.php createdao nom_module nom_dao nom_table

Par exemple, si je veux créer dans le module "myshop", un DAO "product" qui sera basé sur la table "shop_product",vous taperez donc :

php jelix.php createdao myshop product shop_product

Dans le répertoire daos du module myshop vous allez donc avoir un fichier XML product.dao.xml qui va contenir ladescription du mapping.

Bien que la génération automatique permet de gagner du temps, il faut souvent retoucher le fichier pour que lemapping corresponde mieux à ce que l’on veut faire, le générateur ne pouvant tout deviner. Voyez alors la suite pourle compléter, ou en créer un à la main.

Page 88: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

81 / 225

13.1.2 Détails sur le format XML

La structure d’un fichier DAO ressemble à cela :

<dao xmlns="http://jelix.org/ns/dao/1.0"><datasources>

section datasources</datasources><record>

section properties</record><factory>

section methodes</factory>

</dao>

Il y a trois sections, sachant que la section "factory" (ou "methodes") est facultative et est décrite dans une autre pagedédiée.– datasources : indique les tables sur lequel reposera l’objet.– record : indique la correspondance entre les propriétés de l’objet et les champs des tables et définit donc les

propriétés qu’il y aura sur l’objet record.

13.1.3 Correspondance simple

Déclaration de la table

On appelle correspondance simple, une correspondance où un record = une table. Pour déclarer la table sur laquellereposera le DAO, on utilise la balise primarytable, avec les attributs suivants :– name : alias donné à la table et qui sera utilisé dans les requêtes– realname (facultatif) : nom réel de la table dans la base de données. Si cet attribut n’est pas précisé, il prend la

même valeur que l’attribut name. Dans ce cas name doit être le nom réel de la table.– primarykey indique la clé primaire. Vous pouvez indiquer plusieurs clés en les séparant par un espace ou une

virgule.<datasources>

<primarytable name="p" realname="products" primarykey="id_product" /></datasources>

On déclare ici que le record sera basé sur la table "products", qui a pour alias "p", et dont la clé primaire est"id_product".

Il n’y a toujours qu’une seule table "primaire" dans un DAO (donc une seule balise <primarytable>). Vous verrezque l’on peut indiquer des tables annexes (étrangères) plus loin.

Ensuite, il faut déclarer la correspondance propriété - champs.

Déclaration des propriétés

La section record déclare les propriétés d’un objet record (enregistrement). Chaque propriété correspond à l’un deschamps de la table primaire, ou l’un de ceux des tables étrangères comme vous le verrez plus loin. Bien sûr, vousn’êtes pas obligés de déclarer une propriété pour tous les champs existants. On peut ainsi faire plusieurs DAO quitravaillent sur une même table mais qui sont destinés à des usages différents. Par exemple faire un DAO spécifiquepour récupérer des listes légères d’enregistrement (on ne déclarera que les propriétés essentielles), et un autre pour lesgérer de manière complète (on y indiquera tous les champs).

La section record doit donc contenir une ou plusieurs balises <property> :

Page 89: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

82 / 225

<propertyname="nom simplifié"fieldname="nom du champ"datatype="" required="true/false" minlength="" maxlength="" regexp=""sequence="nom de la sequence"updatepattern="" insertpattern="" selectpattern=""default=""

/>

L’attribut name est le nom de la propriété de l’objet.

L’attribut fieldname est le nom du champ qui correspond. Si name et fieldname sont égaux, on peut omettre fieldname.

Les attributs datatype, required, minlength, maxlength, et regexp sont des contraintes. Cela permet par la suite d’ap-peler la méthode check() sur un record pour vérifier les valeurs des propriétés (avant son stockage par exemple).

L’attribut default permet d’indiquer une valeur par défaut.

L’attribut datatype peut prendre les valeurs :– string– int/integer– autoincrement– double/float– numeric/bigautoincrement– date– time– datetime– booleanSur certaines bases, on peut associer une séquence à un champ. L’attribut sequence indique son nom.

Les attributs updatepattern, insertpattern et selectpattern permettent d’indiquer un "motif" à appliquer lors de lamise à jour, l’insertion ou la lecture de la valeur du champ dans la table. Ce motif doit en fait être une expressionSQL, contenant éventuellement la chaîne "%s" qui sera remplacée par la valeur ou le nom du champ. Par défaut leursvaleurs vaut "%s". Si on indique une valeur vide, cela correspond à une opération nulle (le champ n’est pas lu, inséréou mis à jour).

Exemple 1

Pour un champ qui contient une date de mise à jour, on pourra indiquer :

<property name="date_update" datatype="datetime" insertpattern="NOW()" ←↩updatepattern="NOW()" />

Ainsi chaque fois qu’un INSERT ou un UPDATE sera fait, la valeur insérée sera la date du jour (et non celle que l’onaurait indiquée dans la propriété date_update du record).

Exemple 2

On peut aussi avoir une propriété qui ne correspond pas directement à un champ, mais qui soit le résultat d’uneexpression SQL. Dans ce cas, il faut désactiver l’insertion et la mise à jour.

<property name="identite" datatype="string" selectpattern="CONCAT(nom, ’ ’, ←↩prenom)" insertpattern="" updatepattern="" />

Attention, en ce qui concerne l’expression de selectPattern :

Page 90: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

83 / 225

– l’expression doit utiliser des champs d’une même table. Si le dao est basé sur plusieurs tables (ex : A et B, voirsection suivante), il n’est pas possible que l’expression utilise à la fois des champs de la table A et de la table B

– si l’expression utilise des champs d’une table B qui ne soit pas la table principale, la propriété doit être attribué àcette table B, et non à la table principale. Ce qui veut dire que la propriété doit avoir un attribut table ayant pourvaleur le nom/alias de cette table B.

13.1.4 Correspondance avec plusieurs tables

On peut déclarer une table principale, mais aussi des tables annexes qui seraient liées à la table principale par desjointures. Il est utile, lorsque l’on veut récupérer un enregistrement, de récupérer en même temps des informations detables annexes. Par exemple, si on veut récupérer un produit de la table products, et en même temps le libellé de sacatégorie qui se trouve dans une table "category", on déclarera aussi la table "category". À noter que vous ne pourrezmodifier que les données issues de la table principale quand vous voudrez mettre à jour un enregistrement.

Pour déclarer de telles tables étrangères, qui en toute logique sont liées à la table principale par des clés étrangères,il faut utiliser :– foreigntable pour indiquer une table étrangère liée par une jointure normale.– optionalforeigntable pour indiquer une table étrangère liée par une jointure externe.

Exemple

<primarytable name="p" realname="products" primarykey="id_product" /><foreigntable name="cat" realname="categories" primarykey="id_cat" onforeignkey ←↩

="id_cat" /><optionalforeigntable name="man" realname="manufacturers" primarykey="id" ←↩

onforeignkey="id_manufacturer" />

Comme pour la balise primarytable, il y a les attributs name, realname et primarykey. Il y a par contre un attributsupplémentaire, onforeignkey, qui indique le nom du champ dans la table primaire, qui est la clé étrangère sur la tableen question. Ainsi, avec l’exemple ci-dessus, jDao générera pour les requêtes de type SELECT les clauses FROM etWHERE suivantes :

FROM products as p left join manufacturers as man on (p.id_manufacturer = man.id) ←↩, categories as cat

WHERE cat.id_cat = p.id_cat

Indiquer des tables annexes n’a de sens que si vous voulez avoir une ou plusieurs propriétés correspondantes à leurschamps. Vous ajouterez donc autant de balise <property> que vous voudrez. La seule différence est qu’il faut ajouterun attribut table qui indique l’alias de la table dans lequel se trouve le champ.

<propertyname="libelle_categorie"fieldname="label"table="cat"

/>

Dans la propriété libelle_categorie du record, se trouvera la valeur du champ label de la table categories ("cat" étantl’alias de cette table, comme il a été défini plus haut dans la balise foreigntable ).

13.2 Instanciation et utilisation d’une factory et d’un record DAO

Vous avez vu comment décrire dans un fichier XML un DAO (voir fichier_de_base). Ce fichier, vous devez le stockerdans un répertoire "daos/" d’un module et le nommer comme ceci : nom.dao.xml. nom est le nom de votre DAO.

Souvenez vous qu’en fait vous définissez deux objets :

Page 91: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

84 / 225

– un objet DAO qui est une factory : elle permet de récupérer, insérer, modifier, effacer un ou plusieurs enregistre-ments. Elle propose des méthodes de base, mais contient aussi les méthodes dont vous avez décris les propriétésdans le fichier XML

– un objet record DAO qui représente un enregistrement et dont vous avez décris les propriétés dans le fichier XML

13.2.1 Récupérer la factory

Pour récupérer ces objets il faut passer par l’objet jDao qui propose diverses méthodes statiques :– get : permet d’obtenir une factory. renvoi toujours la même instance (utilise un singleton)– create : permet d’obtenir une nouvelle instance d’une factory. rarement utile.– createRecord : permet d’obtenir un objet DAO record vide.– createConditions : permet d’obtenir un objet jDAOConditions qui permet d’indiquer des conditions de sélection

pour récupérer un ensemble d’objet record.get, create et createRecord prennent tous en argument un sélecteur de fichier DAO et un deuxième paramètre facultatif

qui est le nom du profil jDb à utiliser (si paramètre absent, il prendra celui par défaut).

Si le profil jDb utilisé spécifie un préfixe de table, alors toutes les tables indiquées dans le DAO verront leur nompréfixé par la valeur de ce paramètre.

En admettant qu’il y ait un fichier DAO foo.dao.xml dans le module bar :

$maDao = jDao::get("bar~foo");// ou si cette ligne de code est dans un fichier du module bar :$maDao = jDao::get("foo");

$monRecord = jDao::createRecord("foo");

$maDao contient une factory de foo, et $monRecord un enregistrement vide de type foo.

13.2.2 Récupérer des records

Une factory DAO propose par défaut deux méthodes :– findAll : pour récupérer tous les enregistrements– get : pour récuperer un enregistrement en indiquant sa clé

// instanciation de la factory$maFactory = jDao::get("foo");

// récupération d’une liste complète de records de type foo$liste = $maFactory->findAll();

// récupération d’un record dont le contenu correspond// à l’enregistrement ayant pour identifiant 3$baz = $maFactory->get(3);

Vous pouvez réaliser d’autres méthodes de récupération, en les spécifiant dans le fichier XML (voir DAO avancés).

13.2.3 Récupérer des records selon critères

Les factory DAO mettent à disposition la méthode findBy, qui s’utilise en lui passant un objet jDaoConditions :

Page 92: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

85 / 225

$conditions = jDao::createConditions();$conditions->addCondition(’libelle’,’=’,$un_nom);$conditions->addCondition(’status’,’=’,5);

$liste = $maFactory->findBy($conditions);

La méthode addCondition prend en paramètre un nom de propriété, un opérateur (SQL), et une valeur. findBy renvoila liste des records qui correspondent aux critères indiqués. Vous pouvez aussi indiquer un ordre de sélection, etregrouper divers critères ensemble :

$conditions = jDao::createConditions();

// condition : libelle = $un_nom AND (status=5 OR status=4) ORDER BY libelle ←↩desc

$conditions->addCondition(’libelle’,’=’,$un_nom);$conditions->startGroup(’OR’);

$conditions->addCondition(’status’,’=’,5);$conditions->addCondition(’status’,’=’,4);

$conditions->endGroup();$conditions->addItemOrder(’libelle’,’desc’);

$liste = $maFactory->findBy($conditions);

Pour ajouter une clause LIMIT, La méthode findBy prend en plus 2 paramètres optionnels : (int $limitOffset, int$limitCount) Par exemple pour récupérer les 15 premiers enregistrements :

$liste = $maFactory->findBy($conditions, 0, 15);

Vous verrez que vous pouvez obtenir le même résultat via des méthodes dans le fichier XML. Cependant, l’utilisationde l’une ou l’autre des possibilités dépend du contexte.

Vous utiliserez jDaoConditions lorsque que vous ne savez pas à l’avance le nombre de critères et leur type. Celapeut être le cas suite à un formulaire de recherche complexe, où l’utilisateur peut choisir ses critères. Vous utiliserezaussi jDaoConditions lorsque la recherche que vous faîtes n’est utilisée qu’à un seul moment et rarement. En effet,les méthodes XML sont compilées en PHP, et donc incluses à chaque fois que vous faites appel à la factory. Il n’estpeut-être pas utile d’inclure à chaque fois du code qui ne sert presque jamais. Cela améliore les performances globales.

Dans les autres cas, il est recommandé de passer par les méthodes XML, en particulier donc quand vous connaissezles critères à l’avance (sans forcément connaître leur valeur bien sûr), et que c’est une recherche souvent utilisée.

Il arrive souvent par exemple de redéfinir la méthode findAll en XML, pour indiquer un ordre de récupération...

13.2.4 Créer, modifier, effacer un enregistrement

Les méthodes insert, update, et delete de la factory sont faites pour ça. Aux deux premières, vous indiquez un record.Pour delete, vous indiquez les clés de l’enregistrement.

Création

Il faut récupérer un nouvel objet record, le remplir, et ensuite appeler la méthode insert

// instanciation de la factory$maFactory = jDao::get("foo");

// creation d’un record correspondant au dao foo$record = jDao::createRecord("foo");

Page 93: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

86 / 225

// on remplie le record$record->champ1 = "hello";$record->champ2 = "...";

// on le sauvegarde dans la base$maFactory->insert($record);

Si il y a des champs de type autoincrement, les propriétés correspondantes dans $record seront mises à jour avec lanouvelle valeur.

Modification

Le processus est le suivant : on récupère un objet record, on modifie ses propriétés, et on appelle la méthode update :

// instanciation de la factory$maFactory = jDao::get("foo");

// récupération du record dont l’identifiant est 3$record = $maFactory->get(3);

// on modifie le record$record->champ1 = "hello";$record->champ2 = "...";

// on le sauvegarde dans la base$maFactory->update($record);

Destruction

Il suffit d’appeler la méthode delete en donnant l’id du record à détruire

// instanciation de la factory$maFactory = jDao::get("foo");

// destruction du record dont l’identifiant est 3$maFactory->delete(3);

13.3 Ajouter des méthodes en XML

Une factory générée par jDao contient par défaut un certain nombre de méthodes (find, findAll, get, insert, etc...)comme décrit sur la page sur l’utilisation des daos. Cependant, elles ne sont pas forcément suffisantes, et l’on asouvent besoin de faire des sélections, des mises à jour ou des suppressions particulières.

La section <factory> permet de définir des méthodes supplémentaires à générer, chacune des méthodes exécutantune requête SQL. L’avantage de déclarer de telles méthodes ici, par rapport à la création de requête SQL dans uneclasse normale, est que vous n’avez plus à vous préoccuper de problème de sqlinjection, de l’écriture fastidieuse desrequêtes SQL, etc...

Page 94: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

87 / 225

13.3.1 Balise <method>

Les méthodes sont déclarées via la balise <method>. Celle-ci doit avoir au moins un attribut, name, indiquant lenom de la méthode. Il y a différent type de méthode. On indique le type via l’attribut type.

Une balise <method> peut contenir une ou plusieurs balises <parameter>, qui définissent des paramètres. Unebalise <parameter> doit avoir un attribut name indiquant son nom.

<parameter name="foo" />...

Il est possible d’indiquer une valeur par défaut :

<parameter name="foo" default="20"/>

Voici les différents types de méthodes. La balise <conditions> est décrite plus loin.

13.3.2 Méthode de type select, selectfirst

Déclaration

<method type="select"> <!-- ou type="selectfirst" --><parameter /><conditions /><order /><limit />

</method>

Une méthode de type select renvoient une liste d’objets "record", qui ont donc comme propriétés celles indiquéesdans la section record. Une méthode de type selectfirst renvoi le premier objet correspondant aux critères.

À noter qu’il n’est pas possible de limiter un select/selectfirst à un nombre réduit de propriétés. En effet, cela n’auraitpas vraiment de sens au niveau du concept de "mapping" et serait même dangereux pour les données puisqu’alorsles propriétés non sélectionnées seraient vides dans le record, et si on fait ensuite un update derrière... Si on veutsélectionner un nombre restreint des propriétés définies, la seule possibilité pour le moment est de créer un autreDAO.

On peut ajouter un attribut distinct pour récupérer seulement les éléments distincts.

<method type="select" name="findThem" distinct="true">..

La balise <conditions> (facultative) décrit une condition (la clause WHERE en SQL). Voir la section correspondanteplus loin.

On peut aussi ajouter une balise <order> qui permet de spécifier l’ordre des enregistrements récupérés (clauseORDER en SQL). Il faut indiquer une ou plusieurs balises <orderitem>, qui contiennent un attribut property indiquantle nom de la propriété sur lequel l’ordre s’effectue et un attribut way. L’attribut way doit contenir "asc" ou "desc" ouun nom de paramètre de méthode (précédé alors par un $).

<order><orderitem property="foo" way="asc" />

</order>

À noter que property peut contenir, soit un nom d’une propriété, soit un nom de paramètre de la méthode (précédéd’un $) qui doit alors contenir un nom de propriété.

Enfin, une balise <limit> optionnelle permet de restreindre le nombre d’enregistrement retournés.

Page 95: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

88 / 225

<limit offset="5" count="10" />

Les attributs count et offset contiennent soit un nombre, soit un nom de paramètre de méthode (précédé alors par un$).

<method type="select" name="getFewRecord" ><parameter name="count"/><parameter name="offset"/><limit offset="$offset" count="$count"/>

</method>

Utilisation

L’utilisation des méthodes déclarées en XML a été pensée pour être transparente vis-à-vis du développeur qui n’apas envie de se soucier de la déclaration du DAO.

Reprenons notre méthode getFewRecord. On veut normalement récupérer un tableau en PHP afin de manipuler plusfacilement les enregistrements. Rien de plus simple :

$dao = jDao::get(’module~list’); // Récupèration du DAO si ce n’est pas fait$records = $dao->getFewRecord(10, 5); // Appel de la méthode XML avec ses ←↩

arguments et récupération des données

foreach ($records as $record) // Parcours des donnéesjLog::log($record->name); // Accès au champ "name" d’un enregistrement

Ainsi, pour chaque méthode XML ajoutée dans le DAO, une méthode est générée et utilisable directement via PHP.Comme pour toute requête SQL, il ne faut pas oublier de "fetcher" les données.

13.3.3 Méthode de type count

<method type="count"><parameter /><conditions />

</method>

ce type de méthode est équivalent à un SELECT COUNT(*), avec les conditions indiquées. Si on indique unepropriété sur laquelle il faut faire un distinct, via l’attribut distinct comme pour type="select", alors il sera fait unSELECT COUNT(DISTINCT le_champ_correspondant).

13.3.4 Méthode de type delete

<method type="delete"><parameter /><conditions />

</method>

Génère une méthode qui execute une requête DELETE.

13.3.5 Méthode de type update

<method type="update"><parameter /><conditions /><values />

</method>

Page 96: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

89 / 225

Ce type de méthode exécute une requête de type UPDATE. En plus des paramètres et des conditions, il faut indiquerles valeurs que l’on met sur telle ou telle propriété avec les balises <value>.

<values><value property="foo" value="" expr=""/>

</values>

L’attribut property indique la propriété que l’on va mettre à jour. Comme dans les conditions, l’attribut value doitcontenir une valeur. Mais si on veut indiquer une expression SQL ou un paramètre de la méthode, il faut utiliserl’attribut expr.

13.3.6 Clause conditions

Voici la description de la balise <conditions> qui peut être utilisée dans la plupart des méthodes précédentes.

<conditions logic="AND"><eq property="foo" value="" expr=""/><neq property="foo" value="" expr=""/><lt property="foo" value="" expr=""/><gt property="foo" value="" expr=""/><lteq property="foo" value="" expr=""/><gteq property="foo" value="" expr=""/><like property="foo" value="" expr=""/><isnull property="foo"/><isnotnull property="foo"/><in property="foo" value="" expr=""/><notin property="foo" value="" expr=""/>

</conditions>

On peut mettre plusieurs balises <conditions> imbriquées pour faire des groupes or/and. Si l’attribut logic n’est passpécifié, il vaut AND par défaut. Sinon il doit valoir "OR" ou "AND".

L’attribut value doit contenir une valeur. Le type de cette valeur est celui de la propriété. Si on préfère utiliser uneexpression SQL ou indiquer un paramètre de méthode, il faut utiliser l’attribut expr.

Cas de in/notin

<in> et <notin> sont les équivalents de foo IN (a, b, c) et foo NOT IN (a, b, c). L’usage devalue et expr est différente. Si vous avez une liste de valeurs statiques, vous les mettrez dans l’attribut valuecomme vous le feriez en SQL :

<in property="foo" value="5,3,2" />

ou

<in property="foo" value="’toto’,’titi’,’tata’" />

Vous utiliserez expr quand vous aurez un paramètre de méthode (donc une liste de valeurs dynamiques) :

<in property="foo" expr="$liste" />

Ce paramètre doit obligatoirement contenir un tableau PHP de valeurs. Et l’attribut expr ne peut contenir autrechose qu’un nom de paramètre.

Page 97: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

90 / 225

13.4 Développer des méthodes en php

Les méthodes déclarées en XML permettent de créer facilement des méthodes, et peuvent répondre à beaucoup desituations. Néanmoins elles sont tout de même limitées dans la cadre de requêtes complexes. On ne peut pas créer desrequêtes complexes.

Une première solution serait de se créer une classe PHP classique, et utiliser jDb pour effectuer les requêtes. Cepen-dant, lorsque les enregistrements sur lesquels on opère correspondent à ce qui a déjà été défini dans un DAO, il estplus logique de pouvoir intégrer une telle méthode dans la factory d’un DAO.

13.4.1 Déclaration d’une méthode en PHP

C’est relativement simple à faire : il suffit de déclarer en XML une méthode de type "php" :

<method type="php" name="foo"><parameter name="bar" /><body><![CDATA[

ici le code php de la méthode]]></body>

</method>

Les autres balises autorisées dans les autres types de méthodes (conditions, order...) ne peuvent être utiliséesici, puisque vous êtes censés écrire vous même la requête SQL !

Vous devez indiquer bien sûr un nom à la méthode, et vous pouvez déclarer des paramètres comme d’habitude.

13.4.2 API interne d’une factory

Au niveau du code PHP, vous pouvez faire presque ce que vous voulez. Cependant :– pour respecter le pattern DAO, et si vous renvoyez des résultats d’enregistrement, vous devez renvoyer des objets

qui sont des records du même type que ceux définis dans la DAO. Le nom de la classe du record correspondant setrouve dans la propriété _DaoRecordClassName

– Pour effectuer les requêtes, vous devez utiliser l’objet jDbConnection placé dans la propriété _conn.– Vous avez à votre disposition d’autres propriétés et méthodes qui vous facilitent le travail d’écriture.

Manière de coder

Vous avez deux manières de réaliser les méthodes PHP :

1. soit vous écrivez des requêtes quasiment "en dur", statiques

2. soit vous créez les requêtes à partir des informations (comme les noms de tables, les noms des champs, les typesde champs etc...) stockées dans la factory et le record.

La première façon permet d’avoir un fonctionnement un peu plus performant, et peut être plus simple à écrire. Maisla deuxième évite d’avoir systématiquement à mettre à jour votre méthode quand vous modifiez certaines informationsdans la section datasources ou properties. Cependant notez qu’une fois en production, c’est la performancequi prime. À vous de choisir.

Avec la deuxième façon de réaliser les méthodes PHP, vous aurez besoin de lire les informations sur les tables et lespropriétés. Sachez que vous trouverez ces informations dans plusieurs propriétés :– $this->_primaryTable : l’alias de la table primaire,– $this->_tables : une liste d’informations (voir la documentation de référence pour la description détaillée),

Page 98: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

91 / 225

– $this->getProperties() pour avoir des informations détaillées sur chaque propriétés d’un record (voir ladocumentation de référence),

– $this->getPrimaryKeyNames() pour avoir la liste des noms des propriétés servant de clés primaires.Et sur un record que vous aurez préalablement instancié, vous aurez aussi les même méthodes getProperties()

et getPrimaryKeyNames().

Notes :– Pour les versions 1.0 beta 2.1 et inférieures, getPrimaryKeyNames() n’existait pas du tout (mais il y avait la

propriété $_pkFields équivalente sur la factory),– Pour les versions 1.0 beta 2.1 et inférieures, getProperties() n’existait que sur les records.

Préparer les valeurs

Toutes les valeurs qu’on vous passe en paramètre, vous devez les "filtrer", les préparer, avant de les intégrer dans unerequête SQL, ceci pour éviter des problèmes de sécurité type SQL injection.

Pour cela, vous avez une méthode, _prepareValue(), qui accepte en paramètre une valeur, et un nom de typede donnée (celle que l’on indique à l’attribut datatype de la balise property).

<method type="php" name="updateLabel"><parameter name="id" /><parameter name="label" /><body><![CDATA[

$sql = ’update products set label=’ . $this->_prepareValue($label,’string’ ←↩);

$sql.= ’ where product_id=’.$this->_prepareValue($id,’integer’);$this->_conn->exec($sql);

]]></body></method>

Ou encore

<method type="php" name="updateLabel"><parameter name="id" /><parameter name="label" /><body><![CDATA[

$sql = ’update ’.$this->_tables[$this->_primaryTable][’realname’];$sql.= ’ set label=’ . $this->_prepareValue($label,’string’);$sql.= ’ where product_id=’.$this->_prepareValue($id,’integer’);$this->_conn->exec($sql);

]]></body></method>

Faire des SELECTs

Normalement, quand vous faites des SELECT pour renvoyer un ensemble de résultats, vous devez retourner tousles champs déclarés dans les balises property, donc faire aussi les jointures explicitement décrites. Et il faut aussiretourner les résultats sous la forme des objets correspondants aux records. Pour éviter d’avoir à réécrire entièrementles requêtes, il y a une série de propriétés indispensables :– _selectClause : comporte la clause SELECT avec l’ensemble des champs déclarés– _fromClause : comporte la clause FROM avec la déclaration des tables et des jointures externes– _whereClause : comporte la clause WHERE avec les jointures internesUne méthode qui renverrait un ensemble de résultats pourrait ressembler à ceci (ce type de requête pourrait être très

bien réalisé via les méthodes en XML, mais la complexité de la requête n’est pas l’objectif ici) :

Page 99: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

92 / 225

<method type="php" name="findByPrice"><parameter name="price" /><body><![CDATA[

$sql = $this->_selectClause.$this->_fromClause.$this->_whereClause;$sql .= ($this->_whereClause == ’’?’ WHERE ’:’ AND ’);$sql .= ’ price = ’. $this->_prepareValue($price,’float’);$sql .= ’ ORDER BY label ASC’;

$rs = $this->_conn->query($sql);$rs->setFetchMode(8,$this->_DaoRecordClassName);return $rs;

]]></body></method>

– _whereClause peut être vide ou pas, c’est pourquoi il faut toujours tester,– On a préparé la valeur avec _prepareValue(), ainsi on "protège" la requête,– On a utilisé $this->_conn pour faire la requête, et on récupère donc un jDbRecordSet,– Indispensable : on fait un setFetchMode(), pour indiquer le nom de la classe des objets qui contiendront les

enregistrements ! On y indique donc la classe des record du DAO,– Enfin on retourne directement le recordSet : puisque jDbRecordSet implémente Iterator, on peut l’utiliser directe-

ment dans une boucle foreach, et on n’a donc pas besoin de créer une liste intermédiaire.

Récupération d’un seul enregistrement

C’est un peu le même principe que pour récupérer un ensemble :

<method type="php" name="findByLabel"><parameter name="label" /><body><![CDATA[

$sql = $this->_selectClause.$this->_fromClause.$this->_whereClause;$sql .= ($this->_whereClause == ’’?’ WHERE ’:’ AND ’);$sql .= ’ price = ’. $this->_prepareValue($label,’string’);

$rs = $this->_conn->query($sql);$rs->setFetchMode(8,$this->_DaoRecordClassName);

$record = $rs->fetch();return $record;

]]></body></method>

Notez le fetch().

13.4.3 Faire d’autres requêtes

Pour faire des UPDATE, DELETE, INSERT, rien de spécial à dire. Vous ne pouvez bien entendu pas utiliser _sel-ectClause, _fromClause et _whereClause.

Vous avez par contre une méthode qui peut être utile pour les UPDATE et DELETE : _getPkWhereClauseFo-rNonSelect(). Elle génère une condition pour la clause WHERE sur les clés primaires.

<method type="php" name="updateLabel"><parameter name="id" /><parameter name="label" /><body><![CDATA[

Page 100: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

93 / 225

$sql = ’update products set label=’ . $this->_prepareValue($label,’string’ ←↩);

$keys = array_combine($this->getPrimaryKeyNames(), array($id));$sql.= $this->_getPkWhereClauseForNonSelect($keys);

$this->_conn->exec($sql);]]></body>

</method>

Même si l’intérêt est limité quand il y a une seule clé primaire, il augmente quand il y en a plusieurs.

Note :– Pour les versions de Jelix 1.0 beta 2.1 et inférieures, vous deviez utiliser $this->_pkFields au lieu de $th-is->getPrimaryKeyNames().

13.5 Évènements automatiques

Une factory de DAO peut générer automatiquement des évènements pour certains types de méthodes.

13.5.1 Évènements des méthodes natives

Les méthodes update, insert, delete et deleteby peuvent générer des évènements, soit avant la fonction, soit après lafonction, soit avant et après. Pour les activer, il faut indiquer les évènements voulus dans l’attribut events de la balisefactory. Ils doivent être séparés par une virgule. Les noms possibles sont : deletebefore, deleteafter, updatebefore,updateafter, insertbefore, insertafter, deletebybefore, deletebyafter.

Voici les noms des évènements générés avec les noms de leurs paramètres, sachant qu’ils ont tous un paramètre daoqui contient le sélecteur du dao.– daoDeleteBefore : key (valeurs des clés du record à supprimer)– daoDeleteAfter : key, result (1 si l’enregistrement est supprimé)– daoDeleteByBefore : key, criterias (objet jDaoConditions)– daoDeleteByAfter : key, criterias, result (nombre d’enregistrements supprimés)– daoUpdateBefore : record (objet record à mettre à jour)– daoUpdateAfter : record– daoInsertBefore : record– daoInsertAfter : recordExemple :

<factory events="deleteAfter, insertAfter"> ...

Et un listener possible :

class myListener extends jEventListener{

function onDaoDeleteAfter ($event) {$dao = ;if ($event->getParam(’dao’) == ’mymodule~thedao’) {

$key = $event->getParam(’key’);//...

}}

Page 101: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

94 / 225

13.5.2 Évènements des methodes personnalisées

Pour les méthodes personnalisées (celles que vous décrivez en XML), et uniquement les méthodes de type update oudelete, vous pouvez indiquer l’attribut eventbefore, et/ou eventafter qui doivent contenir true ou false.

Les évènements générés sont alors daoSpecificUpdateBefore, daoSpecificUpdateAfter, daoSpecificDeleteBefore etdaoSpecificDeleteAfter. Ils ont pour paramètre– dao, contenant le selecteur du dao conçerné– method, le nom de la méthode– params, contenant la liste des paramètres.

Page 102: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

95 / 225

Chapitre 14

Formulaires classiques

Créer et gérer des formulaires "à la main" (par opposition aux automatismes offert par le système de formulairejForms), n’est pas trés différent par rapport à ce que l’on fait dans une application PHP classique. Quelques petiteschoses sont cependant à savoir pour profiter au mieux de ce qu’offre Jelix dans ce cas.

14.1 Les actions à mettre en oeuvre

L’implémentation très simpliste d’un formulaire consistera au développement de deux actions (les noms sont pure-ment fictifs et servent juste d’exemple) :– une action "show" d’affichage de formulaire– une action "save" qui traite les données du formulaire (après le submit) et affiche le résultatMais dans la plupart des cas, pour répondre correctement aux erreurs, pour éviter que l’utilisation des boutons

"refresh" des navigateurs provoque une nouvelle exécution du traitement des données (action "save"), etc..., il vautmieux avoir ce genre de liste d’actions :– une action "prepare" qui prépare les données pour un nouveau formulaire (initialisation en session par exemple,

avec lecture des données initiales en base de données par exemple) et redirige vers "show"– une action "show" qui affiche le formulaire avec les données en sessions, et affiche les éventuelles erreurs de saisie.– une action "save" qui vérifie les données saisies. Si il y a des erreurs, les sauve en session et redirige vers "show",

ou alors sauve les données et redirige vers "end"– une action "end", qui nettoie les données en session, et affiche une page de confirmation, ou redirige vers une autre

action quelconque...

14.2 Création d’un formulaire

Vous utiliserez en général un template, dans lequel vous y mettrez vos balises html de formulaires. Par exemple :

<form action="index.php" method="POST"><fieldset> <legend>Indiquez votre identité</legend>

<input type="hidden" name="module" value="monmodule" /><input type="hidden" name="action" value="default_save" /><table><tr>

<td><label for="champs-nom">Votre nom</label></td><td><input type="text" name="nom" id="champs-nom" /></td>

</tr><tr>

Page 103: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

96 / 225

<td><label for="champs-prenom">Votre prénom</label></td><td><input type="text" name="prenom" id="champs-prenom" /></td>

</tr></table>

</fieldset><p><input type="submit" value="Valider" /></form>

Vous pouvez bien sûr y ajouter du javascript pour vérifier les données saisies coté client et utiliser tous les types dechamps de saisies HTML.

Par contre, l’exemple n’est pas totalement bon, dans la mesure où l’url est en dur dans le formulaire. Cela estproblématique par exemple quand on utilise des urls significatives, qu’on les change, ou qu’on veuille réutiliser dansun autre projet. En effet, suivant l’url choisie, le contenu de l’attribut action peut être différent, le nombre de champscachés aussi.

Il est donc préférable d’utiliser les plugins de templates formurl et formurlparam, auxquels vous indiquez le sélec-teur de l’action de traitement du formulaire, et de la liste des paramètres (comme quand vous appelez jUrl : :get()). Lepremier sert à générer l’url à mettre dans l’attribut action, et l’autre à générer les champs cachés contenant les éven-tuels paramètres supplémentaires propres à l’action. Vous devez toujours utiliser les deux ensembles. Le formulairedevient alors :

<form action="{formurl ’monmodule~default:save’}" method="POST"><fieldset> <legend>Indiquez votre identité</legend>

{formurlparam ’monmodule~default:save’}<table>...</table>

</fieldset><p><input type="submit" value="Valider" /></form>

Le formulaire résultant sera le même que le premier exemple si le moteur d’url est celui par défaut, mais pourraitdevenir le formulaire suivant si le moteur d’url significant est activé et que l’url correpondante à l’action indiquée est/user/save (sans paramètres supplémentaires, d’où l’absence ici de champs cachés) :

<form action="/user/save" method="POST"><fieldset> <legend>Indiquez votre identité</legend>

<table>...</table>

</fieldset><p><input type="submit" value="Valider" /></form>

14.3 Traitement des données en retour

Dans l’action servant à traiter les données, vous récupèrerez celles-ci grâce à $this->param(’champs’) dans votrecontrôleur. Vous avez d’autres méthodes similaires, comme $this->intParam(’champs’), $this->floatParam(’champs’)et $this->boolParam(’champs’), qui permettent de récupérer directement les valeurs sous un type particulier (voir lapage sur les contrôleurs).

Vous pouvez utiliser en plus jFilter, qui est une classe permettant de vérifier le format des données (utilise l’extensionfilter quand Jelix est généré pour PHP 5.2). exemple :

Page 104: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

97 / 225

function save() {$email = $this->param(’email’);if ($email === null) {

//.. ici erreur, l’email est obligatoire}if( ! jFilter::isEmail($email)){

// erreur, email mal saisie}//....

}

Voir la documentation de référence de jFilter

Page 105: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

98 / 225

Chapitre 15

jForms : des formulaires automatiques

jForms est un système complet qui facilite le travail du développeur pour créer des formulaires. Vous décrivez votreformulaire dans un fichier xml, et par le biais d’une API relativement simple et de plugins de template, jFormss’occupe automatiquement :– de générer le formulaire HTML, en affichant des indications sur les champs qui sont en erreur, des indications sur

les champs obligatoires, l’aide sur chaque champ, sachant que l’affichage est hautement personnalisable.– de générer les labels en tenant compte de l’accessibilité– de générer le code javascript qui validera les données coté client– de valider les données saisies côté serveur– d’afficher les erreurs au niveau du formulaire, soit après validation en javascript, avant l’envoi du formulaire, soit

lors de l’affichage du formulaire (après la validation côté serveur)– de gérer plusieurs instances d’un même formulaire en même temps (permettant d’éditer plusieurs enregistrements

en même temps)– d’initialiser un formulaire à partir de données d’un ou plusieurs DAO (que ce soit au niveau des valeurs des

champs, ou du remplissage de listbox, liste de boutons radio etc)– de sauver les données saisies dans des DAOs– de sauvegarder les fichiers uploadésDans Jelix 1.1, jForms pourra aussi :– générer d’autres types de formulaires (en ajax, XUL, XForms etc...) sans changer une seule ligne de code, par le

biais de plugins.– de prendre en charge automatiquement des champs de type captchas– d’afficher des champs d’édition WYSIWYG– et bien d’autres choses ;-)jForms est composé de trois parties distinctes :– Des fichiers xml qui permettent de décrire vos formulaires.– l’API côté serveur qui permet de créer une instance d’un formulaire et de gérer les données qu’il contient– des plugins de templates pour afficher une instance d’un formulaire.À partir d’un fichier jforms XML, jForms gère un objet (héritant de jFormsBase) créé à partir des informations

contenues dans le fichier XML, et permettant d’initialiser le contenu du formulaire, de gérer son contenu, de lesauvegarder etc. Par conséquent il contient toutes les valeurs saisies, stockées dans des variables de cet objet (variablesde formulaire).

C’est aussi à partir d’un objet jforms que des plugins de templates permettent d’afficher les éléments HTML corres-pondant.

Page 106: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

99 / 225

15.1 Format des fichiers jForms

jForms se base sur des fichiers descriptifs en XML. Tout formulaire est décrit en XML, avec une grammaire assezsimple, à mi-chemin entre HTML et XForms.

Ces fichiers XML sont à placer dans un répertoire forms des modules et doivent avoir comme nom foo.form.xml,où foo est le nom identifiant du formulaire (que vous choisissez bien sûr). Cet identifiant est utilisé ensuite dans lessélecteurs.

Par exemple "monModule~produit" fait référence au formulaire monModule/forms/produit.form.xml.– Format version 1.0

15.1.1 Format version 1.0

La version 1.0 du format décrit dans cette page est utilisable depuis Jelix 1.0. Dans les betas de Jelix 1.0, il estpossible que certains des attributs ou balises n’étaient pas disponibles, mais ces différences ne sont plus documentées.

Structure principale

Le document XML que vous écrivez dans un fichier jForms est composé d’une balise <form> comme racine.

<?xml version="1.0" encoding="utf-8"?><form xmlns="http://jelix.org/ns/forms/1.0">

</form>

Dans cette balise, vous indiquerez les balises correspondantes à chacun des contrôles (champs de saisies) composantle formulaire. Le traitement et l’affichage de ces contrôles se feront dans le même ordre que celui de leur apparitiondans le document.– *Notez que le namespace pour cette version du format est http ://jelix.org/ns/forms/1.0**

Propriétés communes aux contrôles

Identifiant

Chaque contrôle doit avoir un identifiant (= un nom). Vous devez en indiquer un avec l’attribut ref. Cet identifiantcorrespond en fait à ce qu’on appelle une variable de formulaire et qui contiendra la valeur saisie.

Exemple :

<input ref="nom"></input>

Note : quand vous voulez utiliser un formulaire avec un ou plusieurs DAO, il est judicieux d’utiliser les mêmes nomsque les propriétés des DAO, afin de pouvoir utiliser les mécanismes de chargement et sauvegarde automatique dejForms avec les DAO.

Libellé

Tout champ de saisie doit contenir un libellé indiqué au moyen de la balise <label> :

<input ref="nom"><label>Votre nom</label>

</input>

Page 107: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

100 / 225

On peut indiquer une locale plutôt qu’une chaîne "en dur" :

<input ref="nom"><label locale="mymodule~forms.input.name"/>

</input>

Messages informatifs

Un message d’aide (optionnel) peut être affiché en même temps que le contrôle de saisie, grâce à la balise <help> :vous y inscrivez soit le message d’aide, soit la locale (via l’attribut locale).

<input ref="datenaissance" type="date"><label locale="mymodule~forms.input.naissance"/><help>Indiquez votre date de naissance, en respectant le format aaaa-mm-jj</ ←↩

help></input>

ou

<input ref="datenaissance" type="date"><label locale="mymodule~forms.input.naissance"/><help locale="mymodule~forms.input.naissance.help"/>

</input>

Dans les formulaires en HTML, un point d’interrogation s’affichera à côté du champ de saisie et le message d’aides’affichera lors d’un clique sur ce point d’interrogation.

Un autre type de message informatif peut être affiché sous forme de tooltip. Il faut pour cela utiliser la balise <hint>,qui s’utilise comme la balise <help>.

Messages d’erreurs

Quand le contenu du champs de saisie est invalide, ou que la saisie est manquante alors qu’elle est requise, jFormsaffiche des messages d’erreurs prédéfinis. Cependant vous pouvez fournir vous même ces messages au moyen de labalise <alert>. Un attribut type permet de définir soit le message pour l’erreur d’invalidité, soit le message pour lasaisie obligatoire. Et comme les balises précédentes, vous pouvez indiquer le message complet, ou indiquer une localeau moyen de l’attribut locale.

<input ref="datenaissance" type="date"><label locale="mymodule~forms.input.naissance"/><alert type="required" locale="mymodule~forms.input.naissance.error.required" ←↩

/><alert type="invalid">Le format de la date à respecter pour la saisie est aaaa ←↩

-mm-jj</alert></input>

Saisie obligatoire

Pour rendre la saisie obligatoire sur un champ de saisie, il faut mettre l’attribut required avec la valeur true. Cetattribut n’est pas valable sur l’élement <submit>, <checkbox> et <output>.

Lecture seule

Il est possible d’empêcher la modification d’un champ de saisie (c’est toutefois rare d’avoir à le faire). Pour cela, ilfaut mettre l’attribut readonly avec la valeur true. Cet attribut n’est pas valable sur l’élément <submit> et <output>.

Page 108: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

101 / 225

Champs de saisie

Saisie de texte simple

Pour afficher un simple champs de saisie, il faut utiliser la balise <input>. Vous devez y mettre l’attribut ref, et vouspouvez utiliser les balises <label>, <hint>, <alert>, <help> ainsi que les attributs readonly et required. Vous pouvezindiquer aussi cinq attributs supplémentaires : type, defaultvalue, size, minlength et maxlength.– *defaultvalue** permet d’indiquer une valeur par défaut qui sera affichée quand le formulaire est vide. Vous

pouvez mettre la valeur "now" pour les champs de saisies de dates. La valeur par défaut sera alors la date demaintenant.

– *size** permet d’indiquer la largeur de la boite de saisie en nombre de caractères.

– *maxlength et minlength** permet d’ajouter une contrainte sur la valeur saisie : la longueur minimale et maximalede la chaine de caractère saisie. Ces deux attributs ne sont utilisables que pour le type="string".

– *type** permet d’indiquer le format de donnée que l’utilisateur doit respecter. Au moment de l’envoi du formu-laire, il y aura une vérification en javascript du contenu saisie, mais aussi une vérification coté serveur (au cas oùle javascript est désactivé notamment) lors de l’appel à la méthode check() sur l’objet formulaire.

Voici les valeurs possibles pour l’attribut type et ce que doit taper l’utilisateur :– "string" : chaîne contenant n’importe quel caractère. (c’est le type par défaut)– "boolean" : la valeur du champs doit être obligatoirement "true" ou "false"– "decimal" : un nombre avec ou sans virgule– "integer" : un nombre entier– "hexadecimal" : un nombre hexadecimal (chiffres de 0 à 9 et lettres de a à f)– "datetime", "date", "time" : une date et heure, une date ou une heure. Le format précis est respectivement "aaaa-

mm-jj hh :mm :ss", "aaaa-mm-jj", "hh :mm :ss".– "localedatetime", "localedate", "localetime" : une date et heure, une date ou une heure, mais dans le format de la

langue de l’utilisateur. Par exemple, pour un site en français, le format de la date devra être "jj/mm/aaaa", et pourun site en anglais "mm/jj/aaaa".

– "url" : la chaîne doit être une URL valide– "email" : un email– "ipv4" : une adresse IP v4– "ipv6" : une adresse IP v6Un exemple de champs de saisie simple :<input ref="email" type="email">

<label locale="monmodule~monform.email.label" /><hint>L’email doit être valide</hint>

</input>

Saisie de texte multiligne

Pour permettre la saisie d’un texte de plusieurs lignes, il faut utiliser la balise <textarea>. Vous devez y mettrel’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>, <help> ainsi que les attributs readonly etrequired. Il y a plusieurs attributs spécifiques à cette balise : defaultvalue, rows, cols, minlength et maxlength.– *defaultvalue permet d’indiquer une valeur à afficher automatiquement pour un nouveau formulaire, tandis

que rows et cols** permettent de fixer la taille du champs de saisie en hauteur et largeur (comme le textarea enHTML).

Un exemple :<textarea ref="message">

<label locale="monmodule~monform.message.label" /><hint>Saisissez ici le message</hint>

</textarea>

Page 109: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

102 / 225

– *maxlength et minlength** permettent d’ajouter une contrainte sur la valeur saisie : la longueur minimale etmaximale de la chaine de caractères saisie.

Mot de passe

Pour la saisie d’un mot de passe ou tout autre renseignement qui doit être caché lors de la saisie, vous utiliserezla balise <secret>. Vous devez y mettre l’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>,<help> ainsi que les attributs readonly et required.

<secret ref="password"><label>Votre mot de passe</label><hint>Indiquez le mot de passe que l’on vous a donné à l’inscription</hint>

</secret>

Vous pouvez utiliser l’attribut size pour indiquer la largeur du champs de saisie.

Il est souvent utile de demander à l’utilisateur de saisir une deuxième fois un nouveau mot de passe, lors d’uneinscription par exemple. jForms gère cela automatiquement. Il suffit d’indiquer la balise <confirm> dans la balise<secret>, et le formulaire HTML généré contiendra deux champs de saisie. La balise <confirm> doit contenir soitl’intitulé du libellé pour la confirmation, soit un attribut locale contenant le selecteur de la locale pour le libellé de laconfirmation.

<secret ref="newpassword"><label>Mot de passe</label><hint>Indiquez un nouveau mot de passe</hint><confirm>Retapez ce mot de passe</confirm>

</secret>

Cela génèrera en gros, pour un formulaire html :

<label for="newpassword">Mot de passe</label><input type="password" id="newpassword" name="newpassword" title="Indiquez ←↩

un nouveau mot de passe"/>

<label for="newpassword_confirm">Retapez ce mot de passe</label><input type="password" id="newpassword_confirm" name="newpassword_confirm" ←↩

/>

Case à cocher seule

Pour afficher une case à cocher, utiliser la balise <checkbox>. Vous devez y mettre l’attribut ref, et vous pouvezutiliser les balises <label>, <hint>, <alert>, <help> ainsi que l’attribut readonly (mais pas required).

<checkbox ref="souvenir"><label>Se souvenir de moi</label><help>Cochez cette case si vous voulez être identifié automatiquement la ←↩

prochaine fois</help></checkbox>

Par défaut, la valeur de la case à cocher, que vous récupèrerez une fois le contenu du formulaire reçu, vaudra 0 si lacase n’a pas été cochée, ou 1 si elle l’a été.

Vous pouvez décider d’autres valeurs pour chacun de ces deux états. Il suffit d’indiquer les attributs valueonchecket valueonuncheck (qui valent donc par défaut, respectivement 1 et 0). Exemple :

Page 110: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

103 / 225

<checkbox ref="souvenir" valueoncheck="O" valueonuncheck="N"><label>Se souvenir de moi</label><help>Cochez cette case si vous voulez être identifier automatiquement la ←↩

prochaine fois</help></checkbox>

Notez que lorsque vous afficherez un formulaire prérempli, la case sera cochée ou non en fonction de la valeurinitiale, selon que celle-ci corresponde à la valeur de valueoncheck ou de valueonuncheck.

Liste de cases à cocher

On peut avoir à afficher une série de case à cocher qui correspondent à des choix multiples, par exemple afficherune liste de choses à acheter, et l’utilisateur coche les articles qu’il veut acheter. Pour cela on utilisera la balise<checkboxes> (avec un S à la fin).

Vous devez y mettre l’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>, <help> ainsi que lesattributs readonly et required.

Il vous faut aussi indiquer la liste des valeurs possibles et leurs libellés. Voir la section "sources de données" plusbas.

Exemple :

<checkboxes ref="articles"><label>Sélectionnez les articles que vous voulez acheter :</label><item value="54">sucre</item><item value="27">steack</item><item value="32">jus d’orange</item>

</checkboxes>

Ceci affichera une série de trois cases à cocher, ayant pour intitulé "sucre", "steack" et "jus d’orange". Quand leformulaire sera envoyé au serveur, la valeur que vous recevrez pour la variable de formulaire "articles", sera untableau PHP contenant les valeurs des case qui ont été cochée. Par exemple, si l’utilisateur a coché "steack", cotéserveur vous recevrez array(27). Si il a en plus coché "sucre", vous recevrez array(54, 27).

(voir la page sur la gestion du contenu d’un formulaire coté serveur)

Boutons radios

Les boutons radios vont toujours par groupe, d’au moins 2. Pour déclarer un groupe de boutons radio, vous utiliserezla balise <radiobuttons>.

Vous devez y mettre l’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>, <help> ainsi que lesattributs readonly et required. Comme pour les autres contrôles de type liste, vous devez indiquer la liste des valeurspossibles et leurs libellés. Voir la section "sources de données" plus bas.

Exemple :

<radiobuttons ref="couleur"><label>Couleur de votre voiture:</label><item value="r">Rouge</item><item value="b">Bleue</item><item value="v">Verte</item><item value="j">Jaune</item>

</radiobuttons>

Ceci affichera une série de 4 boutons radio, et la valeur choisie sera stockée dans la variable de formulaire "couleur".

Page 111: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

104 / 225

Liste déroulante

La balise <menulist> affiche une liste déroulante (<select size="1"> en HTML), et de par sa nature, un seul choixest possible. Vous devez y mettre l’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>, <help>ainsi que les attributs readonly et required. Comme pour les autres contrôles de type liste, vous devez indiquer la listedes valeurs possibles et leurs libellés. Voir la section "sources de données" plus bas.

Exemple :

<menulist ref="ville"><label>votre ville :</label><item value="75000">Paris</item><item value="37000">Tours</item><item value="44000">Nantes</item><item value="69000">Lyon</item>

</menulist>

La variable de formulaire contiendra la valeur de l’item sélectionné.

Liste non déroulante

Les listes déroulantes, ou encore listbox (Équivalent de la balise <select> en HTML), sont déclarées au moyende balise <listbox>. Vous devez y mettre l’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>,<help> ainsi que les attributs readonly et required. Comme pour les autres contrôles de type liste, vous devez indiquerla liste des valeurs possibles et leurs libellés. Voir la section "sources de données" plus bas.

<listbox ref="rubrique"><label>Rubrique préférée :</label><item value="1">Tutoriels</item><item value="2">Manuels</item><item value="3">Forums</item>

</listbox>

Vous pouvez indiquer un attribut size qui permet d’indiquer le nombre d’items affichables en même temps (donc lahauteur de la liste). Par défaut, elle vaut 4.

Par défaut, un seul choix est possible. Cependant en ajoutant l’attribut multiple="true", l’utilisateur pourra sélec-tionner plusieurs éléments de la liste (dans une page HTML, il faut que l’utilisateur appuie sur la touche CTRL enmême temps qu’il clique sur un item). Dans ce cas, dans la variable de formulaire "rubrique", au lieu d’avoir unesimple valeur correspondant à l’item sélectionné, vous aurez un tableau PHP avec toutes les valeurs des items choisis.

Upload de fichier

Pour permettre à l’utilisateur de télécharger un fichier vers le serveur, vous pouvez utiliser la balise <upload> (équi-valent de <input type="file"> en HTML). Comme pour les autres contrôles, vous devez y mettre l’attribut ref, et vouspouvez utiliser les balises <label>, <hint>, <alert>, <help> ainsi que les attributs readonly et required.

Deux attributs supplémentaires sont à votre disposition, pour contrôler la nature et la taille des fichiers, qui sontrespectivement mimetype (devant contenir un ou plusieurs type mime) et maxsize (taille en octets).

<upload ref="photo" mimetype="image/jpeg;image/png" maxsize="20000"><label>Votre photo</label>

</upload>

À la réception du fichier, jForms vérifie si il correspond au type et à la taille indiqués, et l’on peut ensuite lui indiquéoù stocker le fichier téléchargé. La variable de formulaire contiendra le nom du fichier.

Page 112: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

105 / 225

Boutons de validation

Dans un formulaire, il faut bien sûr au moins un bouton qui permette à l’utilisateur de valider la saisie et envoyer lesdonnées au serveur. Vous déclarez un bouton de ce type avec la balise <submit>. Comme pour les autres contrôles,vous devez y mettre l’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>, <help> (mais pas lesattributs readonly ni required).

<submit ref="submit"><label>Ok</label>

</submit>

La variable de formulaire correspondante ne contiendra rien d’intéressant. À moins que vous ayez besoin de plusieursboutons de soumission, représentant par exemple l’action à effectuer après l’envoi du formulaire comme un bouton"prévisualiser" et un autre "sauvegarder". Dans ce cas, vous utiliserez comme pour les autres contrôles de type liste,un dao ou les balises item :

<submit ref="valider"><label>Veuillez valider</label><item value="preview">Prévisualiser</item><item value="svg">Sauvegarder</item>

</submit>

Dans la variable de formulaire "valider", vous aurez alors la valeur "preview" ou "svg", et vous pourrez agir enfonction de ces valeurs dans le contrôleur. Au niveau du formulaire HTML, cela affichera deux boutons avec leurslibellés respectifs "Prévisualiser" et "Sauvegarder".

Bouton reset

Pour afficher un bouton reset avec jForms, il faut utiliser la balise <reset> :<reset ref="reinit">

<label>Réinitialiser</label></reset>

Affichage de valeurs

La balise <output> ne sert qu’à afficher une valeur. Cette dernière ne sera donc pas éditable. Cela peut être utilepour afficher un formulaire de tout un enregistrement sans pour autant éditer tout les champs. Vous devez y mettrel’attribut ref, et vous pouvez utiliser les balises <label>, <hint>, <alert>, <help> (mais pas les attributs readonly nirequired).

<output ref="categorie"><label>Catégorie</label>

</output>

Source de données

Les contrôles tels que menulist, listbox et radiobuttons, checkboxes contiennent plusieurs choix de valeurs pourl’utilisateur. Il convient donc d’indiquer dans ces contrôles la manière dont jForms va récupérer les valeurs et libellésde ces choix.

Il y a pour le moment trois façons de faire :1. indiquer ces choix en dur dans le fichier jForms (données statiques)2. indiquer un DAO qui permettra de les récupérer.3. indiquer une classe qui fournis ces données.

Page 113: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

106 / 225

Données statiques

Elles doivent être indiquées au moyen d’une ou plusieurs balises <item>. La valeur du choix doit être mis dans unattribut value. Le libellé du choix doit être mis en tant que contenu de la balise <item>, ou dans un fichier de locale etalors vous indiquez la locale au moyen de l’attribut locale. Si aucun label est indiqué, le label sera la valeur. Exemple :

<checkboxes ref="objets"><label>Vous avez </label><item value="maison">Une maison</item><item value="voiture" locale="mymodule~myform.item.car.label" /><item value="bateau"/>

</checkboxes>

Données dynamiques avec un DAO

Le contenu d’une liste peut être rempli grâce à un DAO. Vous devez alors indiquer au moins 3 attributs :

1. dao, indiquant le sélecteur de la DAO à utiliser

2. daomethod, indiquant la méthode de la DAO qui génère la liste des choix

3. daolabelproperty, indiquant quelle est la propriété de la DAO qui contient le libellé du choix

La valeur de chaque choix sera la valeur de la clé primaire de la DAO. Cependant, si vous voulez indiquer une autrepropriété de la DAO, vous pouvez l’indiquer dans l’attribut daovalueproperty.

Exemple :

<menulist ref="conf" dao="testapp~config"daomethod="findAll"daolabelproperty="cvalue"daovalueproperty="ckey">

<label>Sélectionnez l’élément de configuration à éditer</label></menulist>

Données dynamiques avec une classe

Si vous voulez fournir les données dynamiquement d’une autre manière que par un dao, vous pouvez créer une classe,qui devra implémenter l’interface jIFormDatasource. Elle sera stockée dans un répertoire classes/ d’un module, etvous l’indiquerez via l’attribut dsclass.

Exemple de classe :

class listDatas implements jIFormDatasource{

protected $formId = 0;

protected $datas = array();

function __construct($id){

$this->formId = $id;$this->datas = array(0 => ’test’,

1 => ’test 2’,2 => ’Id = ’. $id);

}

public function getDatas()

Page 114: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

107 / 225

{return ($this->datas);

}

public function getLabel($key){

if(isset($this->datas[$key]))return $this->datas[$key];

elsereturn null;

}

}

Et dans le fichier jforms :

<menulist ref="icone" dsclass="monmodule~listDatas"><label locale="elements.crud.label.icone" />

</menulist>

Autre source de données

Si l’utilisation d’un DAO, d’une classe ou de données statiques n’est pas suffisant pour vous, regardez la section"Définir les choix d’un champs à multiple choix" dans la page Utilisation de jforms.

Dans ce cas là, vous ne devez pas indiquer de balises <item> ou d’attributs dao*/dsclass.

Présélection de valeurs

Dans une liste de choix, il est possible d’indiquer des valeurs par défaut qui seront sélectionnées. Vous avez troisfaçons de le faire :

1. soit indiquer un attribut selected="true" sur chaque balise item voulue si vous utilisez celles-ci. Plusieurs itemspeuvent avoir un attribut selected seulement sur les listes de case à cocher (checkboxes), soit sur une listbox"multiple". Dans les autres cas, un seul item doit avoir l’attribut selected.

2. soit indiquer un attribut selectedvalue sur la balise du contrôle, en y stockant la valeur séléctionnée. Cependantvous ne pouvez indiquer qu’une valeur, donc un seul choix ne sera sélectionné par défaut

3. soit indiquer un element <selectedvalues> contenant des éléments <value>. Cette manière de faire est touteindiquée pour checkboxes et listbox en multiple, et quand la source de données est une dao.

Exemples :

<radiobuttons ref="home"><label>Vous habitez</label><item value="pa" selected="true">Paris</item><item value="ma">Marseille</item><item value="ly">Lyon</item><item value="br">Brest</item><item value="li">Lille</item><item value="bo">Bordeaux</item>

</radiobuttons>

<menulist ref="conf" selectedvalue="foo.bar"dao="testapp~config"daomethod="findAll"

Page 115: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

108 / 225

daolabelproperty="cvalue"daovalueproperty="ckey">

<label>Sélectionnez l’élément de configuration à éditer</label></menulist>

<listbox ref="objets" required="true" multiple="true"><label>Vous avez </label><item value="maison">Une maison</item><item value="voiture">Une voiture</item><item value="bateau">Un bateau</item><item value="assiette">Une assiette</item><selectedvalues>

<value>maison</value><value>bateau</value>

</selectedvalues></listbox>

15.2 Utiliser un formulaire dans un contrôleur

Les données d’un formulaire jforms sont stockées en sessions. On manipule ces données au travers d’un objet formu-laire, instance d’une classe héritant de jFormsBase. Cette classe est générée automatiquement à partir du fichier XMLque vous fournissez. Comme pour les DAOs, elle est stockée dans un cache évitant de la recréer à chaque utilisation.

Dans les contrôleurs, vous créez, récupérez et détruisez cet objet formulaire via les méthodes statiques de l’objetjForms.

15.2.1 Les actions à mettre en oeuvre

Comme il est déjà expliqué dans le guide sur les formulaires classiques, pour faire une gestion complète de la saisied’un formulaire, la création des actions suivantes est recommandée (les noms utilisés sont juste à titre d’exemple,vous utilisez les noms que vous voulez bien sûr) :– une action "prepare" qui crée une nouvelle instance d’un objet formulaire avec jforms. S’il faut pré-remplir le

formulaire, cette action devra le faire aussi. Redirection vers "show".– une action "show" qui récupère l’instance du formulaire, et l’utilise dans un template pour l’afficher avec les éven-

tuelles erreurs de saisie trouvées lors d’une validation précédente. La soumission du formulaire par l’utilisateurdirigera vers l’action "save".

– une action "save". l’instance du formulaire est récupérée auprès de jForms, et elle est remplie avec les donnéesreçues du navigateur. Elle pourra ensuite lancer la vérification des données dans le formulaire. Si il y a des erreurs,il y aura une redirection vers "show". Sinon on pourra traiter les données (sauvegarde en base de donnée parexemple) et ensuite rediriger vers "end"

– une action "end", qui détruira l’instance du formulaire jforms (ce qui effacera les données correspondantes en ses-sion), et affichera éventuellement une page de confirmation, ou alors redirigera vers une autre action quelconque...

15.2.2 Créer une instance d’un formulaire

Avant de pouvoir utiliser jForms, il faut bien sûr créer un fichier xml décrivant le formulaire, et il faut ensuite avanttoute utilisation, qu’une de vos actions crée une instance de votre formulaire. Cela se fait au moyen de la méthodestatique create de la classe jForms. Comme toutes les autres méthodes statiques de la class jForms, elle prend enpremier argument le sélecteur du fichier xml, et un deuxième argument facultatif qui est un identifiant de l’instance àcréer.

Page 116: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

109 / 225

En admettant que votre fichier xml soit "contact.form.xml" dans le module "main" :

$form = jForms::create("main~contact");

La variable $form contiendra un objet qui aura pour classe, celle créée lors de la lecture du fichier XML, et qui héritede jFormsBase. Vous utiliserez ensuite cette variable $form pour manipuler les données du formulaire.

Dans cette exemple, nous n’indiquons pas le deuxième paramètre. En effet celui-ci ne sert que lorsque l’on veutéditer des informations qui existent déjà. Par exemple, pour un formulaire pour éditer un produit qui est en base dedonnée, on indiquera l’identifiant de ce produit.

Pourquoi ? Avec un navigateur web, l’utilisateur a la possibilité d’ouvrir plusieurs pages à la fois. Il a donc la possi-bilité d’afficher plusieurs fois la même page qui afficherait par exemple ce formulaire d’édition de produit, mais avecà chaque fois un produit différent. Pour éviter qu’à chaque fois que l’on ouvre cette page, donc qu’à chaque fois quel’on créé une instance du formulaire jForms, on aille écraser les données en sessions du même formulaire d’un autreproduit ouvert en même temps, on donne un identifiant de formulaire. Ainsi il n’y a pas de collision des données dechaque instance de formulaire. On peut donner ce que l’on veut comme identifiant (une chaine, un nombre), et engénéral on donne l’identifiant de l’enregistrement SQL quand il s’agit de l’édition de ce genre d’information.

En admettant que votre fichier xml soit product.form.php dans le module shop, voici un exemple de création d’unformulaire pour éditer un produit existant.

$form = jForms::create("shop~product", $product_id);

Bien sûr, quand il s’agit d’afficher un formulaire vierge pour éditer un nouveau produit, il n’y a pas d’identifiant, etvous n’êtes pas obligé d’en donner un.

$form = jForms::create("shop~product"); // édition d’un nouveau produit

Pour l’exemple précédent avec le formulaire de contact, nous n’indiquons pas d’identifiant, car on émet l’hypo-thèse ici qu’il s’agit d’un formulaire pour que l’utilisateur envoi une demande de contact : ce sera donc toujours unformulaire vierge.

15.2.3 Initialisation d’un formulaire

Après la création d’un formulaire, il est peut être nécessaire de le pré-remplir.

Initialisation simple

Pour cela, vous utiliserez la méthode setData sur l’objet formulaire, qui accepte en argument, le nom du champ àpréremplir, et la valeur à lui donner :

$form->setData("prenom","Laurent");

Les valeurs peuvent être récupérées d’ailleurs, comme bon vous semble.

Initialisation avec un dao

Cependant, si vous voulez utiliser un dao, il existe un moyen rapide pour remplir un formulaire. La méthode init-FromDao() permet d’utiliser un DAO pour remplir plusieurs champs du formulaire. Il suffit d’indiquer à cette méthodele selecteur du dao à utiliser. Par défaut il prendra la valeur de l’identifiant du formulaire comme identifiant de l’enre-gistrement à récupérer. Mais vous pouvez indiquer un autre identifiant dans le deuxième argument.

$form = jForms::create("shop~product", $product_id);$form->initFromDao("shop~products");

Page 117: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

110 / 225

Ici le formulaire sera prérempli avec les valeurs de l’enregistrement dont la clé est $product_id, et le dao "shop~pro-ducts" sera utilisé pour cette lecture.

Cependant, seuls les champs de saisie qui ont le même nom que des propriétés du dao indiqué seront pré-rempli. Lesautres resteront vides.

Notez que vous pouvez utiliser plusieurs daos pour pré-remplir les champs. En effet on peut avoir besoin d’unformulaire qui contient des champs de saisie qui seront stockés dans plusieurs tables.

Initialisation d’un champs à choix multiple

Pour les champs <checkboxes> et <listbox multiple="true">, la valeur à initialiser n’est pas forcément une simplevaleur, mais une liste de valeurs qui correspondent à tous les choix qu’il faut pré-sélectionner. (Attention, on parlebien ici des valeurs présélectionnées, pas de la liste des choix).

On peut donc les initialiser avec setData, en leur passant un tableau contenant les valeurs des choix à présélectionner :$form->setData(’categories’, array(5, 8, 10));

En général cependant, ces listes de valeurs sont stockées dans une base de données, dans ce qu’on appelle une tablede jointure. C’est à dire une table qui fait la jointure entre deux tables, et dont la clé primaire est constituée de deux clésétrangères, l’une et l’autre appartenant à une autre table. Par exemple, on a une table pour les produits (’products’),une table pour les catégories de produits (’categories’), et si un produit peut appartenir à plusieurs catégories, il fautune table de jointure (’products_categories’), contenant les clés des produits et les clés des catégories qui sont enrelation (product_id et category_id).

Pour initialiser la listbox ou les cases à cocher, il va donc aller lire dans cette table ’products_categories’ les relations.Il existe pour cela une méthode, initControlFromDao() :

$form->initControlFromDao("categories", "shop~products_categories");

Le dao "shop~products_categories" sera utilisé pour lire les valeurs sélectionnées pour le champs catégories. jFormss’attend ici à ce que la première clé déclarée dans le dao corresponde à l’identifiant du produit, et la deuxième clé àl’identifiant des catégories. Si ce n’est pas le cas, il faut alors indiquer les noms de ces clés dans le dao, dans un arrayà passer en troisième paramètre :

$form->initControlFromDao("categories", "shop~products_categories", array(’ ←↩product_id’,’category_id’));

Vu qu’il s’agit dans cet exemple de la saisie d’un enregistrement product, et que l’identifiant du formulaire correspondà l’identifiant du produit, la valeur de cet identifiant sera utilisée comme critère de recherche dans la table, pourrécupérer les id de catégories correspondantes.

Définir les choix d’un champs à multiple choix

Dans le fichier xml jforms, vous avez vu que pour indiquer la liste des choix possibles dans un <menulist>, une<listbox>, un <radiobuttons> ou un <checkboxes>, vous pouviez indiquer une liste de valeurs statiques, ou un daoqui servira à récupérer les choix.

Il peut cependant arriver que cela soit insuffisant, et que le remplissage dépende de critères ou autre. Dans ce cas,vous n’indiquerez pas de balise <item> ni d’attribut dao* dans le fichier xml. Et vous indiquerez la liste des choixdans votre contrôleur, des manières suivantes.

// récupérez vos données dans un tableau associatif,$datas = array(...);

// on récupère le contrôle et on lui indique les données$form->getControl(’nom_du_control’)->datasource->datas = $datas;;

Page 118: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

111 / 225

$datas est un tableau dont les clés sont les valeurs des choix, et les valeurs sont les libellés des choix.

Note : ce remplissage doit se faire dans la même action que celle qui affiche le formulaire. Ces données sont perduesà la fin de l’action.

15.2.4 Récupérer une instance d’un formulaire

Dans une action spécifique, vous allez créer un formulaire avec jForms : :create(), mais dans d’autres actions, vousaurez besoin de récupérer le formulaire créé, pour en manipuler ses données. Pour cela il y a deux méthodes statiquesde jForms : get() et fill().

La méthode get() permet de récupérer simplement l’objet formulaire. Comme pour create(), vous indiquez un sélec-teur :

$form = jForms::get("shop~product");

Si vous aviez donné un identifiant à la création, il faudra le donner aussi ici (récupéré ici à partir des paramètres dela requête http) :

$product_id = $this->param(’id’);$form = jForms::get("shop~product", $product_id);

Note : la méthode get renvoie null si le formulaire n’existe pas. Cela veut probablement dire que l’utilisateur a étéà l’url de l’action courante sans passer par les urls de l’action qui a créé le formulaire. Il faudrait alors rediriger versces actions si $form est null. Ou alors créer directement le formulaire, ce qui peut être suffisant pour de simplesformulaires.

$form = jForms::get("main~contact");if ($form === null) {

$form = jForms::create("main~contact");}

La méthode fill() récupère aussi le formulaire (c’est à dire appel jForms : :get(), mais exécute aussi une opérationsupplémentaire : elle remplie le contenu du formulaire avec les données trouvées en paramètres de la requête HTTP.En clair, elle est à utiliser lors de la réception du formulaire rempli par l’utilisateur (voir la section plus loin surl’utilisation d’un formulaire après submit).

$product_id = $this->param(’id’);$form = jForms::fill("shop~product", $product_id);

Note : l’identifiant (ici id) doit être actuellement récupéré manuellement avant de récupérer le formulaire, mais il estprévu dans les versions ultérieures que cela puisse se faire automatiquement.

15.2.5 Gérer un formulaire après submit

Une fois un formulaire créé, il faut, dans une action l’afficher, ce qui est expliqué dans un chapitre à part. Et dans uneautre action, qui sera appelée quand l’utilisateur validera le formulaire, il faudra gérer les données saisies : récupérationdes données, vérification de leur contenu et enfin traitement (stockage par exemple).

Remplissage à partir des données saisies

Vous l’avez déjà vu un peu plus haut, pour récupérer l’objet formulaire tout en le remplissant à partir des donnéesreçues du navigateur, il suffit d’appeler jForms : :fill() :

Page 119: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

112 / 225

$form = jForms::fill("main~contact");

Cela est en fait équivalent à

$form = jForms::get("main~contact");$form->initFromRequest();

Vous pouvez aussi utiliser la méthode setData sur le formulaire pour remplir vous même le contenu du formulaire :

$form = jForms::get("main~contact");$form->setData(’nom’, $this->param(’nom’));

Vérification des données

Une fois le formulaire récupéré avec les bonnes données, il est souvent préférable d’en vérifier exactement le contenuavant de traiter les données. Vous avez à votre disposition la méthode check() qui vérifie les données en fonction dece que vous avez indiqué dans le fichier xml (l’aspect obligatoire de la saisie, le type de donnée pour les inputs etc...).La méthode check() renvoi true si la vérification est bonne, ou false si il y a des erreurs dans le formulaire.

En général, si la validation échoue, vous avez simplement à réafficher le formulaire : les erreurs s’afficheront auto-matiquement et l’utilisateur devra corriger.

$form = jForms::fill("main~contact");if (!$form->check()) {

// invalide : on redirige vers l’action d’affichage$rep = $this->getResponse(’redirect’);$rep->action=’module~default:show’;return $rep;

}

Vous pouvez, bien sûr, faire des vérifications approfondies. Vous pouvez alors utiliser la méthode getData pourrécupérer la valeur d’un champ de saisie, et setErrorOn pour indiquer une erreur sur un champ.

$form = jForms::fill("main~contact");if (!$form->check()) {

// invalide : on redirige vers l’action d’affichage$rep = $this->getResponse(’redirect’);$rep->action=’module~default:show’;return $rep;

}$ok = true;$valeur = $form->getData(’nom’);if( strpos($valeur, ’azerty’) !== null) {

$ok = false;$form->setErrorOn(’nom’, ’tu as un nom bizarre toi !’);

}// autres vérifications//....

if (!$ok) {// invalide : on redirige vers l’action d’affichage$rep = $this->getResponse(’redirect’);$rep->action=’module~default:show’;return $rep;

}

Page 120: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

113 / 225

Stockage des données

Une fois la vérification faite, vous pouvez extraire les données du formulaire avec la méthode getData() ou getDatas()(avec un s) qui renvoie toutes les données sous forme de tableau. Ensuite libre à vous d’en faire ce que vous voulez :les stocker avec jDb ou jDao, les envoyer par mail etc...

Stockage via un dao

Tout comme il y a initFromDao pour initialiser le formulaire, il y a l’opération inverse saveToDao. Cette méthodepermet donc d’enregistrer plusieurs champs via un dao. Les valeurs des champs dont les noms correspondent à despropriétés du dao indiqué seront utilisées pour renseigner les propriétés du dao correspondantes, et le tout sera en-registré dans l’enregistrement dont la clé est indiqué dans l’id du formulaire. Si l’id du formulaire est inexistant, unnouvel enregistrement sera créé, plutôt qu’une mise à jour d’un enregistrement existant.

$form->saveToDao(’shop~products’);

Dans certains cas il peut être utile de récupérer la clé primaire d’un enregistrement créé à l’aide de la méthodesaveToDao.

$primaryKey = $form->saveToDao(’shop~products’);

Stockage des valeurs d’un champ à choix multiples

Il y a la méthode saveControlToDao, qui est l’opération inverse de initControlFromDao. Elle permet donc de sauve-garder les valeurs sélectionnées d’un ensemble de cases à cocher ou d’une liste à choix multiples, dans une table dejointure.

$form->saveControlToDao(’categories’, ’shop~products_categories’);

Le premier paramètre est le nom du champ concerné, et le deuxième le dao utilisé pour le stockage.

15.2.6 Stockage des fichiers

Si le formulaire contient des champs de téléchargement de fichiers, il vous faut sauver les fichiers quelque part. Vousavez pour cela deux méthodes, saveFile() et saveAllFiles. La première pour sauvegarder un fichier précis, et l’autrepour copier tous les fichiers reçus dans un répertoire. Sachez que dans les données du formulaire, la valeur du champ(que l’on récupère via getData) contient le nom du fichier original. Si vous avez besoin de stocker un autre nom, faitesun setData.

saveFile() prend en argument le nom du champ contenant le fichier. Par défaut, le fichier est alors stocké dans lerépertoire var/uploads/nommodule~nomform/. Vous pouvez indiquer un autre répertoire en donnant son chemin endeuxième paramètre de saveFile(). Et si vous voulez stocker le fichier sous un nom différent, indiquez le en troisièmeparamètre.

Exemple :$form->saveFile(’photo’);$form->saveFile(’photo’, JELIX_APP_WWW_PATH.’images/photos/’);$form->saveFile(’photo’, JELIX_APP_WWW_PATH.’images/photos/’, $id.’.png’);$form->saveFile(’photo’, ’’, $id.’.png’);

saveAllFiles sauve tout les fichiers, sans distinction, dans un même répertoire. Le répertoire par défaut est var/u-ploads/nommodule~nomform/, mais vous pouvez le changer en l’indiquant en paramètre.

$form->saveAllFiles();$form->saveAllFiles(JELIX_APP_WWW_PATH.’images/photos/’);

Page 121: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

114 / 225

15.2.7 Détruire une instance d’un formulaire

Quand un formulaire n’est plus utilisé (la saisie est finie, les données sauvegardées), il est préférable de faire leménage pour ne pas encombrer la session de données inutiles. Il faut donc détruire le formulaire. Pour cela on uti-lise jForms : :destroy, à laquelle on indique le sélecteur du formulaire, et éventuellement l’identifiant du formulaireconcerné.

jForms::destroy("main~contact");jForms::destroy(’shop~products’);jForms::destroy(’shop~products’, $product_id);

15.3 Affichage d’un formulaire

Pour afficher les données d’un formulaire jforms, vous pouvez appeler la méthode getDatas() d’un objet formulaire,et vous obtiendrez un tableau contenant toutes les données. Vous pouvez passer ensuite ce tableau à un template pourafficher votre formulaire HTML avec les données. Vous pouvez aussi récupérer les erreurs avec getErrors() et ainsiafficher les éventuelles erreurs.

Cependant des plugins de templates vous permettent d’éviter de faire ce travail répétitif, et surtout font bien plusqu’afficher les valeurs :– affichage de chaque champ de saisie, en accord avec ce qui est décrit dans le fichier XML du formulaire,– affichage des libellés de chaque champ dans des balises <label> pour une meilleure ergonomie/accessibilité,– affichage automatique des messages d’erreurs,– affichage des messages d’aide,– intégration du code javascript qui vérifiera le bon contenu des données saisies avant validation du formulaire,– code HTML généré valide, avec un effort sur l’accessibilité,– des classes sur les balises générés pour pouvoir les styler facilement.

15.3.1 Affichage sans personnalisation

Pour les développeurs pressés, il existe un plugin de template qui affiche tout tout seul : formfull. Vous ne pouvezpas contrôler la façon dont sont affichés les champs de saisie, leur libellés et les boutons de validation. La seule choseque vous pouvez personnaliser c’est l’affichage des messages d’erreurs et d’aide (voir plus loin).

Vous devez passer à ce plugin, les paramètres suivant :– l’objet formulaire– le selecteur de l’action où le contenu du formulaire sera envoyé– facultatif : les paramètres de l’url de cette action (autre que les champs de saisie)Voici un exemple dans le contrôleur :

$form = jForms::get(’monform’);$tpl = new jTpl();$tpl->assign(’formulaire’, $form);

Attention, jForms : :get retourne une instance du formulaire ayant déjà été créée. Si elle n’a jamais été créée, vousdevez la générer :

if (! $form = jForms::get(’monform’)) {$form = jForms::create(’monform’);

}

Et dans le template :

Page 122: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

115 / 225

<h1>Le formulaire</h1><p>Remplissez le formulaire suivant :</p>

{formfull $formulaire, ’monmodule~default:sauver’}

Les libellés et les champs de saisies s’affichent dans un tableau, et les boutons de validation dans une div en dessousdu tableau.

15.3.2 Affichage contrôlé

D’autres plugins que formfull existent permettant de mieux contrôler l’affichage des champs de saisie, en particulier,de pouvoir définir les endroits où les champs seront placés.

Le premier plugin à connaître, est le plugin form. Il a les même paramètres que formfull. C’est un plugin de typebloc, c’est à dire qu’il y a une balise de fin, et qu’entre les deux balises form, on y placera les autres plugins.

affichage contrôlé simple

Le plugin formcontrols permet de faire une boucle sur la liste des champs de saisie. C’est aussi un bloc dans lequelon utilisera les plugins ctrl_label et ctrl_control pour afficher respectivement le libellé et le champs de saisie. Et onutilise le plugin formsubmit pour afficher le bouton de validation déclaré dans le fichier xml, ainsi que formreset pourafficher le bouton reset si il est déclaré lui aussi dans le fichier xml.

Exemple :

{form $formulaire, ’monmodule~default:sauver’}

<fieldset><legend>Saisissez : </legend>

{formcontrols}<p> {ctrl_label} : {ctrl_control} </p>

{/formcontrols}

</fieldset>

<div> {formreset}{formsubmit} </div>

{/form}

Notez que les champs seront affiché dans le même ordre que leur déclaration dans le fichier XML. Notez égalementqu’ici le template est totalement indépendant du contenu du formulaire. Il pourrait être réutilisé avec plusieursformulaires.

aller plus loin dans le contrôle de l’affichage

Il arrive que l’on ne veuille pas présenter tout les champs de saisie de la même façon. On peut alors indiquer uneliste des noms des champs à afficher au plugin formcontrols.

{form $formulaire, ’monmodule~default:sauver’}

<fieldset><legend>Votre identité : </legend>

{formcontrols array(’nom’,’prenom’,’adresse’)}

Page 123: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

116 / 225

<p> {ctrl_label} : {ctrl_control} </p>{/formcontrols}

</fieldset><fieldset><legend>Autres renseignements : </legend>

{formcontrols}<p> {ctrl_label} : {ctrl_control} </p>

{/formcontrols}

</fieldset>

<div> {formsubmit} </div>{/form}

Dans cet exemple, on affiche une première série de champs de saisie (les champs nom, prenom et adresse). Et unedeuxième série dont on ne précise pas la liste de champs : formcontrols bouclera alors uniquement sur les champs quin’ont pas encore été affiché.

Vous pouvez aussi utiliser ctrl_label et ctrl_control en dehors d’une boucle formcontrols. Vous devez alors leurindiquer un nom de champs.

{form $formulaire, ’monmodule~default:sauver’}<fieldset><legend>Votre identité : </legend>

<table><tr><td>{ctrl_label ’nom’}</td><td>{ctrl_control ’nom’}</td> </tr><tr><td>{ctrl_label ’prenom’}</td><td>{ctrl_control ’prenom’}</td></tr>

</table></fieldset><fieldset><legend>Autres renseignements : </legend>

{formcontrols}<p> {ctrl_label} : {ctrl_control} </p>

{/formcontrols}</fieldset><div> {formsubmit} </div>

{/form}

Ici on affiche les champs noms et prenoms à des endroits précis, et le reste sera affiché par le plugin formcontrolsqui suit.

contrôle de l’affichage des champs de type password

Pour les champs de saisie de mot de passe pour lesquels il y a un champ de confirmation (balise confirm), si vousindiquez explicitement leur affichage, il faut aussi indiquer spécifiquement l’affichage du champs de confirmation,sachant que celui-ci a le nom du champs de saisie principale avec un suffixe _confirm.

Par exemple, vous indiquez explicitement d’afficher le champs "motdepasse" qui est un mot de passe :

{form $formulaire, ’monmodule~default:sauver’}<fieldset><legend>Créer votre compte : </legend>

<table><tr><td>{ctrl_label ’login’}</td><td>{ctrl_control ’login’}</td> </tr><tr><td>{ctrl_label ’motdepasse’}</td><td>{ctrl_control ’motdepasse’}</ ←↩

td></tr></table>

</fieldset>

Page 124: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

117 / 225

<fieldset><legend>Autres renseignements : </legend>{formcontrols}

<p> {ctrl_label} : {ctrl_control} </p>{/formcontrols}

</fieldset><div> {formsubmit} </div>

{/form}

Ici, si le champs de confirmation ne s’affichera pas prés du champs de mot de passe. Il faut donc rajouter le champs"motdepasse_confirm" :

<table><tr><td>{ctrl_label ’login’}</td><td>{ctrl_control ’login’}</td> </tr><tr><td>{ctrl_label ’motdepasse’}</td><td>{ctrl_control ’motdepasse’}</td></ ←↩

tr><tr><td>{ctrl_label ’motdepasse_confirm’}</td><td>{ctrl_control ’ ←↩

motdepasse_confirm’}</td></tr></table>

Par contre, il n’est pas besoin de préciser le champs de confirmation quand on afficher le champs de saisie de mot depasse dans une boucle formcontrols.

contrôle de l’affichage des boutons d’envoi

On a vu que l’on pouvait utiliser le plugin formsubmit pour afficher le bouton d’envoi déclaré dans votre formulaire.Mais utilisé comme cela, si vous avez déclaré plusieurs balises submit, seule le premier bouton sera affiché. Dans cecas là il faut utiliser le plugin formsubmits (avec un s), qui est une boucle sur les boutons d’envoi :

<ul>{formsubmits}

<li>{formsubmit}</li>{/formsubmits}</ul>

Ou encore, vous pouvez utiliser plusieurs plugins formsubmit, sans formsubmits, en indiquant le nom du bouton :

<div> {formsubmit ’preview’} {formsubmit ’save’} </div>

– *Attention** : {formsubmits} boucle sur la liste des contrôles submit, pas sur les item d’un submit ! Il n’est paspossible pour le moment de boucler sur les items d’un submit (voir ticket #429)

15.3.3 Classes CSS à connaître

Pour styler les balises générées par jForms, il y a quelques classes de style à connaître (certaines de ces classes ontété ajoutée dans la version 1.0.1).– jforms-table : c’est la classe du tableau généré par le plugin formfull– jforms-submit-buttons : c’est la classe de la div générée par le plugin formfull, contenant les boutons d’envois.– jforms-submit : classe sur chaque bouton submit– jforms-reset : classe sur chaque bouton reset– jforms-error-list : classe de la liste (ul) des messages d’erreurs.– jforms-label : classe placée sur toutes les balises <label>– jforms-required : classe placée sur toutes les balises <label> dont les champs sont obligatoires– jforms-error : classe placée sur toutes les balises <label> et sur les champs de saisies qui sont en erreur– jforms-value : classe sur les élements span contenant les valeurs des champs de type output.

Page 125: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

118 / 225

– jforms-help : classe placée sur les élements span contenant les liens d’aide.– jforms-chkbox : classe placée sur le span qui entoure chaque checkbox d’un controle checkboxes.– jforms-ctl-xxx : classe placée sur chaque checkbox d’un controle checkboxes, ou chaque boutons radio d’un

contrôle radiobuttons (xxx étant remplacé par le ref du controle).– jforms-radio : classe placée sur le span qui entoure boutons radio d’un contrôle radiobuttons.

15.3.4 Utilisation de jforms dans des réponses Ajax

Voir la note sur la page des réponses ajax

15.3.5 Personnalisation de l’affichage des messages

Les messages d’erreurs, qui peuvent survenir lors de la vérification du formulaire avant l’envoi des données, et lesmessages d’aides qui apparaissent quand on clique sur le point d’interrogation , sont affiché dans une boite de dialoguede type alert.

Vous pouvez changer ça, en fournissant aux plugins form ou formfull des objets javascript qui s’occuperont d’afficherces messages.

Affichage des messages d’erreurs

Pour les messages d’erreurs, il faut créer un objet javascript qui contient trois méthodes :– start, qui est appelé quand le processus de vérification commence– addError, qui est appelé quand une erreur est trouvée. Cette méthode reçoit un objet javascript jFormsControl qui

contient des données relatifs au champs de saisie en faute, et un code erreur : 1 si le champs n’est pas renseignéalors qu’il est obligatoire, et 2 si le contenu saisi est invalide.

– end, qui est appelé quand le processus de vérification est terminéDans ces méthodes vous faites ce que vous voulez. Par exemple, dans addError, vous pouvez insérer dans une liste

html le message d’erreur, comme dans l’exemple (l’élément "errors" est une liste <ul> quelque part dans votre pagehtml) :

function MyErrorDecorator(){}

MyErrorDecorator.prototype = {start : function(){},addError : function(control, messageType){

var message=’’;if(messageType == 1){

message = control.errRequired;}else if(messageType == 2){

message = control.errInvalid;}else{

message = "Error on ’"+control.label+"’ field";}var item = document.createElement("li");item.appendChild(document.createTextNode(message));document.getElementById("errors").appendChild(item);

},end : function(){}

}

Page 126: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

119 / 225

Ensuite vous l’indiquez au plugin form ou formfull, en 4ième argument :

{form $formulaire, ’monmodule~default:sauver’, array(), "MyErrorDecorator"}...

{/form}

En ce qui concerne l’objet jFormsControl que addError reçoit en paramètre (ici control), voici les propriétés utilesqu’il contient :– name : le nom du contrôle, du champs de saisie– label : son libellé– datatype : type de donnée (attribut type pour les input dans le fichier xml)– required : booléen indiquant si il est obligatoire– readonly : booléen indiquant si il est en lecture seule– errInvalid : message d’erreur prédéfini quand son contenu est invalide– errRequired : message d’erreur prédéfini quand le champs n’est pas renseigné– help : message d’aide

Affichage des messages d’aides

Pour les messages d’aide, c’est le même principe que pour les messages d’erreur, mais l’objet ne doit contenir qu’uneméthode, show qui est appelé avec en paramètre le message affiché.

function MyHelpDecorator(){ }

MyHelpDecorator.prototype = {show : function(message){

document.getElementById("help").firstChild = document.createTextNode( ←↩message);

}}

Ensuite il faut indiquer cet objet en 5ième argument de form ou formfull :

{form $formulaire, ’monmodule~default:sauver’, array(), "", "MyHelpDecorator"}...

{/form}

Notez ici que l’on a indiqué "" pour l’affichage des erreurs : jforms utilisera alors l’afficheur par défaut. Mais vouspouvez aussi indiquer un autre, en même temps que l’afficheur d’aide.

15.4 Affichage simple des données

Il est possible d’afficher, non pas le formulaire en lui même, mais seulement les données du formulaire. Cela peutêtre utile pour afficher le récapitulatif des données saisies par exemple.

15.4.1 Affichage sans personnalisation

Pour les développeurs pressés, il existe un plugin de template qui affiche tout tout seul : formdatafull. Vous nepouvez pas contrôler la façon dont sont affichés les libellés et les valeurs. Vous devez passer l’objet formulaire à ceplugin.

Voici un exemple dans le contrôleur :

Page 127: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

120 / 225

$form = jForms::get(’monform’);$tpl = new jTpl();$tpl->assign(’formulaire’, $form);

Et dans le template :

<h1>Le formulaire</h1><p>Vous avez saisie les valeurs suivantes:</p>

{formdatafull $formulaire}

Les libellés et les valeurs du formulaires s’affichent dans un tableau.

Note : vous pouvez utiliser formdatafull dans un template pour une réponse text.

15.4.2 Affichage contrôlé

Comme pour l’affichage du formulaire, il est possible de mieux contrôler l’affichage, en particulier les balises géné-rées, et donc de pouvoir définir les endroits où les champs seront placés.

Vous pouvez utiliser les plugins {formcontrols} et {ctrl_label} que vous connaissez déjà, ainsi que {ctrl_value} :

<h1>Le formulaire</h1><p>Vous avez saisie les valeurs suivantes:</p>

<table>{formcontrols $formulaire}

<tr><th scope="row">{ctrl_label}</th><td>{ctrl_value}</td>

</tr>{/formcontrols}</table>

Notez que vous n’avez pas besoin d’utiliser le plugin {form}.

Il est possible aussi de ne pas utiliser la boucle {formcontrols}, afin d’afficher les valeurs où on veut et dans l’ordreque l’on souhaite, avec toujours les plugins {ctrl_label} et {ctrl_value} en leur indiquant le nom du contrôle à afficher.Mais il faut alors les utiliser à l’intérieur d’un plugin {formdata}

<h1>Le formulaire</h1><p>Vous avez saisi les valeurs suivantes :</p>

<table>{formdata $formulaire}

<tr><th>{ctrl_label ’name’}</th><td>{ctrl_value ’name’}</td>

</tr><tr>

<th>{ctrl_label ’address’}</th><td>{ctrl_value ’address’}</td>

</tr>{/formdata}</table>

Page 128: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

121 / 225

Chapitre 16

jDb : accéder à une base de données

Jelix possède un système d’accès abstrait aux bases de données : jDb. jDb propose donc une API commune à toutesles bases de données. Pour le moment, les drivers fournis sont ceux pour :– mysql– postgresql– sqliteIl y a aussi un autre driver, pdo, permettant d’indiquer à jDb d’utiliser pdo plutôt que les classes d’abstractions

internes de jDb. Il est d’ailleurs recommandé d’utiliser pdo pour des raisons de performances.

Si dans la liste ci-dessus, il n’y a pas le driver correspondant à votre base de donnée et que vous n’avez pas PDO,vous pouvez créer votre propre driver pour jDb.

À noter que bien que jDb soit une API commune à toutes les bases de données, ce n’est en aucun cas pas une classequi adaptera les requêtes en fonction des bases de données. Aussi, faites attention à ne pas trop utiliser des spécificitésSQL d’une base de donnée précises dans vos modules, si vous souhaitez qu’il puisse être réutilisé dans d’autres projetsqui n’utiliseront pas la même base.

16.1 Profils et configuration

Pour pouvoir accéder à une base de données, il faut d’abord indiquer les paramètres de connexion dans un fichier deconfiguration. Ce fichier est par défaut dbprofils.ini.php situé dans var/config/. Vous pouvez en avoir un avec un nomdifférent, il faut alors indiquer ce nom dans le fichier de configuration principal de votre application.

Vous pouvez définir plusieurs connexions, que l’on nomme "profiles". Ainsi vous pouvez définir des connexions pourla base de production, la base de développement par exemple, ou encore les différentes bases sur lesquelles s’appuievotre application.

Voici un exemple de fichier dbprofils.ini.php :

default = foo

[foo]driver="mysql"database="jelix"host= "localhost"user= "jelix"password= "jelix"persistent= onforce_encoding=true

Page 129: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

122 / 225

Il y a une section "foo". Chaque section correspond à un profil de connexion. Un paramètre, "default", indique leprofil à utiliser par défaut.

Dans une section, vous voyez un certain nombre de paramètres, dont quelques-un sont utilisables pour tout lesdrivers :– driver indique le driver a utilisé. Le nombre et le nom des autres paramètres diffèrent en fonction du driver utilisé.– table_prefix : permet d’indiquer un préfixe de table. Lors de l’utilisation d’un DAO avec un profil spécifiant ce

paramètre, les tables indiquées dans le DAO sont préfixées dynamiquement par cette valeur. Lors de l’écrituremanuelle de requêtes pour jDb, vous pouvez préfixer vos tables en fonction du profil utilisé grâce à la méthodeprefixTable() de jDbConnection. Cette méthode prend en paramètre le nom de la table à préfixer.

16.1.1 profil mysql

Paramètres possibles :– driver : doit valoir "mysql"– database : le nom de la base de donnée à utiliser– host : le nom du serveur mysql sur lequel se connecter– user et password : le login/mot de passe pour la connexion– persistent : indique si la connexion est persistante (on) ou pas (off)– force_encoding : indique si il faut spécifier le charset utilisé dans l’application, de manière à récupérer les données

avec le bon charset. En effet, certains serveur sont configurés par exemple par défaut avec une connexion en iso-8859-1, même si les données stockées sont en utf-8. Mettez à true si vous voyez que vous n’arrivez pas à afficherles données correctement.

16.1.2 profil postgresql

Paramètres possibles :– driver : doit valoir "pgsql"– database : le nom de la base de donnée à utiliser– host : le nom du serveur postgresql sur lequel se connecter. Si vous le mettez à vide, la connexion se fera via une

socket unix.– port : indique le port de connexion. N’indiquez pas ce paramètre si vous voulez utiliser le port par défaut.– user et password : le login/mot de passe pour la connexion. Ne mettez pas ces paramètres si vous voulez utiliser

le login/mot de passe par défaut (indiqués par exemple dans les variables d’environnement du système).– persistent : indique si la connexion est persistante (on) ou pas (off)– force_encoding : indique si il faut spécifier le charset utilisé dans l’application, de manière à récupérer les données

avec le bon charset. même explication que pour mysql.– timeout : Nombre de seconde autorisées pour l’établissement de la connexion au serveur avant de générer un

timeout– single_transaction : Toutes les requêtes d’une même page seront envoyées au serveur au sein d’un même tran-

saction (entre un BEGIN ; et un COMMIT ;) (on) ou non (off). Défaut : off

16.1.3 profil sqlite

Paramètres possibles :– driver : doit valoir "sqlite"– database : le nom du fichier de base de donnée à utiliser– persistent : indique si la connexion est persistante (on) ou pas (off)A noter que les fichiers de base de données sqlite doivent être déposés dans le répertoire : var/db/sqlite/ de votre

application et qu’à la fois ce répertoire et le fichier de base de données sqlite doivent avoir les droits de lecture/écritureadéquats (ceux du serveur web).

Page 130: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

123 / 225

16.1.4 profil pdo

Paramètres possibles :– driver : doit valoir "pdo"– dsn : contient des informations de connexion (type de base de donnée, serveur, nom de la base..). Le format doit

être celui attendu par PDO (voir la doc de pdo sur php.net).– user et password : le login/mot de passe pour la connexion. Ne mettre ces paramètres que si nécessaire.– force_encoding : indique si il faut spécifier le charset utilisé dans l’application, de manière à récupérer les données

avec le bon charset. même explication que pour mysql, et ce paramètre n’est pour le moment valable que pourmysql et postgresql.

[bar]driver=pdodsn= "mysql:host=localhost;dbname=test"user=password=

16.2 Faire des requêtes

Une fois le fichier de configuration écrit, vous pouvez accéder aux bases de données.

La première chose à faire est de récupérer un objet jDbConnection :

$cnx = jDb::getConnection();

La méthode getConnection() permet de récupérer un objet de type jDbConnection (ou jDbPDOConnection héritantde PDO, si vous utilisez PDO, ils ont toutefois la même API). Cette méthode accepte un paramètre facultatif : le nomdu profil à utiliser. Si il n’est pas indiqué, celui déclaré par défaut sera utilisé.

Pour construire les requêtes, vous avez une méthode importante à connaître : quote(), qui permet d’échapper cer-tains caractères dans les valeurs que vous voulez insérer dans vos requêtes. Elle évite dans une certaine mesure lesproblèmes comme l’injection SQL.

$sql = "INSERT INTO users (nom,prenom) VALUES";$sql .=" (". $cnx->quote("de l’ombre") .",".$cnx->quote(’robert’).")";

Notez que la méthode quote() encadre la valeur avec des quotes.

Pour exécuter des requêtes, il y a principalement deux méthodes, exec et query.

16.2.1 exec

exec doit être utilisé pour les requêtes qui ne renvoient pas de résultat (UPDATE, INSERT, DELETE...). cette mé-thode renvoi juste le nombre de lignes concernées par la requête. Exemple :

$cnx = jDb::getConnection();

$cnx->exec("INSERT INTO users (nom,prenom) VALUES(’dupont’,’toto’)");

16.2.2 query

query est fait pour les requêtes qui renvoient des résultats, vides ou pas (SELECT ou procédures stockées). Laméthode renvoi alors un objet jDbResultSet.

Voici un exemple rapide :

Page 131: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

124 / 225

$cnx = jDb::getConnection();

$rs = $cnx->query(’SELECT nom, prenom FROM users’);$result=’’;while($record = $rs->fetch()){

$result.=’nom = ’.$record->nom.’ prenom=’.$record->prenom."\n";}

16.2.3 limitQuery

Vous pouvez faire des requêtes qui récupèrent un nombre limité d’enregistrement. Vous utiliserez alors la méthodelimitQuery :

$cnx = jDb::getConnection();

$rs = $cnx->limitQuery(’SELECT nom, prenom FROM users’, 5,10);$result=’’;while($record = $rs->fetch()){

$result.=’nom = ’.$record->nom.’ prenom=’.$record->prenom."\n";}

Le premier paramètre est la requête. Le deuxième est le numéro, dans la liste des résultats, du premier enregistrementà récupérer. Le troisième paramètre est le nombre d’enregistrements à récupérer.

16.3 ResultSet

jDbResultSet est l’objet que vous récupérez après avoir fait un SELECT (query ou limitQuery).

Sa méthode fetch() vous permet de récupérer un à un les enregistrements. À noter que jDbResultSet renvoie toujoursun enregistrement sous forme d’objet.

Sa méthode fetchAll() permet de récupérer tout d’un coup dans un tableau PHP.

jDbResultSet implémente l’interface Iterator. De ce fait, vous pouvez utiliser cet objet dans certaines boucles, commeles foreach :

$cnx = jDb::getConnection();

$rs = $cnx->query(’SELECT nom, prenom FROM users’);$result=’’;foreach( $rs as $record){

$result.=’nom = ’.$record->nom.’ prenom=’.$record->prenom."\n";}

Les objets contenant les enregistrements sont des objets "anonymes" (ils n’ont pas de classe précise). Si vous voulezque ce soit des objets d’une certaine classe, vous devez l’indiquer via setFetchMode :

class User {...

}

$cnx = jDb::getConnection();

$rs = $cnx->query(’SELECT nom, prenom FROM users’);$rs->setFetchMode($rs->FETCH_CLASS , ’User’);

Page 132: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

125 / 225

$result=’’;foreach( $rs as $record){

// $record est ici un objet de type User$result.=’nom = ’.$record->nom.’ prenom=’.$record->prenom."\n";

}

Pour le reste des méthodes, voyez la documentation de référence.

16.3.1 Utilisation dans un template

Il est possible de passer un objet jDbResultSet dans un template.

Dans le contrôleur :

$cnx = jDb::getConnection();

$rs = $cnx->query(’SELECT nom, prenom FROM users’);

$template->assign(’resultats’, $rs);

Dans le template :

<table><tr> <th>nom</th> <th>prenom</th></tr>

{foreach $resultats as $user}<tr>

<td>{$user->nom|eschtml}</td><td>{$user->prenom|eschtml}</td>

</tr>{/foreach}</table>

16.4 Transactions

jDb permet de faire des transactions. Bien sûr, il faut que le driver utilisé supporte les transactions.

Pour marquer le début d’une transaction, vous appelerez la méthode beginTransaction (). Ensuite vous lancerez lesrequêtes, Puis aprés avoir fait vos requêtes, vous pourrez valider la transaction en appelant la méthode commit(). Pourannuler une transaction, il suffit d’appeler rollback().

$cnx = jDb::getConnection();

$cnx->beginTransaction();

$cnx->exec(...);$cnx->query(...);//....

if($ok)$cnx->commit();

else$cnx->rollback();

Page 133: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

126 / 225

16.5 jDbWidget

jDbWidget est une classe fournissant des méthodes utiles.

$dbw = jDb::getDbWidget(); // au lieu de getConnection()

$record = $dbw->fetchFirst("SELECT nom, prenom FROM user");

$liste = $dbw->fetchAll("SELECT nom, prenom FROM user");

Pour le reste des méthodes, voyez la documentation de référence.

Page 134: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

127 / 225

Chapitre 17

jClasses : utiliser des classes métiers

Pour respecter le modèle en couche, il est recommandé de réaliser tout ses traitements métiers et services dans desclasses dédiées.

Dans de telles classes, vous manipulerez par exemple des daos, des données issues de daos ou autre, effectuerezdonc des traitements autres que de l’affichage. Aussi les méthodes de vos controllers s’en trouveront allégées et lestraitements réutilisables dans d’autres actions.

17.1 Création d’une classe

Les classes métiers et services dans Jelix sont des classes PHP classiques qui n’ont rien de spécifique. La seule choseà respecter est de la stocker dans un fichier nom_de_la_classe.class.php dans le répertoire classes du module :

class StockService {public function getListeProduits(){

$stock = jDAO::get("products");

$liste = $stock->findAll();

// ici traitement sur la liste... par exemple

return $liste;}

}

Cette classe devra être stockée dans classes/StockService.class.php.

La différence entre une classe service avec les autres classes est qu’une classe service fourni comme son nom l’in-dique, un service. Elle n’a pas besoin d’être instanciée à chaque utilisation car elle ne possède pas de propriétés"discriminantes". Une seule instance suffit pour toute l’application.

Par exemple une classe de type "factory", qui permet de récupérer des ensembles de données, est une classe service.Par contre une classe représentant un produit, qui possède donc des champs identifiants, est une classe non service.

17.2 Instanciation

Jelix propose la classe jClasses, qui vous évite d’avoir à faire un include et une instanciation par vous même.

jClasses fournit deux méthodes statiques, auxquelles vous indiquez un sélecteur :

Page 135: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

128 / 225

– createInstance($selecteurDeClasse) ; (ou create($selecteurDeClasse) )– getService($selecteurDeClasse) ;La première créera à chaque appel une nouvelle instance. Par contre la deuxième renverra toujours une même instance

de la classe. getService sera donc utilisé sur les classes services, et createInstance sur les autres.

Si notre classe StockService se trouve dans le module "shop", voici un exemple d’appel dans un contrôleur :$stocksrv = jClasses::getService("shop~stockservice");$rep->body->assign(’liste_produits’, $stocksrv->getListeProduits());

Cependant dans certains cas, comme celui où le constructeur de la classe métier demande un paramètre, il faut inclurela classe métier puis l’instancier "manuellement".

Dans ce cas la classe jClasses propose la méthode statique inc($selecteurDeClasse). Comme son nom l’indique elleinclue (en fait effectue un require_once) la classe spécifiée par le sélecteur.

Exemple :jClasses::inc(’shop~shoesProduct’);$shoe = new shoesProduct(’43’, ’black’);

Notez que vous pouvez mettre des classes dans des sous-repertoires de "classes/", ce qui donne, si on place Stock-Service dans un répertoire classes/stocks/ :

$stocksrv = jClasses::getService("shop~stocks/stockservice");

17.3 Installer et Utiliser des classes tierces

Il se peut que vous vouliez réutiliser des classes développées en dehors du projet. Il est bien entendu tout à faitpossible de le faire dans Jelix.

Bien que vous puissiez mettre ces classes où bon vous semble et faire un include classique, il y a toutefois deuxemplacements préconisés :– le répertoire lib– le répertoire classes d’un moduleFaire un répertoire spécifique dans lib/ et y placer les fichiers de classes, est interessant quand il s’agit de partager ces

classes entre plusieurs modules, voire entre plusieurs projets. Pour faire les includes, vous pouvez utiliser la constanteLIB_PATH. Par exemple si vous voulez inclure une classe que vous avez dans lib/foo/bar.php, vous ferez alors ceci :

require(LIB_PATH.’foo/bar.php’);$maclasse = new bar();

Placer les classes tierces dans le répertoire classes, est utile si les classes en question ne sont utilisées que par cemodule. Cela permet aussi une réutilisation plus facile : tout est dans le module.

Pour utiliser ces classes, en admettant que vous voulez inclure le fichier bar.php que vous avez placé dans le répertoireclasses du module main, vous pouvez faire :

require(JELIX_APP_PATH.’modules/main/classes/bar.php’);$maclasse = new bar();

Si le nom du fichier de la classe respecte la norme des fichiers de classes pour jelix (bar.class.php), et que la classes’appelle effectivement "bar", vous pouvez bien entendu utiliser jClasses :

$maclasse = jClasses::create(’bar’);

// ou si le constructeur attend des argumentsjClasses::inc(’bar’);$maclasse = new bar(’bla’);

Page 136: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

129 / 225

Chapitre 18

jUrl : des URLs automatiques

Jelix comporte un mécanisme qui permet de ne pas avoir à mettre les URLs concernant les actions en dur dans lestemplates (ou ailleurs). Pour faire simple, il suffit de fournir le module, l’action, le type de requête et éventuellementd’autres paramètres et jUrl se charge de générer l’URL correspondante. À l’inverse, lors d’une requête, jUrl analysel’URL pour en déduire le module, l’action et les paramètres, et ceci, indépendamment du type de requête. Il n’est pasutile alors d’utiliser le mod_rewrite d’apache.

Pour cette tâche jUrl se repose sur un moteur d’URL. Il y en a deux fournis dans Jelix :– un moteur d’URL simple (utilisé par défaut)– un moteur d’URL significatifsSachez que vous pouvez créer votre propre moteur d’URLs pour des besoins plus spécifiques.

18.1 Petit rappel sur les URLs

Une URL est composée de différentes parties :

http://monsite.com/un/chemin/pointentree.php/path/info?param1=value1

– un/chemin/pointentree correspond au chemin du point d’entrée : /index par exemple– .php l’extension du point d’entrée. Elle est facultative si le multiview est activé dans apache– /path/info le pathinfo, partie complémentaire du chemin, ne correspondant pas à un chemin physique sur le disque.– ?param1=value1 : les paramètres.

Les moteurs d’URLs analysent le pathinfo et les paramètres pour déterminer le module/action

Note : il peut y avoir certaines options à activer dans apache. Voir la page installation

18.2 Configuration générale

La configuration de jUrl se fait dans la section urlengine du fichier de configuration dont voici les paramètres :

18.2.1 engine

Indique le type de moteur à utiliser. Les deux valeurs disponibles sont simple et significant.

Page 137: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

130 / 225

18.2.2 enableParser

Active l’analyse d’URL par le moteur d’URL. Si vous préférez l’utilisation du module mod_rewrite d’apache, vouspouvez alors mettre off.

18.2.3 multiview

Indique si le multiview est activé ou non dans apache. Cela indique alors au moteur d’URL de ne pas générerl’extension des points d’entrées (.php) lors de la création des URLs. On a ainsi des URLs un peu plus "propres".

18.2.4 basePath

Chemin jusqu’au répertoire www, ou plutôt, la partie commune des chemins de tous les points d’entrée.

Ainsi, si vous accédez à index.php avec l’URL http ://localhost/jelix/myapp/www/index.php, alors vous indiquez

basePath= /jelix/myapp/www/

Si par contre vous avez spécifié le documentRoot dans apache, pointant sur jelix/myapp/www, alors vous indiquerez

basePath= /

Attention, la valeur de basePath doit toujours commencer par un /.

Si vous n’indiquez aucune valeur, Jelix essaiera de deviner le chemin de base par lui même.

18.2.5 defaultEntrypoint

Point d’entrée par défaut de l’application. index par défaut. Vous ne devez pas indiquer le suffixe (.php).

18.2.6 entrypointExtension

Extensions des points d’entrées. Par défaut, c’est .php, mais peut-être que sur votre serveur, pour utiliser PHP5 ilvous faille utiliser l’extension .php5 par exemple. Auquel cas vous indiquerez .php5.

18.2.7 notfoundAct

L’action à effectuer quand une URL ne correspond à rien. Indiquez là sous forme de sélecteur d’action : "module-~action". L’action indiquée devra correspondre à l’affichage d’une page d’erreur par exemple et renvoyer le code http404.

Attention ! Quand vous êtes en développement, il est recommandé de ne rien mettre dans ce paramètre. Ainsi ce seraplus facile à debogger car en cas d’appel d’une module/action inconnue vous aurez un message d’erreur de la part deJelix qui sera plus explicite qu’une simple page 404.

Page 138: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

131 / 225

18.3 Configuration des moteur d’URLs

En standard Jelix fournis deux moteurs d’URLs :– Le moteur "simple", qui est performant mais qui ne permet pas d’avoir des URLs "cools"– Le moteur "significant", qui permet d’avoir les URLs que vous voulez, bien qu’il soit un peu moins performant.Aller donc lire les pages qui leurs sont dédiées pour les configurer correctement :– Moteur "simple"– Moteur "significant"

18.4 Utilisation

Vous devez éviter de mettre des URLs en dur dans votre code, dans vos modules. Sinon cela crée des dépendanceset la portabilité de vos modules s’en trouve diminuée. Il est impossible alors d’utiliser le module pour plusieursapplications en même temps car les URLs peuvent être différentes en fonction de la configuration des applications. Etsi le module est réutilisé ailleurs, il faudrait alors modifier les templates etc...

De plus, faire générer les URLs par Jelix vous permet de changer à loisir le moteur d’URLs ou sa configuration, sansavoir à changer quoi que ce soit dans vos templates et vos contrôleurs.

Les URLs doivent donc être construites par Jelix. Pour cela, vous avez deux outils à votre disposition.

18.4.1 jUrl : :get

L’objet jUrl a une méthode statique, get(), qui en fonction d’une action et d’autres paramètres, renvoie l’URL cor-respondante pour l’application courante :

$string_url = jUrl::get("news~view@classic", array("id_news"=>"54"));

Le premier paramètre de la fonction est donc un sélecteur d’action. Ici on demande l’URL qui correspond à l’actionview du module news, pour le type de requête classic avec un paramètre id_news. Avec le moteur d’URL simple,l’URL correspondante sera probablement index.php?module=news&action=view&id_news=54.

Si le moteur d’URL significant est utilisé, cela peut être n’importe quoi d’autre, en fonction de ce qui est configurédans le fichier urls.xml.

18.4.2 Plugin de template jurl

Dans les templates vous pouvez utiliser le plugin jurl. Sa syntaxe est identique à jUrl : :get(). Exemple :

<p><a href="{jurl ’news~view@classic’, array(’id_news’=>’54’)}">Détails de la ←↩news</a></p>

Le résultat avec le moteur d’URL simple sera alors :

<p><a href="index.php?module=news&amp;action=view&amp;id_news=54">Détails de la ←↩news</a></p>

18.5 Moteur d’urls ’simple’

Ce moteur est celui activé par défaut. Toutes les URLs ressembleront à pointentree.php ?module=..&action=...&.... C’est un moteur qui est donc très simple et performant. Son principal inconvénient si on peut dire, c’est qu’avec lui,les URLs ne sont pas très "jolies".

Page 139: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

132 / 225

18.5.1 Configuration

Si vous utilisez les points d’entrées fournis en standard vous n’avez rien à configurer. Par contre si vous en rajoutez,il faut les indiquer dans la section simple_urlengine_entrypoints pour les déclarer et dire quels modules et quelstypes de requêtes ils concernent. Les paramètres de cette section ont la forme :

nom_du_script_sans_suffix = "liste de sélecteur séparé par un espace"

Les sélecteurs peuvent être de l’une de ces formes :– mod~act@req : le point d’entrée concerne l’action act du module mod pour le type de requête req– mod~*@req : le point d’entrée concerne toutes les actions du module mod pour le type de requête req– @req : le point d’entrée concerne toutes les actions de tous les modules pour le type de requête reqVous indiquez ainsi quelles actions passent par quel point d’entrée.

Exemple :

[simple_urlengine_entrypoints]index = "@classic"xmlrpc = "@xmlrpc"jsonrpc = "@jsonrpc"testnews = "unittest~url2@classic unittest~url3@classic"foo/bar = "unittest~url4@classic"news = "news~*@classic"

– le point d’entrée index.php concerne toutes les actions des requêtes de type classic (sauf celles spécifiées dansd’autres points d’entrées. C’est donc le point d’entrée par défaut pour les requêtes de type classic.

– idem pour le point d’entrée xmlrpc.php et jsonrpc.php qui concernent respectivement toutes les actions des re-quêtes de type xmlrpc et toutes les actions des requêtes de type jsonrpc.

– le point d’entrée testnew.php concerne l’action url2 et url3 du module unittest pour le type de requête classic– le point d’entrée foo/bar.php concerne l’action url4 du module unittest pour le type de requête classic– le point d’entrée news.php concerne tout le module news

Pour l’action url2, jUrl génèrera donc l’URL testnews.php ?module=unittest&action=url2&autresparametres..

URL avec https

Avec le moteur d’URL simple, pour indiquer les URLs des actions qui devront être en https, vous indiquez la liste desactions dans l’option simple_urlengine_https dans la section urlengine. La syntaxe est la même que dans la sectionsimple_urlengine_entrypoints.

[urlengine]...simple_urlengine_https = "unittest~url6@classic @xmlrpc"

[simple_urlengine_entrypoints]...

18.6 Moteur d’urls significatives

Le moteur d’url "significant" permet d’attribuer à chaque action une url spécifique de la forme que l’on veut.

Le principe de configuration pour ce moteur est d’indiquer dans un fichier var/config/urls.xml toutes les formesd’URLs possibles de l’application et les actions qui leurs sont associées. Voici un exemple de fichier :

Page 140: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

133 / 225

<urls xmlns="http://jelix.org/ns/urls/1.0"><classicentrypoint name="index" default="true">

<url pathinfo="/news/:annee/:mois/:id-:title" module="news" action="view"><param name="annee" type="year"/><param name="mois" type="month" /><param name="id" type="number" /><param name="title" escape="true" />

</url>

<url pathinfo="/articles/:rubrique/:id_art" module="cms" action="show"><param name="id_art" regexp="\d+"/>

</url>

</classicentrypoint><classicentrypoint name="shop">

<url pathinfo="/:category/:product" module="unittest" action="url2"><param name="product" regexp="\d{2}" /><static name="mystatic" value="valeur statique" />

</url></classicentrypoint><classicentrypoint name="foo/bar">

<url handler="urlsig" module="unittest" action="url4" /></classicentrypoint>

<classicentrypoint name="news"><url module="news" />

</classicentrypoint><xmlrpcentrypoint name="xmlrpc" default="true" /><jsonrpcentrypoint name="jsonrpc" default="true" />

</urls>

18.6.1 Balises entrypoint

La balise racine urls contient autant de balises *entrypoint que de points d’entrée disponibles dans votre applica-tion. Leur nom exact précise le type de requête auxquels ils sont affectés :– classicentrypoint pour les requêtes classiques– xmlrpcentrypoint pour du xmlrpc– etc ...Chacune de ces balises a un attribut name indiquant le nom du point d’entrée (sans l’extension .php) et éventuelle-

ment un attribut default indiquant si ce point d’entrée est celui par défaut pour le type de requête en question.

18.6.2 Balise url

Chaque point d’entrée définit une ou plusieurs formes d’URLs possibles, sachant que celles qui ne sont pas définiesseront acceptées lors d’une requête sur un point d’entrée spécifié "default".

Spécifier une forme d’URL complète

Selon un pathinfo

Vous voulez indiquer le module et l’action à exécuter pour une forme particulière d’URL. Vous indiquerez alors unattribut pathinfo, indiquant le "modèle" de la partie pathinfo auquel l’URL doit ressembler, ainsi que le module et

Page 141: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

134 / 225

l’action dans des attributs module et action.

L’attribut pathinfo doit donc contenir la valeur d’un pathinfo. Dans cet exemple, toute URL qui aura pour pathinfola valeur "/foo/bar" correspondra au module et action indiqués (module hello, action default :world dans notre cas).

<url pathinfo="/foo/bar" module="hello" action="default:world" />

Selon un pathinfo contenant des parties indéfinies

Il est possible d’indiquer des parties "dynamiques" dans le pathinfo. Elles sont à définir par un deux-points suivid’un nom. La valeur trouvée sera alors stockée dans un paramètre du même nom. Dans l’exemple qui suit, le pathinfocontient deux parties dynamiques : rubrique et id_art.

<url pathinfo="/articles/:rubrique/:id_art" module="cms" action="default:show" ←↩/>

Si on appelle l’URL "/articles/aviation/544", alors les paramètres rubrique et id_art seront crées et auront pourvaleurs respectives "aviation" et "544".

Attention : pour éviter les ressemblances avec d’autres URLs, il faut au moins une partie "statique" (ici "/articles/")dans l’URL pour la distinguer des autres.

Des parties indéfinies typées ou formatées

Un autre moyen d’éviter ces ressemblances est de spécifier le format ou le type de chaque paramètre. Par défaut letype est une chaîne classique.

Pour cela il faut indiquer des balises param pour chacun des paramètres dont on veut spécifier le type/format. Ellesdevront contenir un attribut name indiquant le paramètre et, soit un attribut type, soit un attribut regexp, contenantune expression régulière du format (sans délimiteur). Dans notre exemple, nous voulons spécifier que rubrique estune chaîne et une expression régulière pour id_art :

<url pathinfo="/articles/:rubrique/:id_art" module="cms" action="show"><param name="rubrique" type="string" /><param name="id_art" regexp="\d+" />

</url>

Quand le paramètre est de type string il n’est pas obligatoire de mettre une balise param. Les types disponibles sont :

Note : vous devrez bien entendu indiquer les valeurs de ces paramètres lors de l’appel à jUrl.

Des paramètres statiques

Il peut être nécessaire parfois de rajouter des paramètres "statiques", attendues par l’action (celle-ci pouvant êtreattribuées à plusieurs URLs différentes), mais non présent dans l’URL. Pour cela il faut ajouter une balise <static>,avec nom et valeur, comme dans cet exemple :

<url pathinfo="/:category/:product" module="shop" action="product:view"><param name="product" regexp="\d{2}" /><static name="details" value="0" />

</url>

Page 142: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

135 / 225

<url pathinfo="/:category/:product/details" module="shop" action="product:view" ←↩><param name="product" regexp="\d{2}" /><static name="details" value="1" />

</url>

Ici on utilise la même action pour deux URLs différentes. Son traitement différera en partie selon le paramètre d-etails, qu’il ne faut donc pas oublier de donner à jUrl : :get. Dans un cas on afficherait le produit d’un catalogueavec ses caractéristiques générales, et dans l’autre avec ses caractéristiques générales et détaillées. Cela évite donc decréer deux actions différentes pour si peu de différence.

On peut aussi utiliser ce mécanisme pour supporter plusieurs langues :

<url pathinfo="/articles/en/:page" module="cms" action="page:view"><param name="page"/><static name="lang" value="en_EN" />

</url><url pathinfo="/articles/fr/:page" module="cms" action="page:view">

<param name="page"/><static name="lang" value="fr_FR" />

</url>

Là encore, il ne faut pas oublier de donner le paramètre lang à jUrl pour que ce dernier puisse savoir quelle url il doitrenvoyer.

18.6.3 Utiliser un handler spécifique

Nous avons vu précédemment comment utiliser, en fin de compte, un système par défaut d’analyse et de générationd’URL avec ses pathinfos et paramètres. Il se peut que ce système ne soit pas suffisant. Imaginons par exemple quevous vouliez transformer une partie de l’information contenu dans le pathinfo, comme par exemple chercher dans unebase de données un id correspondant à un titre contenu dans le pathinfo, et fournir ainsi aux actions, non pas un titre,mais un id (qui n’est pas contenu dans cette URL).

Ou encore que la partie pathinfo puisse être variable.

Aussi c’est à vous de développer l’analyse de l’URL et d’indiquer l’action à exécuter. Vous le ferez dans une classespécialisée :

class myHandlerUrlsHandler implements jIUrlSignificantHandler {

function parse($url){

if(preg_match("/^\/(.*)$/",$url->pathInfo,$match)){$urlact = new jUrlAction($url->params);$urlact->setParam(’page’,jUrl::unescape($match[1]));return $urlact;

}elsereturn false;

}

function create($urlact, $url){

$p=jUrl::escape($url->getParam(’page’));

$url->pathInfo = "/$f";

Page 143: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

136 / 225

$url->delParam(’page’);}

}

Le nom de la classe doit commencer par un préfixe que vous voulez et se terminer par UrlsHandler. La classesera stockée dans le répertoire classes du module indiqué dans la balise url, sous le nom prefixe.urlhandler.php.Pour notre exemple :

myhandler.urlhandler.php.

La méthode parse est chargée d’analyser une URL (objet jUrl que vous recevez en paramètre), en l’occurence, l’URLdemandée dans l’application. Si votre handler reconnaît l’URL, parse() doit renvoyer un objet jUrlAction qui contienttoutes les données pour l’action. Sinon il doit renvoyer false.

La méthode create() est appelée à chaque fois que l’application demande la création d’une URL à partir de paramètresd’action. Elle reçoit donc un objet de type jUrlAction, et un objet de type jUrl. $urlaction contient donc les paramètresde l’action. Ces paramètres ont déjà été inclus dans l’objet $url. Vous devez donc modifier $url de façon à produirel’URL correspondante à l’action demandée. Dans l’exemple, on récupère le paramètre page, que l’on incorpore dansle pathinfo. Et comme il est dans le pathinfo, on le supprime alors des paramètres.

Notez l’usage de jUrl : :escape() et jUrl : :unescape(), pour "nettoyer" les chaînes à inclure dans un pathinfo (accentsenlevés par ex).

Enfin dans le fichier urls.xml, vous devez indiquer l’utilisation de ce handler :

<classicentrypoint name="wiki"><url handler="myHandler" module="unittest" action="url4" />

</classicentrypoint>

Depuis jelix 1.0 beta1, vous pouvez indiquer un handler d’un autre module. Exemple :

<classicentrypoint name="wiki"><url handler="autremodule~myHandler" module="unittest" action="url4" />

</classicentrypoint>

18.6.4 Une même URL pour plusieurs actions possibles

Imaginons que nous avons une URL de ce type : "/article/54-titre" et par défaut, cela affiche l’article 54 avec uneaction nommée view par exemple :

<url pathinfo="/article/:id_art-:title" module="cms" action="view" />

On veut pouvoir, sans changer l’url, indiquer d’autres actions dans certains cas, avec un paramètre action :– "/article/54-titre ?action=edit"– "/article/54-titre ?action=delete"Note : On pourrait faire aussi /article/54-titre/edit ou /article/54-titre/delete , avec donc plusieurs balises urls, ce qui

nous éviterait ce qui suit. Mais ce n’est pas très pratique quand l’URL est appelée suite à un formulaire par exemple.

Pour indiquer les actions alternatives autorisées, on ajoute un attribut actionoverride, contenant la liste des actionsséparées par un espace ou une virgule :

<url pathinfo="/article/:id_art-:title" module="cms" action="view" ←↩actionoverride="edit,delete" />

Page 144: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

137 / 225

18.6.5 Indiquer qu’un point d’entrée est dédié à un module particulier

Vous n’avez pas forcément envie d’indiquer une URL significative pour les actions d’un module particulier. Parcontre vous avez créé un point d’entrée dédié à un module. Toutes ces actions passeront par ce point d’entrée. Vousavez juste alors à faire comme ceci :

<classicentrypoint name="news"><url module="news" />

</classicentrypoint>

18.6.6 Spécifier des URLs en https à certaines actions

Pour certaines actions vous voulez que l’accès soit en mode sécurisé de http (SSL). Vous indiquez alors un attributhttps sur les balises <url> en question avec la valeur true. Si cela concerne toutes les actions/URLs d’un pointd’entrée, alors vous mettrez cet attribut sur la balise <*entrypoint> correspondante.

Attention : pour le moment, Jelix ne vérifie pas lors de l’exécution d’une action que la requête a été faite en https ounon.

18.6.7 Mod_rewrite et suppression du nom du point d’entrée dans l’URL

Vous préférez peut être que l’analyse des URLs se fasse par le serveur web, grâce au module rewrite pour apache parexemple. Vous allez donc écrire les règles de réécriture.

Réécriture complète par le serveur web

On appelle ici réécriture complète, la réécriture qui consiste à fournir à Jelix des URLs simples (index.php ?module=...&action=...),à partir d’URLs significatives.

Pour cela, vous devez indiquer à Jelix, dans la configuration, de ne pas analyser les URLs :

[urlengine]..enableParser = off

Vous devez bien sûr remplir un fichier urls.xml de façon à ce que Jelix génère dans vos templates et ailleurs, lesURLs attendues par vos règles de rewrite.

Et bien sûr, vous devez ensuite mettre dans un fichier .htaccess les règles de réécritures.

Si vous voulez définir des URLs qui ne contiennent pas le nom du point d’entrée, vous devez alors indiquer sur lesbalises <url> l’attribut noentrypoint="true" (ou sur la balise <*entrypoint> si toutes les URLs de ce point d’entréesont conçernées). Ainsi Jelix n’ajoutera pas le nom du point d’entrée (index.php) dans l’URL.

Suppression du nom du point d’entrée dans l’URL

Un exemple d’utilisation du mod_rewrite n’est pas forcément de transformer complètement les URLs, mais parexemple d’ajouter le fichier index.php dans les URLs dans lesquelles on l’aurait supprimé pour faire "joli".

Par exemple nos URLs sont de la forme :

http://monsite.com/index.php/news/2007-02-08-il-neige-a-lille.html

Et on souhaite qu’elles deviennent :

Page 145: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

138 / 225

http://monsite.com/news/2007-02-08-il-neige-a-lille.html

Voyons comment faire.

Tout d’abord, il faut bien sûr utiliser le moteur d’URL "significant" et définir un fichier urls.xml. Comme pour laréécriture complète vous devez indiquer sur les balises <url> ou <*entrypoint> l’attribut noentrypoint="true".Ainsi Jelix n’ajoutera pas le nom du point d’entrée (index.php) dans les URLs concernées.

Ensuite on va utiliser le rewriteEngine de Apache d’une façon toute simple : le chemin appelé sera rajouté aprèsindex.php. En clair il faut copiez ceci dans un fichier .htaccess dans le dossier www de votre application (ou dans lasection virtualhost de la configuration apache) :

<IfModule mod_rewrite.c>RewriteEngine OnRewriteBase /RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule ^(.*)$ index.php/$1 [L,QSA]

</IfModule>

Observez bien :– 3ème et 4ème ligne : Réécrire l’URL seulement si la requête ne correspond pas à un fichier déjà existant, ou un

dossier déjà existant. Ainsi on préserve ses dossiers d’image, de feuille de style, etc. de la règle de réécriture.– 5ème ligne : Tout prendre, et mettre après index.php/On retrouve ainsi notre point d’entrée index.php ainsi que notre pathinfo.

Il se peut que sur certaines configurations, vous ayez une erreur apache du type "Error : No input file specified", enparticulier quand PHP est exécuté en CGI avec cgi.fix_pathinfo=0 dans php.ini.

Depuis Jelix 1.0.2, il y a une solution. Il faut changer la dernière rêgle en :

RewriteRule ^(.*)$ index.php?jpathinfo=/$1 [L,QSA]

Ainsi le but est de mettre le pathinfo dans un paramétre de la requête. Pour que cela fonctionne pleinement, il fautajouter dans la configuration de Jelix, dans la section urlengine, le paramètre pathInfoInQueryParameter qui doitcontenir le nom du paramètre (ici dans l’exemple jpathinfo)

[urlengine]...pathInfoInQueryParameter = jpathinfo

Page 146: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

139 / 225

Chapitre 19

jAuth : système d’authentification

Le système d’authentification de Jelix ne s’occupe que d’une seule chose : gérer des logins/mots de passe et desutilisateurs. Il repose sur des drivers pour accéder aux données d’un utilisateur. C’est ainsi qu’il peut s’appuyer surune base de données, un annuaire LDAP etc. Pour le moment, il existe un driver pour une base de donnée, un driverpour un annuaire géré par un serveur LDS, et un driver pouvant utiliser une classe quelconque.

19.1 Mise en oeuvre

Le système d’authentification repose sur plusieurs choses :– un plugin pour le coordinateur, nommé auth et livré en standard avec jelix, vérifiant si l’authentification est effec-

tuée pour les actions où elle est nécessaire– une classe jAuth, permettant d’effectuer les différentes opérations sur l’authentification et la gestion des logins.

Cette classe repose sur un système de driver.– un module, jauth, proposant un contrôleur et des templates par défaut. Il n’est en principe pas indispensable, vous

pouvez tout à fait utiliser votre propre contrôleur, la mise en oeuvre étant relativement simple.– un objet stocké en session, contenant les informations sur l’utilisateur. Il est fourni par le driver. Cela peut être un

objet DAO, une simple classe etc.

19.1.1 Installer le plugin auth pour le coordinateur

Le rôle du plugin auth :– Vérifier l’authentification– Gérer un timeout de session (optionnel)– Gérer la persistance de l’authentification via un cookie (optionnel)– Indiquer le driver à utiliser pour jAuth– Indiquer les paramètres pour le driver (DAO pour jAuthDb, cn/sn/uid pour un driver LDAP etc...)– Indiquer ce qu’il faut faire en cas de non authentificationAussi, dés lors que l’on veut utiliser le système d’authentification, il faut activer le plugin et le configurer, il est

indispensable.

Dans le fichier de configuration, vous indiquerez alors dans la section plugins :

[plugins]auth = "auth.coord.ini.php"

le fichier de configuration auth.coord.ini.php du plugin est une copie du fichier /lib/jelix/plugins/coord/auth/auth.coord.ini.php.dist,que vous placez dans le repertoire var/config/ de votre application

Page 147: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

140 / 225

Note : pour jelix 1.0beta2 et précédent, le ficher auth.plugin.ini.php.dist se trouve dans un autre répertoire, lib/jelix-plugins/auth/auth.plugin.ini.php.dist. De plus, il faut vérifier que le paramètre pluginsPath dans la configurationcontient bien lib :jelix-plugins. (ce n’est pas nécessaire dans jelix 1.0 beta3 et suivant, car le plugin se trouve danslib/jelix/plugins/, qui est déclaré automatiquement).

Note sur la déclaration du plugin : Si vous utilisez plusieurs plugins de coordinateur, l’ordre de déclaration desplugins dans le fichier de configuration a une importance. Ainsi si vous placez le plugin auth en premier, il faut savoirque les autres plugins ne seront pas éxécutés dans le cas où le plugin auth demande une redirection (par exemple lapage de login). En général, il convient donc de placer ce plugin après les plugins ne nécessitant pas d’authentification.

Pour en savoir plus sur les plugins : plugins

19.1.2 Configurer le plugin

Vous devez ensuite éditer le fichier auth.coord.ini.php, pour indiquer la configuration du système d’authentification.Voici les différents paramètres.

Indiquer le driver

Vous devez indiquer le nom du driver utilisé au niveau de l’option driver. Vous devez ensuite avoir une sectionportant ce même nom, pour les options propres au driver.

driver=XXX

[XXX]foo=bar

Par exemple, pour le driver Db (les informations sont stockées alors dans une base de donnée) :

driver=Db

[Db]dao = "mon_dao"password_crypt_function = md5

Pour en savoir plus sur les spécificités de chaque driver disponibles, ou même en créer un, consultez la documentationsur les drivers jauth.

Timeout

L’option timeout permet d’indiquer en minutes le temps d’inactivité au bout duquel l’authentification ne sera plusvalide. Si vous mettez 0, il n’y a pas de limite de temps. La session expirera à la fermeture du navigateur.

Contrôler l’authentification pour chaque action

Le plugin peut contrôler si l’action demandée a besoin d’une authentification ou non. Avec l’option auth_requireddans le fichier ini, vous pouvez dire si par défaut toutes les actions nécessitent une authentification (valeur "on"), ousi par défaut, il n’y en a pas besoin (valeur "off").

auth_required=on

Dans un cas comme dans l’autre, il faut pouvoir gérer les exceptions (par exemple, une action qui ne nécessite pasune authentification alors que par défaut toutes les actions le nécessitent). Les exceptions sont indiquées au niveau descontrôleurs, dans les paramètres de plugin.

Page 148: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

141 / 225

class xxxCtrl extends jController {

public $pluginParams = array( ... );

}

Pour les actions concernées, vous indiquerez le parametre auth.required et le mettrez à false ou true. Par exemplepour les actions index et affiche, il faut une authentification, alors que pour le reste des actions du contrôleur ("*"indique "toutes les actions"), ce n’est pas utile :

class xxxCtrl extends jController {

public $pluginParams = array(’*’=>array(’auth.required’=>false),’index’=>array(’auth.required’=>true),’affiche’=>array(’auth.required’=>true),

);}

Voir la page sur les plugins de coordinateurs pour mieux comprendre l’usage de $pluginParams.

Spécifier le comportement en cas de défaut d’authentification

Si l’authentification n’est pas faite alors que l’action en nécessite une, le plugin va alors agir en fonction de l’optionon_error.

Si vous mettez la valeur 1, alors le plugin génèrera une erreur dont le message (ou plutôt la clé de la locale dumessage) est dans l’option error_message.

Si par contre la valeur est 2, alors le plugin exécutera l’action définie dans l’option on_error_action. Cela peutêtre une action d’un contrôleur du module auth (comme c’est le cas par défaut), ou alors une action de votre proprecontrôleur dans un module tierce. Cette action en général affiche une page demandant un login/mot de passe (maiscela peut être autre chose...)

Persistance de l’authentification

jAuth propose un mécanisme de persistance d’authentification. C’est à dire la reconnaissance automatique de l’utili-sateur quand il revient sur le site, même plusieurs jours après sa dernière visite (et donc après avoir perdu sa sessionPHP...). Cela se fait par le biais d’un cookie dans lequel sont stockés un certain nombre d’information dont une partieencrypté.

Vous avez pour cela deux paramètres important :– persistant_enable : mettez le à on pour activer la persistance de l’authentification– persistant_crypt_key : c’est un paramètre à renseigner obligatoirement. Vous devez remplacer la valeur par dé-

faut ! Ce paramètre doit contenir une chaîne quelconque de votre choix (plus de 10 lettres de préférence). Elleservira de clé d’encryptage pour les données stockées dans le cookie. Si vous changez de clé en cours de route, lescookies seront invalides et les utilisateurs ne sont pas reconnus. Ils devront s’authentifier à nouveau.

D’autres paramètres sont disponibles :– persistant_cookie_name : indique le nom du cookie à utiliser. Par défaut : "jelixAuthentificationCookie".– persistant_duration : indique la durée en jour de la validité du cookie. Par défaut c’est une journée.– persistant_cookie_path : le chemin du cookie. Par défaut (vide), il vaut la valeur de basePath dans la config

générale.

Page 149: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

142 / 225

19.2 Utiliser le contrôleur par défaut

Le module jauth propose des contrôleurs que vous pouvez utiliser pour gérer les actions de connexion, de décon-nexion, en faisant appel à la classe jAuth. Il propose aussi des zones et des templates.

À l’avenir, il proposera également des zones de formulaire de changement de mot de passe, de formulaire de des-truction de compte (si un utilisateur veut supprimer un compte sur une appli type portail), de création de compte et derécupération de mot de passe. Bien sûr, on aurait des paramètres de configuration qui permettrait de dire si on autoriseun utilisateur à supprimer son compte, à récupérer son mot de passe, etc...

19.2.1 Configuration classique

Quand on utilise le module jauth, il est possible d’ajouter des options de configuration propre au module. Parexemple, une configuration possible dans le fichier auth.plugin.ini.php peut être celle-ci :

driver = Dbon_error_action = "jauth~login:out"after_login = "myapp~default:index"after_logout = "jauth~login:form"on_error_sleep = 3[Db]dao = "jauth~jelixuser"

Le paramètre on_error_sleep est le nombre de secondes d’attente quand l’utilisateur a donné un mauvais mot depasse ou login. Pour after_login et after_logout, voir plus bas.

Vous remarquerez aussi que dans l’exemple, on utilise le driver Db. Le module jauth propose en effet un DAO pourle driver Db. Si vous l’utilisez, il faut créer alors la table jlx_user suivante (ici pour mysql) :

CREATE TABLE ‘jlx_user‘ (‘usr_login‘ VARCHAR( 50 ) NOT NULL ,‘usr_email‘ VARCHAR( 255 ) NOT NULL ,‘usr_password‘ VARCHAR( 50 ) NOT NULL ,PRIMARY KEY ( ‘usr_login‘ ));

Vous pouvez bien sûr ajouter d’autres champs, il faudra alors proposer votre propre DAO. (voir la doc sur le driverDb).

A noter que vous pouvez surcharger les templates du module en créant vos propres templates dans le dossier

myapp/var/themes/default/jauth/

19.2.2 Configuration de la redirection

Dans la configuration du plugin, vous devez spécifier les paramètres after_login, after_logout, et éventuellement lesoptions enable_after_login_override et enable_after_logout_override

Les paramètres after_login et after_logout doivent contenir les selecteurs des actions vers lesquelles il faut redirigerune fois que l’identification ou la déconnexion sont effectuées. Ils sont obligatoires. Si vous ne les indiquez pas, vousallez avoir des redirections vers l’action jauth~default :index qui n’existe pas, donc une erreur...

Page 150: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

143 / 225

Il est possible dans un formulaire d’authentification ou de déconnexion, d’ajouter un paramètre caché contenantl’URL vers laquelle il faut rediriger. Cela permet de rediriger vers une page différente en fonction de la page sur la-quelle on est quand on se connecte ou déconnecte. Dans ce cas, ce paramètre caché doit se nommer "auth_url_return",et doit contenir l’URL. Et vous devez mettre les paramètres de configuration enable_after_login_override et/ou en-able_after_logout_override à "on".

19.3 Utiliser son propre contrôleur

Vous pouvez utiliser vos propres contrôleurs pour gérer l’authentification : formulaire de login, connexion, décon-nexion. Vous ferez appel alors à la classe jAuth et ses méthodes statiques pour verifier les logins/mots de passe,connecter et déconnecter un utilisateur.

19.4 classe jAuth

C’est la classe principale du système d’authentification. Toutes ses méthodes sont statiques. Elle permet de gérer unutilisateur, de "connecter"/"déconnecter" un utilisateur etc.. Vous appellerez ces méthodes quand bon vous semble,sachant que les contrôleurs du module jauth peuvent se charger pour vous d’une bonne partie du travail. Voir sondescriptif dans la référence.

l’objet user que vous passez à certaines méthodes vous est donné par jAuth lui même. C’est un objet contenant lesdonnées d’un utilisateur et il n’a pas de classe précise : son type dépend du driver utilisé et éventuellement de saconfiguration (pour le driver Db, on peut fournir un DAO de notre choix par exemple). Il doit par contre respecterl’interface attendue par le driver, et doit avoir au moins un champ login et un champ password.

jAuth n’a pas à être surchargée. Elle s’appuie sur des "drivers" pour gérer les différents types d’authentification.

19.4.1 Évènements

Pour la plupart des méthodes de jAuth, un évènement est émis. Cela permet à des modules tiers d’être au courant desdifférentes actions d’authentification, et donc de charger des données supplémentaires dans l’objet user, ou de gérerles données dépendantes à l’utilisateur etc.– AuthNewUser : indique qu’un utilisateur vient d’être ajouté– AuthCanRemoveUser : demande si on peut supprimer l’utilisateur ou pas– AuthRemoveUser : l’utilisateur a été supprimé– AuthUpdateUser : l’utilisateur vient d’être mis à jour– AuthCanLogin : demande si l’utilisateur peut se connecter– AuthLogin : un utilisateur vient de se connecter– AuthLogout : un utilisateur vient de se déconnecter

19.5 Les drivers pour jAuth

Il existe en standard plusieurs drivers pour l’authentification dans Jelix.

19.5.1 Db

Le driver Db propose une authentification pour laquelle les informations sont stockées en base de donnée. Pour cela,ce driver Db se repose sur un dao, qu’il faut indiquer dans le fichier de configuration d’authentification :

Page 151: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

144 / 225

driver= Db

[Db]dao = "monmodule~mondao"password_crypt_function = "md5"

Ce que vous indiquez au niveau du paramètre dao, c’est un sélecteur vers le fichier dao que vous voulez utiliser. Vouspouvez utiliser celui fourni dans le module jauth :

dao = "jauth~jelixuser"

Le paramètre password_crypt_function indique la fonction à utiliser pour crypter les mots de passe. Vous pouvezfournir votre propre fonction de cryptage (en la définissant dans le fichier application.init.php par exemple) et indiquerson nom ici.

Pour le dao que vous indiquez, il doit avoir au moins les propriétés "login" et "password". Vous pouvez rajouterd’autres propriétés, autant que vous voulez. Il doit aussi y avoir au moins les méthodes qu’il y a dans le dao jelixuserdu module jauth :– getByLoginPassword (login, password)– getByLogin(login)– updatePassword(login,password)– deleteByLogin(login)– findByLogin(pattern)Note : la table sur laquelle repose le dao, doit avoir comme clé primaire le champs du login.

Exemple

Imaginons que l’on ait la table suivante (script mysql) :

CREATE TABLE ‘jlx_user‘ (‘usr_login‘ varchar(50) NOT NULL default ’’,‘usr_password‘ varchar(50) NOT NULL default ’’,‘usr_email‘ varchar(255) NOT NULL default ’’,PRIMARY KEY (‘usr_login‘)

) AUTO_INCREMENT=2 ;

On a bien le login comme étant la clé primaire, et au moins le champs password.

On crée ensuite le dao suivant, comme indiqué plus haut :

<?xml version="1.0" encoding="UTF-8"?><dao xmlns="http://jelix.org/ns/dao/1.0">

<datasources><primarytable name="usr" realname="jlx_user" primarykey="usr_login" />

</datasources><record>

<property name="login" fieldname="usr_login"required="yes" datatype="string" maxlength="50" />

<property name="email" fieldname="usr_email"datatype="string" required="yes" maxlength="255" />

<property name="password" fieldname="usr_password" datatype="string"maxlength="50" selectmotif="%s" updatemotif="" insertmotif="%s" />

</record>

Page 152: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

145 / 225

<factory><method name="getByLoginPassword" type="selectfirst">

<parameter name="login" /><parameter name="password" />

<conditions><eq property="login" expr="$login" /><eq property="password" expr="$password" />

</conditions></method>

<method name="getByLogin" type="selectfirst"><parameter name="login" />

<conditions><eq property="login" expr="$login" />

</conditions></method>

<method name="updatePassword" type="update"><parameter name="login" /><parameter name="password" />

<values><value property="password" expr="$password"/>

</values><conditions>

<eq property="login" expr="$login" /></conditions>

</method>

<method name="deleteByLogin" type="delete"><parameter name="login" /><conditions>

<eq property="login" expr="$login" /></conditions>

</method>

<method name="findByLogin" type="select"><parameter name="pattern" /><conditions>

<like property="login" expr="$pattern" /></conditions><order>

<orderitem property="login" way="asc" /></order>

</method><method name="findAll" type="select">

<order><orderitem property="login" way="asc" />

</order></method>

</factory></dao>

Et dans le fichier auth.plugin.ini.php, on indique ce dao que l’on aura stocké dans le module foo sous le nomuser.dao.xml.

Page 153: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

146 / 225

driver= Db

[Db]dao = "foo~user"password_crypt_function = "md5"

19.5.2 Class

C’est un driver plus universel que celui de Db, dans la mesure où vous devez lui fournir une classe, dans laquellevous faîtes ce que vous voulez. Elle doit respecter l’interface jIAuthDriverClass. Cette classe doit être stockée dans lerépertoire "classes" d’un de vos modules, comme n’importe quelle classe métier.

Dans la configuration du plugin jauth, vous devez mettre :

driver= Class

[Class]class = "monmodule~maclass"password_crypt_function = "md5"

19.5.3 LDS

C’est un driver qui repose sur un serveur LDS (http ://lds.linbox.org/). Il appelle l’API xml-rpc d’un serveur LDS.La configuration que vous devez indiquer doit donc être celle-ci :

driver= LDS

[LDS]host=foo.comport=80login= foopassword= barscheme= https

Le driver interrogera donc le serveur foo.com sur le port 80, avec le login foo et le mot de passe bar, via uneconnexion sécurisée https.

19.5.4 Créer un driver

Vous avez peut-être votre propre système d’authentification, que vous voulez mieux intégrer dans le framework.Dans ce cas, il vous faut créer un driver. Au passage, nous acceptons toutes contributions de ce type !

Pour les détails, voir la page sur la création des drivers d’authentification.

Page 154: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

147 / 225

Chapitre 20

jAcl : système de droits

Jelix propose un système de gestion de droits, jAcl, comportant des possibilités similaires à ce qui peut existerailleurs.

jAcl est basé sur un système de driver. Le driver fourni par défaut est un driver "db" (noté dans la documentation"jAcl.db"), dont la gestion des droits repose sur une base de données et qui tente de répondre à des problématiquescourantes de gestion de droits.

Notez que l’utilisation de jAcl n’est pas obligatoire pour faire fonctionner une application Jelix. À moins que lesmodules utilisés fassent appel à jAcl bien entendu.– *Note** : la version 1.1 de Jelix contiendra jAcl2, qui est plus simple d’utilisation que jAcl. Cependant jAcl

restera disponible dans Jelix 1.1.

20.1 Les concepts généraux de jAcl

jAcl propose un système qui répond à la plupart des besoins en matière de gestion de droits. Il comporte diverséléments qui ensemble définissent des droits.

20.1.1 Éléments composant un droit

Il faut distinguer les différents éléments qui entrent en jeu dans le système de droits :– un sujet– une valeur de droit– un utilisateur– une ressource (facultatif)une combinaison de chacun de ces types d’éléments représente un droit.

Sujet

C’est un intitulé représentant un type de ressource ou une fonctionnalité sur laquelle on veut apposer un droit. Parexemple, "cms.articles" pourrait être le sujet regroupant les droits sur la gestion des articles d’un CMS.

Par convention, afin d’éviter les collisions entre différents modules, le nom du sujet devrait commencer par le nomdu module. Mais ce n’est pas une obligation.

Page 155: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

148 / 225

Valeur de droit

C’est une chaîne, une valeur indiquant précisément un droit. Pour un sujet donné, il y a un ensemble de valeursprécises possibles. Par exemple, pour le sujet "cms.articles", on pourrait avoir les valeurs "LIRE", "MODIFIER","CREER", "PUBLIER", "EFFACER". Et pour le sujet "comments.management", juste les valeurs "EFFACER" et"MODIFIER".

Ainsi donc, les valeurs de droits sont regroupées en groupes de valeurs.

À noter que les intitulés des valeurs de droits dépendent totalement de la manière dont sont stockées les droits dansle système accédé par le driver.

Utilisateur

Un droit s’exerce toujours sur un ou plusieurs utilisateurs. Mais cette notion est transparente du point de vue del’API de la classe jAcl. C’est le driver qui s’occupe de "reconnaître" l’utilisateur en cours (au moyen de jAuth enprincipe). Il se peut même que le driver repose sur un système où les utilisateurs sont dans des groupes auxquels lesdroits s’appliquent (comme c’est le cas de jAcl.db). Mais vous n’avez pas à vous en préoccuper lors de l’utilisationde jAcl.

Ressource

Dans la plupart des cas, l’association sujet + utilisateur + valeur de droit suffit. Mais parfois on veut pouvoir avoirune granularité plus fine.

Par exemple, dans un système CMS, on veut pouvoir donner le droit de modification à un utilisateur sur ses propresarticles, mais pas sur ceux des autres. Il faut alors rajouter dans cette association l’identifiant de l’article.

Par exemple, on donnera les valeurs de droits suivants– "CREER" sur le sujet "cms.articles" pour le groupe "redacteurs"– "MODIFIER" sur la ressource "monarticle" pour l’utilisateur toto faisant parti du groupe "redacteurs".

20.1.2 Principes de fonctionnement

Le cœur de jAcl contient donc des relations entre trois ou quatre types d’élements.

La mémorisation d’une relation entre un sujet, un utilisateur et une valeur (plus éventuellement une ressource), définitun droit. Quand une relation n’existe pas entre un sujet donné, un utilisateur donné et une valeur donnée, alors celasignifie qu’il n’y a pas de droit défini sur ce triplet.

Par exemple, si on définit juste ces droits suivants dans le système :– "LIRE" sur le sujet "cms.articles" pour l’utilisateur "laurent"– "CREER" sur le sujet "cms.articles" pour l’utilisateur "laurent"– "MODIFIER" sur le sujet "cms.articles" pour l’utilisateur "laurent"L’utilisateur laurent aura donc les droits LIRE, CREER et MODIFIER sur le sujet cms.articles, mais pas le droit

EFFACER puisque la relation n’existe pas.

Un module CMS qui repose sur ces droits devra, pour savoir ce que peut faire un utilisateur, interroger jAcl, en luidemandant si par exemple l’utilisateur courant a le droit MODIFIER au sujet de "cms.articles". Si oui, alors le modulepourra afficher un bouton "modifier" dans l’interface d’administration, et ne l’affichera pas sinon. (Le module devraégalement faire cette vérification lors de la sauvegarde d’un article, pour éviter les "fraudes" ;-) ).

Page 156: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

149 / 225

20.2 Utiliser jAcl dans ses modules

Quand vous voulez que votre module fonctionne selon des droits, il vous faut durant la réalisation de ce module :1. déterminer des sujets et des valeurs de droits que vous utiliserez2. éventuellement les enregistrer dans le système de droits utilisé par le driver que vous indiquez à jAcl : dans

un annuaire ldap si vous utilisez un driver ldap (non fourni pour le moment) ou une base de données si vousutilisez par exemple le driver jAcl.db.

Ensuite vous pouvez utiliser les méthodes statiques de jAcl pour savoir si l’utilisateur courant a tel droit sur tel ou telsujet.

Si le driver gère des groupes d’utilisateurs, vous n’avez pas à les indiquer lors de ces interrogations : le driver s’enoccupe automatiquement. Notez qu’un driver pour jAcl peut utiliser jAuth pour l’authentification.

20.2.1 Configuration

Avant toute chose vous devez indiquer quel driver vous utilisez pour jAcl. Les drivers sont des plugins stockés dansun répertoire acl d’un dépôt de plugins. Un plugin pour jAcl est une classe fooAclDriver (foo étant le nom du plugin)qui doit implémenter l’interface jIAclDriver et qui est enregistrée dans un fichier foo.acl.php. Par exemple le driver"db" est stocké dans db/db.acl.php et est défini dans la classe dbAclDriver.

Dans la configuration de l’application, vous devriez avoir une section acl :[acl]driver=db

Au niveau de l’option driver vous devez y mettre le nom du driver utilisé.

20.2.2 Interrogation du système de droit

Vous avez principalement deux méthodes statiques de jAcl à connaître : check et getRight.

jAcl : :getRight

jAcl : :getRight() permet de savoir toutes les valeurs possibles à propos d’un sujet, pour lesquelles un droit à étédéfini sur l’utilisateur.

$list = jAcl::getRight("cms.articles");

En reprenant l’exemple de l’article jAcl.db, si l’utilisateur fait parti du groupe "lecteurs", la liste vaudra :array(’LIST’,’READ’);

si il appartient au groupe des redacteurs :array(’LIST’,’READ’, ’CREATE’,’UPDATE’,’DELETE’);

Si vous indiquez en plus une ressource, par exemple "opinions" comme dans notre exemple :$list = jAcl::getRight("cms.articles", "opinions");

si l’utilisateur fait parti du groupe "lecteurs", la liste vaudra alors :array(’LIST’,’READ’, ’UPDATE’);

si il appartient au groupe des rédacteurs, cela ne change pas, puisque les rédacteurs ont de toute façon le droit demodifier tout les articles, comme cela a été défini précédemment :

array(’LIST’,’READ’, ’CREATE’,’UPDATE’,’DELETE’);

Page 157: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

150 / 225

jAcl : :check

C’est probablement la méthode que vous utiliserez le plus avec jAcl. Elle permet de savoir si l’utilisateur a tel ou teldroit, et renvoi donc true ou false. Exemple :

if( jAcl::check("cms.articles","CREATE")){// code à executer si l’utilisateur a le droit de créer un article

}else{// code à executer si l’utilisateur n’a pas le droit de créer un article

}

Pour interroger sur une ressource précise :

$article_id = "opinions";

if( jAcl::check("cms.articles","UPDATE", $article_id)){// code à executer si l’utilisateur a le droit de modifier l’article indiqué

}else{// code à executer si l’utilisateur n’a pas le droit de modifier l’article ←↩

indiqué}

Vérification automatique

Dans les contrôleurs dont on veut vérifier les droits automatiquement, on peut utiliser le plugin jacl pour le coordi-nateur.

Pour ce faire, activez le plugin jacl dans la configuration de l’application

[plugins]jacl = jacl.coord.ini.php

Copiez le fichier lib/jelix/plugins/coord/jacl/jacl.coord.ini.php.dist dans var/config/index/jacl.coord.ini.php

Éditez ce fichier pour indiquer les actions vers lesquelles aller en cas de défaut de droits, ou le message à afficher.

Et dans vos contrôleurs, mettez les valeurs suivantes dans la propriété $pluginParams :

public $pluginParams = array(’jacl.right’=>array(’sujet’, ’valeur’)

...);

Ou alors, pour vérifier une série de droits que l’utilisateur doit posséder :

public $pluginParams = array(’jacl.rights.and’=>array(

array(’sujet’, ’valeur’),array(’sujet’, ’valeur’),...

),...

);

ou encore, pour vérifier que l’utilisateur possède un des droits parmis une liste :

Page 158: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

151 / 225

public $pluginParams = array(’jacl.rights.or’=>array(

array(’sujet’, ’valeur’),array(’sujet’, ’valeur’),...

),...

);

Plugins de template ifacl et ifnotacl

Des plugins de templates sont disponibles pour générer des portions de contenus en fonction des droits. Leurs argu-ments sont exactement les mêmes que jAcl : :check.

{ifacl "cms.articles","CREATE"}<input type="button" value="Créer un article" />

{else}<p>Vous ne pouvez pas créer d’articles.</p>

{/ifnotacl}

Il y aussi {ifnotacl} qui est le contraire de ifacl, c’est à dire qui test si l’utilisateur n’a pas le droit indiqué.

La même chose avec une ressource :

{ifacl "cms.articles","UPDATE", $article_id}<input type="button" value="Modifier l’article" />

{/ifacl}

20.3 Les concepts de jAcl.db

jAcl.db est le driver "db" pour jAcl et se sert d’une base de données pour stocker les droits. Il implémente les conceptsgénéraux de jAcl, avec en plus une gestion de groupes d’utilisateurs. Aussi les éléments qui entrent en jeu dans lesystème de droit de jAcl.db sont :– un sujet– une valeur de droit– un groupe d’utilisateurs– une ressource (facultatif)une combinaison de chacun de ces types d’éléments représente un droit.

20.3.1 Groupes et Utilisateur

Chaque utilisateur appartient à un ou plusieurs groupes. Un droit s’exerce toujours sur un ou plusieurs groupes etnon pas sur un utilisateur précis.

Il est possible d’affecter des droits à un seul utilisateur, mais cela se traduit en fait par l’existence d’un groupe ’privé’propre à chaque utilisateur (afin de faciliter les traitements). En clair, chaque utilisateur possède son groupe personneldans lequel il est seul.

Il y a trois types de groupes :– les groupes privés. On ne les "voit" pas dans la liste des groupes– les groupes normaux– les groupes normaux par défaut : ceux dans lesquels un nouvel utilisateur est intégré automatiquement.

Page 159: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

152 / 225

20.3.2 Classes utilitaires

Deux classes accompagnent le driver jAcl.db pour gérer les groupes, utilisateurs, droits etc : jAclDbManager etjAclDbUserGroup (anciennement jAclManager et jAclUserGroup dans jelix 1.0beta2.1 mais leur fonctionnement n’apas changé).

Leur utilisation est similaire d’un point de vue théorique aux commandes de jelix-scripts (décrites dans ConfigurerjAcl.db), aussi nous vous laissons lire la documentation de reference.

20.4 Configurer jAcl.db

Avant de pouvoir utiliser l’API de jAcl dans vos modules et le driver db de jAcl, il faut d’abord initialiser la base dedonnées, et mémoriser les différents éléments utilisés pour les droits.

La configuration est facilitée grâce aux scripts en ligne de commande fournis.

20.4.1 Création de la base

Le driver jAcl.db ne fonctionne qu’avec une base de données. Il vous faut donc configurer une connexion de base dedonnées, et créer les tables nécessaires.

Configuration de la connexion

Pour cela, il vous faut vous reporter à la page sur jDb.

Cependant, si les tables jAcl ne sont pas dans la base indiquée par le profil par défaut, il vous faut alors créer unprofil de connexion, et l’indiquer dans le parametre "jacl_profil". Un exemple de fichier dbprofils.ini.php :

default = foojacl_profil= acl

[foo]driver="mysql"database="jelix"host= "localhost"user= "jelix"password= "jelix"persistent= onforce_encoding=true

[acl]driver="mysql"database="droits"host= "localhost"user= "jelix"password= "xilej"persistent= onforce_encoding=true

Page 160: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

153 / 225

Création des tables

Vous trouverez dans le répertoire install/ du module jelix, des scripts sql pour créer les tables : install_jacl.schema.mysql.sql.Vous devriez avoir alors les tables :– jacl_group– jacl_user_group– jacl_right_values_group– jacl_right_values– jacl_subject– jacl_rightsUne fois ces tables créées, vous pouvez vous lancer dans la configuration de jAcl.

20.4.2 Préparation

La configuration se fait au moyen de commandes du script jelix en ligne de commande. Ouvrez donc un terminal etplacez vous dans le répertoire lib/jelix-scripts.

$ cd lib/jelix-scripts/ # sous linux$ cd lib\jelix-scripts\ # sous windows

(note : $ represente l’invité de commande).

Mémorisez ensuite le nom de votre appli dans la variable d’environnement JELIX_APP_NAME :

$ export JELIX_APP_NAME="myapp" # sous linux$ set JELIX_APP_NAME=myapp # sous windows

Dans la suite, il faut exécuter le script jelix.php. Rappelez vous que l’on fait comme ceci, en appelant php :

$ php jelix.php une_commande argument argument argument...

Sous linux, vous avez un script bash qui facilite un peu les choses :

$ ./jelix une_commande argument argument argument...

Il y a trois commandes pour configurer jAcl.db : aclvalue, aclgroup et aclright. Chacune prenant en argument un nomde "sous-commande" suivi de 0 à n arguments suivant la sous commande.

20.4.3 Création des valeurs

Dans le système de droit, vous devez déterminer des "sujets". Chacun de ces sujets pouvant être associés à une ouplusieurs valeurs d’un ensemble de valeurs précises. Aussi, avant d’enregistrer les sujets, il faut créer ces groupes devaleurs.

Dans l’ordre, on crée un groupe de valeur, et on enregistre ensuite toutes les valeurs possibles dans ce groupe.

Imaginons que l’on veuille créer un sujet "cms.articles", avec les valeurs READ, LIST, CREATE, DELETE, UP-DATE.

On peut d’abord lister les groupes de valeurs qui existent :

$ php jelix.php aclvalue group_list

Au départ, vous devriez obtenir une liste vide :

Page 161: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

154 / 225

----Liste des groupes de valeurs de droits

id label key type--------------------------------------------------------

Si il n’y a pas de groupe de valeurs existant correspondant à ce que vous voulez, il faut en créer un. Vous devez alorsindiquer un identifiant numérique (qui n’est pas déjà pris par un autre groupe), une clé de locale qui indiquera sonlabel (clé que vous devrez enregistrer dans un fichier de locale), ainsi que le type de groupe.

Si le sujet peut être associé à plusieurs valeurs du groupe (c’est notre cas dans l’exemple), le type est 0. Si il ne peutêtre associé qu’à une seule valeur d’un groupe (par exemple, un groupe contenant "true" et "false"), le type est 1.

Créons notre groupe :

$ php jelix.php aclvalue group_add 1 "cms~acl.articles.values" 0

L’identifiant 1 et le nom de locale sont à modifier en fonction bien sûr de l’existant. Si vous n’utilisez pas de modulequi permette de gérer les droits, alors la clé de locale n’est pas indispensable. Mettez alors la chaîne que vous voulez.

À l’exécution de la commande, vous obtenez :

----Ajout d’un groupe de valeurs de droits

OK

Quand une commande acl se passe bien, il y a toujours le message OK. On peut le vérifier en listant à nouveau lesgroupes :

$ php jelix.php aclvalue group_list----Liste des groupes de valeurs de droits

id label key type--------------------------------------------------------1 cms~acl.articles.values 0 (combinable values)

Sachez que vous pouvez détruire un groupe de valeurs en faisant :

$ php jelix.php aclvalue group_delete 1

Maintenant il faut remplir le groupe avec des valeurs. On indique la valeur, une clé de locale pour le libellé de lavaleur, et l’id du groupe dans laquelle on la met.

$ php jelix.php aclvalue add READ "cms~acl.articles.value.read" 1$ php jelix.php aclvalue add LIST "cms~acl.articles.value.list" 1$ php jelix.php aclvalue add CREATE "cms~acl.articles.value.create" 1$ php jelix.php aclvalue add DELETE "cms~acl.articles.value.delete" 1$ php jelix.php aclvalue add UPDATE "cms~acl.articles.value.update" 1

On peut vérifier que tout est bien crée grâce à la sous commande list :

$ php jelix.php aclvalue list----Liste des valeurs de droit

value label key-----------------------------------------GROUP 1 (cms~acl.articles.values)

CREATE cms~acl.articles.value.createDELETE cms~acl.articles.value.deleteLIST cms~acl.articles.value.listREAD cms~acl.articles.value.readUPDATE cms~acl.articles.value.update

Page 162: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

155 / 225

Vous pouvez bien sûr effacer une valeur avec la sous-commande delete, en indiquant la valeur et le numéro de groupede valeur. Par exemple :

$ php jelix.php aclvalue delete LIST 1

Vous pouvez maintenant créer autant de groupe de valeurs que nécessaire, sachant qu’un groupe de valeur peut êtrebien sûr utilisé avec plusieurs sujets.

Tables concernées

– jacl_right_values_group, pour les groupes de valeurs.– jacl_right_values, pour les valeurs.

20.4.4 Création des sujets

Maintenant que les valeurs sont créées, on va pouvoir créer les sujets. La gestion des sujets se fait au moyen de lacommande aclright. Créons notre sujet "cms.articles", en indiquant une clé de locale pour le libellé de ce sujet (ouun libellé quelconque si vous n’utilisez pas de module de gestion de droits), ainsi que le groupe de valeur qui lui estassigné (ici 1).

$ php jelix.php aclright subject_create "cms.articles" "cms~acl.articles.subject" ←↩1

vous pouvez ensuite vérifier la création de ce sujet :

$ php jelix.php aclright subject_list----Liste des sujets

id label key--------------------------------------------------------cms.articles cms~acl.articles.subject

possible values: CREATE DELETE LIST READ UPDATE

Vous avez la possibilité de détruire un sujet en tapant :

$ php jelix.php aclright subject_delete "cms.articles"

Table concernée

– jacl_subject

20.4.5 Création des groupes d’utilisateurs

La déclaration d’un droit, nécessite un triplet valeur/sujet/groupe d’utilisateur. Nous devons donc créer un grouped’utilisateur. La gestion des groupes d’utilisateurs se fait au moyen de la commande aclgroup.

Créons par exemple un groupe de rédacteurs.

$ php jelix.php aclgroup create "rédacteurs"

Le message OK s’affiche, avec l’identifiant du nouveau groupe (ici 1) :

----Création d’un nouveau groupe

OK. Group id is: 1

Page 163: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

156 / 225

Nous allons en créer un deuxième, en indiquant avec l’option -defaultgroup que l’on veut que ce soit un groupe pardéfaut, c’est à dire dans lequel sera mis tout nouvel utilisateur.

$ php jelix.php aclgroup -defaultgroup create "lecteurs"

On peut lister les groupes avec la sous-commande list :

$ php jelix.php aclgroup list----Liste des groupes d’utilisateurs

id label name default--------------------------------------------------------2 lecteurs yes1 rédacteurs

On peut changer le statut "default" plus tard, avec la sous commande setdefault :

$ php jelix.php aclgroup setdefault 1 trueou$ php jelix.php aclgroup setdefault 1 false

Il est aussi possible de changer le nom du groupe :

$ php jelix.php aclgroup changename 1 "super rédacteurs"

Ou encore d’effacer un groupe d’utilisateur :

$ php jelix.php aclgroup delete 1

Tables concernées

– jacl_group, pour les groupes d’utilisateurs.– jacl_user_group, pour associer un utilisateur à un groupe.

20.4.6 Création des droits

Puisque nous avons maintenant tout ce qu’il faut pour définir des droits, définissons-en. On utilise la commandeaclright.

Déjà, pour les lecteurs, on va dire qu’ils peuvent lire et lister les articles. On va donc assigner les valeurs LIST etREAD pour le sujet "cms.articles", sur le groupe des lecteurs dont l’identifiant est 2 :

$ php jelix.php aclright add 2 "cms.articles" LIST$ php jelix.php aclright add 2 "cms.articles" READ

Vérifions la liste des droits définis au moyen de la sous commande list :

$ php jelix.php aclright list----Liste des droits

group subject value resource---------------------------------------------------------------- group lecteurs (2)

cms.articlesLISTREAD

Page 164: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

157 / 225

Passons maintenant au groupe rédacteur. On va leur donner tous les droits sur le sujet cms.articles.

$ php jelix.php aclright add 1 "cms.articles" LIST$ php jelix.php aclright add 1 "cms.articles" READ$ php jelix.php aclright add 1 "cms.articles" CREATE$ php jelix.php aclright add 1 "cms.articles" DELETE$ php jelix.php aclright add 1 "cms.articles" UPDATE

On vérifie :

$ php jelix.php aclright list----Liste des droits

group subject value resource---------------------------------------------------------------- group lecteurs (2)

cms.articlesLISTREAD

- group rédacteurs (1)cms.articles

CREATEDELETELISTREADUPDATE

Imaginons qu’on veuille donner toutefois aux lecteurs le droit de modifier l’article "opinions", on créer alors un droitsur la ressource "opinions", en indiquant l’identifiant de cette ressource en dernier paramètre à la sous commandeadd :

$ php jelix.php aclright add 2 "cms.articles" UPDATE "opinions"

On vérifie :

$ php jelix.php aclright list----Liste des droits

group subject value resource---------------------------------------------------------------- group lecteurs (2)

cms.articlesLISTREADUPDATE opinions

- group rédacteurs (1)cms.articles

CREATEDELETELISTREADUPDATE

On peut aussi retirer un droit avec la sous-commande remove, en indiquant, comme pour la sous-commande create,le groupe d’utilisateur, le sujet, et la valeur conçernés (plus éventuellement la resource si on a une ressource).

Exemple, on change d’avis à propos de l’article "opinions" (il y a vraiment trop de spam :-) ) :

$ php jelix.php aclright remove 2 "cms.articles" UPDATE "opinions"

Page 165: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

158 / 225

Une fois tous les droits établis, l’application peut fonctionner selon vos rêgles, et les modules peuvent faire appels àl’API de jAcl pour agir en fonction des droits que vous avez configuré.

Table concernée

– jacl_rights

Page 166: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

159 / 225

Chapitre 21

jLocale : internationaliser votre application

Jelix possède son propre mécanisme de localisation/internationalisation. Les fonctions setlocale et gettext de php nesont pas utilisées car trop contraignantes à mettre en place, et leur configuration est aléatoire sur les serveurs.

21.1 Principes

Chaque texte ou chaine que vous voulez traduire sont associés à une clé, un code. Ces associations sont stockés dansdes fichiers "properties". Chaque fichier properties étant attribués à une langue et un encodage de caractère. La langueet l’encodage par défaut sont configurés dans le fichier de config de votre application : ce sont les paramètres localeet charset, que vous pouvez récupérer en faisant

$lang = $GLOBALS[’gJConfig’]->locale;

Mais vous n’aurez pas à utiliser ce paramètre, sauf utilisation particulière. En effet, pour récupérer une chaine dansla langue courante, il suffit d’appeler jLocale : :get(’selecteurDeLocale’), ou dans les templates d’utiliser la syntaxe@selecteurDeLocale@ (voir la page sur les templates).

21.2 Fichiers properties

Ce sont des fichiers contenant des traductions. Ils sont situés dans le répertoire locales des modules. Ce répertoirea une organisation spécifique. Il contient des sous répertoires pour chaque langue. Exemple :locales/fr_FR/, loca-les/en_US/, etc. Et dans chacun de ces sous-répertoires, il y a les fichiers properties correspondant à la langue.

21.2.1 Noms des fichiers

Le nom des fichiers properties est structuré comme suit : codefichier.charset.properties. Codefichier est un nom decode que l’on utilisera dans les sélecteurs, et charset correspond à un encodage de caractères. Exemple : foo.ISO-8859-1.properties , foo.UTF-8.properties etc.

Si dans la configuration, "defaultLocale=fr_FR" et "defaultCharset=ISO-8859-1", alors ce sera le fichier fr_FR/foo.ISO-8859-1.properties qui sera utilisé.

Page 167: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

160 / 225

21.2.2 Contenu des fichiers

La structure des fichiers est simple : il s’agit d’une suite de lignes cle=chaine traduite. Exemple, pour un fichierfr_FR/foo.ISO-8859-1.properties :

title.offlineElements = éléments à traitertitle.onlineElements = éléments en lignebuttons.save = Enregistrerbuttons.ok=Validerbuttons.cancel=Annulerbuttons.search=Rechercher

Et dans son équivalent anglais en_US/foo.ISO-8859-1.properties :

title.offlineElements = elements to checktitle.onlineElements = online elements

buttons.save = Savebuttons.ok=Okbuttons.cancel=Cancelbuttons.search=Search

Passage à la ligne

Si un texte est long et que vous voulez l’écrire sur plusieurs lignes, vous devez mettre un anti-slash (\) à la fin dechaque retour à la ligne (sauf sur la dernière du texte)

intro=ceci est un très très\long texte qui fait\plusieurs lignesfoo=bar

Cependant, cela n’insère pas un saut de ligne (\n) dans la chaine.

Commentaires

Vous pouvez aussi mettre des commentaires. Ils doivent commencer par un # le reste de la ligne étant alors ignoré.Vous pouvez mettre un commentaire en début de ligne ou à la suite d’une chaine traduite. De ce fait, si vous voulezutiliser un # dans votre chaine, il faut précéder ce caractère par un "\".

Espaces

Il y a un "trim" qui est fait sur la chaine traduite, c’est à dire que les espaces avant et après sont supprimés. Si vousvoulez que la chaine soit un espace, vous utiliserez alors \w

foo= \w

Entités HTML

Les chaines localisées ne devraient pas contenir du code HTML. D’une part parce qu’une chaine localisée n’estpas forcément destinée à être incluse dans du HTML, mais aussi parce que les réponses HTML échappent (htmlspe-cialchars) à plusieurs endroits le contenu que vous lui donnez. De ce fait, les entités et autres signes HTML seront

Page 168: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

161 / 225

échappés. Si vous donnez par exemple une chaîne pour en faire le titre d’une page. Les entités ne seront donc pasinterprétées comme telles par le navigateur.

Si vous avez besoin d’utiliser des caractères spécifiques, choisissez l’encodage adéquate plutôt que de recourir auxentités HTML. C’est pour cette raison qu’il est fortement encouragé d’utiliser l’encodage UTF-8, qui est d’ailleurs enpasse d’être l’encodage "universel" dans les applications web (en plus d’Unicode/UTF-16).

21.3 Récupération d’une chaîne localisée

Pour récupérer une chaîne, il faut utiliser la méthode statique get de jLocale. Cette méthode accepte en premier ar-gument un sélecteur de locale, qui a cette structure : module~codefichier.clechaine. la partie "module~" est facultativesi il s’agit d’un fichier se trouvant dans le module courant.

Pour récupérer par exemple la valeur de buttons.save dans foo.ISO-8859-1.properties situé dans le module "bar" :

$chaine = jLocale::get("bar~foo.buttons.save");

Dans un template cela donnerait par exemple :

<input type="button" value="{@bar~foo.buttons.save@}" />

Note : pour l’utilisation dans les templates, voir les possibilités dans la page sur les templates

21.4 Chaine localisée avec paramètres

Il peut être utile d’avoir des chaines localisées dans lesquelles on veut insérer des valeurs dynamiquement. Parexemple, imaginons que voulez écrire :

Vous allez sur le site http://foo.com et vous cliquez sur la rubrique voiture

Vous voulez pouvoir changer l’url du site et le nom de la rubrique. Vous pouvez alors passer les données en para-mètres à jLocal :

$chaine = jLocale::get("bar~foo.phrase", array(’http://foo.com’, ’voiture’));

Et dans le fichier properties, vous mettez un %s partout où vous voulez insérer des valeurs dynamiques :

phrase = Vous allez sur le site %s et vous cliquez sur la rubrique %s

Et il faut donner les paramètres dans l’ordre d’apparition des %s. En fait, la chaine est traitée par la fonction sprintfde php, donc vous avez toutes les possibilités syntaxiques de sprintf.

En particulier, il se peut que l’ordre d’insertion des paramètres change d’une langue à une autre. Plutôt donc que demodifier l’ordre des paramètres quand vous appelez jLocale, vous indiquez quel paramètre va à quel endroit dans lachaine localisée, au moyen de la syntaxe %x$s où x est un nombre d’ordre.

phrase = Vous allez sur le site %1$s et vous cliquez sur la rubrique %2$s

En anglais (même si ce n’est pas la véritable traduction, c’est juste pour l’exemple) ça pourrait donner ça :

phrase = Clic on the %2$s section, when you go on the %1$s web site.

Ainsi le premier paramètre ira à l’emplacement de %1$s, le deuxième à la place de %2$s etc...

Par contre, dans un template, vous ne pouvez pas utiliser la notion "@foo@" quand il faut des paramètres. Vousdevez alors utiliser le plugin jlocale :

<p>{jlocale "bar~foo.phrase", array(’http://foo.com’, ’voiture’)}</p>

Page 169: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

162 / 225

21.5 Changer la langue dynamiquement

Jelix fourni un plugin pour le coordinateur qui permet de changer la langue dynamiquement. C’est le plugin autolo-cale (qui est situé dans lib/jelix/plugins/coord/). (voir la section sur les plugins de coordinateur).

Pour cela, le plugin regarde si un paramètre est présent dans l’url, indiquant la nouvelle langue à prendre en compte,et utilisera cette langue durant le reste de la visite. En fait le nouveau code langue est stocké dans une variable desession, et le plugin modifie l’option de configuration locale une fois la configuration lue (le fichier de configurationn’est donc pas modifié).

Aussi c’est totalement transparent pour vous. Pour connaitre la langue à tout moment, il suffit de faire commed’habitude :

$lang = $GLOBALS[’gJConfig’]->locale;

Pour utiliser le plugin, copiez le fichier lib/jelix/plugins/coord/autolocale/autolocale.coord.ini.php.dist dans var/con-fig/ en le renommant autolocale.coord.ini.php.

Les deux paramètres importants dans ce fichier sont :

enableUrlDetection= onurlParamNameLanguage=langavailableLanguageCode = fr_FR,en_US

Il faut bien sûr activer la détection de la langue dans l’url avec le paramètre enableUrlDetection. availableLangua-geCode permet d’indiquer la liste des code des langues disponibles sur le site, ainsi les autres codes langues ne serontpas possibles. Le paramètre urlParamNameLanguage contient le nom du paramètre de l’url qui contiendra le codelangue à utiliser. Aussi, vous pouvez mettre des liens sur votre site qui permettent à l’utilisateur de changer la langue.Exemple :

<a href="index.php?lang=fr_FR">français</a><a href="index.php?lang=en_EN">english</a>

Bien sûr, si vous utilisez le moteur d’url significant, il est possible que vous définissiez des urls significatives spéci-fiques pour chaque langue.

Enfin, il faut activer le plugin. Pour cela, dans la configuration de jelix, mettez dans la section plugins :

[plugins]autolocale = autolocale.coord.ini.php

21.6 Détection automatique de la langue

Le plugin autolocale (voir paragraphe du dessus), permet aussi de détecter automatiquement la langue en fonctiondu navigateur.

Pour cela, il suffit de mettre le paramètre useDefaultLanguageBrowser à on dans la configuration du plugin. Etquand l’internaute arrive pour la première fois sur le site, le plugin détecte la langue utilisée dans son navigateuret donc active la bonne langue dans jelix (si bien sûr, ce code langue est l’un de ceux que vous avez indiqués dansavailableLanguageCode).

Page 170: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

163 / 225

Chapitre 22

jEvents : communication inter-module

Jelix propose un système de communication inter-module sous forme d’évènements.

Il est possible d’émettre un évènement de n’importe quel endroit, et aux modules d’y répondre.

Pour cela, il y a d’une part un objet jEvent, permettant d’émettre un évènement et de récupérer les réponses, etd’autre part, des "listener", qui sont des classes placées dans les modules, contenant les méthodes "répondant" auxévènements.

22.1 Émettre un évènement

L’objet jEvent sert à la fois d’émetteur d’évènement, et en même temps de conteneur des réponses.

sa principale méthode, qui est statique, est notify :

$ev = jEvent::notify(’nom_evenement’, $parametre_event);

Elle accepte en paramètre un nom d’évènement (qui n’est constitué que de caractères alphanumériques), et un tableaufacultatif de paramètres (à utiliser selon l’évènement).

Vous recevez en retour l’objet jEvent instancié pour l’occasion, et contenant les réponses. Les réponses sont unensemble de valeurs dont la structure et le nombre dépend de l’évènement et du nombre de modules ayant répondu.

Pour avoir ces réponses :

$reponses = $ev->getResponse();

22.2 Répondre à un évènement

Pour qu’un module puisse répondre à un évènement, il faut créer un listener, et le déclarer dans le fichier events.xmldu module.

22.2.1 créer le listener

Il faut d’abord lui donner un nom. Foo par exemple, ensuite il faut créer une classe fooListener (se termine toujourspar "Listener"), héritant de jEventListener et stockée dans le fichier classes/foo.listener.php du module.

Cette classe contient une méthode pour chaque évènement auquel le listener répond. Ces noms de méthodes com-mencent par "on" suivit du nom d’évènement. Et ces méthodes prennent en paramètre l’objet jEvent correspondant àl’évènement. Exemple :

Page 171: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

164 / 225

class authListener extends jEventListener{

function onAuthCanLogin ($event) {$user = $event->getParam(’user’);$ok = true;if(isset($user->actif)){

$ok = ($user->actif == ’1’);}

$ok = $ok && ($user->password != ’’);

$event->Add(array(’canlogin’=>$ok));}

}

Ce listener répond à l’évènement "AuthCanLogin". La méthode récupère le paramètre ’user’ de l’évènement. Etajoute une donnée dans la réponse ($event->add). Ce paramètre et cette donnée de réponse dépendent uniquement del’évènement AuthCanLogin. Pour d’autres évènements, il peut y avoir plusieurs paramètres ou aucun, d’autres typesde données de réponses ou aucune réponse.

22.2.2 Déclarer le listener

il faut ensuite déclarer le listener. Cela se fait dans un fichier events.xml placé à la racine du module. Voici unexemple :

<events xmlns="http://jelix.org/ns/events/1.0"><listener name="auth">

<event name="AuthCanLogin" /><event name="FetchXulOverlay" />

</listener></events>

Vous mettez autant de balise listener que de listener stocké dans le répertoire classes du module. Et dans chacuned’elles vous indiquez tous les évènements que prend en charge le listener, grâce à des balises event.

Page 172: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

165 / 225

Quatrième partie

Développement avancé

Page 173: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

166 / 225

Comment profiter des fonctionnalités avancées de Jelix ? comment développer des plugins de toutes sortes ?

Cette partie vous explique tout.

Page 174: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

167 / 225

Chapitre 23

Générer un contenu dans un format personna-lisé

23.1 Créer un objet response

Il est possible que Jelix ne fournisse pas le moyen de générer du contenu dans un format spécifique voulu. Aussi, ilvous faut dans ce cas créer votre propre réponse.

Cela consiste à :

1. créer une classe héritant de jResponse (ou d’une autre réponse existante), et qui doit implémenter les méthodesadéquates pour manipuler le format en question

2. de stocker cette classe dans le répertoire responses de votre application

3. de déclarer ce type de réponse dans le fichier de configuration

23.1.1 créer la classe

Une classe response doit posséder au moins deux méthodes : output() et outputErrors(). Et rédéfinir la propriété$_type avec un identifiant propre à votre type de réponse. output() doit générer le contenu formaté correctement (enfaisant des print ou echo). outputErrors est appelé quand des erreurs bloquantes sont survenues pendant le traitementd’une action. Il génère alors une réponse différente, voir spécifique au format dans ce contexte là. Il ne faut pas oubliernon plus d’envoyer un entête http correspondant au type de format.

Exemple d’un format (bidon :-) ) :

class myFooResponse extends jResponse {protected $_type = ’foo’;

public $content = ’’;

/*** génère le contenu et l’envoi au navigateur.

* @return boolean true si la génération est ok, false sinon

*/public function output(){

global $gJConfig;$this->_httpHeaders[’Content-Type’]=’text/foo;charset=’.$gJConfig-> ←↩

defaultCharset;

Page 175: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

168 / 225

$this->sendHttpHeaders();echo "content:\n".$this->content."/content;";return true;

}

public function outputErrors(){global $gJConfig;header(’Content-Type: text/foo;charset=’.$gJConfig->defaultCharset);echo "errors\n";foreach( $GLOBALS[’gJCoord’]->errorMessages as $e){

echo ’[’.$e[0].’ ’.$e[1].’] ’.$e[2]." \t".$e[3]." \t".$e[4]."\n";}echo "/errors;";

}}

Comme dans l’exemple ci-dessus avec la propriété $content, vous pouvez rajouter toutes les propriétés et méthodesnécessaires à une manipulation aisé de l’objet dans les actions. Par exemple, l’objet jResponseHtml html instancied’office un template, contient une propriété pour spécifier le titre d’une page html, des méthodes pour ajouter deschoses dans le <head> etc..

N’hésitez pas à regarder le code source des fichiers dans lib/jelix/response/. Peut être d’ailleurs que votre formats’apparente à un de ceux fournis par Jelix. Dans ce cas, votre objet response peut hériter de cet objet, ajouter desméthodes, en redéfinir etc.

23.1.2 Stockage de la classe

Le nom de la classe importe peu, mais il doit être utilisé dans le nom du fichier, et précède le suffixe ’.class.php’.Dans notre exemple, la classe sera alors stockée dans le fichier myFooResponse.class.php.

Le fichier doit être enregistré dans le répertoire responses de votre application.

23.1.3 Déclarer la réponse

Pour que la réponse soit utilisable par les actions, il faut la déclarer avec un code. Et c’est ce code que vous indiquerezà la méthode getResponse dans les contrôleurs. Pour cela, vous ajouterez dans la section responses du fichier deconfiguration, une ligne code=classe.

[responses]foo=myFooResponse

Et dans un contrôleur, cela donne :

function index(){$rep = this->getResponse(’foo’);$rep->content=’hello world’;return $rep;

}

Pourquoi ne pas indiquer directement le nom de la classe à getResponse ? Parce que cela permet de redéfinir unmême type de réponse de façon transparente pour les actions et modules.

Page 176: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

169 / 225

23.1.4 À propos des templates

Les plugins de templates sont, pour un certain nombre, attribués à un type de réponse particulier. Aussi, si vous créerun nouveau type de réponse spécifique, il vous faudra adapter aussi dupliquer/copier/recréer les plugins de templatesexistants pour les autres types de réponses.

Si vous héritez par contre d’un objet response existant (de jResponseHtml par exemple), ne changez pas la propriététype de la classe mère, sinon vous ne pourrez pas réutiliser les plugins de templates existants (à moins de les redefinirs).

Voir la doc pour faire des plugins de templates.

Page 177: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

170 / 225

Chapitre 24

Système de thèmes

Jelix propose un système de thèmes, permettant donc de personnaliser les templates et les feuilles de style, sanstoucher aux fichiers originaux.

24.1 Les templates d’un thème

Un thème est un répertoire dans var/themes/. Ce répertoire contient des fichiers templates dans des sous-repertoiresqui correspondent à chaque module.

Par exemple, vous voulez adapter le template main.tpl du module exemple, pour le thème web20, vous stockerez unfichier main.tpl dans var/themes/web20/exemple/. Notez donc que le template original et le nouveau template possèdele même nom.

Le thème par défaut ayant pour nom "default", si vous voulez redéfinir un template d’un module, même si vousn’utilisez pas explicitement les thèmes, vous placerez ce template dans var/themes/default/le_module/le_template.tpl.

24.2 Les fichiers web d’un thème

Par fichier web, on entend les fichiers CSS, les images etc... Ces fichiers ne doivent pas être placé dans var/themes/car var n’est pas censé être accessible publiquement depuis le web.

Vous les placerez donc dans un répertoire themes/le_nom_du_theme/ dans le répertoire de base de votre application(basePath), en général donc dans www/

Pour avoir le chemin web du theme, vous pouvez utiliser ceci :

$chemin = $gJConfig->urlengine[’basePath’].’themes/’.$gJConfig->theme.’/’$rep->addCssLink($chemin.’design.css’);

Dans un template, vous avez une facilité en utilisant la balise meta :

{meta_html csstheme ’design.css’}

D’autres sont disponibles pour les feuilles de styles spéciales pour IE

{meta_html cssthemeie ’design.css’} pour ie{meta_html cssthemeie7 ’design.css’} pour ie7{meta_html cssthemeltie7 ’design.css’} pour ie < 7

Page 178: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

171 / 225

Mais vous avez aussi une variable déclarée automatiquement, j_themepath, dans un template contenant le chemindes thèmes

<img src="{$j_themepath}logo.png" alt="logo"/>

24.3 Déclarer un thème par défaut

L’activation d’un thème se fait dans le fichier de configuration, au niveau du paramètre theme :

theme = web20

24.4 Déclarer un thème dynamiquement

Pour offrir la possibilité à l’internaute de choisir son thème, vous pouvez lui proposer un formulaire avec la liste desthemes (liste que vous construisez vous même).

Ensuite vous stockez le nom du thème choisi quelque part (en session, ou dans un cookie par exemple).

Enfin, pour que le thème soit activé automatiquement, il suffit de récupérer le nom du theme correspondant à l’utili-sateur, et de le spécifier dans la configuration, au niveau du paramètre theme :

$GLOBALS[’gJConfig’]->theme = $themeChoisi;

Bien sûr, le meilleur endroit pour faire ça est dans un plugin de coordinateur qu’il vous faut développer.

Page 179: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

172 / 225

Chapitre 25

Surcharge de fichiers de modules

Il peut arriver que vous utilisiez un module fourni par un tiers, et que certains fichiers ne vous conviennent pas toutà fait. Plutôt que de les modifier directement, Jelix propose un moyen de redéfinir ces fichiers sans les toucher. Celapermet plus tard de mettre à jour ce module tiers sans écraser vos modifications.

Les fichiers d’un module que vous pouvez redefinir sont :– les templates, par le biais de thèmes– les fichiers de locales– les fichiers daos– les fichiers formsPour les thèmes, voir la page spécifique. Le thême par défaut se nommant "default", il suffit de mettre les nouveaux

templates dans le répertoire de ce thème.

Pour les autres types de fichiers, il faut mettre les nouveaux fichiers dans le répertoire var/overloads/. Ce réper-toire contient des sous-répertoires ayant les noms des modules. Ces sous-répertoires sont alors organisés comme lesmodules.

Par exemple, imaginons que vous voulez redefinir des fichiers du module exemple.– vous placerez les daos dans var/overloads/exemple/daos/– vous placerez les forms dans var/overloads/exemple/forms/– vous placerez les locales dans var/overloads/exemple/locales/Les noms des fichiers doivent être les mêmes que les originaux. Pour les daos, n’oubliez pas de respecter l’api du

dao original. C’est à dire que si des méthodes sont définis dans le dao original, il faut aussi les définir dans le nouveaufichier, sinon vous risquez d’avoir des erreurs PHP parce que les classes du module ne pourront appeler les-ditesméthodes.

Ensuite c’est tout. Le fait de mettre un fichier dans le répertoire var/overloads/ redéfini automatiquement le fichieroriginal correspondant. Ce sera ce nouveau fichier qui sera utilisé et non pas l’original.

Page 180: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

173 / 225

Chapitre 26

Développer et utiliser des plugins

Il existe toutes sortes de plugins pour ajouter des fonctionnalités à diverses parties de Jelix. On peut ainsi ajouterdes plugins pour le coordinateur, des drivers pour jDb, des drivers pour jAuth, des plugins pour jTpl ou encore desnouveaux moteurs d’URLs.

Tous les plugins sont regroupés dans des dépôts de plugins (note : ce n’était pas le cas dans jelix 1.0beta2 et inférieur).

26.1 Déclaration d’un dépôt de plugins

Vous pouvez déclarer un ou plusieurs dépôts de plugins. Un dépôt est un répertoire ayant une structure précise (voirplus loin). Il faut déclarer chacun de ces dépôt dans le paramètre pluginsPath de la configuration de l’application. Pardéfaut, ce paramètre vaut :pluginsPath = lib:jelix-plugins/,app:plugins/

Vous remarquez que vous pouvez indiquer plusieurs dépôts, séparés par une virgule. Ici il est indiqué qu’il y a deuxdépôts : le répertoire jelix-plugins dans le répertoire lib/, et un répertoire plugins dans votre application. Il y en a untroisième, implicitement et automatiquement déclaré, qui est le répertoire lib/jelix/plugins/ et contenant les pluginslivrés en standard avec Jelix.

Rappel : lib : est un raccourci indiquant le répertoire de base lib/, et app : un raccourci pour le répertoire de votreapplication. Vous pouvez aussi indiquer un chemin absolu. Attention toutefois si vous migrez votre application d’unemachine à une autre. Il est aussi possible d’utiliser un chemin relatif, mais celui-ci doit être relatif au script de pointd’entrée (index.php par ex).

26.2 Structure d’un dépôt et création de plugins

Un dépôt de plugins contient un répertoire pour chaque type de plugins et dans chacun de ces répertoires, un réper-toire pour chaque plugin.

Voici les types de plugins et les répertoires correspondant :– plugins de coordinateur : coord/– drivers pour jAuth : auth/– drivers pour jDb : db/– plugins de templates : tpl/– moteurs d’URLs : urls/Note : Pour les version 1.0beta2 ou inférieur, la notion de plugin était restreinte aux seuls plugins pour le coordinateur.

Aussi les dépôts de plugins ne contenaient que des plugins pour le coordinateur. Ceux-ci n’étaient pas placés dans unsous-répertoire coord/, mais directement dans le dépôt.

Page 181: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

174 / 225

26.3 Création de plugins

Jelix fournit en standard un certain nombre de plugins dans le dépôt lib/jelix/plugins/. Cependant, il est souventnécessaire de devoir en créer pour ses propres besoins. D’ailleurs toute contribution de nouveaux plugins est vivementencouragée ;-)

Les sections suivantes vous indiquent comment développer ces plugins.

26.4 plugins de coordinateur

Il est possible d’ajouter des plugins au coordinateur (le coeur de Jelix, jCoordinator) qui permettent de faire destraitements supplémentaires à différentes étapes de l’exécution d’une action, quelle que soit cette action.

Il est ainsi possible d’effectuer un traitement au démarrage du processus, juste avant l’exécution de l’action, justeaprès (avant affichage), et en fin de processus.

Les plugins pour le coordinateur sont aussi appelés plugins coord dans le jargon Jelix.

26.4.1 Utilisation d’un plugin coord

Déclaration

Pour activer un plugin coord, vous avez deux choses à faire dans le fichier de configuration d’un point d’entrée :– bien sûr, déclarer le dépôt contenant le répertoire de votre plugin, dans l’option pluginsPath de la configuration– indiquer le plugin dans la section [plugins], ainsi que son éventuel fichier de configurationSi vous placez votre plugin foo dans votreApplication/plugins/coord/ alors vous devez déclarer comme ceci :

pluginsPath = app:plugins/

[plugins]foo = foo.coord.ini.php

Ici on indique un fichier de configuration foo.coord.ini.php pour le plugin (le contenu et la structure de ce fichier deconfiguration dépend totalement du plugin). Dans le cas où votre plugin ne comporte pas de fichier de configuration,vous devez mettre 1 au lieu d’un nom de fichier, comme ceci :

foo = 1

Si vous utilisez plusieurs plugins de coordinateur, l’ordre de déclaration des plugins dans le fichier de configuration aune importance. Ainsi le premier plugin déclaré à la priorité sur les autres. C’est à dire que si ce premier plugin renvoiune action, les autres plugins ne seront pas exécutés. Il convient donc de choisir l’ordre de déclaration des plugins enfonction de la priorité que l’on veut pour chaque plugin. Par exemple si vous considérez que le plugin bar ne peut êtreexécuté que si le plugin foo n’a pas renvoyé d’action, alors il faudrait les déclarer comme ceci :

[plugins]foo = foo.plugin.ini.phpbar = 1

Configuration

Un plugin coord peut avoir besoin d’un fichier de configuration. Ce fichier doit être alors un fichier de type ini, placédans votreApplication/var/config/ et être déclaré dans la configuration comme indiqué précédemment. Le contenu inisera passé au constructeur du plugin sous forme de tableau (résultat de la fonction php parse_ini_file).

Page 182: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

175 / 225

Paramètres de plugins

Certains plugins coord peuvent attendre des paramètres qui sont fournis par les contrôleurs. En effet, un plugin peutvouloir tester quelque chose en fonction de l’action. Par exemple, le plugin coord d’authentification auth va vérifier sil’action demandée nécessite ou non d’être authentifié. Pour cela, on va indiquer dans chaque contrôleur un paramètrepour chaque action, destiné au plugin auth, qui indique cette information.

Ces paramètres sont stockés dans la propriété pluginParams du contrôleur. C’est un tableau associatif. Les clés sontles noms des méthodes, et les valeurs, un tableau contenant tous les paramètres de plugins associés à la méthode (etdonc à l’action correspondante). Une clé particulière, ’*’, indique les paramètres valables pour toutes les méthodes ducontrôleur.

Exemple :

public $pluginParams = array(’*’=>array(’auth.required’=>false)

);

Indique que toutes les actions du contrôleur ont un paramètre nommé "auth.required" et valant false.

26.4.2 Développement d’un plugin coord

Un plugin est en fait une classe qui implémente l’interface jICoordPlugin. Cette classe doit donc implémenter lesméthodes suivantes :

public function __construct($config);public function beforeAction($params);public function beforeOutput();public function afterProcess ();

Le constructeur reçoit la configuration du plugin.

La méthode beforeAction reçoit les paramètres de plugins déclarés dans le contrôleur. Elle peut renvoyer null si toutest ok ou alors un sélecteur d’action, jSelectorAct, si il faut exécuter une autre action que celle prévue.

La méthode beforeOutput sera appelée après exécution de l’action.

Le méthode afterProcess sera appelée en fin de traitement (après affichage donc).

Cette classe est à placer dans un dépôt de plugins. Par exemple, le répertoire plugins/ de votre application. Ou alorsdans un répertoire plugins/ d’un module. Le sous répertoire dans lequel est placé le plugin doit porter le nom duplugin, et la classe doit suivre un nommage particulier. Si le plugin s’appelle exemple, alors :– le répertoire du plugin sera plugins/coord/exemple/– le fichier contenant la classe du plugin devra être plugins/coord/exemple/exemple.coord.php– le nom de la classe du plugin devra être exempleCoordPlugin, implémentant l’interface jICoordPlugin

26.5 drivers pour jAuth

Si les drivers standards pour jAuth ne vous conviennent pas, vous pouvez donc en créer un. Voici comment.

Page 183: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

176 / 225

26.5.1 Création

Un driver est une classe qui respecte l’interface jIAuthDriver, qui reprend à peu de chose près l’API de jAuth (maisne dérive pas de jAuth).

Ces drivers sont appelés par jAuth. Ils font les opérations de "bas" niveau (accès base de données, ou à un annuaireldap, ou à un fichier texte etc...)

Soit exemple le nom de votre driver, vous devez créer une classe exempleAuthDriver, dans un fichier exemple.auth.php,et placer celui-ci dans un répertoire auth/exemple/ dans un dépôt de plugins.

26.5.2 Activation

Pour utiliser votre nouveau driver, vous devez indiquer "exemple" au niveau de l’option "driver" du fichier deconfiguration du plugin auth, et avoir une section "exemple" suivit des éventuelles options spécifiques au driver.

Exemple :

driver=exemple

[exemple]foo=bar

26.6 drivers pour jDb

jDb, la couche d’abstraction d’accés aux bases de données, a un système de plugin, ou "drivers". Un driver permetd’accéder à un type de base de donnée spécifique.

26.6.1 Activation

Pour savoir comment activer un driver pour jDb, voyez le chapitre sur jDb

26.6.2 Création d’un driver

Un driver pour jDb est constitué de trois classes :– une classe pour la connexion à la base et l’exécution des requêtes, héritant de jDbConnection– une classe pour récupérer les résultats, héritant de jDbResultSet– une classe utilitaire héritant de jDbTools, permettant de récupérer la liste des tables, la liste des champs d’une table

etc..

Fichiers et nommages

Un driver possède un nom identifiant. Prenons le nom "exemple" pour la suite.

Les fichiers du driver doivent se trouver dans un répertoire db/exemple dans un dépôt de plugins.

Les noms des fichiers doivent suivre ce nommage :– exemple.dbconnection.php pour la classe de connexion– exemple.dbresultset.php pour la classe de resultset– exemple.dbtools.php pour la classe utilitaire

Page 184: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

177 / 225

Et dans chacun de ces fichiers, les classes doivent respectivement avoir le nommage suivant :– exempleDbConnection– exempleDbResultSet– exempleDbTools

Classe de connexion

Elle doit hériter de jDbConnection qui contient quelques méthodes abstraites qu’il faut définir. Son rôle est de seconnecter/déconnecter à la base de donnée. Elle est chargée aussi d’initier les transactions et de les confirmer ouannuler. Enfin, elle exécute ou prépare les requêtes, en renvoyant un objet résultat.

Pour se faire, elle doit redéfinir les méthodes suivantes :– le constructeur si il y a besoin de faire des choses à l’instanciation du driver. Typiquement, vérifier que les fonctions

PHP nécessaires sont bien là.– _connect() et _disconnect(), pour la connexion et la déconnexion à la base de donnée– _quote, pour échapper une chaîne de caractère avant que celle-ci soit utilisée dans une requête– _doQuery et _doLimitQuery, pour lancer des requêtes qui ramènent des enregistrements (SELECT ou procédures

stockées). Elles doivent renvoyer un objet exempleDbResultSet ou false si la requête a échoué– _doExec, pour lancer des requêtes ne renvoyant pas d’enregistrements (UPDATE, DELETE, INSERT...). Doit

renvoyer le nombre d’enregistrements affectés, ou false si la requête a échoué– la méthode prepare(), pour préparer les requêtes.– beginTransaction(), commit(), rollback(), pour les transactions– errorInfo() et errorCode() renvoyant l’intitulé et le code de la dernière erreur– lastInsertId(), permettant de récupérer la dernière valeur du dernier id autoincrémenté généré.– _autoCommitNotify()Si le driver ne prend pas en charge certaines fonctionnalités, il doit générer une exception.

Voir la référence de jDbConnection pour plus de détails.

Classe de résultat

Elle doit hériter de jDbResultSet qui contient quelques méthodes abstraites qu’il faut définir. Un objet de cette classeest normalement renvoyé par les méthodes prepare, _doQuery et _doLimitQuery de la classe exempleDbConnection.

Vous devez notament redéfinir les méthodes suivantes :– _fetch(), qui doit récupérer l’enregistrement suivant dans la liste des résultats. Elle doit tenir compte de la propriété

_fetchMode. Dans la propriété _idResult, vous trouverez l’identifiant de la ressource liée aux résultats.– _free(), pour libérer la ressource liée aux résultats (_idResult)– _rewind(), pour revenir au début des résultats– rowCount, pour retourner le nombre de résultats– bindColumn, bindParam, bindValue, columnCount et execute pour les requêtes préparées.Voir la référence de jDbResultSet pour plus de détails.

Classe utilitaire

Elle doit hériter de jDbTools. Cette classe permet de récupérer des informations sur la base de donnée, sur une tableetc. Utilisée notamment par les scripts jelix-scripts.

Vous redéfinirez en particulier les méthodes suivantes :– _getTableList(), retournant un tableau contenant les noms des tables présentes

Page 185: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

178 / 225

– _getFieldList(), retournant la liste des champs de la table dont le nom est donné en argument. Cette liste doit êtreconstitué d’objets jDbFieldProperties.

– execSQLScript() si vous voulez redéfinir la manière dont est parsé et executé un ensemble de requêtes SQLprésentes dans un script.

Voir la référence de jDbTools pour plus de détails.

Exemples

Voir les drivers pour mysql, postgresql etc dans le répertoire lib/jelix/plugins/db/.

26.7 plugins de templates

Vous pouvez ajouter vos propres fonctionnalités de templates dans le moteur de template jTpl. Elles doivent êtreimplémentées dans un plugin de template. Il y a quatre types de plugin :– les fonctions– les modificateurs– les blocs– les metaRegardez dans lib/jelix/plugins/tpl/, vous avez plein d’exemples relativement simples à comprendre.

26.7.1 Emplacement

Les plugins sont stockés dans un répertoire ayant une arborescence précise : ils sont classés dans des sous-répertoiresen fonction du type de réponse auxquels ils sont destinés. Cela évite ainsi d’utiliser des plugins pour le XUL quandon fait du HTML par exemple.

C’est ainsi que dans un dépôt de plugin de template, vous avez un sous répertoire "html", "xul", "text" et "common".Le sous-répertoire "common" est celui dans lequel sont mis les plugins qui ne sont pas destinés à des types de réponsesprécis.

lib/jelix/plugins/tpl/ est le dépôt par défaut de jelix pour les plugins de template. Mais vous mettrez en général vospropres plugins de template dans le répertoire plugins/ de votre application, ou dans un autre dépôt à votre convenance(dépôt à déclarer, comme indiqué sur la page des plugins). Sachant que dans le dépôt en question, il vous faut mettrecomme indiqué précédemment vos plugins dans tpl/common/, tpl/html/, ou tpl/text/ etc...

26.7.2 plugin type "function"

Ce sont des plugins que l’on pourra appeler comme ceci :

{mafonction $param1,$param2}

En admettant que c’est un plugin uniquement pour html, vous créerez un fichier function.mafonction.php danstpl/html/, dans lequel vous déclarez une fonction "jtpl_function_html_mafonction". Cette fonction prend au moinsun paramètre : l’objet jTpl qui est utilisé pour le template, et que vous pouvez donc manipuler à loisir. Les autresparamètres sont ceux qui sont indiqués dans le template. La fonction ne doit rien renvoyer.

Dans la fonction, vous faites ce que vous voulez. En général, une fonction affiche quelque chose, donc effectue des"echo".

Exemple, le plugin zone :

Page 186: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

179 / 225

function jtpl_function_html_zone($tpl, $name, $params=array()){

echo jZone::get($name, $params);}

26.7.3 plugin type "cfunction"

Ce sont des plugins qui s’utilisent comme un plugin de fonction (donc du point de vue de l’utilisateur, il n’y a pasde changement), mais qui ne sont pas programmés de la même manière. Contrairement à un plugin function qui esttoujours appelé lors de l’affichage ou plutôt de l’évaluation du template, un plugin cfunction est appelé bien avant,lors de la compilation du template. Pour rappel, un template est d’abord transformé en contenu php (la compilation),ce contenu php est stocké dans un fichier de cache, et il est ensuite évalué lorsque l’on veut afficher le template.

Un plugin cfunction ne génère donc pas un contenu, mais génère du code PHP qui sera inclus dans le contenu PHPmis en cache. Cela est nécessaire dans certains cas, et peut améliorer les performances dans d’autres.

un plugin cfunction doit accepter en paramètre un objet jTplCompiler, et un tableau contenant les paramètres indiquésdans le template. Vous ne devez en général pas toucher à ces paramètres, juste les inclure directement dans le codePHP que va générer le plugin. Le plugin ne doit rien afficher, et doit retourner le contenu généré.

Voici l’exemple d’un plugin cfunction , qui fait au final la même chose que l’exemple de plugin function précédent :

function jtpl_cfunction_html_zone($compiler $params=array()){

if (count($params) < 1 || count($params) > 2) {$compiler->doError2(’errors.tplplugin.cfunction.bad.argument.number’,’zone ←↩

’,’1-2’);}

if (count($params) == 1) {$php = ’ echo jZone::get(’.$params[0].’);’;

}else {

$php = ’ echo jZone::get(’.$params[0].’, ’.$params[1].’);’;}return $php;

}

26.7.4 plugin type "modifier"

Un plugin modificateur est une fonction jtpl_modifier_monmodificateur prenant une chaine en paramètre (et even-tuellement d’autres pour ceux qui ont besoin de paramètre de modificateur, voir plus haut), et renvoie une chainetransformée. La fonction doit être stockée dans un fichier de nom modifier.monmodificateur.php.

Exemple avec le plugin count_characters :

function jtpl_modifier_html_count_characters($string, $include_spaces = false){

if ($include_spaces)return(strlen($string));

return preg_match_all("/[^\s]/",$string, $match);}

Page 187: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

180 / 225

26.7.5 plugin de bloc

Comme les plugins de type cfunction, les plugins de blocs ne sont pas appelés lors de l’affichage du template, maislors de sa compilation. Un plugin de bloc ne renvoie donc pas une valeur transformée, ne fait pas d’affichage, maisrenvoie du code php, qui sera inclus dans la version compilée du template.

Ils permettent de se faire ses propres structures if ou boucle, ou autre blocs spéciaux.

Un plugin de bloc est une fonction jtpl_block_html_monbloc, qui accepte en paramètre un objet jTplCompiler, unbooléen et d’éventuels autres paramètres. La fonction doit être stockée dans un fichier block.monbloc.php.

La fonction est appelée par le compilateur, une première fois quand il rencontre le tag de début, et une deuxième foisquand il rencontre le tag de fin. Le booléen en paramètre permet de savoir à quel moment la fonction est appelée (truequand il s’agit de la première fois).

Exemple du plugin ifuserconnected :

function jtpl_block_ifuserconnected($compiler, $begin, $params=array()){

if($begin){if(count($params)){

$content=’’;$compiler->doError1(’errors.tplplugin.block.too.many.arguments’,’ ←↩

ifuserconnected’);}else{

$content = ’ if(jAuth::isConnected()){’;}

}else{$content = ’ } ’;

}return $content;

}

26.7.6 plugin meta

Un plugin meta est appelé lors de l’évaluation d’un template, mais juste avant l’affichage. En effet, lors de l’évalua-tion, il y a deux phases, l’une qui permet de faire des choses avant l’affichage, puis l’affichage proprement dit. Cettephase de pré-affichage est généralement utilisée pour modifier des propriétés de l’objet response courant. Par exemple,pour une réponse HTML, un template sert uniquement à générer la partie "body" d’une page html. Si on veut, dans leHTML, spécifier des choses du genre, liens css ou script JS à lier (donc concrétement à rajouter des choses au niveaude la balise head), il faut le faire pendant le pré-affichage. Et les plugins meta sont appelés pendant cette phase, grâceà l’instruction {meta ...}.

à compléter.. (voir le plugin lib/jelix/plugins/tpl/html/meta.html.php pour un exemple).

26.8 moteurs de urls

jUrl peut utiliser le moteur d’urls de votre choix.

26.8.1 Activation

Pour activer un plugin d’url, il faut d’abord le placer dans un répertoire portant son nom, dans un répertoire "urls"d’un dépôt de plugin.

Page 188: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

181 / 225

Ensuite, dans la section urlengine du fichier de configuration principal, vous indiquez le nom du moteur d’url dansle paramètre "engine". Ensuite, selon le moteur d’urls, il peut y avoir d’autres choses à paramétrer.

26.8.2 Création

À documenter. En attendant, regarder les moteurs existants dans lib/jelix/plugins/urls.

Page 189: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

182 / 225

Chapitre 27

La configuration en détails

27.1 Points d’entrée

Un point d’entrée est un script par lequel passe une partie ou toutes les actions. Seuls les points d’entrée sont enprincipe accessible depuis le web, donc dans le répertoire www de l’application.

Ce sont eux qui instancient un objet jCoordinator, un objet de type jRequest qui analysera la requète et qui indiquentle fichier de configuration à utiliser.

Un point d’entrée contient un bout de code comme celui-ci :// chargement du fichier principal de jelixrequire_once (’../../lib/jelix/init.php’);

// chargement du fichier d’initialisation de l’applicationrequire_once (’../../testapp/application.init.php’);

// le fichier de configuration à utiliser$config_file = ’index/config.ini.php’;

// instanciation du coordinateur

$jelix = new jCoordinator($config_file);

// instanciation d’un objet de type jRequestrequire_once (JELIX_LIB_CORE_PATH.’request/jClassicRequest.class.php’);$request = new jClassicRequest();

// execution de l’action$jelix->process($request);

Il y aura en principe un point d’entrée pour chaque type de requête : classique, XML-RPC, JSON-RPC, RSS, Atometc..

Et donc il y aura en général une configuration spécifique à chaque point d’entrée.

27.2 Organisation de la configuration

La configuration du framework est stockée dans un fichier de type "ini". Il s’agit d’un fichier contenant des sections,débutant par un nom entre crochet. Chacune de ces sections contenant une série de paramètres "nom=valeur". Il y a

Page 190: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

183 / 225

une section "générale", qui n’a pas de nom, et dont les paramètres sont en début du fichier.

Les fichiers de configurations sont situés dans var/config.

Chaque point d’entrée peut avoir son fichier de configuration spécifique. Mais la plupart du temps ils ont beaucoupde valeurs de paramètres identiques entre eux. Pour éviter de répéter ces paramètres identiques dans chaque fichier, ily a un fichier de configuration commun, qui a pour nom defaultconfig.ini.php. Il est automatiquement lu, en plus dufichier spécifique au point d’entrée, et il n’est pas besoin de l’indiquer dans les points d’entrée.

Un fichier de configuration spécifique ne contiendra donc que les valeurs spécifiques pour le point d’entrée, et peutbien sûr redéfinir des paramètres définis dans le fichier commun.

Exemple d’un fichier defaultconfig.ini.php (extrait) :

locale = "fr_FR"charset = "ISO-8859-1"timeZone = "Europe/Paris"theme = default

checkTrustedModules = off

; list of modules : module,module,moduletrustedModules =

pluginsPath = lib:jelix-plugins/,app:plugins/modulesPath = lib:jelix-modules/,app:modules/

dbProfils = dbprofils.ini.php

[plugins];nom = nom_fichier_ini

[responses]...

Pour les requêtes classiques, passant par index.php, on pourrait avoir le fichier var/config/index/config.ini.php. Onle met ici dans un sous répertoire index pour une meilleure organisation (il peut en effet y avoir des fichiers deconfiguration de plugins propre à chaque point d’entrée, ça peut donc vite devenir peu lisible dans var/config/).

Dans ce fichier, on ne va redéfinir que certaines choses :

startModule = "testapp"startAction = "main:index"

[plugins]autolocale = index/autolocale.ini.php

[responses]html=myHtmlResponse

Pour le fichier de configuration de xmlrpc.php, on pourrait avoir par exemple :

startModule = "testapp"startAction = "xmlrpc:index"

etc.

Page 191: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

184 / 225

27.3 Déscriptif des sections de la configuration

Pour avoir la liste complète des options, voir le fichier lib/jelix/core/defaultconfig.ini.php, qui est "l’original" de lacopie que vous devez avoir dans var/config/.

Voici les différentes sections.

27.3.1 section générale

Ce sont les paramètres situés en début de fichier. Ils définissent des valeurs par défaut ou génériques à l’application.

startModule = "jelix"startAction = "default:index"locale = "fr_FR"charset = "UTF-8"timeZone = "Europe/Paris"

checkTrustedModules = off

; list of modules : module,module,moduletrustedModules =

pluginsPath = lib:jelix-plugins/,app:plugins/modulesPath = lib:jelix-modules/,app:modules/

dbProfils = dbprofils.ini.php

theme = defaultuse_error_handler = on

enableOldActionSelector =

Détails des paramètres :– startModule, startAction : module et action par défaut (redéfinis en général pour chaque type de réponse. Voir la

section précédente)– locale, charset : langue et encodage par défaut des réponses– timeZone : défini le décalage horaire pour toutes les fonctions de dates et heures– checkTrustedModules, trustedModules et modulesPath : options concernant les modules– pluginsPath : liste des chemins d’accès aux plugins– dbProfils : fichier de configuration des profils d’accès aux bases de données. Voir l’accès aux bases de données– theme : nom du thème sélectionné par défaut. Voir la description du système des thèmes de Jelix– use_error_handler : cette option devrait rester à on pour que Jelix retourne des informations pertinentes sur les

erreurs et exceptions des scripts.– enableOldActionSelector : affecter la valeur 1 pour garder une compatibilité avec les sélecteurs d’action de Jelix

version 1.0 beta3 et antérieures. Pour les versions ultérieures, ce paramètre n’est pas nécessaire.

27.3.2 section plugins

Doit contenir les noms des plugins à activer. Ils seront chargés à partir des chemins définis dans le paramètre généralpluginsPath.

Par exemple, ci-dessous la configuration active le plugin de coordinateur gérant l’authentification et dont les para-mètres se trouve dans le fichier auth.coord.ini.php. Pour plus de détails, voir la documentation sur l’authentification

Page 192: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

185 / 225

[plugins];nom = nom_fichier_iniauth = "auth.coord.ini.php"

27.3.3 section responses

Cette section permet de personnaliser les types réponses et leurs alias. Chaque ligne est un couple <alias de ré-ponse>=<class de la réponse>.

Par exemple, Il est assez courant de vouloir surcharger la réponse html par défaut (jResponseHtml) en introduisantune ligne html=myhtmlresponse. Voir plus en détails dans personnalisation de réponse commune

Ci-dessous les valeurs par défaut des différents type de réponses :

[responses]html = jResponseHtmlredirect = jResponseRedirectredirectUrl = jResponseRedirectUrlbinary = jResponseBinarytext = jResponseTextjsonrpc = jResponseJsonrpcjson = jResponseJsonxmlrpc = jResponseXmlrpcxul = jResponseXulxuloverlay = jResponseXulOverlayxuldialog = jResponseXulDialogxulpage = jResponseXulPagerdf = jResponseRdfxml = jResponseXmlzip = jResponseZiprss2.0 = jResponseRss20atom1.0 = jResponseAtom10css= jResponseCssltx2pdf= jResponseLatexToPdftcpdf = jResponseTcpdf

27.3.4 section error_handling

Les paramètres de cette section permettent de configurer les notifications survenant lors de l’exécution d’un scriptde l’application. Pour plus de détails, voir la documentation sur la gestion d’erreurs.

Les notifications ont différents niveaux d’importance. Jelix défini les niveaux suivants correspondant à ceux de PHP :– default = niveau sélectionné si aucun autre niveau ne correspond– error = signale une erreur nécessitant l’interruption du script– warning = signale un mauvais traitement sans toutefois névessiter l’interruption du script– notice = signale une erreur potentielle– strict = signale des messages de moteur PHP pour améliorer l’interopérabilité et la compatibilité du scriptCi-dessous, l’ensemble des paramètres de la section :

[error_handling]messageLogFormat = "%date%\t[%code%]\t%msg%\t%file%\t%line%\n"logFile = error.logemail = root@localhostemailHeaders = "Content-Type: text/plain; charset=UTF-8\nFrom: webmaster@yoursite. ←↩

com\nX-Mailer: Jelix\nX-Priority: 1 (Highest)\n"

Page 193: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

186 / 225

quietMessage="A technical error has occured. Sorry for this trouble."

showInFirebug = off

; mots clés que vous pouvez utiliser : ECHO, ECHOQUIET, EXIT, LOGFILE, SYSLOG, ←↩MAIL, TRACE

default = ECHO EXITerror = ECHO EXITwarning = ECHOnotice = ECHOstrict = ECHO; pour les exceptions, il y a implicitement un EXITexception = ECHO

– messageLogFormat et logFile configurent la sortie en fichier de log (LOGFILE ou SYSLOG)– email et emailHeaders configurent la sortie sous forme de mail (MAIL)– quietMessage défini un message neutre pour l’utilisateur (ECHOQUIET)– showInFirebug : si affectée à on, toutes les notifications seront renvoyés vers la console de l’extension Firebug

du navigateur Firefox via son api console.

les dernières options permettent d’associer un format de sortie à chaque niveau de notification.

27.3.5 section compilation

Défini le comportement du moteur de template de Jelix. Et notamment de la phase de compilation. Voir la documen-tation sur les templates pour plus de détails.

[compilation]checkCacheFiletime = onforce = off

– checkCacheFiletime : si on alors un template est recompilé si sa date de modification est plus récente que lefichier PHP résultant de la compilation.

– force : si on, le template est recompilée systématiquement.

27.3.6 section urlengine

@TODO : à compléter

27.3.7 section logfiles

Cette section défini comment seront écrits les logs à l’aide de jLog.

Les fichiers logs sont stockés dans le dossier /var/log/ de votre application. Vous pouvez définir un fichier de logpar module en associant le nom du module à un nom de fichier log et faisant un appel à jLog en passant en dernierargument le nom du module.

; log par défautdefault = messages.log

; log "news"news = news.log

Page 194: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

187 / 225

Autre exemple utilisant l’extension Firebug du navigateur Firefox (ce qui permet une vision très rapide des messagesde déboggage).

[logfiles]default="!firebug"file = "messages.log"

Et pour un dump de contenu de taille importante, il suffit d’indiquer le type ’file’ au dernier paramètres des méthodesde jLog pour l’obtenir à nouveau dans un fichier de log classique.

Pour plus de détails sur l’utilisation des fichiers log dans Jelix se reporter au manuel concernant jLog

27.3.8 section mailer

Défini les paramètres d’envoi de mail à travers l’application, comme par exemple pour une authentification ou encoreplus bas-niveau pour les notifications.

[mailer]webmasterEmail = root@localhostwebmasterName =

; How to send mail : "mail" (mail()), "sendmail" (call sendmail), or "smtp" (send ←↩directly to a smtp)

mailerType = mail; Sets the hostname to use in Message-Id and Received headers; and as default HELO string. If empty, the value returned; by SERVER_NAME is used or ’localhost.localdomain’.hostname =sendmailPath = "/usr/sbin/sendmail"

; if mailer = smtp , fill the following parameters

; SMTP hosts. All hosts must be separated by a semicolon : "smtp1.example.com:25; ←↩smtp2.example.com"

smtpHost = "localhost"; default SMTP server portsmtpPort = 25; SMTP HELO of the message (Default is hostname)smtpHelo =; SMTP authenticationsmtpAuth = offsmtpUsername =smtpPassword =; SMTP server timeout in secondssmtpTimeout = 10

27.3.9 section acl

Défini les paramètres de la gestion des droits d’accès dans l’application. Voir la documentation sur la gestion desdroits

[acl]driver = dbenableAclDbEventListener = off

Page 195: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

188 / 225

27.3.10 section sessions

Défini le mode de gestion des sessions PHP (fichier ou bases de données). Pour plus de détails, voir la documentationsur les sessions

[sessions]shared_session = off; Use alternative storage engines for sessions;; usage :;; storage = "files"; files_path = "app:var/sessions/";; or;; storage = "dao"; dao_selector = "jelix~jsession"; dao_db_profile = ""

Page 196: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

189 / 225

Cinquième partie

Aide au développement

Page 197: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

190 / 225

Les outils fournis dans Jelix pour aider au développement d’une application.

Page 198: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

191 / 225

Chapitre 28

Configurer le gestionnaire d’erreur

Les classes du framework peuvent générer des erreurs de deux façons différentes par :– un trigger_error (erreur PHP)– une exceptionUne erreur PHP est générée dans le cas d’une erreur technique due à un défaut dans la programmation. C’est alors

au développeur de corriger l’erreur.

Une exception est générée dans le cas d’une erreur qui peut survenir de façon imprévisible durant l’exécution d’uneaction. Par exemple une erreur suite à l’impossibilité de se connecter sur une base de données ou alors une erreur"fonctionnelle", "métier".

28.1 Paramétrage des gestionnaires d’erreurs

Quelle que soit l’origine de l’erreur, celle-ci passe par un gestionnaire d’erreur (sauf les exceptions interceptées parun try/catch). Il y a un gestionnaire d’erreur attribué aux erreurs PHP et un autre attribué aux exceptions.

Les gestionnaires d’erreurs sont chargés d’effectuer les actions indiquées dans la configuration, selon le type d’erreur.Il s’agit des paramètres default, error, warning, notice, strict, exception dans la section error_handling. Chacunde ses paramètres doit contenir un ou plusieurs de ces mots qui indique une action a effectuer :

L’option messageLogFormat indique le formatage du message d’erreur pour son stockage dans le fichier de log,syslog ou le mail.

Si, pour l’action ECHO avec les réponses HTML et XUL, vous voulez afficher les erreurs dans Firebug (une exten-sion pour Firefox), mettez l’option showInFirebug à on (jelix 1.0).

28.2 Code erreur

Chaque message d’erreur est localisé dans les fichiers properties et chaque erreur devrait posséder un numéro. Cenuméro est indiqué dans les fichiers properties des messages localisés, de cette façon :

cle.chaine = (code_erreur)message d’erreur

Le message d’erreur au final ne contiendra pas le code erreur. Et ce dernier sera extrait.

Voici les plages de code erreurs

Si vous générez des erreurs pour vos propres besoins, leurs codes doivent être supérieur à 5000.

Page 199: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

192 / 225

Page 200: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

193 / 225

Chapitre 29

Développer des tests unitaires

29.1 Développer des tests unitaires

Le développement de test unitaires est de plus en plus présents dans les projets, et Jelix propose de quoi en réaliserfacilement. La réalisation des tests unitaires fait d’ailleurs partie des méthodes de développement comme XP (eXtremeprogramming). Le processus de développement veut, en théorie (et en gros), qu’à chaque fois que l’on développe unefonctionnalité, une méthode, on développe aussi les tests qui vont permettre de vérifier le bon fonctionnement de laméthode. Et à chaque fois que l’on modifie ou ajoute un bout de code, on lance tout les tests unitaires pour vérifierqu’il n’y a pas de regressions. Cela permet ainsi de garantir un minimum, un fonctionnement robuste de l’application.

29.1.1 Préparation

Les tests unitaires dans Jelix ne peuvent s’effectuer qu’avec l’édition "developer" de Jelix. Celle-ci contient eneffet un module spécifique pour lancer les tests unitaires, junittests, et la bibliothèque SimpleTest. Si vous voulezabsolument lancer les tests unitaires sur un serveur en production avec une édition "optimized" de jelix, vous devez ycopier les répertoires lib/simpletest/ et lib/jelix-modules/junittests de l’édition "developer".

Pour pouvoir lancer les tests, il faut aussi ajouter au début du fichier de configuration de votre application :

enableTests = on

Vous devez mettre à off quand vous passez votre application sur le serveur de production, ou utilisez une édition"optimized" de jelix (ou encore supprimer le module junittests tout simplement). Cela évite que n’importe qui puisselancer les tests unitaires.

29.1.2 Création de tests unitaires

les fichiers de tests

Les tests unitaires, ce sont des scripts qui font des tests sur des classes, des méthodes, des fonctions.

Les tests dans Jelix doivent reposer sur la bibliothèque simpletest : vous devez donc réaliser des classes, qui héritentde la classe UnitTestCase de simpletest, et vous les placez dans un ou plusieurs fichiers dans les répertoires "tests" devos modules.

Ces fichiers seront ensuite appelés par le module junittests quand vous voudrez les exécuter.

Les tests peuvent être lancés soit par l’interface web de junittests, soit par le script en ligne de commande fourni parjunittests. Certains tests doivent parfois s’exécuter uniquement via le web, ou uniquement via la ligne de commande

Page 201: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

194 / 225

(tout dépend de la nature de ces tests). Aussi les noms des fichiers de tests doivent se terminer par un suffixe précispour faire savoir à junittests les tests qu’il peut lancer dans tel ou tel contexte :– .html.php : le test ne pourra être lancé que via l’interface web– .cli.php : le test ne pourra être lancé que via la ligne de commande– .html_cli.php : le test peut être lancé indifféremment via le web ou via la ligne de commande.Le nom qui précède le suffixe importe peu. Sachez toutefois qu’il sert de libellé lors des affichages des tests, et une

transformation est effectué sur ce nom pour un affichage plus lisible :– les points sont transformés en " : "– les caractères soulignés "_" sont transformés en espaces.Par exemple si on nomme le fichier ainsi, "jdao.main_api_with_pdo.html.php", le libellé des tests contenus dans ce

fichier sera "jdao : main api with pdo". Et comme il a le suffixe ".html.php", il ne pourra être lancé que via l’interfaceweb de junittests.

Création d’un test

Pour créer un test, il faut créer une classe héritant de UnitTestCase ou des autres classes héritières de UnitTestCaseproposées par simpletest, et y écrire des méthodes dont le nom doit commencer par "test". Ces méthodes feront alorsles tests que vous désirez, en utilisant l’API de simpletest. Pour plus de détails sur cette API, lisez la documentation surle site de simpletest, en particulier la page sur unittestcase. Notez que dans cette documentation, vous devez ignorertout ce qui concerne les "reporters" et les "group tests" : le module junittests s’occupant déjà de tout ça. Vous pouvezaussi regarder les tests qui sont présents dans le module unittest de l’application testapp disponible en téléchargement.

Voici un exemple de test. Admettons que l’on veuille faire des tests sur une classe "panier" d’un module "shop". Oncrée alors un fichier "shop/tests/panier.html.php" et on y place la classe suivante :

class testShopPanier extends UnitTestCase {

function testPanierVide () {$panier = jClasses::create("shop~panier");$content = $panier->getProductList();$this->assertIdentical( $content, array());

}}

Le nom de la classe "testShopPanier" est totalement libre. Mais il faut faire attention que ce ne soit pas un nom déjàpris par une autre classe de tests dans d’autres modules. Aussi il est recommandé que le nom contienne le nom dumodule ou autre signe distinctif.

On a ici créé une fonction qui teste si, lors de la création d’un panier, celui-ci est bien vide. On instancie donc laclasse panier, on appelle sa méthode getProductList qui devrait nous renvoyer une liste de produits. Et ensuite on testesi le contenu renvoyé est bien un tableau vide.

Vous pouvez ajouter autant de méthodes de tests que vous voulez dans une même classe de tests, mais aussi declasses dans un seul fichier. Voici un deuxième exemple :

function testAjoutProduit () {// creation d’un panier$panier = jClasses::create("shop~panier");

// creation d’un produit$product = jClasses::create("shop~product");$product->label = "DVD coluche";$product->price = 12.40;

// ajout du produit dans le panier

Page 202: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

195 / 225

$panier->addProduct($product);

$liste = $panier->getProductList();

// test si le panier contient bien un produit$this->assertTrue( count($liste) == 1);

// test si le produit contenu correspond bien à celui mis$p = $liste[0];// verification que c’est un objet productif($this->assertIsA($p , ’product’)){

$this->assertEqual($p->label , ’DVD coluche’);$this->assertEqual($p->price , 12.40);

}

// on enleve le produit$panier->removeProduct(’DVD coluche’);

// on vérifie que le panier est bien vide à nouveau$content = $panier->getProductList();$this->assertIdentical( $content, array());

}

29.2 Lancement des tests

Une fois vos tests réalisés, il faut les lancer avec le module junittests.

29.2.1 Via l’interface web

Le lancement des tests se fait en appelant la page principale du module junittests. Un exemple d’url : http ://tes-tapp.jelix.org/index.php ?module=junittests . Vous pouvez d’ailleurs vous rendre à cette url précise : vous y verreztous les tests unitaires sur Jelix ;-)

N’oubliez pas de mettre dans la configuration le paramètre enableTests = on, sinon vous aurez droit à une erreur 404.

Cette première page présente sur la gauche la liste de tous les tests présents dans votre application, classés parmodule. Il suffit de cliquer sur un des tests pour le lancer et voir le résultat. Vous avez des liens aussi pour lancer tousles tests d’un module, ou tous les tests de votre application (attention cependant, les lancer tous peut être long pourles grosses applications, et provoquer un "timeout" au niveau du navigateur).

À la fin du lancement des tests, il est affiché le nombre de tests unitaires qui sont passés avec succès, et celui destests échoués.

Notez que le module junittests utilise sa propre réponse HTML, et fait appel à une feuille de style tests/design.cssqui doit être placée dans le répertoire www de votre application. Vous en trouverez une dans le répertoire install dumodule junittests.

29.2.2 Via la ligne de commande

Le lancement des tests se fait en exécutant un script tests.php se trouvant dans le répertoire scripts de l’applica-tion Jelix. Vous pouvez utiliser l’application testapp (voir dans "Application de test") pour en voir un exemple.

Voici une liste des différentes commandes disponibles :

Page 203: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

196 / 225

Lister tous les tests

Voir la liste de tous les tests de votre application rangés par modules. Vous devez préciser seulement ici le nom ducontroleur car le mot-clé "help" renvoie vers l’aide générale de la ligne de commande de Jelix. Exemple :

php tests.php default:help

Lancer tous les tests de l’application

Exécuter l’ensemble des tests de votre application. Pas besoin ici de paramètre particulier, car exécuter tous les testsde l’application est l’action par défaut. Exemple :

php tests.php

Lancer tous les tests d’un module

Exécuter l’ensemble des tests d’un module spécifié. Vous devez ici donner le nom de votre module en paramètre.Exemple pour testapp :

php tests.php module jelix_tests

Lancer un test particulier

Exécuter le test spécifié. Vous devez ici donner le nom du module et le nom du test en paramètre, qui est spécifiédans la commande help (entre parenthèses). Exemple :

php tests.php single jelix_tests core.jlocale

À la fin du lancement des tests, il est affiché le nombre de tests unitaires qui sont passés avec succès, et celui destests échoués.

Notez que si vous n’avez pas le fichier tests.php dans le répertoire scripts, vous pouvez récupérer tous les fichiersnécessaires (le script et le fichier de configuration) dans le répertoire install du module junittests.

Page 204: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

197 / 225

Chapitre 30

Les aides pour debogguer

30.1 jLog

jLog est une classe qui permet de tracer, ou plus précisément d’écrire des messages ou le contenu de variable dansun fichier journal. Elle possède pour cela deux méthodes statiques :– jLog : :log($message) pour écrire un message dans le fichier journal– jLog : :dump($variable, $message) pour écrire le contenu de la variable dans le fichier journal (il s’agit en fait

d’un var_export)Le fichier journal par défaut est var/log/messages.log dans votre application.

Vous pouvez avoir plusieurs fichiers journaux. Pour cela, dans la configuration, vous indiquez ces fichiers dans lasection logfile :

[logfiles]default = messages.lognews = modulenews.log

Vous pouvez alors indiquer le code du fichier journal à utiliser, en paramètre supplémentaire aux méthodes log etdump :

jLog::log("hello !", "news");jLog::dump($record, "enregistrement news", "news");

Enfin, il arrive que plusieurs développeurs travaillent sur un même serveur : il y aurait alors dans un même fichiertoutes les traces que chacun aurait mis. Il est possible d’avoir autant de fichier journaux que de développeur, à condi-tion qu’ils aient une adresse IP différente. Il suffit d’inclure "%ip%" dans le nom du fichier :

[logfiles]default = "messages_%ip%.log"news = "%ip%_modulenews.log"

Ainsi, si un développeur a son poste de travail en 192.168.1.2, alors il y aura des fichiers 192.168.1.2_module-news.log et messages_192.168.1.2.log

Vous pouvez aussi construire les noms des fichiers de log avec la date et l’heure : pour cela, incluez un ou plusieursdes "tags" suivant dans le nom : %Y% (année), %m% (mois), %d% (jour), %H% (heure).

Si vous voulez afficher les messages de log dans la réponse, ou dans Firebug (une extension pour Firefox), indiquezrespectivement " !response" et " !firebug" comme nom de fichier :

[logfiles]default = "!response"news = "!firebug"

Page 205: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

198 / 225

Sixième partie

Les classes utilitaires

Page 206: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

199 / 225

Documentation sur les classes utilitaires fournies dans Jelix.

Page 207: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

200 / 225

Chapitre 31

jFilter : vérification et filtrage de données

jFilter est une classe qui permet de vérifier et valider le contenu de chaîne de caractères : mail, nombre, url etc. Elleest utilisée entre autre par jForms, mais vous pouvez l’utiliser pour vos propres besoins. Pour bon nombre de cesméthodes, elle fait appel à l’extension filter de PHP (sauf dans les packages de Jelix déstiné à PHP 5.0 et 5.1).

Pour le moment, voir l’API de réference de jFilter.

Page 208: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

201 / 225

Chapitre 32

jDateTime : manipulation de dates et heures

jDateTime est une classe encapsulant une date, permettant de la convertir dans divers formats, mais aussi de fairedes calculs de dates.

Pour créer un objet jDateTime, on peut– soit passer les valeurs de la date par le constructeur : l’année, le mois, le jour, l’heure, les minutes et les secondes.

Toutes ces valeurs sont facultatives et doivent être des entiers.– soit l’instancier sans paramètre et utiliser la méthode now() pour l’initialiser à la date/heure courante.– soit l’instancier sans paramètre et utiliser la méthode setFromString pour l’initialiser à partir d’une chaîne conte-

nant une date et/ou une heure.

32.1 Initialisation à la date/heure courante

La méthode now() initialise l’objet avec la date/heure actuelle.

Exemple :

$dt = new jDateTime();$dt->now();

echo "la date est ", $dt->year, ",", $dt->month, ",", $dt->day, ",", $dt->hour, ←↩",", $dt->minute, ",", $dt->second;

32.2 Conversion à partir d’une chaîne

La méthode setFromString prend en argument la chaîne en question et un indicateur de format. Ces indicateurs sontdes valeurs numériques qui sont récupérables via des constantes de classe.

jDateTime reconnait les formats suivants :

Pour les formats LANG_*, jDateTime se base sur ce qui est indiqué dans le fichier de locales "format" situé dans lemodule jelix, et correspondant à la langue courante configurée dans Jelix.

Exemple :

Page 209: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

202 / 225

$dt = new jDateTime();

$dt->setFromString("2006-04-10",jDateTime::DB_DFORMAT);

echo "la date est ", $dt->year, ",", $dt->month, ",", $dt->day, ",", $dt->hour, ←↩",", $dt->minute, ",", $dt->second;

Vous aurez remarqué les propriétés qui permettent de connaître chaque élément de la date.

On peut aussi, plutôt que spécifier à chaque fois le format, définir un format par défaut via la propriété defaultFormat.

$dt = new jDateTime();$dt->defaultFormat = jDateTime::DB_DFORMAT;

$dt->setFromString("2006-04-10");

32.3 Conversion vers une chaîne

Pour convertir une date en chaîne, il y a la méthode toString qui accepte en paramètre facultatif l’identifiant de formatdans lequel on veut l’avoir.

$dt->toString(jDateTime::LANG_DFORMAT);

32.4 Calcul de dates

Avec les méthodes sub() et add(), il est possible d’ajouter ou d’enlever des durées à une date. Ces durées sont àindiquer via un objet jDateTime.

$dt = new jDateTime();$dt->setFromString("2006-04-10",jDateTime::DB_DFORMAT);

// on veut retirer deux jours$date2 = new jDateTime(0,0,2);$dt->sub($date2);echo $dt->toString(jDateTime::DB_DFORMAT); // affiche 2006-04-08

// on veut ajouter 27h15 heures$date2 = new jDateTime(0,0,0,27,15);$dt->add($date2);echo $dt->toString(jDateTime::DB_DTFORMAT); // affiche 2006-04-09 03:15:00

Si on veut savoir la durée entre deux dates, on utilise alors la méthode durationTo(), qui renvoi cette durée dans unobjet jDateTime :

$dt = new jDateTime();$dt->setFromString("2006-04-10",jDateTime::DB_DFORMAT);

$dt2 = new jDateTime();$dt2->setFromString("2006-04-12",jDateTime::DB_DFORMAT);

// calcul la durée entre $dt jusqu’à $dt2$dt3 = $dt->durationTo($dt2);echo $dt3->toString(jDateTime::DB_DTFORMAT); //affiche 0000-00-02 00:00:00

Page 210: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

203 / 225

Attention, les dates doivent être supérieur au 01/01/1970.

32.5 Comparaison de dates

Pour comparer deux dates, il y a la méthode compareTo()

$dt = new jDateTime();$dt->setFromString("2006-04-10",jDateTime::DB_DFORMAT);

$dt2 = new jDateTime();$dt2->setFromString("2006-04-12",jDateTime::DB_DFORMAT);

$result = $dt->compareTo($dt2);

compareTo renvoit :– -1 si $dt < $dt2– 0 si les deux dates sont égales– 1 si $dt > $dt2

Page 211: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

204 / 225

Chapitre 33

jMailer : envoi de mails

33.1 Classe jMailer

jMailer est une classe permettant l’envoi d’email depuis un contrôleur.

Quelques fonctionnalités :– Pièces jointes– Email HTML– Destinataires multiples– Plusieurs méthodes d’envoi– Support de l’authentification SMTPjMailer étant basée sur la classe PHPMailer, de nombreux exemples d’utilisation sont disponibles sur internet.

33.1.1 Paramétrage de base

Le paramétrage de base utilisé par jMailer s’effectue dans le fichier var/config/defaultconfig.ini.php de votre appli-cation dans la section [mailer].

Les différentes options de configuration

– mailerType : méthode utilisée pour envoyer les emails (par défaut smtp)– mail : utilise la fonction mail de PHP– sendmail :– smtp : utilise une connexion directe à un/plusieurs hôte SMTP

– hostname– sendmailPath– smtpHost– smtpPort– smtpHelo– smtpAtuh– smtpUsername– smtpPassword– smtpTimeout

Page 212: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

205 / 225

33.2 Envoi d’un email basique

Envoi d’un email texte avec le paramétrage par défaut.

$mail = new jMailer();

$mail->Subject = ’Sujet de l\’email’;$mail->Body = ’Contenu du message texte’;

$mail->AddAddress(’[email protected]’ , ’Nom du destinataire’);

$mail->Send();

Page 213: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

206 / 225

Chapitre 34

jWiki : transformation de texte wiki

jWiki est une classe permettant de transformer un texte wiki dans un autre format, XHTML par exemple. Cette classerepose sur la classe Wikirenderer version 3.0.

Pour que Wikirenderer puisse réaliser la transformation, il lui faut donner un ensemble d’objets précis, qui ensemblevont régir "les rêgles de transformation".

Un certain nombre d’ensemble de rêgles sont fournies (voir lib/wikirenderer/rules/), permettant par exemple detransformer du code wiki wr3 en XHTML. Il est possible d’imaginer des rêgles pour transformer du code dokuwikien XHTML, ou encore du code mediawiki en docbook. Toutes les combinaisons sont possibles. Il suffit de fournir oudévelopper ces rêgles.

Pour utiliser jWiki, il faut l’instancier en indiquant le nom d’un ensemble de rêgles. Par exemple pour transformerdu code wiki wr3 en XHTML, il y a les rêgles wr3_to_xhtml, on fera donc :

$wr = new jWiki(’wr3_to_xhtml’);$xhtml = $wr->render($texte_wiki);

Les rêgles par défaut sont dans lib/wikirenderer/rules, mais vous pouvez ajouter les vôtres dans votre application,par exemple dans votre_appli/plugins/wr_rules/. Bien sûr, il faut déclarer le dépôt de plugins votre_appli/plugins dansla configuration de Jelix.

Pour plus d’informations sur l’utilisation de jWiki, voir la documentation de Wikirenderer 3.0.

Page 214: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

207 / 225

Chapitre 35

jSession : stockage de sessions

35.1 Classe jSession

jSession permet de stocker les sessions de façon personnalisée, en fonction de paramètres déclarés dans app/var/con-fig/defaultconfig.ini.php

35.1.1 Nom de la session

Pour diverses raisons, on peut vouloir changer le nom de la session (par défaut, c’est PHPSESSID).

Pour changer ce nom de variable/cookie, on peut utiliser la configuration suivante :

[sessions]name = "masession"

NB : seuls les caractères alpha-numériques sont autorisés.

35.1.2 Stockage dans un répertoire

Il n’est pas toujours prudent de stocker les sessions dans le répertoire par défaut prévu par l’hébergeur, car celui-cipeut être accessible de tout le monde, comme /tmp/ par exemple.

Pour utiliser jSession avec un répertoire personnalisé :

[sessions]storage = "files"files_path = "app:var/sessions/"

NB : les mots clés app : et lib : sont reconnus.

35.1.3 Stockage dans la base de données

On peut avoir besoin de stocker les données de session en base de données, par exemple pour permettre un partageaisé en cas de répartition de charge entre plusieurs serveurs web.

Pour utiliser jSession avec un Dao :

Page 215: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

208 / 225

[sessions]storage = "dao"dao_selector = "jelix~jsession"dao_db_profile = ""

NB : un dao est fourni par défaut dans le module jelix, son sélecteur est : jelix~jsession.

La structure de table pour ce DAO est :

CREATE TABLE ‘sessions‘ (‘id‘ varchar(64) NOT NULL,‘creation‘ datetime NOT NULL,‘access‘ datetime NOT NULL,‘data‘ text NOT NULL,PRIMARY KEY (‘id‘)) DEFAULT CHARSET=utf8;

Page 216: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

209 / 225

Septième partie

Les plugins de Jelix

Page 217: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

210 / 225

Documentation de référence sur les plugins fournis avec Jelix

Page 218: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

211 / 225

Chapitre 36

Plugins de template

Toute la liste des plugins de templates fournis avec Jelix.

36.1 Modificateurs

36.1.1 Les modificateurs

Les modificateurs sont des fonctions qui permettent de modifier l’affichage d’une variable de template. Ils ne sontdonc utilisé que lors des instructions d’affichage.

cat

Ce modificateur permet de concaténer une chaîne de caractère à une variable. Exemple :

Soit la variable de template $foo ayant pour valeur ’bar’ :

$rep->body->assign(’foo’, ’bar’);

Utilisation du modificateur cat dans le template. On concatène la chaîne ’toto’ à la variable $foo :

<p>{$foo|cat:’toto’}</p>

Ce qui donnera l’affichage :

<p>bartoto</p>

count_characters

Ce modificateur de template compte le nombre de caractères contenus dans une variable. Exemple :

Soit la variable de template $foo ayant pour valeur ‘bar’ :

$rep->body->assign(’foo’, ’bar’);

Utilisation de count_characters dans le template :

<p>$foo contient {$foo|count_characters} caractères</p>

Ce qui donnera l’affichage :

<p>$foo contient 3 caractères</p>

Page 219: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

212 / 225

count_paragraphs

Ce modificateur de template permet de compter le nombre de paragraphes contenus dans une variable. Exemple :

Prenons la variable $foo contenant le texte suivant et qu’on assigne au template :$foo = ’Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n\nVivamus ornare, enim bibendum mollis interdum, magna quam tristique lacus, sed ←↩

vestibulum urna augue et nisi.’;

$rep->body->assign(’foo’, $foo);

On affiche alors le texte ainsi que le nombre de paragraphes qu’il contient :<p>{$foo}<br/>Contient : {$foo|count_paragraphs} paragraphes</p>

Ce qui donne :<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Vivamus ornare, enim bibendum mollis interdum, magna quam tristique lacus, sed ←↩

vestibulum urna augue et nisi.Contient : 2 paragraphes</p>

count_sentences

Ce modificateur de template permet de compter le nombre de phrases contenues dans une variable. Exemple :

Prenons la variable $foo contenant le texte suivant et qu’on assigne au template :$foo = ’Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Vivamus ornare, enim bibendum mollis interdum, magna quam tristique lacus, sed ←↩

vestibulum urna augue et nisi.’;$rep->body->assign(’foo’, $foo);

On affiche alors le texte ainsi que le nombre de phrases qu’il contient :<p>{$foo}<br/>Contient : {$foo|count_sentences} phrases</p>

Ce qui donne :<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Vivamus ornare, enim bibendum mollis interdum, magna quam tristique lacus, sed ←↩

vestibulum urna augue et nisi.Contient : 2 phrases</p>

count_words

Ce modificateur de template permet de compter le nombre de mots contenus dans une variable. Exemple :

Prenons la variable $foo contenant le texte suivant et qu’on assigne au template :$foo = ’Lorem ipsum dolor sit amet, consectetuer adipiscing elit.’;$rep->body->assign(’foo’, $foo);

On affiche alors le texte ainsi que le nombre de mots qu’il contient :<p>{$foo}<br/>Contient : {$foo|count_words} mots</p>

Ce qui donne :<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Contient : 8 mots</p>

Page 220: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

213 / 225

date_format

escxml

eschtml

indent

Ce modificateur de template indente chaque ligne de texte contenu dans une variable.

Exemple d’utilisation

Prenons la variable $foo contenant le texte suivant et qu’on assigne au template :

$foo = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Vivamus ornare, enim bibendum mollis interdum."$rep->body->assign(’foo’, $foo);

On affiche alors le texte contenu dans $foo dans le template :

{$foo|indent}

Ce qui donne :

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Vivamus ornare, enim bibendum mollis interdum.

Paramètres

Indent accepte 2 paramètres :– le nombre de caractères à répéter pour l’indentation. Par défaut vaut 4– le caractère à répéter. Par défaut est un espace.{$foo|indent:"15"}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Vivamus ornare, enim bibendum mollis interdum.

{$foo|indent:"1":"\t"}

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.Vivamus ornare, enim bibendum mollis interdum.

36.1.2 jdatetime

Le modificateur jdatetime permet de convertir une chaîne contenant une date avec un certain format, vers une chaîned’un autre format. Ce modificateur utilise la classe jDateTime. Par défaut, le modificateur attend une chaine au formatbase de données (jDateTime : :BD_DTFORMAT) et renvoi la date au format correspondant à la langue sélectionnée(jDateTime : :LANG_DTFORMAT).

<p>la date est {$myDate|jdatetime}.</p>

Page 221: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

214 / 225

Si $myDate=’2006-04-12 01 :05 :26’ et si la langue est fr, alors cela affiche

la date est 12/04/2006 01h05mn26s.

Pour indiquer d’autres formats, vous devez indiquer l’une des chaînes en paramètre au modificateur :

Le premier paramètre indique le format de la chaîne que le modificateur reçoit, le deuxième, le format de la chaîneen résultat.

<p>la date est {$myDate|jdatetime:’db_date’:’timestamp’}.</p>

si $myDate=’2006-04-15’ alors cela affiche

la date est 1145052000.

36.1.3 regexp_replace

36.1.4 replace

36.1.5 spacify

36.1.6 printf

36.1.7 strip

36.1.8 truncate

36.1.9 wordwrap

36.1.10 html :nl2br

36.2 Fonctions diverses

Divers plugins sont de simple fonctions qui affichent quelque chose selon les paramètres.

36.2.1 zone

Permet l’affichage d’une zone.

<div>{zone ’module~une_zone’}

</div>

C’est en fait l’équivalent de

$tpl->assignZone(’ZONE’,’module~une_zone’);

<div>

{$ZONE}

</div> </code>

Page 222: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

215 / 225

36.2.2 jlocale

36.2.3 jurl

36.2.4 html : pagelinks

Lorsque que l’on doit afficher une liste de résultats à l’écran et que cette liste est longue, il peut être judicieux dela répartir sur plusieurs pages. Le plugin Pagelinks facilite l’affichage d’un tel système de pagination, avec des lienspointant vers les différentes pages de résultats.

Pour utiliser le plugin avec les comportements par défaut, il suffit d’utiliser la syntaxe suivante.

{pagelinks module~action, paramètres de l’action, nombre total de résultats, ←↩index résultat courant, nombre de résultats par page, nom du paramètre d’ ←↩offset, propriétés d’affichage}

Exemple :

<p>{pagelinks ’myModule~default_index’, array(), 283, 60, 15, "offset"}</p>

Paramètres

Module~Action

Sélecteur de l’action qui doit être appelé par les liens de pages.

Paramètres de l’action

Tableau contenant les paramètres métiers à placer dans l’url des liens de pages.

array("param1" => 1, "param2" => "deux")

Si il n’y aucun paramètre à passer, on utilise un tableau vide :

array()

Nombre total de résultats

Nombre entier représentant le nombre total des résultats répondant à votre requête. Vous devez donc l’avoir calculéau préalable.

Index résultat courant

Nombre entier représentant l’offset, c’est à dire l’index du résultat courant. En clair : le numéro d’ordre du premierenregistrement afficher sur la page. Pour la première page, vous metterez 0. Pour les pages suivantes, il est calculéautomatiquement et est passé dans le paramètre dont vous indiquez le nom dans "nom du paramètre d’offset"

Nombre de résultats par page

Nombre entier représentant le nombre de résultats contenus dans une page de résultats.– *Important** : le plugin ne s’affichera pas si il n’y a pas au moins 2 pages de résultats disponibles.

Page 223: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

216 / 225

Nom du paramètre d’offset

Chaîne de caractère contenant le nom que doit prendre le paramètre correspondant à l’offset dans l’url des liens depages.

Propriétés d’affichage

Tableau contenant les paramètres liés à l’affichage du plugin. Ce paramètre est optionnel. S’il est omis, le pluginutilise le comportement par défaut, à savoir qu’il affiche l’intégralité des liens avec leur intitulé par défaut.

Il est donc possible de personnaliser l’affichage, en définissant le nombre de liens à afficher ainsi que les intitulésdes liens spéciaux (page suivante, page précédente, etc.). Pour cela on ajoute simplement un tableau de paramètressupplémentaires comme ci-dessous dans l’appel. <p>{pagelinks ’myModule~default_index’, array(), 283, 60, 15,"offset", array(’start-label’ => ’début’, ’end-label’ => ’fin’, ’prev-label’ => ’précédent’, ’next-label’ => ’suivant’,’area-size’ => 5)}</p>

Il est ainsi possible de renseigner une ou plusieurs des valeurs d’index suivantes qui viendront écraser le comporte-ment défini par défaut.– start-label : Libellé du lien de la première page de résultats disponible. Si la valeur est une chaine vide, le lien ne

sera pas affiché.

– prev-label : Libellé du lien de la page de résultats précédente. Si la valeur est une chaine vide, le lien ne sera pasaffiché.

– next-label : Libellé du lien de la page de résultats suivante. Si la valeur est une chaine vide, le lien ne sera pasaffiché.

– end-label : Libellé du lien de la dernière page de résultats disponible. Si la valeur est une chaine vide, le lien nesera pas affiché.

– area-size : Nombre de liens à afficher avant et après la page courante. Si la valeur est 0, tous les liens serontaffiché.

L’exemple suivant renomme les liens "précédent" et "suivant", et masque les liens de début et de fin. De plus unmaximum de 5 pages sera affiché de part et d’autre de la page courante.

<p>{pagelinks ’myModule~default_index’, array(), 283, 60, 15, "offset", array(’ ←↩start-label’ => ’’, ’end-label’ => ’’, ’prev-label’ => ’précédent’, ’next- ←↩label’ => ’suivant’, ’area-size’ => 5)}</p>

L’exemple suivant renomme les liens "précédent" et "suivant", et utilise le libellé par défaut pour les liens de débutet de fin. De plus l’intégralité des liens sera affichée.

<p>{pagelinks ’myModule~default_index’, array(), 283, 60, 15, "offset", array(’ ←↩prev-label’ => ’précédent’, ’next-label’ => ’suivant’)}</p>

Bien entendu, il est aussi possible de possible d’utiliser un tableau de paramètres déclaré dans le controleur.

$properties = array(’start-label’ => ’’,’prev-label’ => ’précédent’,’next-label’ => ’suivant’,’end-label’ => ’’,’area-size’ => 5);

$rep->body->assign(’properties’,$properties);

L’appel du template aura donc la forme suivante.

<p>{pagelinks ’myModule~default_index’, array(), 283, 80, 15, "offset", ←↩$properties}</p>

Page 224: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

217 / 225

36.2.5 Localisation des intitulés

Il est possible de localiser les intitulés des liens spéciaux en utilisant jLocale de la façon suivante.

$properties = array(’start-label’ => jLocale::get("bar~foo.pagelinks.start"),’prev-label’ => jLocale::get("bar~foo.pagelinks.prev"),’next-label’ => jLocale::get("bar~foo.pagelinks.next"),’end-label’ => jLocale::get("bar~foo.pagelinks.end"),’area-size’ => 0);

36.2.6 Mise en forme avec CSS

Le plugin Pagelinks met à disposition les classes CSS suivantes pour permettre de styler les liens de paginationcomme désiré.– ul.pagelinks : sélecteur css de la liste des pages disponibles– li.pagelinks-start : sélecteur css du lien vers la première page de résultats– li.pagelinks-prev : sélecteur css du lien vers la page de résultats précédente– li.pagelinks-current : sélecteur css de la page de résultats courante– li.pagelinks-disabled : sélecteur css des pages de résultats désactivées– li.pagelinks-next : sélecteur css du lien vers la page de résultats suivante– li.pagelinks-end : sélecteur css du lien vers la dernière page de résultatsExemple de feuille de style minimaliste pour une utilisation de Pagelinks avec les propriétés d’affichage par

défaut.

ul.pagelinks>li {display: inline;

}

ul.pagelinks>li:before {content: ’ | ’;

}

ul.pagelinks>li.pagelinks-start:before {content: ’’;

}

36.2.7 html : urljsstring

Le plugin de template urljsstring permet de générer une chaîne pour du javascript, qui contient une url généré par lemoteur d’url de Jelix, et qui contient aussi des paramètres dynamiques en javascript. Par exemple, imaginons que l’onveuille ça en javascript :

"/index.php?module=foo&action=bar&t=1547&param1=" + uneValeur + "&param2=" + (val*5)

On pourrait bien évidement écrire cela directement dans le script javascript. Mais si la forme d’url change ? On estalors obligé de modifier le template.

urljsstring permet d’éviter cela.

Ce plugin accepte trois paramètres :

1. le sélecteur d’action (ex : "foo~default :bar")

Page 225: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

218 / 225

2. un tableau contenant les paramètres de l’url qui ont une valeur déjà calculée. Clés = noms des paramètres.Valeurs = valeurs des paramètres

3. un tableau contenant les paramètres qui seront créés dynamiquement par le script javascript. Clés = noms desparamètres. Valeurs = expressions javascript.

Pour générer une url comme l’exemple ci-dessus, on affichera :

{urljsstring "foo~default:bar" , array(’t’=>1547) , array(’param1’=>’uneValeur ←↩’, ’param2’=>’(val*5)’)}

Astuce : pour plus de lisibilité, vous pouvez bien sûr utiliser des variables de template

{assign $paramjs=array(’param1’=>’uneValeur’, ’param2’=>’(val*5)’)}{urljsstring $selecteur , $paramstatic , $paramjs}

Note : urljsstring génère les doubles quotes de la chaîne. Donc inutile de les rajouter dans votre script.

// ceci est incorrectvar foo = "{urljsstring $selecteur , $paramstatic , $paramjs}"

// ceci est correctvar foo = {urljsstring $selecteur , $paramstatic , $paramjs}

36.3 Médias

Les plugins pour insérer ou afficher des ressources diverses (images, flash..) dans un template.

36.3.1 html : image

Si vous avez besoin d’afficher une image, une balise image suffit amplement.

Mais si vous devez afficher la même image à plusieurs reprises, dans des formats différents, avec des effets spéciauxhollywoodiens ou presque, le plugin image et là pour vous.

Utilisation du plugin dans un template

Il faut noter que pour les versions 1.0.x le plugin image cherche les images dans le dossier "myapp/www/data/fi-chiers/".

Le plugin image est un plugin function. L’utilisation la plus simple se présente ainsi :

{image ’toupie.png’}

Page 226: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

219 / 225

Ceci crée le code html ci-dessous <img src="./data/fichiers/toupie.png" />

Des attributs

On peut ajouter une classe :

{image ’toupie.png’, array(’class’=>’right cadre’)}

On peut également ajouter un id :

{image ’toupie.png’, array(’id’=>’image’)}

Ainsi qu’un texte alternatif :

{image ’toupie.png’, array(’alt’=>’ici l\’image d\’une toupie’)}

les modifications disponibles

On peut si l’on veut ajouter des arguments pour modifier l’image d’origine.

{image ’toupie.png’, array(’width’=>100)}

Cela va générer une image sauvegardéé dans "myapp/www/cache/images/"

Si gd n’est pas présent sur le serveur, le plugin ajoute la largeur/hauteur a l’image d’origine sous forme de style.

Page 227: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

220 / 225

{image ’toupie.png’, array(’width’=>100)}

<img src="toupie.png" style="width :100px ;height :100px ;"/>

Changer la taille

On peut spécifier la largeur, la hauteur s’adaptera automatiquement, même chose pour la hauteur.

{image ’toupie.png’, array(’height’=>50)}{image ’toupie.png’, array(’width’=>100)}

On peut bien sur utiliser les deux ce qui va déformer l’image.

{image ’toupie.png’, array(’width’=>150, ’height’=>50)}

Pour changer la taille de l’image sans la déformer il suffit de demander.

{image ’toupie.png’, array(’width’=>150, ’height’=>50, ’omo’=>true)}

Faire un zoom

Changer la taille de l’image de manière homothétique permet de recadrer l’image. Une autre façon de recadrer estde faire un zoom.– 100 affiche 100% de l’image– 10 affiche 10% de l’image

{image ’toupie.png’, array(’width’=>100, ’zoom’=>50)}

Page 228: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

221 / 225

Alignement et déplacement

Une fois que l’on a recadré notre image, on peut la déplacer, pour visualiser la zone de l’image que l’on veut.

On peut aligner l’image à gauche,

{image ’toupie.png’, array(’width’=>100, ’zoom’=>60, ’alignh’=>’left’)}

ou à droite,

{image ’toupie.png’, array(’width’=>100, ’zoom’=>60, ’alignh’=>’right’)}

en haut,

{image ’toupie.png’, array(’width’=>100, ’zoom’=>60, ’alignh’=>’top’)}*

ou en bas.

{image ’toupie.png’, array(’width’=>100, ’zoom’=>60, ’alignh’=>’bottom’)}

Changer l’extension et la qualité

On peut également changer l’extension pour par exemple transformer un png en jpeg et ainsi alléger l’image.

{image ’toupie.png’, array(’width’=>100, ’ext’=>’jpg’)}

Le jpeg ne prend pas en charge la transparence, ce qui explique le fond noir. / !\ sur un navigateur qui ne prend pasen charge la transparence des png (<=ie6), le fond ne sera pas noir mais blanc.

Page 229: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

222 / 225

{image ’toupie.png’, array(’width’=>100, ’ext’=>’jpg’, ’quality’=>5)}

C’est léger !

Changer la couleur du fond

– * seulement à partir de la version 1.0.4 **

On peut donner une couleur de fond aux images en png transparent.

{image ’toupie.png’, array(’width’=>100, ’background’=>’#ff5533’)}

Ex : sur cette image convertie en jpeg.

{image ’toupie.png’, array(’width’=>100, ’ext’=>’jpg’, ’background’=>’#ff5533’)}

Ajouter une ombre portée

– * seulement à partir de la version 1.0.4 **

On peut très simplement ajouter une ombre portée.

{image ’toupie.png’, array(’width’=>100, ’shadow’=>true))}

Page 230: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

223 / 225

Une fois l’ombre affichée on peut la déplacer, en modifiant la distance et l’angle.

{image ’toupie.png’, array(’width’=>100, ’shadow’=>true, ’soffset’=>20))}

{image ’toupie.png’, array(’width’=>100, ’shadow’=>true, ’sangle’=>0))}

On peut modifier la netteté de l’ombre (maximum 11),

{image ’toupie.png’, array(’width’=>100, ’shadow’=>true, ’sblur’=>0))}

l’opacité de l’ombre en %

Page 231: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

224 / 225

{image ’toupie.png’, array(’width’=>100, ’shadow’=>true, ’sopacity’=>100))}

et même la couleur.

{image ’toupie.png’, array(’width’=>100, ’shadow’=>true, ’scolor’=>’#ffff00’))}

36.4 Meta

Les plugins meta permettent en général de modifier des propriétés dans la réponse.

36.4.1 meta_html

36.4.2 meta_xul

Page 232: Manuel Jelix 1.0 Draft

Guide du développeurJelix 1.0.6

225 / 225

Chapitre 37

Plugins pour le coordinateur

Toute la liste des plugins pour le coordinateur, fournis avec Jelix.