Overview

Packages

  • Tree

Classes

  • Horde_Tree
  • Horde_Tree_Base
  • Horde_Tree_Exception
  • Horde_Tree_Html
  • Horde_Tree_Jquerymobile
  • Horde_Tree_Select
  • Horde_Tree_Simplehtml
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Horde_Tree_Base:: class provides the abstract interface that all
  4:  * drivers must derive from.
  5:  *
  6:  * Copyright 2010-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * See the enclosed file COPYING for license information (LGPL). If you
  9:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 10:  *
 11:  * @author   Michael Slusarz <slusarz@horde.org>
 12:  * @category Horde
 13:  * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
 14:  * @package  Tree
 15:  */
 16: abstract class Horde_Tree_Base implements Countable
 17: {
 18:     /**
 19:      * Allowed parameters for nodes.
 20:      *
 21:      * @var array
 22:      */
 23:     protected $_allowed = array();
 24: 
 25:     /**
 26:      * The name of this instance.
 27:      *
 28:      * @var string
 29:      */
 30:     protected $_instance = null;
 31: 
 32:     /**
 33:      * Hash with header information.
 34:      *
 35:      * @var array
 36:      */
 37:     protected $_header = array();
 38: 
 39:     /**
 40:      * An array containing all the tree nodes.
 41:      *
 42:      * @var array
 43:      */
 44:     protected $_nodes = array();
 45: 
 46:     /**
 47:      * The top-level nodes in the tree.
 48:      *
 49:      * @var array
 50:      */
 51:     protected $_root_nodes = array();
 52: 
 53:     /**
 54:      * Keep count of how many extra columns there are on the left side
 55:      * of the node.
 56:      *
 57:      * @var integer
 58:      */
 59:     protected $_colsLeft = 0;
 60: 
 61:     /**
 62:      * Keep count of how many extra columns there are on the right side
 63:      * of the node.
 64:      *
 65:      * @var integer
 66:      */
 67:     protected $_colsRight = 0;
 68: 
 69:     /**
 70:      * Option values.
 71:      *
 72:      * @var array
 73:      */
 74:     protected $_options = array(
 75:         'lines' => true
 76:     );
 77: 
 78:     /**
 79:      * Stores the sorting criteria temporarily.
 80:      *
 81:      * @var string
 82:      */
 83:     protected $_sortCriteria;
 84: 
 85:     /**
 86:      * Should the tree be rendered statically?
 87:      *
 88:      * @var boolean
 89:      */
 90:     protected $_static = false;
 91: 
 92:     /**
 93:      * Constructor.
 94:      *
 95:      * @param string $name   The name of this tree instance.
 96:      * @param array $params  Additional parameters.
 97:      * <pre>
 98:      * session - (array) Callbacks used to store session data. Must define
 99:      *           two keys: 'get' and 'set'. Function definitions:
100:      *           (string) = get([string - Instance], [string - ID]);
101:      *           set([string - Instance], [string - ID], [boolean - value]);
102:      *           DEFAULT: No session storage
103:      * </pre>
104:      */
105:     public function __construct($name, array $params = array())
106:     {
107:         $this->_instance = $name;
108:         $this->setOption($params);
109:     }
110: 
111:     /**
112:      * Provide a simpler renderer to fallback to.
113:      *
114:      * @return string  The next best renderer.
115:      * @throws Horde_Tree_Exception
116:      */
117:     public function fallback()
118:     {
119:         throw new Horde_Tree_Exception('No fallback renderer found.');
120:     }
121: 
122:     /**
123:      * Returns the tree.
124:      *
125:      * @param boolean $static  If true the tree nodes can't be expanded and
126:      *                         collapsed and the tree gets rendered expanded.
127:      *
128:      * @return string  The HTML code of the rendered tree.
129:      */
130:     abstract public function getTree($static = false);
131: 
132:     /**
133:      * Renders the tree.
134:      *
135:      * @param boolean $static  If true the tree nodes can't be expanded and
136:      *                         collapsed and the tree gets rendered expanded.
137:      */
138:     public function renderTree($static = false)
139:     {
140:         echo $this->getTree($static);
141:     }
142: 
143:     /**
144:      * Sets an option.
145:      *
146:      * @param mixed $option  The option name -or- an array of option
147:      *                       name/value pairs. See constructor for available
148:      *                       options.
149:      * @param mixed $value   The option's value.
150:      */
151:     public function setOption($options, $value = null)
152:     {
153:         if (!is_array($options)) {
154:             $options = array($options => $value);
155:         }
156: 
157:         foreach ($options as $option => $value) {
158:             $this->_options[$option] = $value;
159:         }
160:     }
161: 
162:     /**
163:      * Gets an option's value.
164:      *
165:      * @param string $option  The name of the option to fetch.
166:      *
167:      * @return mixed  The option's value.
168:      */
169:     public function getOption($option)
170:     {
171:         return isset($this->_options[$option])
172:             ? $this->_options[$option]
173:             : null;
174:     }
175: 
176:     /**
177:      * Adds a node to the node tree array.
178:      *
179:      * @param string $id          The unique node id.
180:      * @param string $parent      The parent's unique node id.
181:      * @param string $label       The text label for the node.
182:      * @param string $indent      Deprecated, this is calculated automatically
183:      *                            based on the parent node.
184:      * @param boolean $expanded   Is this level expanded or not.
185:      * @param array $params       Any other parameters to set (@see
186:      *                            self::addNodeParams() for full details).
187:      * @param array $extra_right  Any other columns to display to the right of
188:      *                            the tree.
189:      * @param array $extra_left   Any other columns to display to the left of
190:      *                            the tree.
191:      */
192:     public function addNode($id, $parent, $label, $indent = null,
193:                             $expanded = true, $params = array(),
194:                             $extra_right = array(), $extra_left = array())
195:     {
196:         $nodeid = $this->_nodeId($id);
197: 
198:         if ($session = $this->getOption('session')) {
199:             $toggle_id = Horde_Util::getFormData(Horde_Tree::TOGGLE . $this->_instance);
200: 
201:             if ($nodeid == $toggle_id) {
202:                 /* We have a URL toggle request for this node. */
203:                 $expanded = (call_user_func($session['get'], $this->_instance, $id) !== null)
204:                     /* Use session state if it is set. */
205:                     ? !call_user_func($session['get'], $this->_instance, $nodeid)
206:                     /* Otherwise use what was passed through the function. */
207:                     : !$expanded;
208:                 call_user_func($session['set'], $this->_instance, $nodeid, $expanded);
209:             } elseif (($exp_get = call_user_func($session['get'], $this->_instance, $nodeid)) !== null) {
210:                 /* If we have a saved session state use it. */
211:                 $expanded = $exp_get;
212:             }
213:         }
214: 
215:         $this->_nodes[$nodeid]['label'] = $label;
216:         $this->_nodes[$nodeid]['expanded'] = $expanded;
217: 
218:         /* If any params included here add them now. */
219:         if (!empty($params)) {
220:             $this->addNodeParams($id, $params);
221:         }
222: 
223:         /* If any extra columns included here add them now. */
224:         if (!empty($extra_right)) {
225:             $this->addNodeExtra($id, Horde_Tree::EXTRA_RIGHT, $extra_right);
226:         }
227:         if (!empty($extra_left)) {
228:             $this->addNodeExtra($id, Horde_Tree::EXTRA_LEFT, $extra_left);
229:         }
230: 
231:         if (is_null($parent)) {
232:             if (!in_array($nodeid, $this->_root_nodes)) {
233:                 $this->_root_nodes[] = $nodeid;
234:             }
235:         } else {
236:             $parent = $this->_nodeId($parent);
237:             if (empty($this->_nodes[$parent]['children'])) {
238:                 $this->_nodes[$parent]['children'] = array();
239:             }
240:             if (!in_array($nodeid, $this->_nodes[$parent]['children'])) {
241:                 $this->_nodes[$parent]['children'][] = $nodeid;
242:             }
243:         }
244:     }
245: 
246:     /**
247:      * Adds additional parameters to a node.
248:      *
249:      * @param string $id     The unique node id.
250:      * @param array $params  Parameters to set (key/value pairs).
251:      */
252:     public function addNodeParams($id, $params = array())
253:     {
254:         $id = $this->_nodeId($id);
255: 
256:         if (!is_array($params)) {
257:             $params = array($params);
258:         }
259: 
260:         foreach ($params as $p_id => $p_val) {
261:             // Set only allowed and non-null params.
262:             if (!is_null($p_val) && in_array($p_id, $this->_allowed)) {
263:                 $this->_nodes[$id][$p_id] = is_object($p_val)
264:                     ? strval($p_val)
265:                     : $p_val;
266:             }
267:         }
268:     }
269: 
270:     /**
271:      * Adds extra columns to be displayed to the side of the node.
272:      *
273:      * @param mixed $id      The unique node id.
274:      * @param integer $side  Which side to place the extra columns on.
275:      * @param array $extra   Extra columns to display.
276:      */
277:     public function addNodeExtra($id, $side, $extra)
278:     {
279:         $id = $this->_nodeId($id);
280: 
281:         if (!is_array($extra)) {
282:             $extra = array($extra);
283:         }
284: 
285:         $col_count = count($extra);
286: 
287:         switch ($side) {
288:         case Horde_Tree::EXTRA_LEFT:
289:             $this->_nodes[$id]['extra'][Horde_Tree::EXTRA_LEFT] = $extra;
290:             if ($col_count > $this->_colsLeft) {
291:                 $this->_colsLeft = $col_count;
292:             }
293:             break;
294: 
295:         case Horde_Tree::EXTRA_RIGHT:
296:             $this->_nodes[$id]['extra'][Horde_Tree::EXTRA_RIGHT] = $extra;
297:             if ($col_count > $this->_colsRight) {
298:                 $this->_colsRight = $col_count;
299:             }
300:             break;
301:         }
302:     }
303: 
304:     /**
305:      * Sorts the tree by the specified node property.
306:      *
307:      * @param string $criteria  The node property to sort by.
308:      * @param integer $id       Used internally for recursion.
309:      */
310:     public function sort($criteria, $id = -1)
311:     {
312:         if (!isset($this->_nodes[$id]['children'])) {
313:             return;
314:         }
315: 
316:         if ($criteria == 'key') {
317:             ksort($this->_nodes[$id]['children']);
318:         } else {
319:             $this->_sortCriteria = $criteria;
320:             usort($this->_nodes[$id]['children'], array($this, 'sortHelper'));
321:         }
322: 
323:         foreach ($this->_nodes[$id]['children'] as $child) {
324:             $this->sort($criteria, $child);
325:         }
326:     }
327: 
328:     /**
329:      * Helper method for sort() to compare two tree elements.
330:      */
331:     public function sortHelper($a, $b)
332:     {
333:         if (!isset($this->_nodes[$a][$this->_sortCriteria])) {
334:             return 1;
335:         }
336: 
337:         if (!isset($this->_nodes[$b][$this->_sortCriteria])) {
338:             return -1;
339:         }
340: 
341:         return strcoll($this->_nodes[$a][$this->_sortCriteria],
342:                        $this->_nodes[$b][$this->_sortCriteria]);
343:     }
344: 
345:     /**
346:      * Returns whether the specified node is currently expanded.
347:      *
348:      * @param mixed $id  The unique node id.
349:      *
350:      * @return boolean  True if the specified node is expanded.
351:      */
352:     public function isExpanded($id)
353:     {
354:         $id = $this->_nodeId($id);
355: 
356:         return isset($this->_nodes[$id])
357:             ? $this->_nodes[$id]['expanded']
358:             : false;
359:     }
360: 
361:     /**
362:      * Adds column headers to the tree table.
363:      *
364:      * @param array $header  An array containing hashes with header
365:      *                       information.
366:      */
367:     public function setHeader($header)
368:     {
369:         $this->_header = $header;
370:     }
371: 
372:     /**
373:      * Set the indent level for each node in the tree.
374:      *
375:      * @param array $nodes     TODO
376:      * @param integer $indent  TODO
377:      */
378:     protected function _buildIndents($nodes, $indent = 0)
379:     {
380:         foreach ($nodes as $id) {
381:             $this->_nodes[$id]['indent'] = $indent;
382:             if (!empty($this->_nodes[$id]['children'])) {
383:                 $this->_buildIndents($this->_nodes[$id]['children'], $indent + 1);
384:             }
385:         }
386:     }
387: 
388:     /**
389:      * Check the current environment to see if we can render the tree.
390:      *
391:      * @return boolean  Whether or not this backend will function.
392:      */
393:     public function isSupported()
394:     {
395:         return true;
396:     }
397: 
398:     /**
399:      * Returns the escaped node ID.
400:      *
401:      * @param string $id  Node ID.
402:      *
403:      * @return string  Escaped node ID.
404:      */
405:     protected function _nodeId($id)
406:     {
407:         return rawurlencode($id);
408:     }
409: 
410:     /* Countable methods. */
411: 
412:     public function count()
413:     {
414:         return count($this->_nodes);
415:     }
416: 
417: }
418: 
API documentation generated by ApiGen