wbraganca/yii2-nested-set-behavior

该扩展允许您获取嵌套集合树的函数。

dev-master 2014-12-01 10:58 UTC

This package is not auto-updated.

Last update: 2024-09-10 03:09:59 UTC


README

该扩展允许您获取嵌套集合树的函数。

安装

安装此扩展的首选方式是通过 composer

运行

php composer.phar require wbraganca/yii2-nested-set-behavior "*"

或添加

"wbraganca/yii2-nested-set-behavior": "*"

到您的 composer.json 文件的 require 部分。

配置

首先,您需要按照以下方式配置模型

use wbraganca\behaviors\NestedSetBehavior;
use wbraganca\behaviors\NestedSetQuery; 

class Category extends ActiveRecord
{
    public function behaviors()
    {
        return [
            [
                'class' => NestedSetBehavior::className(),
                // 'rootAttribute' => 'root',
                // 'levelAttribute' => 'level',
                // 'hasManyRoots' => true
            ],
        ];
    }

    public static function find()
    {
        return new NestedSetQuery(get_called_class());
    }
}

不需要验证在 leftAttributerightAttributerootAttributelevelAttribute 选项中指定的字段。此外,如果存在这些字段的验证规则,可能会出现问题。请检查模型规则()方法中是否有字段提到的规则。

如果要在数据库中存储单个树,可以使用 schema/schema.sql 构建数据库结构。如果您打算存储多个树,则需要 schema/schema-many-roots.sql

默认情况下,leftAttributerightAttributelevelAttribute 的值与默认数据库模式中的字段名称相匹配,因此您可以跳过这些配置。

此行为可以通过两种方式工作:每张表一个树和每张表多个树。模式是根据 hasManyRoots 选项的值选择的,默认值为 false,表示单树模式。在多树模式下,您可以设置 rootAttribute 选项以匹配存储树的表中的现有字段。

从树中选择

以下我们将使用一个示例模型 Category,其在数据库中的如下所示

- 1. Mobile phones
    - 2. iPhone
    - 3. Samsung
        - 4. X100
        - 5. C200
    - 6. Motorola
- 7. Cars
    - 8. Audi
    - 9. Ford
    - 10. Mercedes

在这个例子中,我们有两个树。树的根是 ID=1 和 ID=7 的记录。

获取所有根节点

$roots = Category::find()->roots()->all();

结果

与 Mobile phones 和 Cars 节点对应的 Active Record 对象数组。

获取一个节点的所有后代

$category = Category::findOne(1);
if ($category) {
    $descendants = $category->descendants()->all();
    var_dump($descendants);
}

结果

与 iPhone、Samsung、X100、C200 和 Motorola 对应的 Active Record 对象数组。

获取一个节点的所有子节点

$category = Category::findOne(1);
if ($category) {
    $descendants = $category->children()->all();
    var_dump($descendants);
}

结果

与 iPhone、Samsung 和 Motorola 对应的 Active Record 对象数组。

获取一个节点的所有祖先

$category = Category::findOne(5);
if ($category) {
    $ancestors = $category->ancestors()->all();
    var_dump($ancestors);
}

结果

与 Samsung 和 Mobile phones 对应的 Active Record 对象数组。

获取一个节点的父节点

$category = Category::findOne(9);
if ($category) {
    $parent = $category->parent()->one();
    var_dump($parent);
}

结果

与 Cars 对应的 Active Record 对象数组。

获取节点兄弟

使用 NestedSet::prev()NestedSet::next()

$category = Category::findOne(9);
if ($category) 
    $nextSibling = $category->next()->one();
}

结果

与 Mercedes 对应的 Active Record 对象数组。

获取整个树

您可以使用以下标准 AR 方法获取整个树。

对于每张表一个树

Category::find()->addOrderBy('lft')->all();

对于每张表多个树

Category::find()->andWhere('root = ?', [$root_id])->addOrderBy('lft')->all();

修改树

在本节中,我们将构建与上一节中使用相同的树。

创建根节点

您可以使用 NestedSet::saveNode() 创建根节点。

$root = new Category;
$root->title = 'Mobile Phones';
$root->saveNode();

$root = new Category;
$root->title = 'Cars';
$root->saveNode();

结果

- 1. Mobile Phones
- 2. Cars

添加子节点

有多个方法允许您添加子节点。有关更多信息,请参阅 API。让我们使用这些方法将节点添加到我们拥有的树中

$category1 = new Category;
$category1->title = 'Ford';

$category2 = new Category;
$category2->title = 'Mercedes';

$category3 = new Category;
$category3->title = 'Audi';

$root = Category::findOne(1);
$category1->appendTo($root);
$category2->insertAfter($category1);
$category3->insertBefore($category1);

结果

- 1. Mobile phones
    - 3. Audi
    - 4. Ford
    - 5. Mercedes
- 2. Cars

逻辑上,上面的树看起来并不正确。我们稍后会修复它。

$category1 = new Category;
$category1->title = 'Samsung';

$category2 = new Category;
$category2->title = 'Motorola';

$category3 = new Category;
$category3->title = 'iPhone';

$root = Category::findOne(2);
$category1->appendTo($root);
$category2->insertAfter($category1);
$category3->prependTo($root);

结果

- 1. Mobile phones
    - 3. Audi
    - 4. Ford
    - 5. Mercedes
- 2. Cars
    - 6. iPhone
    - 7. Samsung
    - 8. Motorola
$category1 = new Category;
$category1->title = 'X100';

$category2 = new Category;
$category2->title = 'C200';

$node = Category::findOne(3);
$category1->appendTo($node);
$category2->prependTo($node);

结果

- 1. Mobile phones
    - 3. Audi
        - 9. С200
        - 10. X100
    - 4. Ford
    - 5. Mercedes
- 2. Cars
    - 6. iPhone
    - 7. Samsung
    - 8. Motorola

移动一个节点使其成为新的根节点

有一个特殊的 moveAsRoot() 方法允许移动一个节点并将其变成新的根节点。在这种情况下,所有后代也会被移动。

示例

$node = Category::findOne(10);
$node->moveAsRoot();

递归树遍历

Category::find()->options();     // List all the tree
Category::find()->options(1);    // List all category in tree with root.id=1
Category::find()->options(1, 3); // List 3 levels of category in tree with root.id=1

Fancytree 的数据格式。

Category::find()->dataFancytree();     // List all the tree
Category::find()->dataFancytree(1);    // List all category in tree with root.id=1
Category::find()->dataFancytree(1, 3); // List 3 levels of category in tree with root.id=1