Welcome to the Cookbook

loading...

6.4.2 Utilisation basique

Le comportement en arbre de données (Tree behavior) possède beaucoup de fonctionnalités, mais commençons avec un exemple simple. Créons la table suivante :

CREATE TABLE categories (
	id INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	parent_id INTEGER(10) DEFAULT NULL,
	lft INTEGER(10) DEFAULT NULL,
	rght INTEGER(10) DEFAULT NULL,
	name VARCHAR(255) DEFAULT '',
	PRIMARY KEY  (id)
);

INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(1, 'Mes  Catégories', NULL, 1, 30);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(2, 'Fun', 1, 2, 15);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(3, 'Sport', 2, 3, 8);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(4, 'Surf', 3, 4, 5);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(5, 'Tricot extrême', 3, 6, 7);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(6, 'Amis', 2, 9, 14);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(7, 'Gérard', 6, 10, 11);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(8, 'Gwendoline', 6, 12, 13);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(9, 'Travail', 1, 16, 29);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(10, 'Rapports', 9, 17, 22);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(11, 'Annuel', 10, 18, 19);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(12, 'Statut', 10, 20, 21);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(13, 'Voyages', 9, 23, 28);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(14, 'National', 13, 24, 25);
INSERT INTO `categories` (`id`, `name`, `parent_id`, `lft`, `rght`) VALUES(15, 'International', 13, 26, 27);

Dans le but de vérifier que tout est défini correctement, nous pouvons créer une méthode de test et afficher les contenus de notre arbre de catégories, pour voir à quoi il ressemble. Avec un simple contrôleur :

<?php
class CategoriesController extends AppController {

        var $name = 'Categories';
        
        function index() {
                $this->data = $this->Category->generatetreelist(null, null, null, '&nbsp;&nbsp;&nbsp;');
                debug ($this->data); die;       
        }
}
?>
  1. <?php
  2. class CategoriesController extends AppController {
  3. var $name = 'Categories';
  4. function index() {
  5. $this->data = $this->Category->generatetreelist(null, null, null, '&nbsp;&nbsp;&nbsp;');
  6. debug ($this->data); die;
  7. }
  8. }
  9. ?>

et une définition de modèle encore plus simple :

<?php
// app/models/category.php
class Category extends AppModel {
	var $name = 'Category';
	var $actsAs = array('Tree');
}
?>
  1. <?php
  2. // app/models/category.php
  3. class Category extends AppModel {
  4. var $name = 'Category';
  5. var $actsAs = array('Tree');
  6. }
  7. ?>

Nous pouvons vérifier à quoi ressemble les données de notre arbre de catégories, en visitant /categories. Vous devriez voir quelque chose comme :

  • Mes Catégories
    • Fun
      • Sport
        • Surf
        • Tricto extrême
      • Amis
        • Gérard
        • Gwendoline
    • Travail
      • Rapports
        • Annuel
        • Statut
      • Voyages
        • National
        • International

6.4.2.1 Ajouter des données

Dans la section précédente, nous utilisions des données existantes et nous vérifiions qu'elles semblaient hiérarchiques via la méthode generatetreelist. Toutefois, vous aimeriez normalement ajouter vos données exactement de la même façon que vous le feriez pour tout modèle. Par exemple :

// pseudo code de contrôleur
$data['Category']['parent_id'] =  3;
$data['Category']['nom'] =  'Skate';
$this->Category->save($data);
  1. // pseudo code de contrôleur
  2. $data['Category']['parent_id'] = 3;
  3. $data['Category']['nom'] = 'Skate';
  4. $this->Category->save($data);

En utilisant le comportement en arbre, il n'est pas nécessaire de faire autre chose que de définir le parent_id, et le comportement en arbre s'occupera du reste. Si vous ne définissez pas le parent_id, le comportement en arbre ajoutera l'enregistrement à la racine, faisant de votre nouvel ajout une nouvelle entrée de niveau supérieur :

// pseudo code de contrôleur
$data = array();
$data['Category']['nom'] =  'Autres catégories de Personnes';
$this->Category->save($data);
  1. // pseudo code de contrôleur
  2. $data = array();
  3. $data['Category']['nom'] = 'Autres catégories de Personnes';
  4. $this->Category->save($data);

Exécuter les deux fragments de code ci-dessus modifiera votre arbre de cette façon :

  • Mes Catégories
    • Fun
      • Sport
        • Surf
        • Tricot extrême
        • Skate Nouveau
      • Amis
        • Gérald
        • Gwendolyne
    • Travail
      • Rapports
        • Annuel
        • Statut
      • Voyages
        • National
        • International
  • Catégories des autres Personnes Nouveau

6.4.2.2 Modifier les données

Modifier des données est aussi transparent que d'en ajouter des nouvelles. Si vous modifiez quelque chose, mais que vous ne changez pas le champ parent_id, la structure de vos données sera finalement inchangée. Par exemple :

// pseudo code de contrôleur
$this->Category->id = 5; // id de Tricot extrême
$this->Category->save(array('nom' =>'Pêche extrême'));
  1. // pseudo code de contrôleur
  2. $this->Category->id = 5; // id de Tricot extrême
  3. $this->Category->save(array('nom' =>'Pêche extrême'));

Le code ci-dessus n'affecte pas le champ parent_id, même si le parent_id est inclus dans les données qui sont passées au save lorsque sa valeur ne change pas, il n'affecte pas non plus la structure de données. Par conséquent, l'arbre de données devrait maintenant ressembler à :

  • Mes Catégories
    • Fun
      • Sport
        • Surf
        • Pêche extrême Mis à jour
        • Skate
      • Amis
        • Gérald
        • Gwendolyne
    • Travail
      • Rapports
        • Annuel
        • Statut
      • Voyages
        • National
        • International
  • Catégories des autres Personnes

Déplacer les données au sein de votre arbre est également une simple formalité. Disons que Pêche extrême ne va plus sous Sport, mais qu'elle devrait plutôt être placée sous Autres catégories de Personnes. Avec le code suivant :

// pseudo code de contrôleur
$this->Category->id = 5; // id de Pêche extrême
$nouveauParentId = $this->Category->field('id', array('nom' => 'Autres catégories de Personnes'));
$this->Category->save(array('parent_id' => $nouveauParentId)); 
  1. // pseudo code de contrôleur
  2. $this->Category->id = 5; // id de Pêche extrême
  3. $nouveauParentId = $this->Category->field('id', array('nom' => 'Autres catégories de Personnes'));
  4. $this->Category->save(array('parent_id' => $nouveauParentId));

Comme attendu, la structure est modifiée en :

  • Mes Catégories
    • Fun
      • Sport
        • Surf
        • Skate
      • Amis
        • Gérald
        • Gwendolyne
    • Travail
      • Rapports
        • Annuel
        • Statut
      • Voyages
        • National
        • International
  • Catégories des autres Personnes
    • Pêche extrême Déplacé

6.4.2.3 Supprimer des données

Le comportement en arbre fournit de nombreuses manières de gérer la suppression de données. Pour commencer avec l'exemple le plus simple, imaginons que la catégorie des rapports n'est plus utilisée. Pour la supprimer et tous les enfants qu'elle pourrait avoir appelez simplement delete comme vous le feriez pour tout modèle. Par exemple, avec le code suivant :

//  pseudo code de contrôleur
$this->Category->id = 10;
$this->Category->delete();
  1. // pseudo code de contrôleur
  2. $this->Category->id = 10;
  3. $this->Category->delete();

L'arbre de catégories sera modifié comme ainsi :

  • Mes Catégories
    • Fun
      • Sport
        • Surf
        • Skate
      • Amis
        • Gérald
        • Gwendolyne
    • Travail
      • Voyages
        • National
        • International
  • Catégories des autres Personnes
    • Pêche extrême

6.4.2.4 Interroger et utiliser vos données

Utiliser et manipuler des données hiérarchiques peut s'avérer une entreprise compliquée. En plus des méthodes find du cœur, avec le comportement en arbre il y a quelques permutations plus orientées arborescence à votre disposition.

La plupart des méthodes du comportement en arbre retournent et dépendent de données qui ont été triées par le champ lft. Si vous appelez find() et que vous ne faites pas un order by lft ou si vous appelez une méthode du comportement en arbre et que vous lui passez un ordre de tri, vous pourriez obtenir des résultats indésirables.

6.4.2.4.1 children

La méthode children prend la valeur de la clé primaire (l'id) d'une ligne et retourne ses enfants, par défaut dans l'ordre où ils apparaissent dans l'arbre. Le second paramètre, optionnel, définit si oui ou non les enfants direct uniquement doivent être retournés. Utilisons les données de l'exemple de la section précédent :

$tousEnfants = $this->Category->children(1); // un tableau simple avec 11 items
// -- ou --
$this->Category->id = 1;
$tousEnfants = $this->Category->children(); // un tableau simple avec 11 items

// Retourne uniquement les enfants directs
$enfantsDirects = $this->Category->children(1, true); // un tableau simple avec 2 items
  1. $tousEnfants = $this->Category->children(1); // un tableau simple avec 11 items
  2. // -- ou --
  3. $this->Category->id = 1;
  4. $tousEnfants = $this->Category->children(); // un tableau simple avec 11 items
  5. // Retourne uniquement les enfants directs
  6. $enfantsDirects = $this->Category->children(1, true); // un tableau simple avec 2 items

Si vous voulez un tableau récursif, utilisez find('threaded')

6.4.2.4.2 childCount

Tout comme la méthode children, childCount prend la valeur de la clé primaire (l'id) d'une ligne et retourne combien d'enfants elle a. Le second paramètre, optionnel, définit si oui ou non les enfants direct uniquement sont comptés. Utilisons les données de l'exemple de la section précédente :

$nbEnfants = $this->Category->childCount(1); // affichera11
// -- ou --
$this->Category->id = 1;
$directChildren = $this->Category->childCount(); // affichera 11

// Compte uniquement les descendants directs de cette catégorie
$nbEnfants = $this->Category->childCount(1, true); // affichera 2
  1. $nbEnfants = $this->Category->childCount(1); // affichera11
  2. // -- ou --
  3. $this->Category->id = 1;
  4. $directChildren = $this->Category->childCount(); // affichera 11
  5. // Compte uniquement les descendants directs de cette catégorie
  6. $nbEnfants = $this->Category->childCount(1, true); // affichera 2

6.4.2.4.3 generatetreelist

Le texte original de cette section a changé depuis qu'il a été traduit. Aidez-nous à corriger cette différence. Vous pouvez :

Plus d'information à propos des traductions

generatetreelist (&$model, $conditions=null, $keyPath=null, $valuePath=null, $spacer= '_', $recursive=null)

Cette méthode retourne des données similaires à un find('list'), avec un préfixe d'indentation pour mettre en évidence la structure de l'arbre. Voici un exemple de rendu de cette méthode.

array(
	[1] =>  "Mes Catégories",
	[2] =>  "_Fun",
	[3] =>  "__Sport",
	[4] =>  "___Surf",
	[16] => "___Skate",
	[6] =>  "__Amis",
	[7] =>  "___Gérald",
	[8] =>  "___Gwendolyne",
	[9] =>  "_Travail",
	[13] => "__Voyages",
	[14] => "___National",
	[15] => "___International",
	[17] => "Catégories des autres personnes",
	[5] =>  "_Pêche extrême"
)

6.4.2.4.4 getparentnode

Cette fonction pratique retournera, comme son nom l'indique, le nœud parent d'un nœud ou false si le nœud n'a pas de parent (c'est le nœud racine). Par exemple :

$parent = $this->Category->getparentnode(2); //<- id pour fun
// $parent contient Mes Catégories
  1. $parent = $this->Category->getparentnode(2); //<- id pour fun
  2. // $parent contient Mes Catégories

6.4.2.4.5 getpath

Le 'path' quand on se réfère à des données hiérarchiques, c'est comment vous faites pour aller d'où vous êtes jusqu'en haut. Ainsi par exemple, le chemin depuis la catégorie "International" est :

  • Mes Catégories
    • ...
    • Travail
      • Voyages
        • ...
        • International

Utiliser l'id de "International" pour getpath retournera chacun de ses parents à tour de rôle (en commençant depuis le sommet).

$parents = $this->Category->getpath(15);
  1. $parents = $this->Category->getpath(15);
// contenus de $parents
array(
	[0] =>  array('Category' => array('id' => 1, 'name' => 'Mes Catégories', ..)),
	[1] =>  array('Category' => array('id' => 9, 'name' => 'Travail', ..)),
	[2] =>  array('Category' => array('id' => 13, 'name' => 'Voyages', ..)),
	[3] =>  array('Category' => array('id' => 15, 'name' => 'International', ..)),
)