Tutoriel composant example
Contents |
Tutoriel développeur basé sur le composant example de framework
Contexte
Ce tutoriel a pour but la modification de l'entité Exemple et l'ajout de nouvelles fonctionnalités. Il présente dans une première partie les modifications du diagramme UML (classe et activité). Une seconde partie présente la création d'une page qui permet l'appel à des services de création et de modification en mini-langage. La troisième partie permet l'affichage en liste des éléments de l'entité Example, afin de visualiser les paramètres d'un élément lors de sa recherche et pour simplifier sa modification. La dernière partie explique l'utilisation des decorators ainsi que des fichier .ftl qui permettent de créer des entêtes.
Diagramme UML des entités du composant
Le diagramme de classe suivant représente la classe du projet avant l'ajout d'une entité Example2
Nous souhaitons en fin de modifications que le projet respecte ce diagramme.
Voici le diagramme d'activité representant la modification ou la création d'un nouvel élément ainsi que l'affichage de la table Example2 après succés des opérations.
Ce diagramme represente la recherche d'un élément à l'aide du service PerformFind.
Ajout de example dans le projet
Dans un premier temps nous modifions le fichier applications/component-load.xml en ajoutant la ligne:
<load-component component-location="${ofbiz.home}/framework/example"/>
nous pouvons ainsi inclure le dossier /framework/example pour le compiler et l'exécuter.
Provisoirement il nous faut commenter le decorator screen dans framework/example/widget/example/CommonScreens.xml tant que nous n'avons pas encore mis les decorators à nos views
<screen name="main">
<container>
<label text="${uiLabelMap.ExampleWelcome}" />
</container>
</container>
</container>
<!-- </decorator-section>
</decorator-screen>-->
</widgets>
</section>
</screen>
Réalisation d'un écran example
- une entité example2 : avec 3 champs
Nous créons une nouvelle entité qui se nommera Example2 en ajoutant une ligne dans framework/example/entitydef/entitygroup.xml
<entity-group group="org.ofbiz" entity="Example2"/>
Puis il nous faut définir les champs de l'entité Example2, pour cela nous ajoutons dans framework/example/entitydef/entitymodel.xml une balise field pour chaque nouveau champ. Notre table Exemple2 possédera donc le champ exampleId (identifiant d'un élément), exampleTypeId qui nous donne le type d'un élément) et statusId (qui corespond au statut d'un élément).
<entity entity-name="Example2" package-name="org.ofbiz.example.example" title="Example Entity2">
<field name="exampleId" type="id-ne"></field>
<field name="exampleTypeId" type="id-ne"></field>
<field name="statusId" type="id-ne"></field>
<prim-key field="exampleId"/>
</entity>
- un screen (sans decorator)
Il nous faut pouvoir insérer ou modifier des données pour cela nous créons un screen qui ne contiendra pas de decorator.
Dans framework/example/widget/example/ExampleScreens.xml nous ajoutons un screen
<screen name="EditExample2"> </screen>
- une form single
Le screen précédent fera appel à une forme définie dans framework/example/widget/example/ExampleForms.xml. Cette forme affiche automatiquement tous les champs de la table Example2.
<form name="EditExample2" type="single" target="createExample2" title="" default-map-name="example">
<auto-fields-entity entity-name="Example2"/>
<field name="submitButton" title="Submit"><submit button-type="button"/></field>
</form>
- une entrée dans le controller
Dans framework/example/webapp/example/WEB-INF/controller.xml nous ajoutons l'uri qui correspondra à la view-map affichée. La page affichée possédera une adresse se terminant par EditExample2.
<request-map uri="EditExample2"><security https="true"/><response name="success" type="view" value="EditExample2"/></request-map>
puis dans ce même fichier nous créons une view-map
<view-map name="EditExample2" type="screen" page="component://example/widget/example/ExampleScreens.xml#EditExample2"/>
- 2 services réalisés en mini-language
Nous ajoutons 2 services, le service createExample2 et le service updateExample2 définis dans le fichier framework/example/servicedef/services.xml. createExample2 va créer une nouvelle entrée dans la table Example2 avec un identifiant donné automatiquement et les autres paramètres saisis par l'utilisateur. updateExample2 modifie les champs de l'élément dont l'utilisateur aura fourni son identifiant en entrée.
<service name="createExample2" default-entity-name="Example2" engine="simple" location="org/ofbiz/example/example/ExampleServices.xml" invoke="createExample2"> <description>Create a Example2</description> <attribute name="exampleTypeId" mode="IN" type="String" /> <attributes name="statusId" mode="IN" type="String" /> </service>
<service name="updateExample2" default-entity-name="Example2" engine="simple" location="org/ofbiz/example/example/ExampleServices.xml" invoke="updateExample2"> <description>Update a Example2</description> <auto-attributes mode="IN" entity-name="Example2" optional="true" /> </service>
Les 2 services précédents sont en mini langage et leur corps se trouve dans framework/example/script/org/ofbiz/example/example/ExampleServices.xml
<simple-method method-name="createExample2" short-description="create a Example2"> <make-value entity-name="Example2" value-name="newEntity" /> <sequenced-id-to-env sequence-name="Example2" env-name="newEntity.exampleId" /> <set-nonpk-fields map-name="parameters" value-name="newEntity" /> <create-value value-name="newEntity" /> </simple-method>
<simple-method method-name="updateExample2" short-description="update a Example2"> <entity-one entity-name="Example2" value-name="lookedUpValue" /> <set-nonpk-fields value-name="lookedUpValue" map-name="parameters" /> <store-value value-name="lookedUpValue" /> </simple-method>
Dans framework/example/webapp/example/WEB-INF/controller.xml nous ajoutons les uri qui correpondent aux services.
<request-map uri="createExample2"><security https="true"/>
<event type="service" path="" invoke="createExample2"/>
<response name="success" type="view" value="ListExample2"/>
<response name="error" type="view" value="EditExample2"/>
</request-map>
<request-map uri="updateExample2">
<security https="true" auth="true"/>
<event type="service" path="" invoke="updateExample2"/>
<response name="success" type="view" value="ListExample2"/>
<response name="error" type="view" value="EditExample2"/>
</request-map>
Voici un aperçu de la view pour createExample2
complément sur les form
- réalisation de la form de recherche
Pour effectuer une recherche dans la table Example2 nous devons créer 2 forms. La première form "LookExample2" nous permet de saisir un identifiant et de lancer la recherche par le bouton "Recherche". La deuxième form "FindExample2" affiche le résultat s'il est existant sous forme de liste. Chaque élément est affiché avec un bouton "edit" à son coté. L'appui sur le bouton edit renvoie sur la page "createExample2" avec les champs existant de cet élément près remplis. Ceci permet la modification d'un des attributs de l'élément.
Ces formes sont ajoutées dans framework/example/widget/example/ExampleForms.xml:
<form name="LookExample2" type="single" target="FindExample2" default-map-name="Example2" focus-field-name="exampleId">
<auto-fields-service service-name="createExample2" />
<field name="submitButton" title="Recherche">
<submit button-type="button" />
</field>
<field name="cancelLink" title="" widget-style="smallSubmit">
<hyperlink target="${donePage}?partyId=${partyId}" also-hidden="false" description="${uiLabelMap.CommonCancelDone}" />
</field>
</form>
<form name="FindExample2" type="list" list-name="listIt" target="EditExample2"> <actions> <service service-name="performFind" result-map-name="result" result-map-list-name="listIt"> <field-map field-name="inputFields" env-name="parameters" /> <field-map field-name="entityName" value="Example2" /> </service> </actions> <auto-fields-service service-name="updateExample2" default-field-type="display" /> <field name="submitButton" title="edit"> <submit button-type="button" /> </field> </form>
Il nous faut par la suite ajouter les entrées dans le controleur example/webapp/example/WEB-INF/controller.xml
<request-map uri="LookExample2"> <security https="true" /> <response name="success" type="view" value="LookExample2" /> </request-map>
<request-map uri="FindExample2"><security https="true"/> <response name="success" type="view" value="FindExample2"/> </request-map>
ainsi qu'une view-map pour chaque screen
<view-map name="LookExample2" type="screen" page="component://example/widget/example/ExampleScreens.xml#LookExample2"> </view-map>
<view-map name="FindExample2" type="screen" page="component://example/widget/example/ExampleScreens.xml#FindExample2"></view-map>
- réalisation du screen de recherche - list
Dans framework/example/widget/example/ExampleScreens.xml nous ajoutons les 2 screens qui utiliseront les forms réalisées précédemment:
<screen name="LookExample2"> </screen>
<screen name="FindExample2"> </screen>
- réalisation de la form de list
La form ListExample2 nous permet d'afficher tous les éléments de la table Example2 en liste après création ou modification d'un élément. Pour cela nous ajoutons dans framework/example/widget/example/ExampleForms.xml
<form name="ListExample2" type="list" list-name="ListExample2" target="EditExample2"> <actions> <entity-condition entity-name="Example2" list-name="ListExample2"> <condition-expr field-name="exampleId" operator="not-equals" value="" /> </entity-condition> </actions> <auto-fields-service service-name="createExample2" default-field-type="display" /> <field name="submitButton" title="edit"> <submit button-type="button" /> </field> </form>
dans example/webapp/example/WEB-INF/controller.xml
<request-map uri="ListExample2"> <security https="true" auth="true" /> <response name="success" type="view" value="ListExample2" /> </request-map>
<view-map name="ListExample2" type="screen" page="component://example/widget/example/ExampleScreens.xml#ListExample2" />
et nous ajoutons dans framework/example/widget/example/ExampleScreens.xml
<screen name="ListExample2"> </screen>
- ajout d'une association avec la table status
Nous allons ajouter 2 associations. La première association sera entre Example2 et ExampleType et la seconde entre Example2 et StatusItem. Ces 2 relations unitaires (relation type="one") ont respectivement pour nom "ExampleType" et "StatusItem" et pour clé "exampleTypeId" et "statusId". dans framework/example/entitydef/entitymodel.xml
<entity entity-name="Example2" package-name="org.ofbiz.example.example" title="Example Entity2">
<field name="exampleId" type="id-ne"></field>
<field name="exampleTypeId" type="id-ne"></field>
<field name="statusId" type="id-ne"></field>
<prim-key field="exampleId"/>
<relation type="one" fk-name="EXMPL_TYP" rel-entity-name="ExampleType">
<key-map field-name="exampleTypeId"/>
</relation>
<relation type="one" fk-name="EXMPL_STTS" rel-entity-name="StatusItem">
<key-map field-name="statusId"/>
</relation>
</entity>
- ajout d'un drop down dans le form edit et find
Afin de faire apparaître une liste déroulante nous ajoutons un nouveau champ contenant un drop down dans LookExample2 et dans EditExample2.
<form name="LookExample2" type="single" target="FindExample2" default-map-name="Example2" focus-field-name="exampleId">
<auto-fields-service service-name="createExample2" />
<field name="exampleId" tooltip="${uiLabelMap.CommonRequired}" widget-style="required">
</field>
<field name="statusId" title="${uiLabelMap.CommonStatus}">
<drop-down allow-empty="true">
<entity-options entity-name="StatusItem" description="${description}">
<entity-order-by field-name="sequenceId" />
</entity-options>
</drop-down>
</field>
<field name="submitButton" title="Recherche">
<submit button-type="button" />
</field>
<field name="cancelLink" title="" widget-style="smallSubmit">
<hyperlink target="${donePage}?partyId=${partyId}" also-hidden="false" description="${uiLabelMap.CommonCancelDone}" />
</field>
</form>
Aperçu de la view pour une recherche dans la table Example2.
- ajout du display entity
<form name="EditExample2" type="single" target="updateExample2" title="">
<alt-target use-when="exampleId==null" target="createExample2" />
<auto-fields-entity entity-name="Example2" />
<field name="exampleItemSeqId">
<display-entity entity-name="ExampleItem" description="${description}">
</display-entity>
</field>
<field name="statusId" title="${uiLabelMap.CommonStatus}">
<drop-down allow-empty="true">
<entity-options entity-name="StatusItem" description="${description}">
<entity-order-by field-name="sequenceId" />
</entity-options>
</drop-down>
</field>
<field name="submitButton" title="Submit">
<submit button-type="button" />
</field>
</form>
- ajout d'une association avec une entité avec 2 primaryKeys
<entity entity-name="Example2" package-name="org.ofbiz.example.example" title="Example Entity2">
<field name="exampleId" type="id-ne"></field>
<field name="exampleItemSeqId" type="id-ne"></field>
<field name="statusId" type="id-ne"></field>
<prim-key field="exampleId"/>
<relation type="one" fk-name="EXMPL_STTS" rel-entity-name="StatusItem">
<key-map field-name="statusId"/>
</relation>
<relation type="one" fk-name="EXMPL_ITEM" rel-entity-name="ExampleItem">
<key-map field-name="exampleId,exampleItemSeqId"/>
</relation>
</entity>
- ajout d'un row-actions au niveau de la liste pour pouvoir faire une display de la description
<form name="ListExample2" type="list" list-name="ListExample2" target="EditExample2"> <actions> <entity-condition entity-name="Example2" list-name="ListExample2"> <condition-expr field-name="exampleId" operator="not-equals" value="" /> </entity-condition> </actions> <row-actions> <set field="statusId" value="statusId" /> </row-actions> <auto-fields-service service-name="updateExample2" default-field-type="display" /> <field name="submitButton" title="edit"> <submit button-type="button" /> </field> </form>
les decorators
- decorator avec ftl d'entête
- faire un petit ftl d'entête: juste des libéllé fixe et l'affichage de 2 variables
On a créé un fichier /framework/example/webapp/example/includes/header.ftl.
<h2>${uiLabelMap.Welcome}</h2>
<h2>${uiLabelMap.ExampleApplication}</h2>
Pour internationaliser l'affichage, on a ajouté des textes dans les fichiers de propriété. Par exemple, dans le fichier par défaut /framework/example/config/ExampleUiLabels.properties, les champs sont définis comme ci-dessous:
ExampleApplication=Example Application Welcome=Welcome
- faire un screen l'affichant
On a créé un fichier /framework/example/widget/example/Example2Screens.xml
<?xml version="1.0" encoding="UTF-8"?> <screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/widget-screen.xsd"> <screen name="main"> </screen> </screens>
- faire un screen de type decorator
Dans le fichier /framework/example/widget/example/Example2Screens.xml, on a ajouté un decorator.
<screen name="main-decorator"> </screen>
- modifier les screens précédents pour utiliser ce decorator
Dans le fichier /framework/example/widget/example/Example2Screens.xml,le screen <<main>> devient:
<screen name="main"> </screen>
- decorator dans 1 decorator
- ajout du menu dans un decorator
On a modifié le fichier /framework/example/webapp/example/includes/appheader.ftl comme ci-dessous:
<#assign selected = headerItem?default("void")>
<div id="app-navigation">
<h2>${uiLabelMap.ExampleApplication}</h2>
<ul>
<li<#if selected = "List"> class="selected"</#if>>
<a href="<@ofbizUrl>ListExample2</@ofbizUrl>">${uiLabelMap.List}</a>
</li>
<li<#if selected = "Create"> class="selected"</#if>>
<a href="<@ofbizUrl>CreateExample2</@ofbizUrl>">${uiLabelMap.Create}</a>
</li>
<li<#if selected = "Edit"> class="selected"</#if>>
<a href="<@ofbizUrl>LookExample2</@ofbizUrl>">${uiLabelMap.Find}</a>
</li>
<#if userLogin?has_content>
<li class="opposed"><a href="<@ofbizUrl>logout</@ofbizUrl>">${uiLabelMap.CommonLogout}</a></li>
<#else>
<li class="opposed"><a href="<@ofbizUrl>${checkLoginUrl?if_exists}</@ofbizUrl>">${uiLabelMap.CommonLogin}</a></li>
</#if>
</ul>
<br class="clear" />
</div>
Après, il faut ajouter les champs correspondants dans le fichier /framework/example/config/ExampleUiLabels.properties.
ExampleCreate=Create ExampleFind=Find ExampleList=List
En suite, on a ajouté un nouveau decorator dans le fichier /framework/example/widget/example/Example2Screens.xml en utilisant le fichier ftl.
<screen name="menu"> </screen>
- ajout dans ce decorator de l'appel au decorator précédent
Le decorator est ajouté via la balise <<include-screen>>.
<screen name="main-decorator"> </screen>
- affichage des screens précédent
Pour activer le nouveau screen, il faut changer le lien d'entrée dans le fichier /framework/example/webapp/example/WEB-INF/controller.xml.
<view-map name="main" type="screen" page="component://example/widget/example/Example2Screens.xml#main"/>
Et puis, pareil pour les decorators dans le fichier /framework/example/widget/example/ExampleScreens.xml.
<screen name="EditExample2"> </screen>
<screen name="ListExample2"> </screen>
<screen name="LookExample2"> </screen>
<screen name="FindExample2"> </screen>
- decorator avec 2 include : les search et le list
On a l'entête de la page. Maintenant, il faut ajouter le corps dans le <<main-decorator>> du fichier/framework/example/widget/example/Example2Screens.xml.
<screen name="main-decorator"> </screen>
Avant, nous avions enlevé le paramètre <<auth>> dans le <<request-map>> dans le fichier /framework/example/webapp/example/WEB-INF/controller.xml. Avec le decorator, nous pouvons desormais le remettre pour activer la securité.
<request-map uri="EditExample2">
<security https="true" auth="true"/>
<response name="success" type="view" value="EditExample2"/>
</request-map>
<request-map uri="CreateExample2">
<security https="true" auth="true"/>
<response name="success" type="view" value="EditExample2"/>
</request-map>
<request-map uri="createExample2">
<security https="true" auth="true"/>
<event type="service" path="" invoke="createExample2"/>
<response name="success" type="view" value="ListExample2"/>
</request-map>
<request-map uri="ListExample2">
<security https="true" auth="true"/>
<response name="success" type="view" value="ListExample2"/>
</request-map>
<request-map uri="LookExample2">
<security https="true" auth="true"/>
<response name="success" type="view" value="LookExample2"/>
</request-map>
<request-map uri="FindExample2">
<security https="true" auth="true"/>
<response name="success" type="view" value="FindExample2"/>
</request-map>
objet : Tutoriel basé sur le composant example du framework OFBiz/Néogia langue de la page de référence : Français auteurs : multiples (Wenlong, Jing, Julien)







