Outils pour utilisateurs

Outils du site


Panneau latéral

devguide:zzz_previous_releases:3.0.4:create_module:add_new_document

ATTENTION :
Le contenu de cette page porte sur une ancienne version

Ajouter un nouveau document

Ajouter un document dans un module se fait en plusieurs étapes :

  1. Initialisation du fichier de structure du document (commande create-document),
  2. Définition des propriétés du document (par édition du fichier de structure du document),
  3. Confirmation de la structure : initialisation de la base de données et des classes du document (commande add-document).

Initialisation du fichier de structure du document

Pour initialiser la structure du document, utilisez create-document :

intsimoa@srbswebrd:~/aproject$ changedev.php create-document -h
Create-document: initialize a document
Usage: changedev.php create-document <moduleName> <name>

Nous allons créer le document recipe dans le module recipes :

intsimoa@srbswebrd:~/aproject$ changedev.php create-document recipes recipe
== Create document ==
=> Document recipes/recipe initialized.
You must now edit /home/intsimoa/aproject/modules/recipes/persistentdocument/recipe.xml and later call add-document

Le fichier de structure du document recette (modules/recipes/persistentdocument/recipe.xml) est maintenant initialisé :

<?xml version="1.0" encoding="utf-8"?>
<document xmlns="http://www.rbs.fr/schema/change-document/1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.rbs.fr/schema/change-document/1.0 http://www.rbschange.fr/static/schema/change-document/1.0.xsd"
    model-version="1.0">
    <properties>
    </properties>
</document>

Edition du fichier de structure du document

Par défaut, tous les documents héritent des propriétés du document generic/Document qui définit entre autres les propriétés :

  • Auteur (automatiquement renseigné avec l’utilisateur courant),
  • Date de création (automatiquement renseigné à la création),
  • Date de modification (automatiquement renseigné à la création et lors des mises à jour),
  • Statut de publication (par défaut, le statut vaut « brouillon » (DRAFT),
  • Date de début de publication,
  • Date de fin de publication,
  • Langue du document.

En plus des propriétés standards, notre document recette aura les propriétés suivantes :

  • Végétarien (oui/non),
  • Ingrédients (texte formaté),
  • Nombre de personnes (entier)
  • Préparation (texte formaté)
  • Durée de préparation en minutes (entier)
  • Durée de cuisson en minutes (entier)
  • Difficulté (parmi les éléments de la liste « Très facile », « Facile », « Moyen », « Difficile »),
  • Coût (parmi les éléments de la liste « Bon marché », « Moyen », « Assez cher »),
  • Catégories (une ou plusieurs parmi les éléments de la liste « Accompagnement », « Plat », « Dessert », …),
  • Image (document du module Médiathèque)

Soit le fichier modules/recipes/persistentdocument/recipe.xml modifié :

<document xmlns="http://www.rbs.fr/schema/change-document/1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.rbs.fr/schema/change-document/1.0 http://www.rbschange.fr/static/schema/change-document/1.0.xsd"
    model-version="1.0">
    <properties>
        <add name="vegetarian" type="Boolean" />
        <add name="ingredients" type="XHTMLFragment"/>
        <add name="peopleNumber" type="Integer"/>
        <add name="preparation" type="XHTMLFragment"/>
        <add name="preparationTime" type="Integer"/>
        <add name="cookingTime" type="Integer"/>
        <add name="picture" type="modules_media/media" />
        <add name="difficulty" type="Integer" from-list="recipes/difficulty"/>
        <add name="cost" type="Integer" from-list="recipes/cost"/>
        <add name="categories" type="modules_list/item" from-list="recipes/categories" max-occurs="-1" />
    </properties>
</document>

Remarquez l’utilisation de l’attribut max-occurs sur la propriété “categories” : valant -1, celui-ci indique que la propriété peut prendre une ou plusieurs valeurs.

Création des listes

Vous avez peut-être remarqué l’utilisation de l’attribut from-list sur les propriétés “difficulty”, “categories” ou “cost”. Cet attribut permet de lier une propriété à une liste du module de base “list”. Le module list centralise la gestion de liste de données.

Nous allons ici créer les listes suivantes :

  • recipes/difficulty : liste des difficultés possibles des recettes, fixée une fois pour toute de « très facile » à « difficile ». Ce sera une liste dite « statique », non éditable par l’utilisateur,
  • recipes/cost : liste statique des coûts possibles des recettes, de « bon marché » à « assez cher »,
  • recipes/categories : liste des catégories possibles des recettes, comme « Plat » ou « Dessert ». Cette liste sera elle éditable par l’utilisateur.

Ces listes devront être crées à l’initialisation du module, nous allons donc les persister dans le fichier setup/init.xml :

<?xml version="1.0" encoding="UTF-8"?>
<script>
    <binding fileName="modules/list/persistentdocument/import/list_binding.xml" />
    <binding fileName="modules/generic/persistentdocument/import/generic_binding.xml" />
 
    <systemfolder module="list" relatedmodule="recipes">
        <staticlist listid="recipes/difficulty" label="Difficultés de recette" description="Difficultés de recette">
            <staticitem 
                label="&amp;modules.recipes.document.recipe.difficulty.veryeasy;"
                value="1" />
            <staticitem 
                label="&amp;modules.recipes.document.recipe.difficulty.easy;"
                value="2" />
            <staticitem
                label="&amp;modules.recipes.document.recipe.difficulty.medium;"
                value="3" />
            <staticitem 
                label="&amp;modules.recipes.document.recipe.difficulty.hard;"
                value="4" />
        </staticlist>
        <staticlist listid="recipes/cost" label="Coûts de recette" description="Coûts de recette">
            <staticitem 
                label="&amp;modules.recipes.document.recipe.cost.cheap;"
                value="1" />
            <staticitem 
                label="&amp;modules.recipes.document.recipe.cost.medium;"
                value="2" />
            <staticitem 
                label="&amp;modules.recipes.document.recipe.cost.expensive;"
                value="3" />
        </staticlist>
        <editablelist listid="recipes/categories" label="Catégories de recette" description="Catégories de recette">
            <item label-fr="Plat" label-en="Meal" />
            <item label-fr="Entrée" label-en="Appetizer" />
            <item label-fr="Dessert" label-en="Dessert" />
            <item label-fr="Amuse-gueule" label-en="Appetizers" />
            <item label-fr="Boisson" label-en="Drink" />
            <item label-fr="Sauce" label-en="Sauce" />
            <item label-fr="Accompagnement" label-en="Accompaniment" />
            <item label-fr="Confiserie" label-en="Sweetmeat" />
        </editablelist>
    </systemfolder>
</script>

Remarquez que listes statiques utilisent pour libellé des messages internationalisés (locales), reconnaissables au pattern &amp;modules.XXX.YYY; (commençant par une esperluette et terminant par un point virgule) que nous définissons dans le fichier locale/document/recipe.xml :

<?xml version="1.0" encoding="utf-8"?>
<localization>
  <!-- Difficulty list items labels -->
  <entity id="difficulty.veryeasy">
    <locale lang="fr">Très facile</locale>
    <locale lang="en">Very easy</locale>
  </entity>
  <entity id="difficulty.easy">
    <locale lang="fr">Facile</locale>
    <locale lang="en">Easy</locale>
  </entity>
  <entity id="difficulty.medium">
    <locale lang="fr">Moyenne</locale>
    <locale lang="en">Medium</locale>
  </entity>
  <entity id="difficulty.hard">
    <locale lang="fr">Difficile</locale>
    <locale lang="en">Hard</locale>
  </entity>
  <!-- Cost list items labels -->
  <entity id="cost.cheap">
    <locale lang="fr">Bon marché</locale>
    <locale lang="en">Cheap</locale>
  </entity>
  <entity id="cost.medium">
    <locale lang="fr">Moyen</locale>
    <locale lang="en">Medium</locale>
  </entity>
  <entity id="cost.expensive">
    <locale lang="fr">Assez cher</locale>
    <locale lang="en">Expensive</locale>
  </entity>
</localization>

Des locales ont été ajoutées dans le module recipes, importons les dans la base de données :

intsimoa@srbswebrd:~/aproject$ change.php compile-locales recipes 
== Compile locales ==
recipes module locales compiled
== Clear webapp cache ==
Webapp cache directory cleared
=> Locales successfully compiled

Pour importer le fichier init.xml dans le module, utilisons la commande change import-data :

intsimoa@srbswebrd:~/aproject$ change.php import-data recipes init.xml 
== Import data recipes/init.xml ==
=> recipes/init.xml imported

Et enfin, pour activer l’importation du fichier init.xml à l’initialisation du module, dé-commentons la bonne ligne dans le fichier setup/initData.php :

<?php
/**
 * @package modules.recipes.setup
 */
class recipes_Setup extends object_InitDataSetup
{
    public function install()
    {
        // Ligne décommentée :
        $this->executeModuleScript('init.xml');
    }
 
    /**
     * @return String[]
     */
    public function getRequiredPackages()
    {
        // Return an array of packages name if the data you are inserting in
        // this file depend on the data of other packages.
        // Example:
        // return array('modules_website', 'modules_users');
        return array();
    }
}

Régler les contraintes du document

Pour l’instant, seule la propriété label, héritée de generic/Document, est obligatoire. Mais que serait donc une recette sans ingrédients ni instructions de préparation ? De même, que voudrait dire un nombre de participant négatif ?

Pour rendre une propriété obligatoire, on agit sur l’attribut min-occurs, valant par défaut 0. Pour appliquer d’autres types de contraintes, on ajoute un élément constraints comme fils de l’élément add et on le renseigne avec des validateurs que l’on configure. Le framework Change fournit un certain nombre de validateurs (Cf. framework/validation/). Les modules peuvent également apporter leur propres validateurs ; ainsi le module media définit le validateur MimetypeValidator.

Nous utilisons ici le validateur MinValidator que nous configurons pour nous assurer que les valeurs des propriétés entières seront positives. Rajoutons également une contrainte max (MaxValidator) sur le nombre de convives pour découvrir comment cumuler des validations sur une même propriété.

Soit le fichier de structure persistentdocument/recipe.xml modifié :

<?xml version="1.0" encoding="utf-8"?>
<document xmlns="http://www.rbs.fr/schema/change-document/1.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.rbs.fr/schema/change-document/1.0 http://www.rbschange.fr/static/schema/change-document/1.0.xsd"
       model-version="1.0">
    <properties>
        <add name="vegetarian" type="Boolean" />
        <add name="ingredients" type="XHTMLFragment" min-occurs="1" />
        <add name="peopleNumber" type="Integer" min-occurs="1">
            <constraints>min:0;max:100</constraints>
        </add>
        <add name="preparation" type="XHTMLFragment" min-occurs="1" />
        <add name="preparationTime" type="Integer" min-occurs="1">
            <constraints>min:0</constraints>
        </add>
        <add name="cookingTime" type="Integer" min-occurs="1">
            <constraints>min:0</constraints>
        </add>
        <add name="picture" type="modules_media/media" />
        <add name="difficulty" type="Integer" from-list="recipes/difficulty" min-occurs="1" />
        <add name="cost" type="Integer" from-list="recipes/cost" min-occurs="1"/>
        <add name="categories" type="modules_list/item" from-list="recipes/categories" max-occurs="-1" />
    </properties>
</document>

Multilinguisme

Change permet la gestion multilingue de contenus, en particulier au niveau du document. Un document est multilingue à partir du moment où il possède au moins une propriété dite « localisée ». Ces propriétés devront alors être traduites dans la langue souhaitée.

Pour déclarer une propriété localisée, placez l’attribut localized à “true” sur la propriété concernée dans le fichier de structure.

Pour le document recipe, il paraît raisonnable de traduire les ingrédients (ingredients) et les instructions de préparation (preparation). Soit le fichier de structure persistentdocument/recipe.xml modifié :

<?xml version="1.0" encoding="utf-8"?>
<document xmlns="http://www.rbs.fr/schema/change-document/1.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.rbs.fr/schema/change-document/1.0 http://www.rbschange.fr/static/schema/change-document/1.0.xsd"
       model-version="1.0" indexable="true">
    <properties>
        ...
        <add name="ingredients" type="XHTMLFragment" min-occurs="1" localized="true" />
        ...
        </add>
        <add name="preparation" type="XHTMLFragment" min-occurs="1" localized="true" />
        ...
    </properties>
</document>

N.B. : La propriété titre (label) est implicitement déclarée “localisée” pour tous les documents multilingues.

Le traducteur aura ainsi la possibilité de traduire le titre, les ingrédients et les instructions de préparation.

Confirmation de la structure du document

Une fois le fichier de structure correctement renseigné, il faut confirmer la structure du document à l’aide de la commande changedev.php add-document :

intsimoa@srbswebrd:~/aproject$ changedev.php add-document recipes recipe
== Add document ==
Generating /home/intsimoa/aproject/modules/recipes/persistentdocument/recipe.class.php
Generating /home/intsimoa/aproject/modules/recipes/persistentdocument/import/RecipeScriptDocumentElement.class.php
Updating /home/intsimoa/aproject/modules/recipes/persistentdocument/import/recipes_binding.xml
Generating /home/intsimoa/aproject/modules/recipes/locale/document/recipe.xml
Generating /home/intsimoa/aproject/modules/recipes/lib/services/RecipeService.class.php
Add recipe in /home/intsimoa/aproject/modules/recipes/config/rights.xml
compile-locales... done
compile-tags... done
compile-db-schema... done
clear-webapp-cache... done
=> Document recipe added in module recipes.

Ceci a pour effet de :

  • Créer les classes de manipulation du document (modèle, document de base, classe finale du document et service),
  • Créer la classe de gestion des importations de données pour le document,
  • Créer les tables nécessaires au stockage du document dans la base de données,
  • Initialiser les permissions autour du cycle de vie du document,
  • Initialiser le fichier de localisation des champs du document.

⇒ A ce stade, tout est prêt pour permettre la manipulation (par code PHP) de documents recipes/recipe.

Modification de la structure du document après confirmation

Après confirmation de la structure d’un document, le schéma de la base de données permet le stockage des propriétés définies. Ce schéma se retrouve dans les fichiers build/<profil>/modules/<module>/dataobject/*.sql qui sont régénérés à chaque compilation des fichiers de structure (change.php compile-documents).

RBS Change ne gère pas les changements de structure automatiquement après édition manuelle des fichiers de structure. Vous devrez extraire des fichiers SQL générés les instructions nécessaires à l’altération du schéma après édition manuelle du fichier de structure.

La commande changedev.php edit-document vous permet de manipuler les fichiers de structure et le schéma de base de données en une seule opération. De plus, cette commande génère des patchs permettant à vos utilisateurs de mettre à jour correctement leurs projets avec la nouvelle version de votre module :

intsimoa@srbswebrd:~/aproject$ changedev.php edit-document -h
Edit-document: edit an existing document
Usage: changedev.php edit-document <moduleName> <documentName> <action>
Where action in:
- add-property <propertyName> <propertyType>
- del-property <propertyName>
- rename-property <propertyName> <newPropertyName>

devguide/zzz_previous_releases/3.0.4/create_module/add_new_document.txt · Dernière modification: 2017/01/19 14:54 (modification externe)