PHPでループされた要素をループする方法は?
-
22-07-2019 - |
質問
このように子から呼び出すことができるparentidを使用して、カテゴリのツリー構造を作成しています:
ID | Name | ParentID
1 1 0
2 2 1
3 3 2
4 4 1
この結果:
1 = 1
2 = 1 -> 2
3 = 1 -> 2 -> 3
4 = 1 -> 4
つまり、 3は2の子、つまり1の子です>
このアイデアを取得しようとすると(->で設定されている関係が表示されます)、2年生(1-> 2)しか取得できず、3年生(1-> 2-> 3)私が使用しているループ機能のため。
//put all ID's in an array
while ($row2 = $connector->fetchArray($result2)){
$id = $row2['ID'];
$parents[$id] = $row2['name'];
}
// show the tree-structure
while ($row = $connector->fetchArray($result)){
if($row['parentid']!=0)echo $parents[$row['parentid']].' -> ';
echo $row['name'].' - ';
echo '<br>';
}
次の2つの変更を希望します:
- コードに必要なサイズのツリーを自動的に生成させます。
- whileループでは、$ resultを2回(1回は$ resultとして、1回は$ result2として)選択して動作させる必要があります。これらの$ resultのデータベースクエリはまったく同じです:
SELECT ID、name、parentid FROM Categories
結果を取得します。これを一度だけ宣言したいと思います。
すべての良い答えをありがとう。私は、最も簡単で実装が少ないコードアプローチを採用しました。
$result = $connector->query('SELECT ID,name,parentid FROM categories');
// Get an array containing the results.
$parents = array();
while ($row = $connector->fetchArray($result)){
$id = $row['ID'];
$parents[$id] = array('ID' => $row['ID'],'name' => $row['name'],'parentid' => $row['parentid']);
}
foreach ($parents as $id => $row){
$pid=$id;
$arrTmp= array();
do { // iterate through all parents until top is reached
$arrTmp[]=$pid;
$pid = $parents[$pid]['parentid'];
}while ($pid != 0);
$arrTmp = array_reverse($arrTmp);
foreach($arrTmp as $id){
echo $parents[$id]['name'].' -> ';
}
echo '<br>';
}
解決
親IDで階層化を本当に行いたい場合(少数のアイテム/階層にのみ適しています)
コードを少し変更しました(テストしなかったため、構文エラーが発生する可能性があります):
//put all recordsets in an array to save second query
while ($row2 = $connector->fetchArray($result2)){
$id = $row2['ID'];
$parents[$id] = array('name' => $row2['name'],'parent' => $row2['parentid']);
}
// show the tree-structure
foreach ($parents as $id => $row){
$pid = $row['parentid'];
while ($pid != 0){ // iterate through all parents until top is reached
echo $parents[$pid]['name'].' -> ';
$pid = $parents[$pid]['parentid'];
}
echo $parents[$id]['name'].' - ';
echo '<br>';
}
コメントに回答するには:
$parents = array();
$parents[2] = array('ID'=>2,'name'=>'General','parentid'=>0);
$parents[3] = array('ID'=>3,'name'=>'Gadgets','parentid'=>2);
$parents[4] = array('ID'=>4,'name'=>'iPhone','parentid'=>3);
foreach ($parents as $id => $row){
$pid=$id;
$arrTmp= array();
do { // iterate through all parents until top is reached
$arrTmp[]=$pid;
$pid = $parents[$pid]['parentid'];
}while ($pid != 0);
$arrTmp = array_reverse($arrTmp);
foreach($arrTmp as $id){
echo $parents[$id]['name'].' -> ';
}
echo '<br>';
}
印刷:
全般-&gt;
全般-&gt;ガジェット-&gt;
全般-&gt;ガジェット-&gt; iPhone-&gt;
他のヒント
PHPでアイテムをツリーに整理するのではなく、データベースに依頼してください。 階層データに関する記事は非常に優れていることがわかりました。例はあなたのものとほとんど同じです。
編集
隣接モデルを使用してフルツリーを取得するためのSQLは理想的ではありません。記事で説明されているように、小さな階層でもかなり多くの結合が必要です。ネストセットアプローチを使用することはできませんか? SQLは、階層のサイズに関係なく同じままであり、INSERTとDELETEもそれほど難しくないはずです。
OOPの方が簡単かもしれません。 parentIdでクエリを並べ替える
注:listChildrenメソッドと下部の印刷は、正しくリストされていることを示すためのものです。表示が重要であるという質問を解釈しませんでした。
class Element {
public $id;
public $name;
public $parent = null;
public $children = array();
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
public function addChild($element)
{
$this->children[$element->id] = $element;
$element->setParent($this);
}
public function setParent($element)
{
$this->parent = $element;
}
public function hasChildren()
{
return !empty($this->children);
}
public function listChildren()
{
if (empty($this->children)) {
return null;
}
$out = array();
foreach ($this->children as $child) {
$data = $child->id . ':' . $child->name;
$subChildren = $child->listChildren();
if ($subChildren !== null) {
$data .= '[' . $subChildren . ']';
}
$out[] = $data;
}
return implode(',', $out);
}
}
$elements = array();
$noParents = array();
while ($row = $connector->fetchArray($result)) {
$elements[$row['id']] = $element = new Element($row['id'], $row['name']);
if (isset($elements[$row['parent']])) {
$elements[$row['parent']]->addChild($element);
} else {
$noParents[] = $element;
}
}
foreach ($noParents as $element) {
if ($element->hasChildren()) {
echo "Element {$element->id} has children {$element->listChildren()}.\n";
} else {
echo "Element {$element->id} has no children.\n";
}
}
データベースとして PostgreSQL を使用している場合、 connectby ()関数を使用してレコードセットを作成します。
SELECT *
FROM connectby('tableName', 'id', 'parent_id')
AS t(keyid text, parent_keyid text, level int);
私はこの機能が大好きで、コードで常に使用しています。非常に強力な機能を非常に迅速に実行でき、(隣接モデル)のような左/右の値を維持できません。