<?php
/*
Name: SB Menu - A PHP Class for Building Menus
File: class.sb_menu.php
License: BSD 3-Clause License <https://opensource.org/licenses/BSD-3-Clause>
Description: A flatfile (look ma! no DB!) based php class to create/modify/save/load/display a menu tree.
Author: https://www.phpclasses.org/browse/author/144301.html
Homepage URL: https://www.phpclasses.org/package/12978-PHP-SB-Menu-A-PHP-Class-for-Building-Menus.html
PHP Version: 8+
Version: 1.0
Long Description:
The SB Menu class is a PHP class that allows for the creation, modification, saving, loading, and display of a menu tree without the need for a database. This class is designed to be simple, efficient, and easily customizable. It uses a flatfile approach, meaning that the menu structure is stored in a text file rather than a database.
'label' (user) and 'id' (generated) are default fields in the base class.
Methods:
save($filename) - saves the menu tree to a file
load($filename) - loads the menu tree from a file
getNodeByField($field, $value) - returns a reference to the node with a field that matches a value
applyCallbackToNode($id, $callback) - applies a callback to a node with a specific id
applyCallbackToNodeByField($field, $value, $callback) - applies a callback to a node with a specific field that matches a value
Categories/Keywords:
Menu Creation
Tree Structure
PHP Class
Extended Class
Flatfile Database
Database-less
No DB
Menu Modification
Menu Manipulation
Callback Function
Node Manipulation
File Handling
Dynamic Data
Tree Root Node
Child Nodes
// include this file
include_once("class.sb_menu_1.0.php");
// example creation... (look at class.sb_menu.test.simple.php for extended class needed to render)
class SimpleTree_Extended extends Tree { ... extended code ( render(), renderNode(), etc ) ... }
// create extended class of Tree and throw in a render and renderNode to customize display based on dynamic data fields
// we pass the name we want for the main root node. In the example, we skip rendering this root node.
$menu = new SimpleTree_Extended(new TreeNode('Main Menu')); // .. or the extended class to seperate the render() method
// now add some menus...
// when menu is created, a root node is created and assigned to $menu->root. This is our main level.
$last_menu = $menu->root->addChild(new TreeNode('Submenu 1'));
$last_menu = $menu->root->addChild(new TreeNode('Submenu 2'));
// another level
$next_level = $last_menu->addChild(new TreeNode('Item 2.1'));
// example adding more data for our extended class to use with a custom render() method
$next_level->data['url'] = "https://www.google.com"; // handled in extended class render
$next_level->data['target'] = "_blank"; // handled in extended class render
// # use a callback to run some code on a specific node via its id (id and label are default fields in base class)
$menu->applyCallbackToNode($s2_id, function($node) {
$node->data['label'] = 'New Label';
$new_submenu = new TreeNode('New Submenu');
$node->addChild($new_submenu);
});
// example usage of applyCallbackToNodeByField($field, $value, $callback)
// (this example changes the label of the node with label 'Submenu 1' to 'New Label')
$menu->applyCallbackToNodeByField('label', 'Submenu 1', function($node) {
$node->data['label'] = 'New Label';
});
// get the reference to the node by a field for modification. (only returns first match)
// example usage of getNodeByField($key, $value)
$s2 = $menu->getNodeByField('label', 'Submenu 2');
$s2_id = $s2->data['id'];
# save (ez) (make sure directory or file is writeable)
$menu->save('menu-simple.txt');
# load (pz)
$menu2 = $menu->load('menu-simple.txt');
// render (display the menu :: see example Tree extended class in class.sb_menu.test.simple.php )
echo $menu->render('sbmenu'); // render defined in extended class
*/
class TreeNode {
public $data;
public $children = [];
public function __construct($data) {
#$this->data = $data;
$this->data['label'] = $data;
$this->data['id'] = uniqid();
}
public function addChild(TreeNode $child) {
$this->children[] = $child;
// return a reference to the created object
return $child;
}
}
class Tree {
public $root;
public function __construct(TreeNode $root) {
$this->root = $root;
}
public function render() {
// extended class for customizing rendering output
return '';
}
private function renderNode(TreeNode $node, $depth)
{
// extended class for customizing (see example in class.sb_menu.test.simple.php)
}
# a function to get a node by a field that matches a value
public function getNodeByField($field, $value) {
return $this->getNodeByFieldHelper($this->root, $field, $value);
}
private function getNodeByFieldHelper($node, $field, $value) {
if (!empty($node->data[$field]) && $node->data[$field] == $value) {
return $node;
}
foreach ($node->children as $child) {
$result = $this->getNodeByFieldHelper($child, $field, $value);
if ($result !== null)
return $result;
}
return null;
}
/*
// example usage of getNodeByField()
$s2 = $menu->getNodeByField('label', 'Submenu 2');
$s2_id = $s2->data['id'];
*/
# a function to apply a callback to node with a specific id in the tree
public function applyCallbackToNode($id, $callback) {
$this->applyCallbackToNodeHelper($this->root, $id, $callback);
}
private function applyCallbackToNodeHelper($node, $id, $callback) {
if ($node->data['id'] == $id) {
$callback($node);
}
foreach ($node->children as $child) {
$this->applyCallbackToNodeHelper($child, $id, $callback);
}
}
/*
// example usage of applyCallbackToNode()
$menu->applyCallbackToNode('id', function($node) {
$node->data['label'] = 'New Label';
});
*/
# callback based off some other field...
public function applyCallbackToNodeByField($field, $value, $callback) {
$this->applyCallbackToNodeByFieldHelper($this->root, $field, $value, $callback);
}
private function applyCallbackToNodeByFieldHelper($node, $field, $value, $callback) {
if ($node->data[$field] == $value) {
$callback($node);
}
foreach ($node->children as $child) {
$this->applyCallbackToNodeByFieldHelper($child, $field, $value, $callback);
}
}
/*
// example usage of applyCallbackToNodeByField()
$menu->applyCallbackToNodeByField('label', 'Submenu 1', function($node) {
$node->data['label'] = 'New Label';
});
*/
# save
public function save($filename) {
$serializedData = serialize($this);
file_put_contents($filename, $serializedData);
}
# load
public static function load($filename) {
$serializedData = file_get_contents($filename);
if ($serializedData !== false) {
$tree = unserialize($serializedData);
if ($tree instanceof Tree) {
return $tree;
}
}
return null;
}
}
// # use a callback to run some code on a specific node via its id
// $menu->applyCallbackToNode($s2_id, function($node) {
// $node->data['label'] = 'New Label';
// $new_submenu = new TreeNode('New Submenu');
// $node->addChild($new_submenu);
// });
?>
|