À l'aide sur les jointures automatiques de SPIP !

Bonjour,

Je ne comprends pas ce qu’il est possible ou pas de faire avec les jointures.
Je cherche a afficher les champs d’une table B depuis une table A de manière automatique sans devoir déclarer explicitement dans mes boucles les tables de jointures.

J’ai un objet CHIEN et un objet RACE.
Sur chien j’ai déclaré un champ id_race.
Je cherche à afficher le champs #ORIGINE présent dans spip_races :

<BOUCLE_chien(CHIENS){id_chien?}>

	Comment afficher #ORIGINE de la table spip_races en faisant la jointure via le champ id_race présent dans les deux tables ?

</BOUCLE_chien>

La doc semble indiquer que la jointure est automatique dès lors que id_race est la clé primaire de spip_races et que le champ id_race existe bien sur spip_chiens.

J’ai aussi tenté de compléter avec dans declarer_tables_interfaces :

# Test jointure
$interface['tables_jointures']['spip_chiens'][] = 'races';
$interface['tables_jointures']['spip_chiens']['origine'] = 'races';
$interface['exceptions_des_jointures']['origine'] = array('spip_races', 'origine');

Merci pour toute aide que vous pourrez apporter, j’ai parcouru en long et en long large les différentes pages de la doc sans réussir, malgré sa qualité, à comprendre si c’était possible et comment s’y prendre…

Possible que la doc ne soit pas complètement à jour sur le sujet.
On peut aussi déclarer explicitement des jointures sur les clés primaires dans declarer_tables_objets_sql, ça pourrait aider.
Exemple ici entre commandes et commandes_details via id_commande : commandes/commandes.php at master - commandes - SPIP on GIT

Merci pour ton aide.

Je ne m’en sors pas encore, mais je continue de creuser…

Il suffirait de déclarer dans le join la colonne servant de jointure sur la table que l’on cherche à compléter ?

Dans mon cas sur spip_chiens, j’ajoute :

join' => [
'id_race' => 'id_race',
],

Mais pour le moment ça ne fonctionne pas.

est-ce que tu fais des ?var_mode=recalcul après les declarations. Ca pourrait jouer.

Il se peut que ce qui est automatique dans les jointures, ainsi que la doc l’indique nous dis-tu, c’est le choix du champ sur lequel faire la jointure. Et donc pas forcément le choix des tables, qu’il faut parfois encore expliciter dans la boucle, selon les déclarations php qu’on fait ou qu’on ne fait pas.

Par exemple, dans une situation où

  • il existe une table t_cccc avec une clé primaire id_cccc
  • il existe une table t_dddd qui contient un champ id_cccc
  • on ne rien déclare du tout à SPIP en PHP, ni tables, ni champs, ni jointures etc, ce qui a la vertu de la simplicité de permettre de « SPIPer direct clé en main sans prise de tête »

alors, des boucles <BOUCLE_ouafouaf(spip_cccc spip_dddd){id_cccc}> par exemple sont correctement compilées (avec, donc, les 2 tables explicitement indiquées)

Oui, et actualise=2 sur les plugins aussi au passage :wink:

C’est frustrant de n’avoir aucun résultat jusqu’à présent !

C’est très intéressant ton retour et ça pourrait expliquer que je n’arrive a aucuyn résultat concret : peut-être que SPIP choisit automatiquement une autre table portant la même clef que j’ai indiqué pour le join, il me semble que c’est ça que tu dis ?

J’aimerais vraiment comprendre, car mon modèle conceptuel a été taillé sur le fait que je puisse faire ensuite de jolies boucles sans devoir expliciter les jointures.

N’est-il pas possible de tout déclarer en amont pour ne pas laisser de choix à SPIP : je demande le champ #MACHIN depuis objet_truc : la jointure se fait sur tel champs de tel table ?

J’ai tenté de faire marcher ces jointures sur un autre plugin :

Avec une AGENCE (lieu physique) qui porte une clé étrangère id_entreprise.
Et donc un objet ENTREPRISE (clef primaire id_entreprise) qui contient des informations complémentaires auxquels je souhaite accéder depuis une simple boucle <BOUCLE_agence(AGENCES){…}>

J’ai déclaré le join et les keys à la fois sur declarer_tables_objets_sql puis dans declarer_tables_principales suite à la lecture d’une nouvelle page de la doc. Mais rien n’y fait !

J’ai aussi l’impression que si je passais par une table de jointure classique comme du documents_liens, ça fonctionnerait. Question de priorité des jointures peut-être ?

ça c’est facile de le savoir : ?var_mode=debug t’indiquera précisément comment spip comprend et compile ta boucle.

Non, je dis juste que c’est possible de demander à spip de jointer sans faire de déclaration préalable en PHP. Mais il se peut que ça ne soit pas compatible avec ton envie de ne pas devoir expliciter la 2eme table.

Perso, s’il faut galérer pour obtenir une jointure automatique invisible… alors je préfère la beauté d’une jointure visible qui marche direct .

Le plugin La Fabrique est un super outil pour fabriquer des objets… et les déclarations PHP qui vont bien et font ce qu’il faut. Je te conseille vivement de l’essayer car il intègre aussi un paramétrage click and play des jointures… Toute les complexités des situations et projets possibles ne sont pas pris en compte avec autant de facilité, et l’interface et les indications affichées sont un peu simplistes et ça reste donc complexe à fine-tuner au besoin, mais il n’est pas impossible que ça génère pile poil ce qui te convient.

Je te conseillerais donc d’essayer et quand tu auras reproduit ce que tu veux, soit utiliser direct le résultat, soit t’en inspirer pour réintégrer les bouts de code générés dans ton plugin.

Merci @JLuc , effectivement, je vois dans le debug que la requête qui part ne cherche à faire aucune jointure malgré la demande d’un champ externe, le from est juste centré sur l’objet de la boucle, logique qu’il ne trouve rien… :frowning:

Super, j’utilisais la Fabrique a sa sortie, mais je l’ai perdu de vue depuis, je m’y remets :wink:

Dans le debug je peux voir que dans le select, mon champs externe n’est pas présent, et que le paramètre join est vide, mais aussi que le from n’indique que la table de l’objet :

if (!isset($command['table'])) {
16        $command['table'] = 'agences';
17        $command['id'] = '_agence';
18        $command['from'] = array('agences' => 'spip_agences');
19        $command['type'] = array();
20        $command['groupby'] = array();
21        $command['select'] = array("agences.nom");
22        $command['orderby'] = array();
23        $command['join'] = array();
24        $command['limit'] = '';
25        $command['having'] = 
26            array();
27    }

Il me semble donc qu’aucune jointure automatique ou explicite via les déclarations dans les pipelines ne soient tentées.

Les jointures ne se font que via des champs qui sont aussi des clés de la table. La déclaration join est un helper pour les cas ou il faut faire la jointure entre des champs pas homonymes par exemple.

Pour reprendre ton exemple du début, si tu veux qu’une jointure entre spip_chiens et spip_race puisse se faire, il faut que le champ id_race de la table spip_chiens soit déclaré en index de la table, comme ici le champ id_rubrique de la table spip_articles

Bonjour à tous, et merci encore une fois pour vos retours.

Je galère sévère !

J’ai eu quelques résultats en forçant les tables dans les boucles comme le proposait @JLuc.
Néanmoins, j’ai l’impression d’être limité dans mon projet lorsque je veux faire une jointure sur une troisième table ou plus pour récupérer d’autres informations.

Si je reprends les exemples canins avec 3 objets :

spip_chiens
	id_chien (PK)
	nom
	id_race (KEY)

spip_races
	id_race (PK)
	nom
	id_pelage (KEY)

spip_pelages
	id_pelage (PK)
	nom
	type_pelage (KEY)

Est-ce que cela est juste, possible :

<BOUCLE_recuperer_pelage(CHIENS spip_races spip_pelages){id_chien=21}{0,1}{tout}>

		#NOM (chien N°#ID_CHIEN) a le pelage #TYPE_PELAGE

</BOUCLE_recuperer_pelage>

Vous semble t’il intéressant de créer un plugin test/tuto avec plusieurs objets de ce type pour relever ces challenges de jointures et documenter cela ?

Il ya bien longtemps déjà, j’avais rédigé ça sur le sujet Divagations sur les jointures avec SPIP - Le labo

1 « J'aime »

Ah, aussi, une dernière interrogation, au sujet de la déclaration des cles des objets dans le pipeline declarer_tables_objets_sql($tables)

Dans « key » on voit généralement ce format :

'key' => array(
	'PRIMARY KEY'  => 'id_chien',
	'key id_race'  => 'id_race',
),

Mais la doc de MYSQL indique que le terme « key » est propres à MYSQL et est un alias de « INDEX » qui est plus facilement portable.

Est-ce que modifier la déclaration par

'key' => array(
	'PRIMARY KEY'     => 'id_chien',
	'UNIQUE INDEX'  => 'id_race',
),

a une incidence pour SPIP et son mécanisme de jointures ?

Merci beaucoup, ma nouvelle bible à compulser :wink:
Je vais tenter de suivre cela et voir si cela me décoince, merci encore !

Un grand merci à tout le monde et notamment à @b_b dont les divagations sur les jointures m’ont permis d’aboutir.

Je n’explique toujours pas pourquoi je n’arrive pas à joindre des informations en utilisant une deuxième table qui dispose d’une clé égale à la clé primaire de la première table…

Mais la définition d’un critère personnalisé surchargeant le « from » et explicitant dans le « where » la jointure à faire m’ont permis de trouver une issue favorable. Voici pour ceux qui chercherait un exemple simple :

function critere_agence_augmentee_dist($idb, &$boucles, $crit) {
	
	$boucle = &$boucles[$idb];
	
	$boucle->from['agences_details'] = 'spip_agences_details';
	
	$where = array("'='", "'agences.id_agence'", "'agences_details.id_agence'");
	$boucle->where[] = $where;	
	
}