alibayat/laravel-categorizable

为 Eloquent 模型实现嵌套结构层次分类系统。

2.1 2023-01-24 07:52 UTC

README

本包实现了嵌套集合层次结构,使您能够以多态方式对 Eloquent 模型进行分类。只需在模型中使用该特性,即可完成。还有一个 Category 模型,您可以直接使用它或在其选择的模型中扩展它。

要求

  • PHP 8+
  • Laravel 8+

安装

composer require alibayat/laravel-categorizable

发布并运行迁移

php artisan vendor:publish --provider="AliBayat\LaravelCategorizable\CategorizableServiceProvider"

php artisan migrate

Laravel Categorizable 包将被 Laravel 自动发现。如果没有,请手动在 config/app.php 提供者数组中注册该包。

'providers' => [
    ...
    \AliBayat\LaravelCategorizable\CategorizableServiceProvider::class,
],

设置模型 - 只需在模型中使用特性。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use AliBayat\LaravelCategorizable\Categorizable;

class Post extends Model
{
    use Categorizable;
}

用法

首先我们需要创建一些分类来使用。此包依赖于另一个名为 laravel-nestedset 的包,该包负责创建、更新、删除和检索单个或嵌套结构的分类。在这里,我将演示如何创建分类并将一个分类作为另一个分类的子分类。但您也可以查看测试或参考包的仓库以获取完整文档。 https://github.com/lazychaser/laravel-nestedset

use App\Models\Post;
use AliBayat\LaravelCategorizable\Category;

// first we create a bunch of categories

// create categories
$backEnd = Category::create(['name' => 'Back End']);
$frontEnd = Category::create(['name' => 'Front End']);
$php = Category::create(['name' => 'PHP']);

// assign "PHP" as a child of "Back End" category
$backEnd->appendNode($php);

//  assuming that we have a post instance
$post = Post::first();

多级分类结构

有时您可能希望为不同的模型有不同的分类结构。在这种情况下,您也可以在创建分类时传递一个 type 参数。默认情况下,类型设置为 default。在具有类型的情况下,您还可以利用 Eloquent 模型作用域轻松过滤分类。

在创建新分类时创建树

还可以将嵌套结构作为 children 属性传递给 create 方法

$categoryWithChildAndGrandchild = Category::create([
    'name' => 'Foo',
    'children' => [
        [
            'name' => 'Bar',
            'children' => [
                [ 'name' => 'Baz' ],
            ],
        ],
    ],
]);

将文章附加到分类

    $post->attachCategory($php);

将文章从分类中分离

    $post->detachCategory($php);

将文章附加到分类列表

    $post->syncCategories([
	    $php,
	    $backEnd
    ]);

将文章从所有分类中分离

    $post->syncCategories([]);

同步附加到文章的分类

    $post->syncCategories([$frontEnd]);

检查文章是否附加到指定的分类(布尔值)

    // single use case
    $post->hasCategory($php);

    // multiple use case
    $post->hasCategory([
	    $php,
	    $backEnd
    ]);

附加到文章的分类列表(数组 [1 => 'BackEnd'])

    $post->categoriesList();

附加到文章的分类 ID 列表(数组 [1, 2, 3])

    $post->categoriesIds();

获取附加到给定分类的所有文章(MorphToMany)

    $categoryPosts = Category::find(1)->entries(Post::class);

获取附加到给定分类及其子分类的所有文章(Builder)

    $categoryAndDescendantsPosts = Category::find(1)->allEntries(Post::class);

方法

在基础 Category 模型(或任何扩展此类的其他模型)上,您将能够访问各种方法

$result = Category::ancestorsOf($id);
$result = Category::ancestorsAndSelf($id);
$result = Category::descendantsOf($id);
$result = Category::descendantsAndSelf($id);
$result = Category::whereDescendantOf($node)->get();
$result = Category::whereNotDescendantOf($node)->get();
$result = Category::orWhereDescendantOf($node)->get();
$result = Category::orWhereNotDescendantOf($node)->get();
$result = Category::whereDescendantAndSelf($id)->get();
$result = Category::whereDescendantOrSelf($node)->get();
$result = Category::whereAncestorOf($node)->get();
$result = Category::whereAncestorOrSelf($id)->get();

$siblings = Category::find($id)->getSiblings();
$nextSibling = Category::find($id)->getNextSibling();
$nextSiblings = Category::find($id)->getNextSiblings();
$prevSibling = Category::find($id)->getPrevSibling();
$prevSiblings = Category::find($id)->getPrevSiblings();

$withDepth = Category::withDepth()->find($id);
$withSpecificDepth = Category::withDepth()->having('depth', '=', 1)->get();

$tree = Category::get()->toTree();
$flatTree = Category::get()->toFlatTree();

$bool = Category::isBroken();
$data = Category::countErrors();
Category::fixTree();

这些方法的完整文档可在 laravel-nestedset 包的 README 中找到。

关系

categories() 关系

    $postWithCategories = Post::with('categories')->get();

parent 关系

    $categoryWithParent = Category::with('parent')->find(1);

children 关系

    $categoryWithChildren = Category::with('children')->find(1);

ancestors 关系

    $categoryWithAncestors = Category::with('ancestors')->find(1);

descendants 关系

    $categoryWithDescendants = Category::with('descendants')->find(1);

测试

本包包含单元测试和功能测试(共 47 个测试,169 个断言),以确保提供的功能按预期工作。您可以通过以下 composer 命令运行测试

composer test

鸣谢