Files
server/usr/share/psa-pear/pear/php/Horde/Tree.php
2026-01-07 20:52:11 +01:00

271 lines
7.9 KiB
PHP

<?php
/**
* The Horde_Tree class provides a tree view of hierarchical
* information. It allows for expanding/collapsing of branches.
*
* Copyright 2003-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Marko Djukic <marko@oblo.com>
* @author Michael Slusarz <slusarz@horde.org>
* @author Jan Schneider <jan@horde.org>
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Tree
*/
class Horde_Tree implements Countable
{
/**
* The preceding text, before the Horde_Tree instance name, used for
* collapse/expand submissions.
*/
const TOGGLE = 'ht_toggle_';
/**
* The name of this instance.
*
* @var string
*/
public $instance;
/**
* Callbacks used to store session data.
*
* @var array
*/
protected $_session = array();
/**
* An array containing all the tree nodes.
*
* @var array
*/
protected $_nodes = array();
/**
* The top-level nodes in the tree.
*
* @var array
*/
protected $_root_nodes = array();
/**
* Constructor.
*
* @param string $name The name of this tree instance.
* @param array $session Callbacks used to store session data. Must define
* two keys: 'get' and 'set'. Function definitions:
* (string) = get([string - Instance], [string - ID]);
* set([string - Instance], [string - ID], [boolean - value]);
* DEFAULT: No session storage
*/
public function __construct($name, $session = array())
{
$this->instance = $name;
$this->_session = $session;
}
/**
* Adds a node to the node tree array.
*
* @param array $node A hash with node properties:
* - id: (string) The unique node id.
* - parent: (string) The parent's unique node id.
* - label: (string) The text label for the node.
* - expanded: (boolean) Is this level expanded or not.
* - params: (array) Any other parameters to set
* (see addNodeParams() of the renderers
* for full details).
*/
public function addNode($node)
{
$node = array_merge(
array('parent' => null,
'expanded' => true,
'params' => array()),
$node);
$nodeid = $this->nodeId($node['id']);
$expanded = $node['expanded'];
if ($this->_session) {
$toggle_id = Horde_Util::getFormData(Horde_Tree::TOGGLE . $this->instance);
if ($nodeid == $toggle_id) {
/* We have a URL toggle request for this node. */
$expanded = (call_user_func($this->_session['get'], $this->instance, $node['id']) !== null)
/* Use session state if it is set. */
? !call_user_func($this->_session['get'], $this->instance, $nodeid)
/* Otherwise use what was passed through the function. */
: !$node['expanded'];
call_user_func($this->_session['set'], $this->instance, $nodeid, $expanded);
} elseif (($exp_get = call_user_func($this->_session['get'], $this->instance, $nodeid)) !== null) {
/* If we have a saved session state use it. */
$expanded = $exp_get;
}
}
$this->_nodes[$nodeid]['label'] = $node['label'];
$this->_nodes[$nodeid]['expanded'] = $expanded;
/* If any params included here add them now. */
if (!empty($node['params'])) {
$this->addNodeParams($node['id'], $node['params']);
}
if (is_null($node['parent'])) {
if (!in_array($nodeid, $this->_root_nodes)) {
$this->_root_nodes[] = $nodeid;
}
} else {
$parent = $this->nodeId($node['parent']);
if (empty($this->_nodes[$parent]['children'])) {
$this->_nodes[$parent]['children'] = array();
}
if (!in_array($nodeid, $this->_nodes[$parent]['children'])) {
$this->_nodes[$parent]['children'][] = $nodeid;
}
}
}
/**
* Adds additional parameters to a node.
*
* @param string $id The unique node id.
* @param array $params Parameters to set (key/value pairs).
*/
public function addNodeParams($id, $params = array())
{
$id = $this->nodeId($id);
if (!is_array($params)) {
$params = array($params);
}
foreach ($params as $p_id => $p_val) {
// Set only non-null params.
if (!is_null($p_val)) {
// TODO: In H6 don't convert to string here.
$this->_nodes[$id][$p_id] = is_object($p_val)
? strval($p_val)
: $p_val;
}
}
}
/**
* Returns the root node IDs.
*
* @return array The root nodes.
*/
public function getRootNodes()
{
return $this->_root_nodes;
}
/**
* Returns the nodes of the tree.
*
* @return array The nodes with IDs as keys and node hashes as values.
*/
public function getNodes()
{
$this->_buildIndents($this->_root_nodes);
return $this->_nodes;
}
/**
* Sorts the tree by the specified node property.
*
* @param string $criteria The node property to sort by.
* @param integer $id Used internally for recursion.
*/
public function sort($criteria, $id = -1)
{
if (!isset($this->_nodes[$id]['children'])) {
return;
}
if ($criteria == 'key') {
ksort($this->_nodes[$id]['children']);
} else {
$this->_sortCriteria = $criteria;
usort($this->_nodes[$id]['children'], array($this, 'sortHelper'));
}
foreach ($this->_nodes[$id]['children'] as $child) {
$this->sort($criteria, $child);
}
}
/**
* Helper method for sort() to compare two tree elements.
*/
public function sortHelper($a, $b)
{
if (!isset($this->_nodes[$a][$this->_sortCriteria])) {
return 1;
}
if (!isset($this->_nodes[$b][$this->_sortCriteria])) {
return -1;
}
return strcoll($this->_nodes[$a][$this->_sortCriteria],
$this->_nodes[$b][$this->_sortCriteria]);
}
/**
* Returns whether the specified node is currently expanded.
*
* @param mixed $id The unique node id.
*
* @return boolean True if the specified node is expanded.
*/
public function isExpanded($id)
{
$id = $this->nodeId($id);
return isset($this->_nodes[$id])
? $this->_nodes[$id]['expanded']
: false;
}
/**
* Set the indent level for each node in the tree.
*
* @param array $nodes TODO
* @param integer $indent TODO
*/
protected function _buildIndents($nodes, $indent = 0)
{
foreach ($nodes as $id) {
$this->_nodes[$id]['indent'] = $indent;
if (!empty($this->_nodes[$id]['children'])) {
$this->_buildIndents($this->_nodes[$id]['children'], $indent + 1);
}
}
}
/**
* Returns the escaped node ID.
*
* @param string $id Node ID.
*
* @return string Escaped node ID.
*/
public function nodeId($id)
{
return rawurlencode($id);
}
/* Countable methods. */
public function count()
{
return count($this->_nodes);
}
}