Completed
Push — master ( 306975...ae8034 )
by cam
01:18
created
ecrire/public/jointures.php 1 patch
Indentation   +396 added lines, -396 removed lines patch added patch discarded remove patch
@@ -17,7 +17,7 @@  discard block
 block discarded – undo
17 17
  **/
18 18
 
19 19
 if (!defined('_ECRIRE_INC_VERSION')) {
20
-	return;
20
+    return;
21 21
 }
22 22
 
23 23
 
@@ -33,11 +33,11 @@  discard block
 block discarded – undo
33 33
  *     Chaine sinon : le nom du champ (non décomposable donc)
34 34
  */
35 35
 function decompose_champ_id_objet($champ) {
36
-	if (($champ !== 'id_objet') and preg_match(',^id_([a-z_]+)$,', $champ, $regs)) {
37
-		return ['id_objet', 'objet', objet_type($champ)];
38
-	}
36
+    if (($champ !== 'id_objet') and preg_match(',^id_([a-z_]+)$,', $champ, $regs)) {
37
+        return ['id_objet', 'objet', objet_type($champ)];
38
+    }
39 39
 
40
-	return $champ;
40
+    return $champ;
41 41
 }
42 42
 
43 43
 /**
@@ -56,21 +56,21 @@  discard block
 block discarded – undo
56 56
  *     - array(id_objet, objet), si le champ n'existe pas mais qu'on peut décomposer
57 57
  */
58 58
 function trouver_champs_decomposes($champ, $desc) {
59
-	if (
60
-		!is_array($desc) // on ne se risque pas en conjectures si on ne connait pas la table
61
-		or array_key_exists($champ, $desc['field'])
62
-	) {
63
-		return [$champ];
64
-	}
65
-	// si le champ se décompose, tester que les colonnes décomposées sont présentes
66
-	if (is_array($decompose = decompose_champ_id_objet($champ))) {
67
-		array_pop($decompose);
68
-		if (count(array_intersect($decompose, array_keys($desc['field']))) == count($decompose)) {
69
-			return $decompose;
70
-		}
71
-	}
72
-
73
-	return [$champ];
59
+    if (
60
+        !is_array($desc) // on ne se risque pas en conjectures si on ne connait pas la table
61
+        or array_key_exists($champ, $desc['field'])
62
+    ) {
63
+        return [$champ];
64
+    }
65
+    // si le champ se décompose, tester que les colonnes décomposées sont présentes
66
+    if (is_array($decompose = decompose_champ_id_objet($champ))) {
67
+        array_pop($decompose);
68
+        if (count(array_intersect($decompose, array_keys($desc['field']))) == count($decompose)) {
69
+            return $decompose;
70
+        }
71
+    }
72
+
73
+    return [$champ];
74 74
 }
75 75
 
76 76
 
@@ -100,23 +100,23 @@  discard block
 block discarded – undo
100 100
  *     Alias de la table de jointure (Lx)
101 101
  */
102 102
 function calculer_jointure(&$boucle, $depart, $arrivee, $col = '', $cond = false, $max_liens = 5) {
103
-	// les jointures minimales sont optimales :
104
-	// on contraint le nombre d'etapes en l'augmentant
105
-	// jusqu'a ce qu'on trouve une jointure ou qu'on atteigne la limite maxi
106
-	$max = 1;
107
-	$res = false;
108
-	$milieu_exclus = ($col ? $col : []);
109
-	while ($max <= $max_liens and !$res) {
110
-		$res = calculer_chaine_jointures($boucle, $depart, $arrivee, [], $milieu_exclus, $max);
111
-		$max++;
112
-	}
113
-	if (!$res) {
114
-		return '';
115
-	}
116
-
117
-	list($nom, $desc) = $depart;
118
-
119
-	return fabrique_jointures($boucle, $res, $cond, $desc, $nom, $col);
103
+    // les jointures minimales sont optimales :
104
+    // on contraint le nombre d'etapes en l'augmentant
105
+    // jusqu'a ce qu'on trouve une jointure ou qu'on atteigne la limite maxi
106
+    $max = 1;
107
+    $res = false;
108
+    $milieu_exclus = ($col ? $col : []);
109
+    while ($max <= $max_liens and !$res) {
110
+        $res = calculer_chaine_jointures($boucle, $depart, $arrivee, [], $milieu_exclus, $max);
111
+        $max++;
112
+    }
113
+    if (!$res) {
114
+        return '';
115
+    }
116
+
117
+    list($nom, $desc) = $depart;
118
+
119
+    return fabrique_jointures($boucle, $res, $cond, $desc, $nom, $col);
120 120
 }
121 121
 
122 122
 /**
@@ -155,79 +155,79 @@  discard block
 block discarded – undo
155 155
  *     Alias de la table de jointure (Lx)
156 156
  */
157 157
 function fabrique_jointures(&$boucle, $res, $cond = false, $desc = [], $nom = '', $col = '', $echap = true) {
158
-	static $num = [];
159
-	$id_table = '';
160
-	$cpt = &$num[$boucle->descr['nom']][$boucle->descr['gram']][$boucle->id_boucle];
161
-	foreach ($res as $cle => $r) {
162
-		list($d, $a, $j) = $r;
163
-		if (!$id_table) {
164
-			$id_table = $d;
165
-		}
166
-		$n = ++$cpt;
167
-		if (is_array($j)) { // c'est un lien sur un champ du type id_objet,objet,'article'
168
-			list($j1, $j2, $obj, $type) = $j;
169
-			// trouver de quel cote est (id_objet,objet)
170
-			if ($j1 == "id_$obj") {
171
-				$obj = "$id_table.$obj";
172
-			} else {
173
-				$obj = "L$n.$obj";
174
-			}
175
-			// le where complementaire est envoye dans la jointure et dans le where
176
-			// on utilise une clé qui le relie a la jointure pour que l'optimiseur
177
-			// sache qu'il peut enlever ce where si il enleve la jointure
178
-			$boucle->where["JOIN-L$n"] =
179
-				$echap ?
180
-					["'='","'$obj'","sql_quote('$type')"]
181
-					:
182
-					['=',"$obj",sql_quote($type)];
183
-			$boucle->join["L$n"] =
184
-				$echap ?
185
-					["'$id_table'", "'$j2'", "'$j1'", "'$obj='.sql_quote('$type')"]
186
-					:
187
-					[$id_table, $j2, $j1, "$obj=" . sql_quote($type)];
188
-		} else {
189
-			$boucle->join["L$n"] = $echap ? ["'$id_table'", "'$j'"] : [$id_table, $j];
190
-		}
191
-		$boucle->from[$id_table = "L$n"] = $a[0];
192
-	}
193
-
194
-
195
-	// pas besoin de group by
196
-	// (cf http://article.gmane.org/gmane.comp.web.spip.devel/30555)
197
-	// si une seule jointure et sur une table avec primary key formee
198
-	// de l'index principal et de l'index de jointure (non conditionnel! [6031])
199
-	// et operateur d'egalite (https://core.spip.net/issues/477)
200
-
201
-	if ($pk = (isset($a[1]) && (count($boucle->from) == 2) && !$cond)) {
202
-		$pk = nogroupby_if($desc, $a[1], $col);
203
-	}
204
-
205
-	// pas de group by
206
-	// si une seule jointure
207
-	// et si l'index de jointure est une primary key a l'arrivee !
208
-	if (
209
-		!$pk
210
-		and (count($boucle->from) == 2)
211
-		and isset($a[1]['key']['PRIMARY KEY'])
212
-		and ($j == $a[1]['key']['PRIMARY KEY'])
213
-	) {
214
-		$pk = true;
215
-	}
216
-
217
-	// la clause Group by est en conflit avec ORDER BY, a completer
218
-	$groups = liste_champs_jointures($nom, $desc, true);
219
-	if (!$pk) {
220
-		foreach ($groups as $id_prim) {
221
-			$id_field = $nom . '.' . $id_prim;
222
-			if (!in_array($id_field, $boucle->group)) {
223
-				$boucle->group[] = $id_field;
224
-			}
225
-		}
226
-	}
227
-
228
-	$boucle->modificateur['lien'] = true;
229
-
230
-	return "L$n";
158
+    static $num = [];
159
+    $id_table = '';
160
+    $cpt = &$num[$boucle->descr['nom']][$boucle->descr['gram']][$boucle->id_boucle];
161
+    foreach ($res as $cle => $r) {
162
+        list($d, $a, $j) = $r;
163
+        if (!$id_table) {
164
+            $id_table = $d;
165
+        }
166
+        $n = ++$cpt;
167
+        if (is_array($j)) { // c'est un lien sur un champ du type id_objet,objet,'article'
168
+            list($j1, $j2, $obj, $type) = $j;
169
+            // trouver de quel cote est (id_objet,objet)
170
+            if ($j1 == "id_$obj") {
171
+                $obj = "$id_table.$obj";
172
+            } else {
173
+                $obj = "L$n.$obj";
174
+            }
175
+            // le where complementaire est envoye dans la jointure et dans le where
176
+            // on utilise une clé qui le relie a la jointure pour que l'optimiseur
177
+            // sache qu'il peut enlever ce where si il enleve la jointure
178
+            $boucle->where["JOIN-L$n"] =
179
+                $echap ?
180
+                    ["'='","'$obj'","sql_quote('$type')"]
181
+                    :
182
+                    ['=',"$obj",sql_quote($type)];
183
+            $boucle->join["L$n"] =
184
+                $echap ?
185
+                    ["'$id_table'", "'$j2'", "'$j1'", "'$obj='.sql_quote('$type')"]
186
+                    :
187
+                    [$id_table, $j2, $j1, "$obj=" . sql_quote($type)];
188
+        } else {
189
+            $boucle->join["L$n"] = $echap ? ["'$id_table'", "'$j'"] : [$id_table, $j];
190
+        }
191
+        $boucle->from[$id_table = "L$n"] = $a[0];
192
+    }
193
+
194
+
195
+    // pas besoin de group by
196
+    // (cf http://article.gmane.org/gmane.comp.web.spip.devel/30555)
197
+    // si une seule jointure et sur une table avec primary key formee
198
+    // de l'index principal et de l'index de jointure (non conditionnel! [6031])
199
+    // et operateur d'egalite (https://core.spip.net/issues/477)
200
+
201
+    if ($pk = (isset($a[1]) && (count($boucle->from) == 2) && !$cond)) {
202
+        $pk = nogroupby_if($desc, $a[1], $col);
203
+    }
204
+
205
+    // pas de group by
206
+    // si une seule jointure
207
+    // et si l'index de jointure est une primary key a l'arrivee !
208
+    if (
209
+        !$pk
210
+        and (count($boucle->from) == 2)
211
+        and isset($a[1]['key']['PRIMARY KEY'])
212
+        and ($j == $a[1]['key']['PRIMARY KEY'])
213
+    ) {
214
+        $pk = true;
215
+    }
216
+
217
+    // la clause Group by est en conflit avec ORDER BY, a completer
218
+    $groups = liste_champs_jointures($nom, $desc, true);
219
+    if (!$pk) {
220
+        foreach ($groups as $id_prim) {
221
+            $id_field = $nom . '.' . $id_prim;
222
+            if (!in_array($id_field, $boucle->group)) {
223
+                $boucle->group[] = $id_field;
224
+            }
225
+        }
226
+    }
227
+
228
+    $boucle->modificateur['lien'] = true;
229
+
230
+    return "L$n";
231 231
 }
232 232
 
233 233
 /**
@@ -242,17 +242,17 @@  discard block
 block discarded – undo
242 242
  * @return bool
243 243
  */
244 244
 function nogroupby_if($depart, $arrivee, $col) {
245
-	if (empty($arrivee['key']['PRIMARY KEY'])
246
-	  or !($pk = $arrivee['key']['PRIMARY KEY'])
247
-	  or empty($depart['key']['PRIMARY KEY'])) {
248
-		return false;
249
-	}
250
-	$id_primary = $depart['key']['PRIMARY KEY'];
251
-	if (is_array($col)) {
252
-		$col = implode(', *', $col);
253
-	} // cas id_objet, objet
254
-	return (preg_match("/^$id_primary, *$col$/", $pk) or
255
-		preg_match("/^$col, *$id_primary$/", $pk));
245
+    if (empty($arrivee['key']['PRIMARY KEY'])
246
+      or !($pk = $arrivee['key']['PRIMARY KEY'])
247
+      or empty($depart['key']['PRIMARY KEY'])) {
248
+        return false;
249
+    }
250
+    $id_primary = $depart['key']['PRIMARY KEY'];
251
+    if (is_array($col)) {
252
+        $col = implode(', *', $col);
253
+    } // cas id_objet, objet
254
+    return (preg_match("/^$id_primary, *$col$/", $pk) or
255
+        preg_match("/^$col, *$id_primary$/", $pk));
256 256
 }
257 257
 
258 258
 /**
@@ -270,46 +270,46 @@  discard block
 block discarded – undo
270 270
  */
271 271
 function liste_champs_jointures($nom, $desc, $primary = false) {
272 272
 
273
-	static $nojoin = ['idx', 'maj', 'date', 'statut'];
273
+    static $nojoin = ['idx', 'maj', 'date', 'statut'];
274 274
 
275
-	// si cle primaire demandee, la privilegier
276
-	if ($primary && isset($desc['key']['PRIMARY KEY'])) {
277
-		return split_key($desc['key']['PRIMARY KEY']);
278
-	}
275
+    // si cle primaire demandee, la privilegier
276
+    if ($primary && isset($desc['key']['PRIMARY KEY'])) {
277
+        return split_key($desc['key']['PRIMARY KEY']);
278
+    }
279 279
 
280
-	// les champs declares explicitement pour les jointures
281
-	if (isset($desc['join'])) {
282
-		return $desc['join'];
283
-	}
284
-	/*elseif (isset($GLOBALS['tables_principales'][$nom]['join'])) return $GLOBALS['tables_principales'][$nom]['join'];
280
+    // les champs declares explicitement pour les jointures
281
+    if (isset($desc['join'])) {
282
+        return $desc['join'];
283
+    }
284
+    /*elseif (isset($GLOBALS['tables_principales'][$nom]['join'])) return $GLOBALS['tables_principales'][$nom]['join'];
285 285
 	elseif (isset($GLOBALS['tables_auxiliaires'][$nom]['join'])) return $GLOBALS['tables_auxiliaires'][$nom]['join'];*/
286 286
 
287
-	// si pas de cle, c'est fichu
288
-	if (!isset($desc['key'])) {
289
-		return [];
290
-	}
291
-
292
-	// si cle primaire
293
-	if (isset($desc['key']['PRIMARY KEY'])) {
294
-		return split_key($desc['key']['PRIMARY KEY']);
295
-	}
296
-
297
-	// ici on se rabat sur les cles secondaires,
298
-	// en eliminant celles qui sont pas pertinentes (idx, maj)
299
-	// si jamais le resultat n'est pas pertinent pour une table donnee,
300
-	// il faut declarer explicitement le champ 'join' de sa description
301
-
302
-	$join = [];
303
-	foreach ($desc['key'] as $v) {
304
-		$join = split_key($v, $join);
305
-	}
306
-	foreach ($join as $k) {
307
-		if (in_array($k, $nojoin)) {
308
-			unset($join[$k]);
309
-		}
310
-	}
311
-
312
-	return $join;
287
+    // si pas de cle, c'est fichu
288
+    if (!isset($desc['key'])) {
289
+        return [];
290
+    }
291
+
292
+    // si cle primaire
293
+    if (isset($desc['key']['PRIMARY KEY'])) {
294
+        return split_key($desc['key']['PRIMARY KEY']);
295
+    }
296
+
297
+    // ici on se rabat sur les cles secondaires,
298
+    // en eliminant celles qui sont pas pertinentes (idx, maj)
299
+    // si jamais le resultat n'est pas pertinent pour une table donnee,
300
+    // il faut declarer explicitement le champ 'join' de sa description
301
+
302
+    $join = [];
303
+    foreach ($desc['key'] as $v) {
304
+        $join = split_key($v, $join);
305
+    }
306
+    foreach ($join as $k) {
307
+        if (in_array($k, $nojoin)) {
308
+            unset($join[$k]);
309
+        }
310
+    }
311
+
312
+    return $join;
313 313
 }
314 314
 
315 315
 /**
@@ -320,14 +320,14 @@  discard block
 block discarded – undo
320 320
  * @return array
321 321
  */
322 322
 function split_key($v, $join = []) {
323
-	foreach (preg_split('/,\s*/', $v) as $k) {
324
-		if (strpos($k, '(') !== false) {
325
-			$k = explode('(', $k);
326
-			$k = trim(reset($k));
327
-		}
328
-		$join[$k] = $k;
329
-	}
330
-	return $join;
323
+    foreach (preg_split('/,\s*/', $v) as $k) {
324
+        if (strpos($k, '(') !== false) {
325
+            $k = explode('(', $k);
326
+            $k = trim(reset($k));
327
+        }
328
+        $join[$k] = $k;
329
+    }
330
+    return $join;
331 331
 }
332 332
 
333 333
 /**
@@ -350,135 +350,135 @@  discard block
 block discarded – undo
350 350
  * @return array
351 351
  */
352 352
 function calculer_chaine_jointures(
353
-	&$boucle,
354
-	$depart,
355
-	$arrivee,
356
-	$vu = [],
357
-	$milieu_exclus = [],
358
-	$max_liens = 5
353
+    &$boucle,
354
+    $depart,
355
+    $arrivee,
356
+    $vu = [],
357
+    $milieu_exclus = [],
358
+    $max_liens = 5
359 359
 ) {
360
-	static $trouver_table;
361
-	if (!$trouver_table) {
362
-		$trouver_table = charger_fonction('trouver_table', 'base');
363
-	}
364
-
365
-	if (is_string($milieu_exclus)) {
366
-		$milieu_exclus = [$milieu_exclus];
367
-	}
368
-	// quand on a exclus id_objet comme cle de jointure, il faut aussi exclure objet
369
-	// faire une jointure sur objet tout seul n'a pas de sens
370
-	if (in_array('id_objet', $milieu_exclus) and !in_array('objet', $milieu_exclus)) {
371
-		$milieu_exclus[] = 'objet';
372
-	}
373
-
374
-	list($dnom, $ddesc) = $depart;
375
-	list($anom, $adesc) = $arrivee;
376
-	if (!count($vu)) {
377
-		$vu[] = $dnom; // ne pas oublier la table de depart
378
-		$vu[] = $anom; // ne pas oublier la table d'arrivee
379
-	}
380
-
381
-	$akeys = [];
382
-	foreach ($adesc['key'] as $k) {
383
-		// respecter l'ordre de $adesc['key'] pour ne pas avoir id_trad en premier entre autres...
384
-		$akeys = array_merge($akeys, preg_split('/,\s*/', $k));
385
-	}
386
-
387
-	// enlever les cles d'arrivee exclues par l'appel
388
-	$akeys = array_diff($akeys, $milieu_exclus);
389
-
390
-	// cles candidates au depart
391
-	$keys = liste_champs_jointures($dnom, $ddesc);
392
-	// enlever les cles dde depart exclues par l'appel
393
-	$keys = array_diff($keys, $milieu_exclus);
394
-
395
-	$v = !$keys ? false : array_intersect(array_values($keys), $akeys);
396
-
397
-	if ($v) {
398
-		return [[$dnom, [$adesc['table'], $adesc], array_shift($v)]];
399
-	}
400
-
401
-	// regarder si l'on a (id_objet,objet) au depart et si on peut le mapper sur un id_xx
402
-	if (count(array_intersect(['id_objet', 'objet'], $keys)) == 2) {
403
-		// regarder si l'une des cles d'arrivee peut se decomposer en
404
-		// id_objet,objet
405
-		// si oui on la prend
406
-		foreach ($akeys as $key) {
407
-			$v = decompose_champ_id_objet($key);
408
-			if (is_array($v)) {
409
-				$objet = array_shift($v); // objet,'article'
410
-				array_unshift($v, $key); // id_article,objet,'article'
411
-				array_unshift($v, $objet); // id_objet,id_article,objet,'article'
412
-				return [[$dnom, [$adesc['table'], $adesc], $v]];
413
-			}
414
-		}
415
-	} else {
416
-		// regarder si l'une des cles de depart peut se decomposer en
417
-		// id_objet,objet a l'arrivee
418
-		// si oui on la prend
419
-		foreach ($keys as $key) {
420
-			if (count($v = trouver_champs_decomposes($key, $adesc)) > 1) {
421
-				if (count($v) == count(array_intersect($v, $akeys))) {
422
-					$v = decompose_champ_id_objet($key); // id_objet,objet,'article'
423
-					array_unshift($v, $key); // id_article,id_objet,objet,'article'
424
-					return [[$dnom, [$adesc['table'], $adesc], $v]];
425
-				}
426
-			}
427
-		}
428
-	}
429
-	// si l'on voulait une jointure direct, c'est rate !
430
-	if ($max_liens <= 1) {
431
-		return [];
432
-	}
433
-
434
-	// sinon essayer de passer par une autre table
435
-	$new = $vu;
436
-	foreach ($boucle->jointures as $v) {
437
-		if (
438
-			$v
439
-			and !in_array($v, $vu)
440
-			and $def = $trouver_table($v, $boucle->sql_serveur)
441
-			and !in_array($def['table_sql'], $vu)
442
-		) {
443
-			// ne pas tester les cles qui sont exclues a l'appel
444
-			// ie la cle de la jointure precedente
445
-			$test_cles = $milieu_exclus;
446
-			$new[] = $v;
447
-			$max_iter = 50; // securite
448
-			while (
449
-				count($jointure_directe_possible = calculer_chaine_jointures(
450
-					$boucle,
451
-					$depart,
452
-					[$v, $def],
453
-					$vu,
454
-					$test_cles,
455
-					1
456
-				))
457
-				and $max_iter--
458
-			) {
459
-				$jointure_directe_possible = reset($jointure_directe_possible);
460
-				$milieu = end($jointure_directe_possible);
461
-				$exclure_fin = $milieu_exclus;
462
-				if (is_string($milieu)) {
463
-					$exclure_fin[] = $milieu;
464
-					$test_cles[] = $milieu;
465
-				} else {
466
-					$exclure_fin = array_merge($exclure_fin, $milieu);
467
-					$test_cles = array_merge($test_cles, $milieu);
468
-				}
469
-				// essayer de rejoindre l'arrivee a partir de cette etape intermediaire
470
-				// sans repasser par la meme cle milieu, ni une cle deja vue !
471
-				$r = calculer_chaine_jointures($boucle, [$v, $def], $arrivee, $new, $exclure_fin, $max_liens - 1);
472
-				if ($r) {
473
-					array_unshift($r, $jointure_directe_possible);
474
-
475
-					return $r;
476
-				}
477
-			}
478
-		}
479
-	}
480
-
481
-	return [];
360
+    static $trouver_table;
361
+    if (!$trouver_table) {
362
+        $trouver_table = charger_fonction('trouver_table', 'base');
363
+    }
364
+
365
+    if (is_string($milieu_exclus)) {
366
+        $milieu_exclus = [$milieu_exclus];
367
+    }
368
+    // quand on a exclus id_objet comme cle de jointure, il faut aussi exclure objet
369
+    // faire une jointure sur objet tout seul n'a pas de sens
370
+    if (in_array('id_objet', $milieu_exclus) and !in_array('objet', $milieu_exclus)) {
371
+        $milieu_exclus[] = 'objet';
372
+    }
373
+
374
+    list($dnom, $ddesc) = $depart;
375
+    list($anom, $adesc) = $arrivee;
376
+    if (!count($vu)) {
377
+        $vu[] = $dnom; // ne pas oublier la table de depart
378
+        $vu[] = $anom; // ne pas oublier la table d'arrivee
379
+    }
380
+
381
+    $akeys = [];
382
+    foreach ($adesc['key'] as $k) {
383
+        // respecter l'ordre de $adesc['key'] pour ne pas avoir id_trad en premier entre autres...
384
+        $akeys = array_merge($akeys, preg_split('/,\s*/', $k));
385
+    }
386
+
387
+    // enlever les cles d'arrivee exclues par l'appel
388
+    $akeys = array_diff($akeys, $milieu_exclus);
389
+
390
+    // cles candidates au depart
391
+    $keys = liste_champs_jointures($dnom, $ddesc);
392
+    // enlever les cles dde depart exclues par l'appel
393
+    $keys = array_diff($keys, $milieu_exclus);
394
+
395
+    $v = !$keys ? false : array_intersect(array_values($keys), $akeys);
396
+
397
+    if ($v) {
398
+        return [[$dnom, [$adesc['table'], $adesc], array_shift($v)]];
399
+    }
400
+
401
+    // regarder si l'on a (id_objet,objet) au depart et si on peut le mapper sur un id_xx
402
+    if (count(array_intersect(['id_objet', 'objet'], $keys)) == 2) {
403
+        // regarder si l'une des cles d'arrivee peut se decomposer en
404
+        // id_objet,objet
405
+        // si oui on la prend
406
+        foreach ($akeys as $key) {
407
+            $v = decompose_champ_id_objet($key);
408
+            if (is_array($v)) {
409
+                $objet = array_shift($v); // objet,'article'
410
+                array_unshift($v, $key); // id_article,objet,'article'
411
+                array_unshift($v, $objet); // id_objet,id_article,objet,'article'
412
+                return [[$dnom, [$adesc['table'], $adesc], $v]];
413
+            }
414
+        }
415
+    } else {
416
+        // regarder si l'une des cles de depart peut se decomposer en
417
+        // id_objet,objet a l'arrivee
418
+        // si oui on la prend
419
+        foreach ($keys as $key) {
420
+            if (count($v = trouver_champs_decomposes($key, $adesc)) > 1) {
421
+                if (count($v) == count(array_intersect($v, $akeys))) {
422
+                    $v = decompose_champ_id_objet($key); // id_objet,objet,'article'
423
+                    array_unshift($v, $key); // id_article,id_objet,objet,'article'
424
+                    return [[$dnom, [$adesc['table'], $adesc], $v]];
425
+                }
426
+            }
427
+        }
428
+    }
429
+    // si l'on voulait une jointure direct, c'est rate !
430
+    if ($max_liens <= 1) {
431
+        return [];
432
+    }
433
+
434
+    // sinon essayer de passer par une autre table
435
+    $new = $vu;
436
+    foreach ($boucle->jointures as $v) {
437
+        if (
438
+            $v
439
+            and !in_array($v, $vu)
440
+            and $def = $trouver_table($v, $boucle->sql_serveur)
441
+            and !in_array($def['table_sql'], $vu)
442
+        ) {
443
+            // ne pas tester les cles qui sont exclues a l'appel
444
+            // ie la cle de la jointure precedente
445
+            $test_cles = $milieu_exclus;
446
+            $new[] = $v;
447
+            $max_iter = 50; // securite
448
+            while (
449
+                count($jointure_directe_possible = calculer_chaine_jointures(
450
+                    $boucle,
451
+                    $depart,
452
+                    [$v, $def],
453
+                    $vu,
454
+                    $test_cles,
455
+                    1
456
+                ))
457
+                and $max_iter--
458
+            ) {
459
+                $jointure_directe_possible = reset($jointure_directe_possible);
460
+                $milieu = end($jointure_directe_possible);
461
+                $exclure_fin = $milieu_exclus;
462
+                if (is_string($milieu)) {
463
+                    $exclure_fin[] = $milieu;
464
+                    $test_cles[] = $milieu;
465
+                } else {
466
+                    $exclure_fin = array_merge($exclure_fin, $milieu);
467
+                    $test_cles = array_merge($test_cles, $milieu);
468
+                }
469
+                // essayer de rejoindre l'arrivee a partir de cette etape intermediaire
470
+                // sans repasser par la meme cle milieu, ni une cle deja vue !
471
+                $r = calculer_chaine_jointures($boucle, [$v, $def], $arrivee, $new, $exclure_fin, $max_liens - 1);
472
+                if ($r) {
473
+                    array_unshift($r, $jointure_directe_possible);
474
+
475
+                    return $r;
476
+                }
477
+            }
478
+        }
479
+    }
480
+
481
+    return [];
482 482
 }
483 483
 
484 484
 /**
@@ -489,18 +489,18 @@  discard block
 block discarded – undo
489 489
  * @return array
490 490
  */
491 491
 function trouver_cles_table($keys) {
492
-	$res = [];
493
-	foreach ($keys as $v) {
494
-		if (!strpos($v, ',')) {
495
-			$res[$v] = 1;
496
-		} else {
497
-			foreach (preg_split('/\s*,\s*/', $v) as $k) {
498
-				$res[$k] = 1;
499
-			}
500
-		}
501
-	}
502
-
503
-	return array_keys($res);
492
+    $res = [];
493
+    foreach ($keys as $v) {
494
+        if (!strpos($v, ',')) {
495
+            $res[$v] = 1;
496
+        } else {
497
+            foreach (preg_split('/\s*,\s*/', $v) as $k) {
498
+                $res[$k] = 1;
499
+            }
500
+        }
501
+    }
502
+
503
+    return array_keys($res);
504 504
 }
505 505
 
506 506
 
@@ -527,34 +527,34 @@  discard block
 block discarded – undo
527 527
  *     - 'alias' : alias utilisé pour la table (si pertinent. ie: avec `$boucle->from` transmis par exemple)
528 528
  */
529 529
 function chercher_champ_dans_tables($cle, $tables, $connect, $checkarrivee = false) {
530
-	static $trouver_table = '';
531
-	if (!$trouver_table) {
532
-		$trouver_table = charger_fonction('trouver_table', 'base');
533
-	}
534
-
535
-	if (!is_array($cle)) {
536
-		$cle = [$cle];
537
-	}
538
-
539
-	foreach ($tables as $k => $table) {
540
-		if ($table && $desc = $trouver_table($table, $connect)) {
541
-			if (
542
-				isset($desc['field'])
543
-				// verifier que toutes les cles cherchees sont la
544
-				and (count(array_intersect($cle, array_keys($desc['field']))) == count($cle))
545
-				// si on sait ou on veut arriver, il faut que ca colle
546
-				and ($checkarrivee == false || $checkarrivee == $desc['table'])
547
-			) {
548
-				return [
549
-					'desc' => $desc,
550
-					'table' => $desc['table'],
551
-					'alias' => $k,
552
-				];
553
-			}
554
-		}
555
-	}
556
-
557
-	return false;
530
+    static $trouver_table = '';
531
+    if (!$trouver_table) {
532
+        $trouver_table = charger_fonction('trouver_table', 'base');
533
+    }
534
+
535
+    if (!is_array($cle)) {
536
+        $cle = [$cle];
537
+    }
538
+
539
+    foreach ($tables as $k => $table) {
540
+        if ($table && $desc = $trouver_table($table, $connect)) {
541
+            if (
542
+                isset($desc['field'])
543
+                // verifier que toutes les cles cherchees sont la
544
+                and (count(array_intersect($cle, array_keys($desc['field']))) == count($cle))
545
+                // si on sait ou on veut arriver, il faut que ca colle
546
+                and ($checkarrivee == false || $checkarrivee == $desc['table'])
547
+            ) {
548
+                return [
549
+                    'desc' => $desc,
550
+                    'table' => $desc['table'],
551
+                    'alias' => $k,
552
+                ];
553
+            }
554
+        }
555
+    }
556
+
557
+    return false;
558 558
 }
559 559
 
560 560
 /**
@@ -580,52 +580,52 @@  discard block
 block discarded – undo
580 580
  */
581 581
 function trouver_champ_exterieur($cle, $joints, &$boucle, $checkarrivee = false) {
582 582
 
583
-	// support de la recherche multi champ :
584
-	// si en seconde etape on a decompose le champ id_xx en id_objet,objet
585
-	// on reentre ici soit en cherchant une table les 2 champs id_objet,objet
586
-	// soit une table avec les 3 champs id_xx, id_objet, objet
587
-	if (!is_array($cle)) {
588
-		$cle = [$cle];
589
-	}
590
-
591
-	if ($infos = chercher_champ_dans_tables($cle, $joints, $boucle->sql_serveur, $checkarrivee)) {
592
-		return [$infos['table'], $infos['desc'], $cle];
593
-	}
594
-
595
-	// au premier coup, on essaye de decomposer, si possible
596
-	if (
597
-		count($cle) == 1
598
-		and $c = reset($cle)
599
-		and is_array($decompose = decompose_champ_id_objet($c))
600
-	) {
601
-		$desc = $boucle->show;
602
-
603
-		// cas 1 : la cle id_xx est dans la table de depart
604
-		// -> on cherche uniquement id_objet,objet a l'arrivee
605
-		if (isset($desc['field'][$c])) {
606
-			$cle = [];
607
-			$cle[] = array_shift($decompose); // id_objet
608
-			$cle[] = array_shift($decompose); // objet
609
-			return trouver_champ_exterieur($cle, $joints, $boucle, $checkarrivee);
610
-		}
611
-		// cas 2 : la cle id_xx n'est pas dans la table de depart
612
-		// -> il faut trouver une cle de depart zzz telle que
613
-		// id_objet,objet,zzz soit a l'arrivee
614
-		else {
615
-			$depart = liste_champs_jointures((isset($desc['table']) ? $desc['table'] : ''), $desc);
616
-			foreach ($depart as $d) {
617
-				$cle = [];
618
-				$cle[] = array_shift($decompose); // id_objet
619
-				$cle[] = array_shift($decompose); // objet
620
-				$cle[] = $d;
621
-				if ($ext = trouver_champ_exterieur($cle, $joints, $boucle, $checkarrivee)) {
622
-					return $ext;
623
-				}
624
-			}
625
-		}
626
-	}
627
-
628
-	return '';
583
+    // support de la recherche multi champ :
584
+    // si en seconde etape on a decompose le champ id_xx en id_objet,objet
585
+    // on reentre ici soit en cherchant une table les 2 champs id_objet,objet
586
+    // soit une table avec les 3 champs id_xx, id_objet, objet
587
+    if (!is_array($cle)) {
588
+        $cle = [$cle];
589
+    }
590
+
591
+    if ($infos = chercher_champ_dans_tables($cle, $joints, $boucle->sql_serveur, $checkarrivee)) {
592
+        return [$infos['table'], $infos['desc'], $cle];
593
+    }
594
+
595
+    // au premier coup, on essaye de decomposer, si possible
596
+    if (
597
+        count($cle) == 1
598
+        and $c = reset($cle)
599
+        and is_array($decompose = decompose_champ_id_objet($c))
600
+    ) {
601
+        $desc = $boucle->show;
602
+
603
+        // cas 1 : la cle id_xx est dans la table de depart
604
+        // -> on cherche uniquement id_objet,objet a l'arrivee
605
+        if (isset($desc['field'][$c])) {
606
+            $cle = [];
607
+            $cle[] = array_shift($decompose); // id_objet
608
+            $cle[] = array_shift($decompose); // objet
609
+            return trouver_champ_exterieur($cle, $joints, $boucle, $checkarrivee);
610
+        }
611
+        // cas 2 : la cle id_xx n'est pas dans la table de depart
612
+        // -> il faut trouver une cle de depart zzz telle que
613
+        // id_objet,objet,zzz soit a l'arrivee
614
+        else {
615
+            $depart = liste_champs_jointures((isset($desc['table']) ? $desc['table'] : ''), $desc);
616
+            foreach ($depart as $d) {
617
+                $cle = [];
618
+                $cle[] = array_shift($decompose); // id_objet
619
+                $cle[] = array_shift($decompose); // objet
620
+                $cle[] = $d;
621
+                if ($ext = trouver_champ_exterieur($cle, $joints, $boucle, $checkarrivee)) {
622
+                    return $ext;
623
+                }
624
+            }
625
+        }
626
+    }
627
+
628
+    return '';
629 629
 }
630 630
 
631 631
 /**
@@ -657,21 +657,21 @@  discard block
 block discarded – undo
657 657
  * @return string
658 658
  */
659 659
 function trouver_jointure_champ($champ, &$boucle, $jointures = false, $cond = false, $checkarrivee = false) {
660
-	if ($jointures === false) {
661
-		$jointures = $boucle->jointures;
662
-	}
663
-	// TODO : aberration, on utilise $jointures pour trouver le champ
664
-	// mais pas poour construire la jointure ensuite
665
-	$arrivee = trouver_champ_exterieur($champ, $jointures, $boucle, $checkarrivee);
666
-	if ($arrivee) {
667
-		$desc = $boucle->show;
668
-		array_pop($arrivee); // enlever la cle en 3eme argument
669
-		$cle = calculer_jointure($boucle, [$desc['id_table'], $desc], $arrivee, '', $cond);
670
-		if ($cle) {
671
-			return $cle;
672
-		}
673
-	}
674
-	spip_log("trouver_jointure_champ: $champ inconnu");
675
-
676
-	return '';
660
+    if ($jointures === false) {
661
+        $jointures = $boucle->jointures;
662
+    }
663
+    // TODO : aberration, on utilise $jointures pour trouver le champ
664
+    // mais pas poour construire la jointure ensuite
665
+    $arrivee = trouver_champ_exterieur($champ, $jointures, $boucle, $checkarrivee);
666
+    if ($arrivee) {
667
+        $desc = $boucle->show;
668
+        array_pop($arrivee); // enlever la cle en 3eme argument
669
+        $cle = calculer_jointure($boucle, [$desc['id_table'], $desc], $arrivee, '', $cond);
670
+        if ($cle) {
671
+            return $cle;
672
+        }
673
+    }
674
+    spip_log("trouver_jointure_champ: $champ inconnu");
675
+
676
+    return '';
677 677
 }
Please login to merge, or discard this patch.