IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Créer un arbre généalogique descendant


Sujet :

Langage PHP

  1. #1
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 615
    Points : 823
    Points
    823
    Par défaut Créer un arbre généalogique descendant
    Bonjour à tous,

    D'habitude, on crée des arbres généalogiques ascendant. Ici je voudrais créer un arbre généalogique descendant qui ressemblerait à une structure de répertoire. Je n'arrive pas à créer la bonne boucle qui me permettrait d'itérer la recherche.
    J'arrive à créer le premier niveau, c'est à dire les enfants de la personne racine.
    Je ne sais pas si c'est la bonne méthode, mais mon idée serait de créer un tableau de ce type:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    racine=>[
    	Niv1Enf1=>[
    		Niv2Enf1=>[
    			Niv3Enf1,
    			Niv3Enf2,
    			Niv3Enf3
    		],
    		Niv2Enf2
    	],
    	Niv1Enf2
    	Niv1Enf3=>[
    		Niv2Enf3
    	]
    ]
    J'ai commencé le code suivant et je n'arrive pas à aller plus loin:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    <?php
     
    function getPerson($id)
    {
    	global $db;
     
    	$dateFormat = LOCAL_DATE_FORMAT;
    	$query = "
    		SELECT id,
    			CONCAT(COALESCE(first_name, ''), ' ', COALESCE(last_name, '')) AS full_name,
    			CONCAT(
    				COALESCE(DATE_FORMAT(birth_date, '%d/%m/%Y'), ''),
    				' - ',
    				COALESCE(DATE_FORMAT(death_date, '%d/%m/%Y'), '')
    			) AS live_dates
    		FROM dat_persons
    		WHERE id=:id
    		LIMIT 1
    	;";
    	$result = $db->prepare($query);
    	$result->bindParam('id', $id);
    	$result->execute();
    	return $result->fetch();
    }
     
    function getChildren($id)
    {
    	global $db;
     
    	$dateFormat = LOCAL_DATE_FORMAT;
    	$query = "
    		SELECT id
    		FROM dat_persons
    		WHERE father_id=:id XOR mother_id=:id
    		ORDER BY birth_date, birth_order
    	;";
    	$result = $db->prepare($query);
    	$result->bindParam('id', $id);
    	$result->execute();
    	return $result->fetchAll(PDO::FETCH_ASSOC);
    }
     
     
    if ( ! $idMain = (int) $_GET['idMain']) {
    	header('location: '.DEFAULT_PAGE);
    	exit;
    }
     
    $newIds = [];
    $ids = getChildren($idMain);
    $ids = array_column($ids, 'id');
    foreach ($ids as $id)
    {
    	$children[] = getPerson($id);
    	$newIds[] = $id;
    }
    var_dump($children);
    var_dump($newIds);

  2. #2
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    edit : j'ai testé ceci avec une table qui a une arborescence...
    Une fonction récursive.
    Chez moi, le XOR me vire les mamans solos ou les papas solos...
    Et puis bon, je parle de parent1 et parent2 parce qu'il y a des parents du même sexe... La loi a changé, donc les bases doivent suivre...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    function fetch_liste_enfant(PDO $db,$parent_id=0,$array=''){
      if(!is_array($array)){
        $array = array();
      }
      $sql = "
      SELECT count( distinct enfant.id) as nb
      FROM filia__individu enfant
      WHERE enfant.parent_1=$parent_id OR enfant.parent_2=$parent_id";
      $stmt = $db->prepare($sql);
      $stmt->execute();
      $how_much= $stmt->fetch(PDO::FETCH_ASSOC);
      if($how_much['nb']>0){
        $sql = "
        SELECT enfant.id,enfant.nom_naissance as nom,enfant.prenom,DATE_FORMAT(enfant.naissance, '%d/%m/%Y') as naissance_fr,ifnull(DATE_FORMAT(enfant.deces, '%d/%m/%Y'), NULL) AS deces_fr
        FROM filia__individu enfant
        WHERE enfant.parent_1=$parent_id OR enfant.parent_2=$parent_id
        ORDER BY enfant.naissance";
        $stmt = $db->prepare($sql);
        $stmt->execute();
        $array[] = "<ol>\n";
        while($row= $stmt->fetch(PDO::FETCH_ASSOC)){
          $array[] = "<li>". $row['nom']." ".$row['prenom']." ".$row['naissance_fr'].($row['deces_fr']==""?NULL:" - ".$row['deces_fr'])."</li>\n";
          $array = fetch_liste_enfant($db,$row['id'], $array);
        }
        $array[] = "</ol>\n";
      }
      return $array;
    }
    $params=array(
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_EMULATE_PREPARES => false
    );
    $pdo = new PDO('mysql:host=localhost;port=3306;dbname=entrepot;charset=utf8','root', '', $params);
    $liste_recursive=fetch_liste_enfant($pdo,1);
    $pdo=NULL;
    $ol='';
    foreach($liste_recursive as $liste_item){
      $ol.=$liste_item;
    }
    echo $ol;
    Et si tu n'étais pas en mysql, mais en postgreSQL ou en DB2, tu pourrais aussi faire directement une requête récursive.

  3. #3
    Membre émérite
    Avatar de badaze
    Homme Profil pro
    Chef de projets info
    Inscrit en
    Septembre 2002
    Messages
    1 412
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets info
    Secteur : Transports

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 412
    Points : 2 522
    Points
    2 522
    Par défaut
    Voici un exemple qui permet d'afficher une liste avec descendance. Le fichier sql en pièce jointe permet de tester le code.

    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    <?php
    $connexion = new mysqli("localhost","root","", "tests"); 
    function descendance($pere,&$string)
    {
     GLOBAL $connexion;
     $requete   = "select fils from table4 where pere = $pere order by pere, fils";
     $result    = mysqli_query($connexion,$requete);
     
     while (list($fils) = mysqli_fetch_array($result)) { 
      $string = $string."<li>".$fils."<ul>";
      descendance($fils,$string);
      $string = $string."</ul></li>";
     }
    }
    descendance(0,$string);
    print $string;

    Nom : Capture20180616_001.JPG
Affichages : 1363
Taille : 25,7 Ko
    Fichiers attachés Fichiers attachés

  4. #4
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 615
    Points : 823
    Points
    823
    Par défaut
    @Dendrite
    S'agissant de généalogie, ce sont les lois de la génétique et non celles de la république qui s'appliquent. A ma connaissance, il faut toujours un père et une mère pour concevoir un enfant.

    @badaze
    Je n'ai pas le temps ce matin, mais je vais tester.

  5. #5
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Je ne sais pas, je n'ai fait un arbre généalogique que pour ma fascination pour les arborescences hiérarchiques. Côté base, je voulais vérifier si sur une table je pouvais faire 2 auto-jointures en clé étrangère : sur le parent1 et sur le parent2... Réponse : oui, aucun problème...
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    DROP TABLE IF EXISTS `filia__individu`;
    CREATE TABLE IF NOT EXISTS `filia__individu` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `genre` enum('H','F','N') NOT NULL,
      `nom_naissance` varchar(100) NOT NULL,
      `nom_usage` varchar(100) DEFAULT NULL,
      `prenom` varchar(100) NOT NULL,
      `naissance` date NOT NULL,
      `deces` date DEFAULT NULL,
      `parent_1` int(11) DEFAULT NULL,
      `parent_2` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `unicite_1` (`nom_naissance`,`prenom`,`naissance`,`parent_1`),
      UNIQUE KEY `unicite` (`nom_naissance`,`prenom`,`naissance`,`parent_2`),
      KEY `genre` (`genre`),
      KEY `prenom` (`prenom`),
      KEY `deces` (`deces`),
      KEY `parent_1` (`parent_1`),
      KEY `parent_2` (`parent_2`),
      KEY `nom_naissance` (`nom_naissance`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8;
    ALTER TABLE `filia__individu`
      ADD CONSTRAINT `parent_1_FK` FOREIGN KEY (`parent_1`) REFERENCES `filia__individu` (`id`),
      ADD CONSTRAINT `parent_2_FK` FOREIGN KEY (`parent_2`) REFERENCES `filia__individu` (`id`);
    Du coup, pour les données, j'ai collé les infos de mon grand-père (décédé né en 1910) jusqu'à ses arrières arrières petits enfants puisque ma génération est grand-parent (dernier né en 2016) ! 5 générations convoquées, un intervalle de 4 générations sur 100 ans donc. Et j'ai réalisé que ça lui faisait une cinquantaine de descendants directs !

    1) tu ne tiens pas compte des enfants adoptés de façon plénière du coup ? Moi, j'ai eu plusieurs fois le cas dans ma famille, et j'ai fait le choix de les mettre.
    2) une autre problématique que j'ai du résoudre en "marchant" : signe des temps, beaucoup de familles recomposées, avec des demi-frères et des demi-soeurs.
    3) une dernière problématique que j'ai trouvée intéressante : j'ai mis l'âge quand la personne était encore vivante, et l'âge du décès quand la personne était décédée.

    Revenons à l'algo de la fonction que j'ai développée juste pour ce fil :
    J'ai commencé comme toi par me dire : il y a 2 cas, une requête pour faire remonter ses données si il ou elle n'a pas d'enfant, une requête pour faire remonter les données de ses enfants, s'il ou elle en a... Puis, j'ai compris que c'était inutile : car si l'on peut ne pas avoir d'enfants, on est toujours répertorié comme l'enfant de quelqu'un, du moins si l'on apparaît sur cette fonction en dehors du sommet hiérarchique...
    Sur la fonction que je t'ai proposée dans le message précédent, tu as juste le SQL à changer, et ça fonctionnera chez toi...

    @badaze : je vais étudier la question, ton algo est bien plus simple et plus ramassée que la mienne. Mais fait-elle la même chose ? Il semble que oui.

  6. #6
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 615
    Points : 823
    Points
    823
    Par défaut
    Citation Envoyé par Dendrite Voir le message
    1) tu ne tiens pas compte des enfants adoptés de façon plénière du coup ? Moi, j'ai eu plusieurs fois le cas dans ma famille, et j'ai fait le choix de les mettre.
    2) une autre problématique que j'ai du résoudre en "marchant" : signe des temps, beaucoup de familles recomposées, avec des demi-frères et des demi-soeurs.
    3) une dernière problématique que j'ai trouvée intéressante : j'ai mis l'âge quand la personne était encore vivante, et l'âge du décès quand la personne était décédée.
    Tes questions sont intéressantes mais je me concentre d'abord sur ce qui ne fonctionne pas avec la solution de @badaze.
    1) Fonctionne si on a un père et une mère. A réfléchir
    2) Fonctionne avec les familles recomposées.
    3) Je préfère travailler avec des dates, sachant que les dates inconnues compliquent les recherches avec une base de 4000 personnes.
    Edit:
    Je n'ai pas regardé ta solution, je la regarderai si je ne m'en sors pas avec celle de badaze.
    Je viens de regarder et ta solution fonctionne bien. Merci.

    @badaze
    J'ai testé ta solution. Elle fonctionne avec ton exemple où les données sont déjà hiérarchisées. Elle ne fonctionne plus avec des données aléatoires. Les id étant créés au fur et à mesure des saisies.
    Voici 3 versions avec leurs problèmes.
    La version 1 PDO provoque une erreur "Undefined offset: 0" à la ligne 14
    La version 2 fonctionne
    La version 3 fournit des données incomplètes (les données sont dans l'ordre des naissances):
    • 23
    • 21
    • 33 // Il manque les enfants (69 et 99)
    • 35
    • 36 // Il manque les enfants (66, 292, 1612)
    • 37 // Il manque les enfants (27, 55, 293)
    • 38
    • 39 // Il manque les enfants (94)
    • 40
    • 25 // Il manque les enfants (158, 159, 160)
    • 31 // Il manque les enfants (230, 231)
    • 32 // Il manque les enfants (184, 183, 181, 41)

  7. #7
    Membre émérite
    Avatar de badaze
    Homme Profil pro
    Chef de projets info
    Inscrit en
    Septembre 2002
    Messages
    1 412
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets info
    Secteur : Transports

    Informations forums :
    Inscription : Septembre 2002
    Messages : 1 412
    Points : 2 522
    Points
    2 522
    Par défaut
    Mon but était de montrer une technique. Les données étaient hiérarchisées pour faciliter le test. Il suffit de faire une requête qui sélectionne les pères qui ne sont pas des fils.

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    //---- Sélection des pères qui ne sont pas des fils
    $requete = "select distinct t1.pere from table4 t1 left join table4 t2 on t1.pere = t2.fils where t2.fils is null";
    $result    = mysqli_query($connexion,$requete);
    while (list($pere) = mysqli_fetch_array($result)) 
    { 
     $string = "";
     print "<li>$pere<ul>";
     descendance($pere,$string);
     print $string;
     print "</ul></li>";
    }

  8. #8
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Et moi, j'ai simplifié ma fonction récursive. Pas besoin de tableau PHP intermédiaire, on peut passer directement une liste en paramètre.
    Et surtout, pas besoin de double requête, une pour compter, une pour traiter les détails... Du 2 en 1...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function fetch_liste_enfant(PDO $db,$parent_id=0,$ol=''){
      $sql = "SELECT enfant.id,enfant.nom_naissance as nom,enfant.prenom,DATE_FORMAT(enfant.naissance, '%d/%m/%Y') as naissance_fr,ifnull(DATE_FORMAT(enfant.deces, '%d/%m/%Y'), NULL) AS deces_fr
      FROM filia__individu enfant
      WHERE enfant.parent_1=$parent_id OR enfant.parent_2=$parent_id
      ORDER BY enfant.naissance";
      $stmt = $db->query($sql);
      $data=$stmt->fetchAll();
      if(isset($data[0])){//si enfant(s) seulement
        $ol .= "<ol>\n";
        foreach($data as $row){
          $ol .= "<li>". $row['nom']." ".$row['prenom']." ".$row['naissance_fr'].($row['deces_fr']==""?NULL:" - ".$row['deces_fr'])."</li>\n";
          $ol = fetch_liste_enfant($db,$row['id'], $ol);
        }
        $ol .= "</ol>\n";
      }
      return $ol;
    }
    //utilisation
    $eldest_id=1;
    $params=array(
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_EMULATE_PREPARES => false
    );
    $pdo = new PDO('mysql:host=localhost;port=3306;dbname=entrepot;charset=utf8','root', '', $params);
    $liste_recursive=fetch_liste_enfant($pdo,$eldest_id);
    echo $liste_recursive;
    Et juste pour le fun, le code source avec l'indentation... Je voulais vérifier qu'il y avait 0 erreur HTML

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    function fetch_liste_enfant(PDO $db,$parent_id=0,$ol='',$tabul=-1){
      $sql = "SELECT enfant.id,enfant.nom_naissance as nom,enfant.prenom,DATE_FORMAT(enfant.naissance, '%d/%m/%Y') as naissance_fr,ifnull(DATE_FORMAT(enfant.deces, '%d/%m/%Y'), NULL) AS deces_fr
      FROM filia__individu enfant
      WHERE enfant.parent_1=$parent_id OR enfant.parent_2=$parent_id
      ORDER BY enfant.naissance";
      $stmt = $db->query($sql);
      $data=$stmt->fetchAll();
      if(isset($data[0])){//si enfant(s) seulement
        $tabul++;
        $indentation='';
        for($i=0;$i<$tabul;$i++){
          $indentation .="\t";
        }
        $ol .= $indentation."<ol>\n";
        $indentation_li =$indentation."\t";
        foreach($data as $row){
          $ol .= $indentation_li."<li>". $row['nom']." ".$row['prenom']." ".$row['naissance_fr'].($row['deces_fr']==""?NULL:" - ".$row['deces_fr'])."</li>\n";
          $ol = fetch_liste_enfant($db,$row['id'], $ol,$tabul);
        }
        $ol .= $indentation."</ol>\n";
      }
      return $ol;
    }
    //utilisation
    $eldest_id=1;
    $params=array(
      PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_EMULATE_PREPARES => false
    );
    $pdo = new PDO('mysql:host=localhost;port=3306;dbname=entrepot;charset=utf8','root', '', $params);
    $liste_recursive=fetch_liste_enfant($pdo,$eldest_id);
    echo $liste_recursive;

  9. #9
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Et un nouveau billet de blog, 1 !

    Filiation parentale et récursivité en MYSQL et PHP

  10. #10
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 615
    Points : 823
    Points
    823
    Par défaut
    @Dendrite: Voici quelques questions en vrac:
    Pourquoi ne pas mettre directement $ol='' au lieu de remplacer le -1 par ''?
    Pourquoi utilises-tu ISNULL plutôt que COALESCE?
    Pourquoi ne paramètres-tu pas $parent_id dans ta requête?
    Pourquoi appelle t-on souvent stmt la variable résultat d'une requête? J'ai cherché ce que ça signifie et je n'ai pas trouvé.

  11. #11
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Voici quelques réponses en vrac...

    Pourquoi ne pas mettre directement $ol='' au lieu de remplacer le -1 par ''?
    Parce que je suis fatiguée ... je corrige, merci.

    Pourquoi utilises-tu ISNULL plutôt que COALESCE?
    Parce que j'en ai pris l'habitude... bien que la syntaxe soit assez contre-intuitive (ifnull, "ce_que_je_veux_si_pas_nul","ce_que_je_veux_si_null") => une condition ternaire à l'envers... bizarre. coalesce est peut etre très bien, je le voyais souvent sur les syntaxes informix et apparemment, il adopte le même ordre dans les paramètres.

    Pourquoi ne paramètres-tu pas $parent_id dans ta requête?
    Que veux-tu dire ? requête préparée ? parce que ce sont des données issues de ma base, des id sécurisés par clé étrangère, ça ne risque pas d'être des injections SQL. Même, le premier : en aucun cas, je ne ferai saisir à la main par les gens l'id du patriarche ou de la matriarche. Ce sera un select html.

    Pourquoi appelle t-on souvent stmt la variable résultat d'une requête? J'ai cherché ce que ça signifie et je n'ai pas trouvé.
    stmt pour statement => instruction en français

  12. #12
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 615
    Points : 823
    Points
    823
    Par défaut
    Merci Dendrite pour tes réponses.

    En adaptant ton code en fonction de ma base et de mes habitudes de travail, j'ai introduit un bug au niveau de l'indentation. Elle se fait toujours vers la droite et ne revient jamais vers la gauche. La numérotation s'en trouve erronée. J'ai beau cherché, je ne trouve pas mon erreur. J'ai mis ton code en commentaire en changeant les noms de table et de colonnes, tel qu'il fonctionne.
    Voici mon code:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    <?php
     
    ##################################################################### SECTION TETE : PARAMETRAGE AUTORISATION ##########################################################
     
    require_once('libraries/defines.php');
     
    ##################################################################### Fin SECTION TETE : PARAMETRAGE AUTORISATION ######################################################
     
    ##################################################################### SECTION MODELE ###################################################################################
     
    connect();
     
    function getChildren($parentId) {
    	global $db;
     
    	$dateFormat = LOCAL_DATE_FORMAT;
    	$query = "
    		SELECT id, last_name, first_name, IFNULL(DATE_FORMAT(birth_date, '$dateFormat'), NULL) as birthdate, IFNULL(DATE_FORMAT(death_date, '$dateFormat'), NULL) AS deathdate
    		FROM dat_persons
    		WHERE father_id=:parentId OR mother_id=:parentId
    		ORDER BY birth_date
    	";
    	$result = $db->prepare($query);
    	$result->bindParam('parentId', $parentId);
    	$result->execute();
    	return $result->fetchAll();
    }
     
    ##################################################################### FIN section MODELE ###############################################################################
     
    ##################################################################### SECTION CONTROLE #################################################################################
     
    /*
    function fetch_liste_enfant(PDO $db, $parent_id=0, $ol='', $tabul=-1){
    	$sql = "
    	SELECT id, last_name, first_name, DATE_FORMAT(birth_date, '%d/%m/%Y') as birthdate, IFNULL(DATE_FORMAT(death_date, '%d/%m/%Y'), NULL) AS deathdate
    	FROM dat_persons
    	WHERE father_id=$parent_id OR mother_id=$parent_id
    	ORDER BY birth_date
    	";
      $stmt = $db->query($sql);
      $data=$stmt->fetchAll();
      if(isset($data[0])){//si enfant(s) seulement
        $tabul++;
        $indentation='';
        for($i=0;$i<$tabul;$i++){
          $indentation .="\t";
        }
        $ol .= $indentation."<ol>\n";
        $indentation_li =$indentation."\t";
        foreach($data as $row){
          //$ol .= $indentation_li."<li>". $row['nom']." ".$row['prenom']." ".$row['naissance_fr'].($row['deces_fr']==""?NULL:" - ".$row['deces_fr'])."</li>\n";
          $ol .= $indentation_li."<li>". $row['last_name']." ".$row['first_name']." ".$row['birthdate'].($row['deathdate']==""?NULL:" - ".$row['deathdate'])."</li>\n";
          $ol = fetch_liste_enfant($db,$row['id'], $ol,$tabul);
        }
        $ol .= $indentation."</ol>\n";
      }
      return $ol;
    }
    */
    function getDescent($parentId, $ol='', $tab=-1)
    {
    	$data = getChildren($parentId);
     
    	if(isset($data[0])){ //si enfant(s) seulement
    		$tab++;
    		$indent='';
    		for ($i=0; $i<$tab; $i++) {
    			$indent .= "\t";
    		}
    		$ol .= $indent."<ol>\n";
    		$indent_li = $indent."\t";
    		foreach ($data as $row) {
    			//$ol .= $indent_li."<li>".$row['last_name']." ".$row['first_name']." ".($row['birthdate']==""?NULL:" - ".$row['birthdate']).($row['deathdate']==""?NULL:" - ".$row['deathdate'])."</li>\n";
    			//$ol .= $indent_li."<li>".$row->last_name." ".$row->first_name." ".($row->birthdate==""?NULL:" - ".$row->birthdate).($row->deathdate==""?NULL:" - ".$row->deathdate)."</li>\n";
    			$ol .= "$indent_li<li>$row->last_name $row->first_name ".($row->birthdate==''?NULL:' - '.$row->birthdate).($row->deathdate==''?NULL:' - '.$row->deathdate)."</li>\n";
    			$ol = getDescent($row->id, $ol, $tab);
    		}
    		$ol .= $indent."<ol>\n";
    	}
    	return $ol;
    }
    // ...........................................................................................
     
    if ( ! $idMain = (int) $_GET['idMain']) {
    	header('location: '.DEFAULT_PAGE);
    	exit;
    }
     
    $idMain = 50; // Pour test uniquement
    $recursiveList = getDescent($idMain);
    echo $recursiveList;

  13. #13
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Tu veux récupérer un tableau d'objets ? Il faut revoir alors getChildren... car fetchAll() te renverra un tableau mélangé de tableaux indexés et de tableaux associatifs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function getChildren($parentId) {
      global $db;
      $dateFormat = LOCAL_DATE_FORMAT;
      $query = "SELECT id, last_name, first_name, IFNULL(DATE_FORMAT(birth_date, '$dateFormat'), NULL) as birthdate, IFNULL(DATE_FORMAT(death_date, '$dateFormat'), NULL) AS deathdate
      FROM dat_persons
      WHERE father_id=? OR mother_id=?
      ORDER BY birth_date";
      $data=array();
      $stmt = $db->prepare($query);
      $stmt->execute(array($parentId,$parentId));
      while($row=$stmt->fetch(PDO::FETCH_OBJ)){
        $data[]=$row;
      }
      return $data;
    }
    Teste ceci ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    <?php
     
    ##################################################################### SECTION TETE : PARAMETRAGE AUTORISATION ##########################################################
     
    require_once('libraries/defines.php');
     
    ##################################################################### Fin SECTION TETE : PARAMETRAGE AUTORISATION ######################################################
     
    ##################################################################### SECTION MODELE ###################################################################################
     
    connect();
     
    function getChildren($parentId) {
      global $db;
      $dateFormat = LOCAL_DATE_FORMAT;
      $query = "SELECT id, last_name, first_name, IFNULL(DATE_FORMAT(birth_date, '$dateFormat'), NULL) as birthdate, IFNULL(DATE_FORMAT(death_date, '$dateFormat'), NULL) AS deathdate
      FROM dat_persons
      WHERE father_id=? OR mother_id=?
      ORDER BY birth_date";
      $data=array();
      $stmt = $db->prepare($query);
      $stmt->execute(array($parentId,$parentId));
      while($row=->fetch(PDO::FETCH_OBJ)){
        $data[]=$row;
      }
      return $data;
    }
     
    ##################################################################### FIN section MODELE ###############################################################################
     
    ##################################################################### SECTION CONTROLE #################################################################################
     
    /*
    function fetch_liste_enfant(PDO $db, $parent_id=0, $ol='', $tabul=-1){
    	$sql = "
    	SELECT id, last_name, first_name, DATE_FORMAT(birth_date, '%d/%m/%Y') as birthdate, IFNULL(DATE_FORMAT(death_date, '%d/%m/%Y'), NULL) AS deathdate
    	FROM dat_persons
    	WHERE father_id=$parent_id OR mother_id=$parent_id
    	ORDER BY birth_date
    	";
      $stmt = $db->query($sql);
      $data=$stmt->fetchAll();
      if(isset($data[0])){//si enfant(s) seulement
        $tabul++;
        $indentation='';
        for($i=0;$i<$tabul;$i++){
          $indentation .="\t";
        }
        $ol .= $indentation."<ol>\n";
        $indentation_li =$indentation."\t";
        foreach($data as $row){
          //$ol .= $indentation_li."<li>". $row['nom']." ".$row['prenom']." ".$row['naissance_fr'].($row['deces_fr']==""?NULL:" - ".$row['deces_fr'])."</li>\n";
          $ol .= $indentation_li."<li>". $row['last_name']." ".$row['first_name']." ".$row['birthdate'].($row['deathdate']==""?NULL:" - ".$row['deathdate'])."</li>\n";
          $ol = fetch_liste_enfant($db,$row['id'], $ol,$tabul);
        }
        $ol .= $indentation."</ol>\n";
      }
      return $ol;
    }
    */
    function getDescent($parentId, $ol='', $tab=-1)
    {
    	$data = getChildren($parentId);
     
    	if(isset($data[0])){ //si enfant(s) seulement
    		$tab++;
    		$indent='';
    		for ($i=0; $i<$tab; $i++) {
    			$indent .= "\t";
    		}
    		$ol .= $indent."<ol>\n";
    		$indent_li = $indent."\t";
    		foreach ($data as $row) {
    			//$ol .= $indent_li."<li>".$row['last_name']." ".$row['first_name']." ".($row['birthdate']==""?NULL:" - ".$row['birthdate']).($row['deathdate']==""?NULL:" - ".$row['deathdate'])."</li>\n";
    			//$ol .= $indent_li."<li>".$row->last_name." ".$row->first_name." ".($row->birthdate==""?NULL:" - ".$row->birthdate).($row->deathdate==""?NULL:" - ".$row->deathdate)."</li>\n";
    			$ol .= $indent_li.'<li>'.$row->last_name.' '.$row->first_name.' '.($row->birthdate==''?NULL:'- '.$row->birthdate).($row->deathdate==''?NULL:'- '.$row->deathdate).'</li>'."\n";
    			$ol = getDescent($row->id, $ol, $tab);
    		}
    		$ol .= $indent."<ol>\n";
    	}
    	return $ol;
    }
    // ...........................................................................................
     
    $idMain = 50; // Pour test uniquement
    $recursiveList = getDescent($idMain);
    echo $recursiveList;

  14. #14
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 615
    Points : 823
    Points
    823
    Par défaut
    Ce que j'aurais du préciser c'est que ma fonction connect() contient ceci:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
    Ceci devrait suffire? J'obtiens bien d'ailleurs un tableau d'objets.
    Si à l'inverse, je fais l'essai en tableau associatif avec FETCH_ASSOC, j'ai toujours la même erreur de décalage de tabulation. Le problème ne vient donc pas de là.

  15. #15
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Oui... alors modifie juste cette ligne dans ta fonction getDescent...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $ol .= $indent_li.'<li>'.$row->last_name.' '.$row->first_name.' '.($row->birthdate==''?NULL:'- '.$row->birthdate).($row->deathdate==''?NULL:'- '.$row->deathdate).'</li>'."\n";

  16. #16
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 615
    Points : 823
    Points
    823
    Par défaut
    Ne cherche plus, je viens de trouver. A l'avant dernière ligne de getDescent(), j'ai une balise d'ouverture au lieu d'une balise de fermeture sur la balise ol. Fatigue??

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2007] créer un arbre généalogique
    Par AgriPhilou dans le forum Modélisation
    Réponses: 4
    Dernier message: 19/12/2011, 18h56
  2. Créer un arbre généalogique
    Par batataw dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 22/10/2009, 09h39
  3. Créer Arbre généalogique
    Par PIEPLU dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 31/12/2007, 21h02
  4. Réaliser un arbre généalogique
    Par Nessie dans le forum Access
    Réponses: 10
    Dernier message: 22/12/2005, 11h58
  5. [débutant] java2D pour arbre généalogique
    Par pingoui dans le forum 2D
    Réponses: 4
    Dernier message: 16/11/2004, 13h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo