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

ORM PHP Discussion :

Doctrine Nested set: récupérer les items de toute la sous-arborescence.


Sujet :

ORM PHP

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 32
    Points : 24
    Points
    24
    Par défaut Doctrine Nested set: récupérer les items de toute la sous-arborescence.
    Bonjour,

    Je poste ce message pour être sûr que mon idée est bien la bonne car je suis débutant.
    Petit récapitulatif (juste l'affichage des items couplé à leur catégorie):

    Schema.yml:
    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
     
    Category:
      actAs:
        NestedSet:
          hasManyRoots: true
          rootColumnName: root_id
      columns:
        name:
          type: string()
     
    Item:
      columns:
        name:
          type: string()
        category_id:
          type: integer
      relations:
        Category:
          local: category_id
          foreign: id
          foreignAlias: Items
    fixture:
    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
     
    Category:
      arbre:
        name: Arbre
        children:
          1:
            name: Catégorie principale 1
            children:
                11:
                  name: Catégorie secondaire 1
                12:
                  name: Catégorie secondaire 2
                13:
                  name: Catégorie secondaire 3
                14:
                  name: Catégorie secondaire 4
                  children:
                    141:
                      name: Catégorie tertiaire 1
                    142:
                      name: Catégorie tertiaire 2
                15:
                  name: Catégorie secondaire 5
                16:
                  name: Catégorie secondaire 6
          2:
            name: Catégorie principale 2
          3:
            name: Catégorie principale 3
            children:
                31:
                  name: Catégorie secondaire 1
                32:
                  name: Catégorie secondaire 2
                33:
                  name: Catégorie secondaire 3            
          4:
            name: Catégorie principale 4
            children:
              41:
                name: Catégorie secondaire 1
     
     
    Item:
      i1:
        name: Baseline
        Category: 11
      i2:
        name: Product
        Category: 11
      i3:
        name: Analysis
        Category: 12
      i4:
        name: Architecture
        Category: 12
      i5:
        name: Design review
        Category: 12
      i6:
        name: Feature analysis
        Category: 13
      i7:
        name: Implementation
        Category: 141
      i8:
        name: Review
        Category: 141
      i9:
        name: Test
        Category: 142
      i10:
        name: Stabilization
        Category: 16
      i11:
        name: Feature 
        Category: 16
      i12:
        name: Feature view
        Category: 2
      i13:
        name: Fixing
        Category: 2
      i14:
        name:  Repport
        Category: 41
    Avec ça je peux afficher les items couplé à leur catégorie dans mon template avec un truc du genre:
    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
     
    class CategoryTable extends Doctrine_Table
    {
    	public function withItems()
    	{
    		$q = Doctrine_Query::create()
    		->select('c.name')
    		->from('Category  c')
    		->leftJoin('c.Items i');
     
    		$treeObject = Doctrine_Core::getTable('Category')->getTree();
    		$treeObject->setBaseQuery($q);
    		$tree = $treeObject->fetchTree();
    		$treeObject->resetBaseQuery();
     
    		return $tree;
    	}
    }
    et:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class Category extends BaseCategory
    {
     
    	public function getItems()
    	{
    		  $q = Doctrine_Query::create()
    		->from('Item i')
    		->where('i.category_id = ?', $this->getId());
     
    		return $q->execute();
    	}
    }
    MAINTENANT:
    Je veux afficher une categorie avec ses items et ceux des categories sous-adjacentes.
    J'ai eu l'idée de rajouter les colonnes "rgt" et "lft" à ma table Item, ces dernières couplé avec "rgt" et "lft" de la table Category.
    et de faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class Category extends BaseCategory
    {
     
    	public function getItems()
    	{
    		 $q = Doctrine_Query::create()
    		->from('Item i')
    		->where('i.lft BETWEEN ? AND ?', array($this->getLft(), $this->getRgt())
     
    		return $q->execute();
    	}
    }
    Cette methode est-elle bonne oubien il y a t-il une meilleure?

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 32
    Points : 24
    Points
    24
    Par défaut
    Pour info je n'arrive pas à faire les liaisons foreign key entre les tables Category et Item sur les colonnes lft et rgt...
    J'effectue la liaison en initialisant la colonne lft.item avec la valeur de lft.category en surchargeant la méthode save() de la classe du modèle.

  3. #3
    Expert éminent
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Points : 8 486
    Points
    8 486
    Par défaut
    Ce ne serait pas un truc dans le genre ...

    La requêtes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    $q = Doctrine_Query::create()
        ->from('Category c')
        ->leftJoin('c.Items i');
    Récupérer l'arbre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $treeObject = Doctrine_Core::getTable('Category')->getTree();
    Y joindre la requête et récupérer les données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $treeObject->setBaseQuery($q);
    $tree = $treeObject->fetchTree();
    Ensuite, tu te déplace dans $tree avec les méthodes dédiées aux arbres.
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).

    • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
    • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
    • Une discussion est terminée ? Alors le bouton est votre ami !

  4. #4
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2003
    Messages
    307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Février 2003
    Messages : 307
    Points : 378
    Points
    378

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 32
    Points : 24
    Points
    24
    Par défaut
    merci, mais j'ai réussi en utilisant la méthode du parcours d'arbre.
    voir le lien (très intéressant):
    http://articles.sitepoint.com/articl...ata-database/2

  6. #6
    Membre averti
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2003
    Messages
    307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Février 2003
    Messages : 307
    Points : 378
    Points
    378
    Par défaut
    ha ben si tu as réussis tant mieux
    je vais bientot utiliser ça aussi, si jamais tu as envie de me passer ton code sf...

  7. #7
    Expert éminent
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Points : 8 486
    Points
    8 486
    Par défaut
    En fait, ces méthodes sont celle utilisées par doctrine, encapsulée dans le mode objet.

    Il marche bien, à condition de l'utiliser comme un mode objet et non pas comme une table à manipuler directement.

    Mais si l'autre méthode te conviens, c'est certainement la bonne, pour toi. Et c'est cela qui compte.
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).

    • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
    • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
    • Une discussion est terminée ? Alors le bouton est votre ami !

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 32
    Points : 24
    Points
    24
    Par défaut
    mimi68,

    j'ai éplucher la doc de Nested set que tu m'as donné et il y a tout sauf ça (à part si j'ai mal vu).
    Donc d'après ma lecture (de débutant): si on veux récupérer les items d'une catégorie bien précise il faut utiliser ta méthode. Mais si on veux récupérer tous les items de la catégorie ainsi que ceux de toutes ses sous-catégories en même temps, il vaut mieux utilisé le parcours d'arbre, car se déplacer dans le $tree pour récupérer toutes les données de façon "dynamique" n'est pas super pratique.

    Donc pour jf_homer, voila comment j'ai fait:

    _Un exemple de CategoryTable:
    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
     
    class CategoryTable extends Doctrine_Table
    {
     
    	public function withAll()
    	{
    		$q = Doctrine_Query::create()
    		->select('c.nom')
    		->from('Category c')
    		->where('c.level = 1')
    		->orderBy('c.name');
     
    		$treeObject = Doctrine_Core::getTable('Category')->getTree();
    		$treeObject->setBaseQuery($q);
    		$tree = $treeObject->fetchTree();
    		$treeObject->resetBaseQuery();
     
    		return $tree;
    	}
     
    }
    Ca c'est un exemple pour afficher les catégories principales et tu peux utiliser les fonctions Nested set dessus.

    Sinon pour afficher tous les items de la catégorie ainsi que ceux de toutes ses sous-catégories en même temps, j'ai rajouté dans la classe Category:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class Category extends BaseCategory
    {
    	public function getItems()
    	{
    		 $q = Doctrine_Query::create()
    		->from('Items i')
    		->leftJoin('i.Category c')
    		->where('c.lft BETWEEN ? AND ?', array($this->getLft(), $this->getRgt()));
    		/* tu peux faire un ->andWhere() et un ->orderBy() pour affiner ta requête */
     
    		return $q->execute();
    	}
    }
    Tu peux utiliser cette fonction dans ton showSuccess.php par exemple avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    <?php	foreach ($category->getItems() as $item):
     
    			echo $item->getName();
     
    		endforeach; ?>
    Voila. Après je rappel que je débute donc j'emets des reserves sur le code et le procédé pour aller dans le sens de mimi68.

  9. #9
    Expert éminent
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Points : 8 486
    Points
    8 486
    Par défaut
    Pour récupérer toute l'arborescence d'un arbre (quant il y a plusieurs racines possibles.

    L'arbre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    Category:
      actAs:
        NestedSet:
          hasManyRoots: true
          rootColumnName: root_id
      columns:
        name: string(255)
    Simpliste, mais suffisant pour illustrer nos propos.

    Un peu de fixatures pour habiller la bête
    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
     
    Category:
      cat1:
        name: Catégorie 1
        children:
          cat11:
            name: Catégorie 11
            children:
              cat111:
                name: Catégorie 111
              cat112:
                name: Catégorie 112
          cat12:
            name: Catégorie 12
      cat2:
        name: Catégorie 2
        children:
          cat21:
            name: Catégorie 21
          cat22:
            name: Catégorie 22
            children:
              cat221:
                name: Catégorie 221
              cat222:
                name: Catégorie 222
                children:
                  cat2221:
                    name: Catégorie 2221
                  cat2222:
                    name: Catégorie 2222
              cat223:
                name: Catégorie 223
                children:
                  cat2231:
                    name: Catégorie 2231
    On a donc deux racines Catégorie 1 et catégorie 2.

    Le problème pour récupérer l'arbre pour une racine donnée est qu'il faut, au minimum deux requêtes, je n'ai pas trouvé avec moins, mais je suis preneur... La première va récupérer la root_id de l'arbre (on ne la connait pas, elle est auto générée) Si on vient d'un autre formulaire avec une combo box, il est possible qu'elle y soit et on économisera ainsi une requête. Et ensuite la récupération des données, le code est commenté.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
        public function executeIndex( sfWebRequest $request )
        {
            // retrouve le root_id voulu
            $result = Doctrine::getTable('Category')->findOneByName( 'Catégorie 2' );
            // un pointeur sur l'arbre
            $treeObject = Doctrine_Core::getTable( 'Category' )->getTree();
            // la condition qui va permettre de retrouver la racine de l'arbre pour la condition ci-dessus
            $options = array( 'root_id' => $result->getRootId() );
            // on récupère toutes les données de l'arbre d'un coup
            $this->tree = $treeObject->fetchtree( $options );
        }
    Et l'affichage (minimaliste).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <?php foreach ($tree as $node) : ?>
       <?php echo str_repeat('&nbsp;&nbsp;', $node['level']) . $node['name'] ?><br />
    <?php endforeach; ?>
    Ainsi, on ne touche pas aux données internes de la gestion de l'arbre, juste aux nôtres. Suivant l'hydratation que l'on va donner, il est possible d'avoir un tableau différent. Il doit aussi être possible de gérer un partial en récursif pour afficher mieux la chose.

    Le code ici est testé.

    Je pense que cette solution est plus dans le style doctrine.
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).

    • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
    • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
    • Une discussion est terminée ? Alors le bouton est votre ami !

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 32
    Points : 24
    Points
    24
    Par défaut
    Le problème est que je ne veux pas récupérer toute l'arborescence d'un arbre mais la sous-arborescence d'une catégorie.
    par exemple:
    récupérer les données de catégorie 222 ainsi que les données des sous-catégories 222x, le tout, sans récupérer les données de la catégorie 2 ni celle de la 22 ni celle de la 221.

  11. #11
    Expert éminent
    Avatar de Michel Rotta
    Homme Profil pro
    DPO
    Inscrit en
    Septembre 2005
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : DPO
    Secteur : Distribution

    Informations forums :
    Inscription : Septembre 2005
    Messages : 4 954
    Points : 8 486
    Points
    8 486
    Par défaut
    Modifie l'action ainsi !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
        public function executeIndex( sfWebRequest $request )
        {
            // récupère l'enregistrement du début de la branche
            $StartId = Doctrine::getTable('Category')->findOneByName('Catégorie 22');
            // un pointeur sur l'arbre
            $tree = Doctrine_Core::getTable('Category')->getTree();
            // on récupère la branche qui démare à l'objet de départ
            $this->tree = $tree->fetchBranch($StartId->getId());
        }
    Le reste du code est identique.

    Par contre, le fetchBranch génère 2 requête pour trouver tous les objets. Mais c'est simple et portable.
    Si tu donnes un poisson à un homme, il mangera un jour. Si tu lui apprends à pêcher, il mangera toujours (Lao Tseu).

    • Pensez à valoriser les réponses pertinantes, cliquez sur le bouton vert +1 pour indiquer votre accord avec la solution proposée.
    • Pensez à utiliser la balise [code] pour afficher du code, elle est cachée sous le bouton [#] dans l'éditeur.
    • Une discussion est terminée ? Alors le bouton est votre ami !

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 06/10/2008, 12h04
  2. Réponses: 6
    Dernier message: 10/10/2007, 12h28
  3. Réponses: 2
    Dernier message: 20/08/2007, 09h22
  4. Réponses: 7
    Dernier message: 05/04/2007, 16h15

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