ユーザーがナビゲーションアイテムの順序を変更できるサイトを作成しています。ただし、ナビゲーションアイテムはさまざまなソースから動的に読み込まれるため、ナビゲーションアイテムの数や、期待できるアイテムがわかりません。私が知っているのは、次のような複数のファイルがあることだけです。
return array(
array('Google', 'http://www.google.com'),
array('StackOverflow', 'http://www.stackoverflow.com',
array(
array('Contact', 'contact.html'),
array('Test', 'test.html')
)
),
array('Home', 'index.html')
);
ご覧のとおり、これはメニューアイテムのツリーであり、サブアイテムは任意のレイヤーの深さにすることができます。これらの配列はすべて1つのナビゲーションメニューにまとめる必要があり、ファイルは頻繁に変更される可能性があります。明らかに、アイテムをユーザーが並べ替える必要がない場合、これは難しいことではありません。しかし、その機能では、効率的な解決策を思い付くことができません。特に、ビジネスロジックとプレゼンテーションを混在させたくないので。
現在、私は次のコードを持っています(少し簡略化されています):
コントローラ:
$view = new \View('navigation.html');
$navigation = new mappers\Navigation();
$view->items = $navigation->fetchAll();
mapper \ Navigation:
class Navigation {
private $type;
// Create a tree from:
// $items: array(title, url, children); title = string; url = array / null / string; children = array / null
// $order: url => array(position, children); position = integer; children = array / null
// Pass $order by reference so that found items can be added
private function buildTree($items, &$order) {
$tree = array();
foreach ($items as $item) {
$uri = $item[1];
// Get order
if (isset($order[$uri])) {
$position = $order[$uri][0];
$childrenOrder = $order[$uri][1];
} else {
$order[$uri] = array(count($order), array()); // Create the item for this uri
$position = $order[$uri][0];
$childrenOrder = $order[$uri][1];
}
// Get children tree if specified
if (isset($item[2])) {
$children = $this->buildTree($item[2], $childrenOrder);
} else {
$children = null;
}
$tree[$position] = array($item[0], $uri, $children);
}
ksort($tree);
return $tree;
}
public function fetchAll() {
$items = array();
foreach (new \FilesystemIterator('navigation', \FilesystemIterator::SKIP_DOTS) as $file) {
if ($file->isDir()) { // Ignore everything which isn't a directory
$array = new \PersistentArray($file->getPathname() . '/items.php');
foreach ($array as $item) {
$items[] = $item;
}
}
}
// Load the order settings
$order = new \PersistentArray('order.php');
// Build a tree of all navigation items in the right order
$tree = $this->buildTree($items, $order);
Save the order settings (have been changed, since $order is passed by reference)
$order->save();
return $tree;
}
}
Navigation.html:
$echo = '';
$echo = function($item) use($echo) { // Use a closure, in order not to pollute the global namespace
printf('<li><a href="%s">%s</a>', $item[1], $item[0]);
if (!empty($item[2])) {
printf('<ul>%s</ul>', $echo($item[2]));
}
echo '</li>';
}
?>
<ul>
<?php foreach ($items as $item) {
$echo($item);
} ?>
</ul>
このコードPersistentArray
には、ファイルから配列をロードする単純なクラスがあります。このクラスのオブジェクトは、他の配列と同じようにアクセスできます。save()
また、配列をファイルに書き込むメソッドも提供します。このファイルは、後でこのクラスを使用して再度開くことができます。
上記のコードは機能しますが、私にはかなり非効率に見える方法で機能します。このコードには4つのループがあります!言うまでもなく、参照とクロージャーはかなり「ハッキー」です。しかし、私はこの問題を解決するためのより良い方法を思い付くことができませんでした。
だから私の質問は:これを行うためのより良い方法を思い付くことができますか?よく使う方法はありますか?フォアハンドありがとう!
保存された順序配列の例は次のとおりです。
return array(
'index.html' => array(
0 => 0,
1 => array(
'page1.html' => array(
0 => 0,
1 => array()
),
'page2.html' => array(
0 => 1,
1 => array()
)
)
),
'test.html' => array(
0 => 1,
1 => array()
)
);