[spip-dev] Ajout d'une colonne data dans les articles

J'ai fini une première version d'ajout de données spécifique à
des éléments spip. Pour l'instant, ça se limite aux articles, mais le
même principe peut être facilement appliqué au reste, à coups de
copier/coller.

* Le patch pour spip 1.6 est ici :
  http://piif.lautre.net/tmp/spip.data.patch
  Pour l'installer : depuis le répertoire qui contient le répertoire
spip, il suffit de faire
patch -Np1 < spip.data.patch

  Attention au fichier ecrire/mes_options.php3 qui peut être différent
si on n'est pas dans une install "de base".

  Le patch installe un fichier ajouterData.sql dans spip/ecrire. Il
s'agit des commandes sql à executer pour ajouter une colonne data à
toutes les tables.
  En fait, pour l'instant, "ALTER TABLE spip_articles ADD data BLOB;"
suffit.

* Ce qui est fait :
- une colonne data est ajoutée à la table spip_article. Elle contient un
  tableau sérialisé.
- depuis une boucle ARTICLES, la balise #DATA retourne le tableau
  associé
- le filtre data permet de récupérer une entrée de ce tableau. Exemple :
  [le champ xyz : (#DATA|data{"xyz"})]
- dans mes_options.php3, on peut définir une fonction champs_data
  qui retourne une liste des champs à définir pour un article ou une
  rubrique donnée. Dans l'exemple fourni dans le patch, les articles
  de la rubrique 7 ont des champs "machin" et "truc".
    Dans ce cas, dans l'édition d'articles, des zones de saisie pour
  chaque champ sont gérées automatiquement (sous le PS).

* Ce qui reste à faire :
- tester de plus près
- même boulot pour les autres objets spip (rubrique, auteur et forum en
  priorité je suppose, mais c'est à définir)
- définir une boucle DATAS afin d'énumérer les champs d'un élément ?

À vos commentaires :slight_smile:

À+, Pif.

- depuis une boucle ARTICLES, la balise #DATA retourne le tableau
  associé

hum, tu es sûr ? Je pense plutôt (sans avoir testé, hein) que cette balise
utilisée toute seule va donner la chaîne "Array"... à mon sens il faut la
laisser serializée, et ne faire le unserialize() que dans le filtre

data{"xyz"}

- dans mes_options.php3, on peut définir une fonction champs_data
  qui retourne une liste des champs à définir pour un article ou une
  rubrique donnée. Dans l'exemple fourni dans le patch, les articles
  de la rubrique 7 ont des champs "machin" et "truc".
    Dans ce cas, dans l'édition d'articles, des zones de saisie pour
  chaque champ sont gérées automatiquement (sous le PS).

Est-ce qu'on peut préciser, pour chacun des champs, le type de formulaire de
saisie qu'on veut voir apparaitre (enum(a,b,c,d), uneligne, petit
formulaire, grand formulaire) ?

- même boulot pour les autres objets spip (rubrique, auteur et forum en
  priorité je suppose, mais c'est à définir)

c'est aussi simple de faire un truc général sur tous les objets ?

- définir une boucle DATAS afin d'énumérer les champs d'un élément ?

bof. Vu qu'on est déjà de l'autre côté de la barrière du php, on peut aussi
bien donner un "truc" simple en php qui récupère cette liste dans un
tableau.

Par ailleurs, je pense qu'il faut préférer un LONGBLOB ou LONGTEXT à un BLOB.

-- Fil

  J'ai fini une première version d'ajout de données spécifique à
des éléments spip. Pour l'instant, ça se limite aux articles, mais le

PS, si ça ne t'ennuie pas, j'aimerais vraiment qu'on appelle ça #EXTENSION,
spip_articles.extension, etc. Comme tu sais nous accordons autant
d'importance à l'interface et à l'intuition qu'à la performance technique,
et "data" ne voulant rien dire de particulier...

Pour le filtre |data{"champ"}, je n'ai pas d'idée de nom, par contre, pas
plus que pour la fonction à définir dans mes_options (d'ailleurs, a-t-on
réellement besoin d'une fonction ? un tableau ne suffit pas ?)

Autree idée, si jamais le champ demandé à ce filtre n'existe pas, prévois de
mettre un message d'erreur :
    spip_log("ERREUR l'extension '$champ' demandee n'existe pas dans mes_options.php3");

ce qui permettra de débugguer...

-- Fil

> - depuis une boucle ARTICLES, la balise #DATA retourne le tableau
> associé

hum, tu es sûr ? Je pense plutôt (sans avoir testé, hein) que cette balise
utilisée toute seule va donner la chaîne "Array"... à mon sens il faut la
laisser serializée, et ne faire le unserialize() que dans le filtre
>data{"xyz"}

  Effectivement. En fait, je ne voyais pas trop quoi faire du résultat
de cette balise en dehors sur filtre data. C'est pour ça que j'ai fait
comme ça. Au moins, s'il y a x références, on ne fait le unserialize
qu'une seule fois.

> - dans mes_options.php3, on peut définir une fonction champs_data
> qui retourne une liste des champs à définir pour un article ou une
> rubrique donnée. Dans l'exemple fourni dans le patch, les articles
> de la rubrique 7 ont des champs "machin" et "truc".
> Dans ce cas, dans l'édition d'articles, des zones de saisie pour
> chaque champ sont gérées automatiquement (sous le PS).

Est-ce qu'on peut préciser, pour chacun des champs, le type de formulaire de
saisie qu'on veut voir apparaitre (enum(a,b,c,d), uneligne, petit
formulaire, grand formulaire) ?

  Pour l'instant, c'est texte, point. Je pensais faire ça par la suite
(j'en ai parlé dans un mail précédent). Il suffirait de retourner un
tableau "champ=>type" à la place d'une liste à plat. Il faut ensuite
prévoir le switch de choc dans l'admin, mais d'abord définir les types
qu'on veut pouvoir gérer.

> - même boulot pour les autres objets spip (rubrique, auteur et forum en
> priorité je suppose, mais c'est à définir)

c'est aussi simple de faire un truc général sur tous les objets ?

  C'est le cas. Il suffit d'ajouter 'DATA' au balises possibles à tous
les types et ajouter les colonnes en base. Par contre, coté admin, il
faut ajouter les bouts de code générant les formulaire dans chacune
des pages d'admin concernées, c'est ça le plus long à faire.

> - définir une boucle DATAS afin d'énumérer les champs d'un élément ?
bof. Vu qu'on est déjà de l'autre côté de la barrière du php, on peut aussi
bien donner un "truc" simple en php qui récupère cette liste dans un
tableau.

j'me disais ça aussi en fait :slight_smile:

Par ailleurs, je pense qu'il faut préférer un LONGBLOB ou LONGTEXT à un BLOB.

  heu, 64Ko c'est déjà pas mal non ? 'fin, c'est que le alter qui
change, mais un champ data de 2Go, le unserialize à pas fini de
tourner, faudra pas mettre ça sur free :slight_smile:

À+, Pif.

> hum, tu es sûr ? Je pense plutôt (sans avoir testé, hein) que cette balise
> utilisée toute seule va donner la chaîne "Array"... à mon sens il faut la
> laisser serializée, et ne faire le unserialize() que dans le filtre
> >data{"xyz"}
  Effectivement. En fait, je ne voyais pas trop quoi faire du résultat
de cette balise en dehors sur filtre data. C'est pour ça que j'ai fait
comme ça. Au moins, s'il y a x références, on ne fait le unserialize
qu'une seule fois.

Tu penses sérieusement que unserialize() pose un problème de perfs :wink: Non,
il faut que la balise #DATA soit fonctionnelle, sinon personne ne comprendra
ce qui se passe. Tant pis si unserialize est appliquée deux (dix) fois au
lieu d'une.

> Est-ce qu'on peut préciser, pour chacun des champs, le type de formulaire de
> saisie qu'on veut voir apparaitre (enum(a,b,c,d), uneligne, petit
> formulaire, grand formulaire) ?
  Pour l'instant, c'est texte, point. Je pensais faire ça par la suite
(j'en ai parlé dans un mail précédent). Il suffirait de retourner un
tableau "champ=>type" à la place d'une liste à plat. Il faut ensuite
prévoir le switch de choc dans l'admin, mais d'abord définir les types
qu'on veut pouvoir gérer.

Super.

> c'est aussi simple de faire un truc général sur tous les objets ?
  C'est le cas. Il suffit d'ajouter 'DATA' au balises possibles à tous
les types et ajouter les colonnes en base. Par contre, coté admin, il
faut ajouter les bouts de code générant les formulaire dans chacune
des pages d'admin concernées, c'est ça le plus long à faire.

Un include() bien senti dans toutes les pages devrait suffire ?

  heu, 64Ko c'est déjà pas mal non ? 'fin, c'est que le alter qui
change, mais un champ data de 2Go, le unserialize à pas fini de
tourner, faudra pas mettre ça sur free :slight_smile:

Mh. Comme on ne peut pas prévoir tous les suages, autant voir grand tout de
suite. Et de toutes façons il vaut mieux éviter de faire tourner spip sur
free...

-- Fil

> J'ai fini une première version d'ajout de données spécifique à
> des éléments spip. Pour l'instant, ça se limite aux articles, mais le

PS, si ça ne t'ennuie pas, j'aimerais vraiment qu'on appelle ça #EXTENSION,
spip_articles.extension, etc. Comme tu sais nous accordons autant
d'importance à l'interface et à l'intuition qu'à la performance technique,
et "data" ne voulant rien dire de particulier...

no problemo

Pour le filtre |data{"champ"}, je n'ai pas d'idée de nom, par contre, pas
plus que pour la fonction à définir dans mes_options (d'ailleurs, a-t-on
réellement besoin d'une fonction ? un tableau ne suffit pas ?)

  La fonction permet de dire quels champs on veut utiliser, selon
l'endroit où on est. Comme ça, on peut mettre des champs spécifique à
une rubrique, et d'autres, dans une aute rubrique. Et par la suite, on
pourra, avec la même fonction, retourner les champs spécifiques aux
auteurs, ou aux rubriques d'un secteur donné par exemple.
  Si on veut les même champs partout, il suffit que la fonction ne
contienne qu'un return.

Autree idée, si jamais le champ demandé à ce filtre n'existe pas, prévois de
mettre un message d'erreur :
    spip_log("ERREUR l'extension '$champ' demandee n'existe pas dans mes_options.php3");

Ok.

À+, Pif.

Tu penses sérieusement que unserialize() pose un problème de perfs :wink:

  Aucune idée en fait. Mais en général, tout ce qui est parsing, même si
c'est la base de tout langage interprété, c'est jamais léger.

Non, il faut que la balise #DATA soit fonctionnelle, sinon personne ne
comprendra ce qui se passe. Tant pis si unserialize est appliquée deux
(dix) fois au lieu d'une.

adjugé.

> > Est-ce qu'on peut préciser, pour chacun des champs, le type de formulaire de
> > saisie qu'on veut voir apparaitre (enum(a,b,c,d), uneligne, petit
> > formulaire, grand formulaire) ?
> Pour l'instant, c'est texte, point. Je pensais faire ça par la suite
> (j'en ai parlé dans un mail précédent). Il suffirait de retourner un
> tableau "champ=>type" à la place d'une liste à plat. Il faut ensuite
> prévoir le switch de choc dans l'admin, mais d'abord définir les types
> qu'on veut pouvoir gérer.

Super.

heu, ouais, mais pas tout de suite hein :wink:

> > c'est aussi simple de faire un truc général sur tous les objets ?
> C'est le cas. Il suffit d'ajouter 'DATA' au balises possibles à tous
> les types et ajouter les colonnes en base. Par contre, coté admin, il
> faut ajouter les bouts de code générant les formulaire dans chacune
> des pages d'admin concernées, c'est ça le plus long à faire.

Un include() bien senti dans toutes les pages devrait suffire ?

  à peu de choses près oui, mais il faut quand même adapter le
select/update et insérer l'appel/include pour l'affichage et pour la
saisie => savoir où les insérer. J'ai pas dit que c'était dur, mais
c'est long et chiant :wink:

> heu, 64Ko c'est déjà pas mal non ? 'fin, c'est que le alter qui
> change, mais un champ data de 2Go, le unserialize à pas fini de
> tourner, faudra pas mettre ça sur free :slight_smile:
Mh. Comme on ne peut pas prévoir tous les suages, autant voir grand tout de
suite.

Ok.

Et de toutes façons il vaut mieux éviter de faire tourner spip sur
free...

Ça, c'est un autre débat, plutôt pour la liste spip-troll :wink:

  La fonction permet de dire quels champs on veut utiliser, selon
l'endroit où on est. Comme ça, on peut mettre des champs spécifique à
une rubrique, et d'autres, dans une aute rubrique.

Super bien vu !
JL

  La fonction permet de dire quels champs on veut utiliser, selon
l'endroit où on est. Comme ça, on peut mettre des champs spécifique à
une rubrique, et d'autres, dans une aute rubrique. Et par la suite, on
pourra, avec la même fonction, retourner les champs spécifiques aux
auteurs, ou aux rubriques d'un secteur donné par exemple.

C'est totalement délirant : que se passera-t-il si tu déplaces un article
d'une rubrique vers une autre ? Si tu veux avoir cette logique, il faudra
tout démonter (y compris les champs déjà existants), tout personnaliser
rubrique par rubrique, mettre les brèves dans la même table que les
articles, etc., pour obtenir un système entièrement configurable, un meccano
d'objets reliés les uns aux autres et appelables par des boucles. Pourquoi
pas, hein, pour un SPIP2 ou SPIP3... mais je ne vois pas l'intérêt
d'introduire ça en contrebande par le biais des extensions. A l'heure
actuelle un article est un article, une brève est une brève, et un admin
peut les déplacer où bon lui semble dans l'arborescence.

Fais simple ; tu feras compliqué plus tard :wink:

-- Fil

> La fonction permet de dire quels champs on veut utiliser, selon
> l'endroit où on est. Comme ça, on peut mettre des champs spécifique à
> une rubrique, et d'autres, dans une aute rubrique. Et par la suite, on
> pourra, avec la même fonction, retourner les champs spécifiques aux
> auteurs, ou aux rubriques d'un secteur donné par exemple.

C'est totalement délirant :

Meuh non, c'est l'usage extrème que tu décris qui est délirant.

que se passera-t-il si tu déplaces un article
d'une rubrique vers une autre ?

  Si les rubriques ne prévoient pas les mêmes champs, il y en a des
perdus et d'autres qui se retrouvent vide dès la première modification,
c'est à dire exactement le comportement auquel on pourrait s'attendre,
non ?
  Bien sur, l'idée est de déplacer les articles "intelligemment". S'il y
a une rubrique "agenda" qui prévoit un champ "lieu de l'événement" et
une rubrique "livres" qui prévois un champ "éditeur", y'a pas trop de
raison de déplacer un article livre vers agenda.
  Donc, si on le fait quand même, on paume des morceaux, et ça me parait
normal.

Si tu veux avoir cette logique, il faudra
tout démonter (y compris les champs déjà existants), tout personnaliser
rubrique par rubrique, mettre les brèves dans la même table que les
articles, etc., pour obtenir un système entièrement configurable, un meccano
d'objets reliés les uns aux autres et appelables par des boucles.

  Je vois pas le rapport.
  Quand je dis de faire ça pour les rubriques et les auteurs, je ne veux
pas dire qu'un champ pourra être commun à une rubrique, un article et un
auteur.
  Je veux dire qu'on pourra mettre un champ "éditeurs" aux articles,
un champ "droit d'accès" aux rubriques et/ou un champ "groupe"
aux auteurs, c'est à dire la réponse à 3 questions différentes déjà
posées sur la liste.

  Maintenant, si tu trouves tordu de retourner les 3 via la même
fonction, no problémo : on fait des fonctions extensions_article,
extensions_rubrique, extensions_auteur ...

Pourquoi
pas, hein, pour un SPIP2 ou SPIP3... mais je ne vois pas l'intérêt
d'introduire ça en contrebande par le biais des extensions.

contrebande, contrebande, tu t'énerves là :wink:

A l'heure
actuelle un article est un article, une brève est une brève, et un admin
peut les déplacer où bon lui semble dans l'arborescence.

  Avec ce que je propose aussi. S'il y a 12 sous-rubriques
dans le secteur "livres", alors, on peut avoir un champ "éditeur" pour
toutes ces rubriques et balader des livres d'une sous rubrique à
l'autre. Qu'est-ce que ça change ?

Fais simple ; tu feras compliqué plus tard :wink:

  Dans ce cas, on laisse tomber l'histoire des types de champs (ce qui
ne me dérange aucunement, car ça sent l'usine à gaz ce truc).

À+, Pif.

  Bien sur, l'idée est de déplacer les articles "intelligemment". S'il y
a une rubrique "agenda" qui prévoit un champ "lieu de l'événement" et
une rubrique "livres" qui prévois un champ "éditeur", y'a pas trop de
raison de déplacer un article livre vers agenda.

Ah oui, hum, pas con, tu as raison.

  Je veux dire qu'on pourra mettre un champ "éditeurs" aux articles,
un champ "droit d'accès" aux rubriques et/ou un champ "groupe"
aux auteurs, c'est à dire la réponse à 3 questions différentes déjà
posées sur la liste.

Pour "droits d'accès" il y a toujours les mots-clés, hein :wink:

  Maintenant, si tu trouves tordu de retourner les 3 via la même
fonction, no problémo : on fait des fonctions extensions_article,
extensions_rubrique, extensions_auteur ...

Non, non, une seule ça va.

  Dans ce cas, on laisse tomber l'histoire des types de champs (ce qui
ne me dérange aucunement, car ça sent l'usine à gaz ce truc).

La partie "enum(...)" fait usine à gaz, oui :wink: Mais avoir le choix entre
"ligne" et "bloc", c'est pas mal. Et, pour le rendu dans l'espace privé, il
faut avoir le choix entre "brut", "typo" ou "propre"...

-- Fil

  l’Autre Net, hébergeur associatif autogéré

Dans la fonction à définir dans mes_options (rappel ci-dessous), tu proposes
de passer comme arguments le type, l'id_objet, et l'id_ensemble ; la
difficulté est que, pour un article, l'id_ensemble pertinent peut être,
selon les applications, l'id_secteur ou l'id_rubrique - voire le titre du
secteur, etc.

Suggestion : on devrait donc peut-être se limiter à passer le type et
l'id_objet, sachant que si un malade de l'agenda veut récupérer le titre du
secteur il peut mettre des commandes SQL dans la fonction. L'API serait plus
simple, les appels plus rapides en général (sauf en cas de besoin précis,
qui seraient explicitement codés dans la fonction "champs_data"). Il suffit
de le faire une fois puis de copier-coller... on mettra le code qui va bien
dans la doc.

+<?php
+// Fonction a personnaliser selon les besoins pour retourner la liste des
+// champs specifiques a une categorie d'objets, sous forme de tableau.
+// Arguments :
+// $type = "article", "rubrique", "mots", "auteur" ...
+// $id_objet = id de l'article, de la rubrique ...
+// $id_ensemble = id de la rubrique de l'article, le secteur de la rubrique,
+// le groupe du mot ...
+function champs_data($type, $id_objet, $id_ensemble) {
+ if($type="article" && $id_ensemble==7) {
+ return array("machin", "truc");
+ }
+ // par defaut, il n'y a aucun champ dans data.
+ return array();
+}
+?>

-- Fil

Hello,

C'est totalement délirant [...]
Pourquoi pas, hein, pour un SPIP2 ou SPIP3... mais je ne vois pas
l'intérêt d'introduire ça en contrebande par le biais des
extensions.

Tout cela me semble très dangereux déjà, avec grosse usine à gaz à la
clef. Attention, je ne critique pas l'initiative ou le code, j'ai
aussi ce besoin, c'est juste que la solution adoptée ne me plait pas
trop.

Pourquoi ne pas effectivement y réfléchir plus sereinement pour le
faire proprement dans une future version de SPIP ?

Objectivement, si une abstraction de données est adoptée, cela devrait
grandement simplifier la tâche.

Fais simple ; tu feras compliqué plus tard :wink:

Le plus simple, c'est de ne pas se mettre des verrues impossible à
supprimer ensuite lorsqu'on voudra faire plus propre ...

-Nicolas

Tout cela me semble très dangereux déjà, avec grosse usine à gaz à la
clef. Attention, je ne critique pas l'initiative ou le code, j'ai
aussi ce besoin, c'est juste que la solution adoptée ne me plait pas
trop.

Son seul défaut amha c'est qu'on ne peut pas faire de boucle trop facilement
sur des critères {extension=...} (quoique, avec des regexp bien foutues, on
doit pouvoir faire pas mal de choses).

Objectivement, si une abstraction de données est adoptée, cela devrait
grandement simplifier la tâche.

tss tss tss

Le plus simple, c'est de ne pas se mettre des verrues impossible à
supprimer ensuite lorsqu'on voudra faire plus propre ...

Récupérer des données dans le champ extension pour les cloquer dans d'autres
champs gérés autrement ne me semble pas difficile. Je l'ai fait très
récemment pour les langues des utilisateurs, qui étaient dans .prefs et sont
passées dans .lang

-- Fil

Son seul défaut amha c'est qu'on ne peut pas faire de boucle trop
facilement sur des critères {extension=...} (quoique, avec des
regexp bien foutues, on doit pouvoir faire pas mal de choses).

Ca devient un truc élististe pour une population plus que restreinte,
là ...

Objectivement, si une abstraction de données est adoptée, cela
devrait grandement simplifier la tâche.

tss tss tss

Je n'essaie pas de vendre notre travail, mais d'être objectif.

Le plus simple, c'est de ne pas se mettre des verrues impossible à
supprimer ensuite lorsqu'on voudra faire plus propre ...

Récupérer des données dans le champ extension pour les cloquer dans
d'autres champs gérés autrement ne me semble pas difficile.

Je pense plus aux squelettes.

-Nicolas

Nicolas Hoizey wrote:

Son seul défaut amha c'est qu'on ne peut pas faire de boucle trop
facilement sur des critères {extension=...} (quoique, avec des
regexp bien foutues, on doit pouvoir faire pas mal de choses).

Ca devient un truc élististe pour une population plus que restreinte,
là ...

Idées pour démocratiser l'élite :
des critères
  {titre_extension=...}{texte_extension=...}
ou des boucles
  <boucle_yop(EXTENSIONS){titre=...}>
...
JLuc

Je ne m'était pas encore mélé de cette discussion, mais
personnellement, ça me parait très compliquè à mettre en place.
  Ajouter un niveau de virtualisation implique de générer
automatiquement du code beaucoup plus complexe, puisqu'il faudra
déterminer dynamiquement le type de chacun des éléments à menipuler
pour savoir comment les trier/selectionner/mettre à jour ...
  Ça parait con à première vue, mais il suffit de regarder le tas
de if/then/else/but qu'il y a inc-calcl-squel et compagnie pour
différencier le traitement des dates, des champs textuels, ceux
à passer par typo/propre et compagnie par défaut, ceux pour
lesquels la balise en * à un sens, sans parler du cas particulier
des boucle HIERARCHIE.

  Généraliser ça me parait trop compliqué pour en valoir la peine.
Autant passer en jsp avec une gros machin genre ejb entre la base de
données et le html. Et là, la partie admin, tu l'oubli et tu la
recodes de zéro.

  Bref, pour moi, cette idée, c'est pas spip 1.12 ou spip 3, c'est
whatever-you-want-other-than-spip.

À+, Pif (qu'à gouté à vignette, ejb et autres joyeusetés et qu'à
moyennement apprécié ;-).

Sympa comme idée, mais pas évident à coder !
  De plus, on ne peut faire que le =, != et ==!, mais pas de <, >, ni
{par ..}
  Mais j'va y réfléchir :wink:
(au moins pour le {..}, pour la boucle, j'laisse ça aux pros :wink:

À+, Pif.