ターゲットと宛先の両方(またはデータオブジェクト全体など)のIDを取得し、ターゲットが宛先パスにあるかどうかを確認するメソッドがあると思います。そうである場合、メソッドは false を返すか例外をスローし、そうでない場合は true を返します。このメソッドは、制御構造としてコード フローをコピーするディレクトリに導入できます。
個人的には、階層データ構造の場合は、ネストされた setとして実装します。ネストされたセットのセットアップと修正は面倒ですが、ノード間の関係をチェックし、サブツリー全体を取得するには非常に便利です。
これは、私のアイデアの部分的でやや単純な実装を使用した PHPUnit テストです。
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(-1);
require 'vendor/autoload.php';
class ParentingSucks
{
public $data = array();
public function isAllowed($targetId, $destId)
{
$target = $this->getById($targetId);
$dest = $this->getById($destId);
$parent = $this->getById($dest['childOf']);
$isAllowed = true;
while ($parent) {
if ($parent['id'] == $targetId) {
$isAllowed = false;
break;
}
$parent = $this->getById($parent['childOf']);
}
return $isAllowed;
}
public function getById($id)
{
if (isset($this->data[$id])) {
return $this->data[$id];
}
return array();
}
}
class HowIMetYourParentDir extends PHPUnit_Framework_TestCase
{
/**
* @test
* @dataProvider generate
*/
public function droppingOnParentNotAllowed($data, $target, $dest, $outcome)
{
$stub = $this->getMock('ParentingSucks', null);
$stub->data = $data;
$result = $stub->isAllowed($target, $dest);
$this->assertEquals($result, $outcome, 'Oh no!');
}
public function generate()
{
$fakeData = array(
1 => array('id' => 1, 'name' => 'A', 'childOf' => 0),
2 => array('id' => 2, 'name' => 'B', 'childOf' => 1),
3 => array('id' => 3, 'name' => 'C', 'childOf' => 0),
4 => array('id' => 4, 'name' => 'D', 'childOf' => 3),
5 => array('id' => 5, 'name' => 'E', 'childOf' => 2),
6 => array('id' => 6, 'name' => 'F', 'childOf' => 5),
);
return array(
array(
$fakeData,
2, // target
6, // dest
false, // outcome
),
array(
$fakeData,
4,
2,
true,
),
array(
$fakeData,
4,
2,
true,
),
array(
$fakeData,
3,
4,
false,
),
);
}
} false, // outcome
),
array(
$fakeData,
4,
2,
true,
),
array(
$fakeData,
4,
2,
true,
),
array(
$fakeData,
3,
4,
false,
),
);
}
}
変数/関数/クラスの名前はおそらくドメイン モデルに適合しないため、気にしないでください。