Carnet Wiki

De Forms&Tables à Formidable, retour d’expérience

Version 7 — Juin 2016 — erf consult

Attention ! Le plugin Formidable d’importe automatiquement les formulaires et les données de Forms & Tables. Plus besoin de faire ce genre de gymnastique.

Avant

A l’origine un site spip 2.1 avec Forms&Tables pour gérer un agenda événementiel. Le formulaire d’ajout d’événements est constitué de :
-  un champ texte pour saisie de la date au format jj/mm/aaaa (sans vérification). Champ utilisé pour trier les enregistrements. Obligatoire
-  un champ texte pour saisir une précision pour la date (par exemple « Du 3 au 8 décembre »). Si rempli, ce champ est affiché à la place du champ précédent
-  un champ heure
-  un champ texte pour saisie d’un nom de spectacle
-  un champ texte pour saisie d’une ville
-  un champ texte pour saisie d’un département
-  un champ texte de saisie d’un nom de festival ou d’événement.
-  un champ de saisie d’url (site officiel de l’événement)
-  une zone de commentaire

L’ajout d’événement ne peut se faire que dans le Back Office.

L’agenda est présenté sur le site public dans un tableau avec une ligne par événement. 2 liens permettent d’afficher les événements de l’année en cours ou des années passées triés chronologiquement.

Les 2 squelettes

(appel dans article.htm : <INCLURE{fond=inc-agenda}{ajax}{env}{id_article,senstri}>)

Fichier inc-agenda.html

#SET{tri,date_1}
[(#SET{senstri,#ENV{senstri,0}})]


<p>
[<a href="[(#SELF|parametre_url{senstri, })]" title="Année en cours" class='ajax'>Année en cours</a>]
[<a href="[(#SELF|parametre_url{senstri, 1})]" title="Années passées" class='ajax'>Années passées</a>]
</p>


<B_donnees>


<table class="spip donnees" id='donnees-#ENV{id_table}'>
	<BOUCLE_donnees(FORMS_DONNEES){id_form=1}{tri_donnee #GET{tri}}{inverse #GET{senstri}}>
		<BOUCLE_date(FORMS_CHAMPS){id_form}{titre=Date}>#SET{dateevenement,#VALEUR}</BOUCLE_date>
		
		[(#GET{senstri}|=={0}|oui)
			[(#GET{dateevenement}|dansfutur|>={0}|oui)
				[<tr><td class="agenda-annee">
						<span>(#GET{dateevenement}|annee|unique)</span>
				</td></tr>]
				<tr class="[(#_donnees:COMPTEUR_BOUCLE|alterner{row_even,row_odd})]">
					<INCLURE{fond=inc-agenda-ligne}{id_form}{id_donnee}>
				</tr>
			]
		]
		[(#GET{senstri}|=={1}|oui)
			[(#GET{dateevenement}|dansfutur|<{0}|oui)
				[<tr><td class="agenda-annee">
						<span>(#GET{dateevenement}|annee|unique)</span>
				</td></tr>]
				<tr class="[(#_donnees:COMPTEUR_BOUCLE|alterner{row_even,row_odd})]">
					<INCLURE{fond=inc-agenda-ligne}{id_form}{id_donnee}>
				</tr>
			]
		]
	</BOUCLE_donnees>
</table>


</B_donnees>

Fichier inc-agenda-ligne.html

<BOUCLE_date(FORMS_CHAMPS){id_form}{titre=Date}>#SET{dateevenement,#VALEUR}</BOUCLE_date>


<td>
   <BOUCLE_datetxt(FORMS_CHAMPS){id_form}{titre=Datetxt}>
      <span class="#_reponses:EDIT{#CHAMP}" >#VALEUR</span>
      [(#VALEUR|?{'',' '})<span class="#_reponses:EDIT{#CHAMP}" >[(#GET{dateevenement}|affdate_jourcourt)]</span>]
   </BOUCLE_datetxt>
   <BOUCLE_horaire(FORMS_CHAMPS){id_form}{titre=Heure}>[ - <span class="#_reponses:EDIT{#CHAMP}" >(#VALEUR)</span>]</BOUCLE_horaire>
</td>
<td>
   <BOUCLE_spectacle(FORMS_CHAMPS){id_form}{titre=Spectacle}>[<span class="#_reponses:EDIT{#CHAMP}" >(#VALEUR)</span>]</BOUCLE_spectacle>
</td>
<td>
   <BOUCLE_ville(FORMS_CHAMPS){id_form}{titre=Ville}>[<span class="#_reponses:EDIT{#CHAMP}" >(#VALEUR)</span>]</BOUCLE_ville>
   <BOUCLE_dept(FORMS_CHAMPS){id_form}{titre=Département}>[ (<span class="#_reponses:EDIT{#CHAMP}" >(#VALEUR)</span>)]</BOUCLE_dept>
</td>
<td>
   <B_festival>
      #SET{fermer,0}
      <BOUCLE_lien(FORMS_CHAMPS){id_form}{titre=Site}>[#SET{fermer,1}<a href="(#VALEUR)" class="spip_out">]</BOUCLE_lien>
   <BOUCLE_festival(FORMS_CHAMPS){id_form}{titre=Festival}>[<span class="#_reponses:EDIT{#CHAMP}" >(#VALEUR)</span>]</BOUCLE_festival>
      [(#GET{fermer}|=={1}|?{'</a>',''})]
   </B_festival>
</td>
<td>
   <BOUCLE_commentaire(FORMS_CHAMPS){id_form}{titre=Commentaire}>
      [<span class="infobulle" title="(#VALEUR|attribut_html)"><img src="#CHEMIN{images/info.png}" alt="Infos" /></span>]
   </BOUCLE_commentaire>
</td>

Migration

Le Formulaire

  1. Exportation du formulaire depuis Forms&Tables (nécessite d’activer le plugin Snippets) dans un fichier xml
  2. Suppression des warnings au début du fichier xml
  3. Vérifier le charset du fichier qui doit être au format ANSI. Faire une convertion le cas échéant.
  4. Importation du formulaire dans Formidable

Remarque : si à cette étape vous modifiez le formulaire, le nom des champs risque de ne plus correspondre dans la table spip_formulaires_reponses_champs. Donc si par exemple, votre premier champ est un input de type date ’nommé date_1, et que vous modifiez le formulaire pour utiliser le champ « date » de Formidable qui utilise un petit calendrier de saisie de date, ce nouveau champ se nommera date_2. Il faudra donc modifier le nom lors de l’importation décrite ci-après.

Les données

On ne peut pas actuellement les importer directement. Il faut donc passer par phpMyAdmin par exemple pour récupérer les données sous forme de fichier csv des tables spip_forms_donnees (contient les réponses) et spip_forms_donnees_champs (contient les saisies de chaque réponse). Il va falloir insérer ces données dans les tables nommées respectivement spip_formulaires_reponses et spip_formulaires_reponses_champs après un petit traitement « manuel » pour satisfaire les correspondances de champs.

Structure de spip_forms_donnees Structure de spip_formulaires_reponses
id_donnee (bigint) id_formulaires_reponse (bigint)
id_form (bigint) id_formulaire (bigint)
date (datetime) date (datetime)
ip (varchar) ip (varchar)
id_auteur (bigint) id_auteur (bigint)
cookie (varchar) cookie (varchar)
statut (varchar) statut (varchar)
maj (timestamp) maj (timestamp)
id_article_export (bigint)
url (varchar)
confirmation (varchar)
rang (bigint)
bgch (bigint)
bdte (bigint)
niveau (bigint)
Structure de spip_forms_donnees_champs Structure de spip_formulaires_reponses_champs
id_donnee (bigint) id_formulaires_reponse (bigint)
champ (varchar) nom (varchar)
valeur (text) valeur (text)
maj (timestamp) maj (timestamp)

Une méthode possible pour migrer ces données :
-  sous phpMyAdmin, exporter les données en Table Open Office en gardant les noms de champ en première ligne.
-  Supprimer les colonnes qui n’existent pas dans la table destination et faire concorder l’ordre des colonnes. Faire attention pour les champs de date que celles-ci restent au format MySql (aaaa-mm-jj hh:mm:ss).
-  Dans le fichier CSV export de la table spip_forms_donnees, dans la colonne id_form, remplacer par le nouveau numéro donné par FORMIDABLE pendant l’import du formulaire (xml).
-  Si la table spip_formulaires_reponses contient déjà des données, il est nécessaire de modifier l’index id_form en adoptant un index n’existant pas déjà spip_formulaires_reponses. Personnellement, je repart d’un index rond, par exemple 1000. Dans le fichier CSV exporté de spip_forms_donnees_champs, reprendre la même indexation en conséquence.
-  Dans le fichier CSV export de la table spip_forms_donnees_champs, il faut éliminer les doublons sur le couple id_donnee/nom car la table destination spip_formulaires_reponses_champs n’autorise pas les doublons. Pour repérer facilement les doublons, appliquer par exemple la recette de cette page. Dans la colonne E, vous aurez donc =A1&B1 et dans la colonne F, vous aurez =IF(COUNTIF($E$1:E1;E1)>1;"Doublon";"") ou =SI(NB.($E$1:E1;E1)>1;"Doublon";"") . Ainsi vous repérez rapidement les lignes en doublons, ne reste plus qu’à les supprimer.
-  Enregistrer le fichier résultat en csv (UTF-8, séparateur de champ : point-virgule, séparateur de texte : guillemets doubles).
-  Dans phpMyAdmin, importer le fichier csv (en ignorant la première ligne qui contient le nom des champs) dans la table destination.

Vous pouvez vérifier que tout s’est correctement déroulé en visualisant et analysant les réponses dans Formidable.

Adapter les squelettes.

(appel dans article.htm : <INCLURE{fond=inc-agenda}{env}{id_article,senstri}>)

Fichier inc-agenda.html

[(#SET{senstri,#ENV{senstri,0}})]


<div id="menu-agenda">
   [<a href="[(#SELF|parametre_url{id_reponse,''}|parametre_url{gerer,-1}|parametre_url{senstri, })]" title="Année en cours">Année en cours</a>]
   [<a href="[(#SELF|parametre_url{id_reponse,''}|parametre_url{gerer,-1}|parametre_url{senstri, 1})]" title="Années passées">Années passées</a>]
   [(#REM) affichage du menu d'ajout d'événement. Uniquement pour les administrateurs ]
   [(#SESSION{statut}|=={0minirezo}|oui)
      <a href="[(#SELF|parametre_url{id_reponse,''}|parametre_url{gerer,1})]" title="Ajouter une date" class="agenda-ajouter">Ajouter une date</a>
   ]
</div>


[(#ENV{gerer}|=={1}|non) 
   <div id="agenda" class="table">
      <INCLURE{fond=inc-agenda-afficher}{env}{id_article,senstri=#GET{senstri}}>
   </div>
]


[(#REM) affichage du formulaire si demande d'ajout ou de modification ]
[(#ENV{gerer}|=={1}|oui|et{#SESSION{statut}|=={0minirezo}|oui})
   #FORMULAIRE_FORMIDABLE{1,#ARRAY,#ENV{id_reponse}}
]

Fichier inc-agenda-afficher.html

#SET{cpt,0}
<BOUCLE_formulaire(FORMULAIRES){id_formulaire=1}>
   [(#REM) lister les saisies par leur nom de champ]
   #SET{saisies, #SAISIES|unserialize|saisies_lister_par_nom}


<BOUCLE_reponse(FORMULAIRES_REPONSES){id_formulaire}{tri_selon_donnee date_2}{inverse #ENV{senstri}}>


#SET{valeurs,#ARRAY}
      <BOUCLE_champs(FORMULAIRES_REPONSES_CHAMPS){id_formulaires_reponse}>
         #SET{test_array,#VALEUR|unserialize}
         #SET{valeur,#GET{test_array}|is_array|?{#GET{test_array},#VALEUR}}
         #SET_MERGE{valeurs,#ARRAY{#NOM,#GET{valeur}}}
      </BOUCLE_champs>


#SET{dateevenement,#GET{valeurs}|table_valeur{date_2}}
      
      #SET{cpt, #GET{cpt}|plus{1}}
      [(#ENV{senstri}|=={1}|non|et{#GET{dateevenement}|dansfutur|>={0}|oui})
         [(#INCLURE{fond=inc-agenda-ligne}
                              {id_formulaires_reponse}
                              {cpt=#GET{cpt}}
                              {dateevt=#GET{dateevenement}}
                              {saisies=#GET{saisies}}
                              {valeurs=#GET{valeurs}})]
      ]
      [(#ENV{senstri}|=={1}|oui|et{#GET{dateevenement}|dansfutur|<{0}|oui})
         [(#INCLURE{fond=inc-agenda-ligne}
                              {id_formulaires_reponse}
                              {cpt=#GET{cpt}}
                              {dateevt=#GET{dateevenement}}
                              {saisies=#GET{saisies}}
                              {valeurs=#GET{valeurs}})]
      ]


</BOUCLE_reponse>


</BOUCLE_formulaire>

Fichier inc-agenda-ligne.html

#SET{saisies, #ENV{saisies}}
#SET{valeurs, #ENV{valeurs}}
#SET{dateevenement, #ENV{dateevt}}
#SET{env_affichage,#ARRAY{valeur_uniquement,oui,sans_reponse,""}}


[<div class="agenda_annee">(#GET{dateevenement}|annee|unique)</div>]


<div class="ligne [(#ENV{cpt}|alterner{row_even,row_odd})]">
   [(#REM) Date et heure de l'evenement ]
   <div class="afficher cellule">
      [(#GET{saisies}|table_valeur{ligne_1}|saisies_generer_vue{#GET{valeurs},#GET{env_affichage}}|textebrut)]
      [(#GET{valeurs}|table_valeur{ligne_1}|?{'',' '}) [(#GET{dateevenement}|affdate_jourcourt)]]
      [ - (#GET{saisies}|table_valeur{ligne_2}|saisies_generer_vue{#GET{valeurs},#GET{env_affichage}}|textebrut)]
   </div>


[(#REM) Spectacle ]
   <div class="afficher cellule">
      [(#GET{saisies}|table_valeur{ligne_3}|saisies_generer_vue{#GET{valeurs},#GET{env_affichage}}|textebrut)]
   </div>


[(#REM) Departement Ville ]
   <div class="afficher cellule">
      ([(#GET{saisies}|table_valeur{ligne_4}|saisies_generer_vue{#GET{valeurs},#GET{env_affichage}}|textebrut)]
      [ (#GET{saisies}|table_valeur{ligne_5}|saisies_generer_vue{#GET{valeurs},#GET{env_affichage}}|textebrut)])
   </div>


[(#REM) Lien vers site officiel de l'evenement ]
   <div class="afficher cellule">
   	#SET{fermer,0}
      [#SET{fermer,1}<a href="(#GET{valeurs}|table_valeur{url_1})" class="spip_out">]
      [(#GET{saisies}|table_valeur{ligne_6}|saisies_generer_vue{#GET{valeurs},#GET{env_affichage}}|textebrut)]
      [(#GET{fermer}|=={1}|oui)</a>]
	</div>
   
   [(#REM) affichage des icones de modification et suppression. Uniquement pour les administrateurs non restreints ]
   [(#SESSION{statut}|=={0minirezo}|oui)
      <div class="afficher cellule">
      <a href="[(#SELF|parametre_url{gerer,1}|parametre_url{id_reponse,#ID_FORMULAIRES_REPONSE})]">
      	<img src="#CHEMIN{images/formulaire-configurer-16.png}" alt="<:Modifier:>" title="<:Modifier:>" />
      </a>
      </div>
      <div class="afficher cellule">
      <a onclick="javascript:return confirm('<:confirmer_supprimer_evt:>');" 
      	href="#URL_ACTION_AUTEUR{instituer_formulaires_reponse, #ID_FORMULAIRES_REPONSE-poubelle, #SELF|parametre_url{var_mode,recalcul}}">
         <img src="#CHEMIN{images/formulaire-annuler-16.png}" alt="<:Supprimer:>" title="<:Supprimer:>" />
      </a>
      </div>
   ]
</div>

Ceci n’est sûrement pas parfait, mais si ca peut aider... Je n’ai pas encore eu le temps de travailler sur « l’ajaxisation », il y a un recalcul à forcer quelque part, mais je n’ai trouvé ni où ni comment faire. "Avec spip, on apprend tous les jours".

A noter que formidable est compatible avec le plugin multilang. Il suffit d’ajouter aux champs désirés la classe multilang