function calculer_chaine_jointures(&$boucle, $depart, $arrivee, $vu=array(), $milieu_exclus = array(), $max_liens = 5) { static $trouver_table; if (!$trouver_table) $trouver_table = charger_fonction('trouver_table', 'base'); if (is_string($milieu_exclus)) $milieu_exclus = array($milieu_exclus); list($dnom,$ddesc) = $depart; list($anom,$adesc) = $arrivee; if (!count($vu)) $vu[] = $dnom; // ne pas oublier la table de depart $akeys = $adesc['key']; if ($v = $akeys['PRIMARY KEY']) { unset($akeys['PRIMARY KEY']); $akeys = array_merge(preg_split('/,\s*/', $v), $akeys); } // enlever les cles d'arrivee exclues par l'appel $akeys = array_diff($akeys,$milieu_exclus); // cles candidates au depart $keys = liste_champs_jointures($dnom,$ddesc); // enlever les cles dde depart exclues par l'appel $keys = array_diff($keys,$milieu_exclus); $v = !$keys ? false : array_intersect(array_values($keys), $akeys); if ($v) return array(array($dnom, array($adesc['table'],$adesc), array_shift($v))); // regarder si l'on a (id_objet,objet) au depart et si on peut le mapper sur un id_xx if (count(array_intersect(array('id_objet','objet'),$keys))==2){ // regarder si l'une des cles d'arrivee peut se decomposer en // id_objet,objet // si oui on la prend foreach($akeys as $key){ $v = decompose_champ_id_objet($key); if (is_array($v)){ $objet = array_shift($v);// objet,'article' array_unshift($v,$key); // id_article,objet,'article' array_unshift($v,$objet); // id_objet,id_article,objet,'article' return array(array($dnom, array($adesc['table'],$adesc), $v)); } } } else { // regarder si l'une des cles de depart peut se decomposer en // id_objet,objet a l'arrivee // si oui on la prend foreach($keys as $key){ if (count($v = trouver_champs_decomposes($key,$adesc))>1){ if (count($v)==count(array_intersect($v, $akeys))) $v = decompose_champ_id_objet($key); // id_objet,objet,'article' array_unshift($v,$key); // id_article,id_objet,objet,'article' return array(array($dnom, array($adesc['table'],$adesc), $v)); } } } // si l'on voulait une jointure direct, c'est rate ! if ($max_liens<=1) return array(); // sinon essayer de passer par une autre table $new = $vu; foreach($boucle->jointures as $v) { if ($v && (!in_array($v,$vu)) && ($def = $trouver_table($v, $boucle->sql_serveur))) { // ne pas tester les cles qui sont exclues a l'appel // ie la cle de la jointure precedente $test_cles = $milieu_exclus; $new[] = $v; $max_iter = 50; // securite while (count($jointure_directe_possible = calculer_chaine_jointures($boucle,$depart,array($v, $def),$vu,$test_cles,1)) AND $max_iter--) { $jointure_directe_possible = reset($jointure_directe_possible); $milieu = end($jointure_directe_possible); if (is_string($milieu)) $test_cles[] = $milieu; else $test_cles = array_merge($test_cles,$milieu); // essayer de rejoindre l'arrivee a partir de cette etape intermediaire // sans repasser par la meme cle milieu $r = calculer_chaine_jointures($boucle, array($v, $def), $arrivee, $new, $milieu,$max_liens-1); if ($r) { array_unshift($r, $jointure_directe_possible); return $r; } } } } return array(); }
/** * Cherche une colonne (ou plusieurs colonnes) dans les tables de jointures * possibles indiquées. * * @param string|array $cle * Nom de la ou des colonnes à trouver dans les tables de jointures * @param array $joints * Liste des jointures possibles (ex: $boucle->jointures ou $boucle->jointures_explicites) * @param Boucle $boucle * Description de la boucle * @param bool|string $checkarrivee * false : peu importe la table, si on trouve le/les champs, c'est bon. * string : nom de la table jointe où on veut trouver le champ. * @return array|string * chaîne vide : on n'a pas trouvé * liste si trouvé : nom de la table, description de la table */ function trouver_champ_exterieur($cle, $joints, &$boucle, $checkarrivee = false) { static $trouver_table = ''; if (!$trouver_table) { $trouver_table = charger_fonction('trouver_table', 'base'); } // support de la recherche multi champ : // si en seconde etape on a decompose le champ id_xx en id_objet,objet // on reentre ici soit en cherchant une table les 2 champs id_objet,objet // soit une table avec les 3 champs id_xx, id_objet, objet if (!is_array($cle)) { $cle = array($cle); } foreach ($joints as $k => $join) { if ($join && ($table = $trouver_table($join, $boucle->sql_serveur))) { if (isset($table['field']) and count(array_intersect($cle, array_keys($table['field']))) == count($cle) and $checkarrivee == false || $checkarrivee == $table['table']) { return array($table['table'], $table); } } } // au premier coup, on essaye de decomposer, si possible if (count($cle) == 1 and $c = reset($cle) and is_array($decompose = decompose_champ_id_objet($c))) { $desc = $boucle->show; // cas 1 : la cle id_xx est dans la table de depart // -> on cherche uniquement id_objet,objet a l'arrivee if (isset($desc['field'][$c])) { $cle = array(); $cle[] = array_shift($decompose); // id_objet $cle[] = array_shift($decompose); // objet return trouver_champ_exterieur($cle, $joints, $boucle, $checkarrivee); } else { $depart = liste_champs_jointures($desc['table'], $desc); foreach ($depart as $d) { $cle = array(); $cle[] = array_shift($decompose); // id_objet $cle[] = array_shift($decompose); // objet $cle[] = $d; if ($ext = trouver_champ_exterieur($cle, $joints, $boucle, $checkarrivee)) { return $ext; } } } } return ""; }