0

考虑下面的节点图:

在此处输入图像描述

如上图所示,我想创建一个函数,可以从顶级节点告诉我关系的深度。

实例模型

/**
 * Get the immediate parent instance of the instance.
 */
public function parent()
{
    return $this->hasOne(Instance::class);
}

/**
 * Get the children instances of the instance.
 */
public function children()
{
    return $this->hasMany(Instance::class);
}

/**
 * Get the depth of an instance.
 * @return int
 */
public function getDepthAttribute()
{
    // TODO
}

实例表

Schema::create('instances', function (Blueprint $table) {
    $table->id();
    $table->string('name', 32);
    $table->foreignId('instance_id')->nullable();
    $table->timestamps();
});

Schema::table('instances', function (Blueprint $table)
{
    $table->foreign('instance_id')->references('id')->on('instances')->onUpdate('cascade')->onDelete('cascade');
});

实例表示例

id    name     instance_id | (getDepthAttribute() should return)
-------------------------- |
1     A        NULL        |  0
2     B        1           |  1
3     C        2           |  2
4     D        3           |  3
5     E        3           |  3
6     F        3           |  3

一句话,我的问题是:“如果一个实例有父实例,加1。重复直到父实例没有父实例。然后返回最终值。”

我怎样才能在 Laravel 中正确地做到这一点?

4

2 回答 2

0

Below is the solution I came up with:

DepthHelper.php

use \App\Models\Instance;
/**
 * Returns the depth of an Instance
 * @param $idToFind
 * @return int
 */
function DepthHelper($idToFind){
    return GetParentHelper($idToFind);
}

// Recursive Helper function
function GetParentHelper($id, $depth = 0) {
    $model = Instance::find($id);

    if ($model->instance_id != null) {
        $depth++;

        return GetParentHelper($model->instance_id, $depth);
    } else {
        return $depth;
    }
}

Instance Model

    /**
     * Get the depth of this instance from the top-level instance.
     */
    public function getDepthAttribute()
    {
        return DepthHelper($this->id);
    }

    protected array $appends = ['depth'];
于 2022-02-20T19:11:31.867 回答
0

我的解决方案没有使用递归,我不知道它将如何处理大数据。我不认为这会是一个问题,但我建议你播种一个巨大的表并衡量性能。我的解决方案是创建一个深度图数组。

public $depthMap = [];
public $data = [
    ['id' => 1, 'name' => 'a', 'iid' => null],
    ['id' => 2, 'name' => 'b', 'iid' => 1],
    ['id' => 3, 'name' => 'c', 'iid' => 2],
    ['id' => 4, 'name' => 'd', 'iid' => 2],
    ['id' => 5, 'name' => 'e', 'iid' => 3],
    ['id' => 6, 'name' => 'f', 'iid' => 4],
    ['id' => 7, 'name' => 'g', 'iid' => 3],
    ['id' => 8, 'name' => 'h', 'iid' => 5],
    ['id' => 9, 'name' => 'i', 'iid' => null],
    ['id' => 10, 'name' => 'j', 'iid' => 7],
    ['id' => 11, 'name' => 'k', 'iid' => 9],
    ['id' => 12, 'name' => 'l', 'iid' => 10],
    ['id' => 13, 'name' => 'm', 'iid' => 4],
    ['id' => 14, 'name' => 'n', 'iid' => 3],
    ['id' => 15, 'name' => 'o', 'iid' => 12],
    ['id' => 16, 'name' => 'p', 'iid' => 10],
];

public function handle()
{
    foreach ($this->data as $item) {
        $this->depthMap[] = trim($this->getDepth($item) . ".{$item['id']}", '.');
    }
}

public function getDepth($item)
{
    foreach (array_reverse($this->depthMap) as $mapItem) {
        if (array_reverse(explode('.', $mapItem))[0] == $item['iid']) return $mapItem;
    }
    
    return '';
}

/* The output
[
    "1",
    "1.2",
    "1.2.3",
    "1.2.4",
    "1.2.3.5",
    "1.2.4.6",
    "1.2.3.7",
    "1.2.3.5.8",
    "9",
    "1.2.3.7.10",
    "9.11",
    "1.2.3.7.10.12",
    "1.2.4.13",
    "1.2.3.14",
    "1.2.3.7.10.12.15",
    "1.2.3.7.10.16",
]; 
*/

现在,您不仅可以对深度的长度进行explode()、array_reverse()、count() 操作,还可以对整个关系图进行操作。

于 2022-02-19T19:12:24.703 回答