Example #1
0
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();
}
Example #2
0
/**
 * 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 "";
}