/Tree/src/visitors/xhtml.php

https://github.com/oluwalataz/zetacomponents · PHP · 264 lines · 128 code · 22 blank · 114 comment · 14 complexity · 422a6bc1725cb54de4402ddb50326f10 MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the ezcTreeVisitorXHTML class.
  4. *
  5. * Licensed to the Apache Software Foundation (ASF) under one
  6. * or more contributor license agreements. See the NOTICE file
  7. * distributed with this work for additional information
  8. * regarding copyright ownership. The ASF licenses this file
  9. * to you under the Apache License, Version 2.0 (the
  10. * "License"); you may not use this file except in compliance
  11. * with the License. You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing,
  16. * software distributed under the License is distributed on an
  17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  18. * KIND, either express or implied. See the License for the
  19. * specific language governing permissions and limitations
  20. * under the License.
  21. *
  22. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  23. * @version //autogentag//
  24. * @filesource
  25. * @package Tree
  26. */
  27. /**
  28. * An implementation of the ezcTreeVisitor interface that generates
  29. * an XHTML representatation of a tree structure.
  30. *
  31. * <code>
  32. * <?php
  33. * $options = new ezcTreeVisitorXHTMLOptions;
  34. * $options->xmlId = 'menu_tree';
  35. * $visitor = new ezcTreeVisitorXHTML( $options );
  36. * $tree->accept( $visitor );
  37. * echo (string) $visitor; // print the plot
  38. * ?>
  39. * </code>
  40. *
  41. * Shows (something like):
  42. * <code>
  43. * </code>
  44. *
  45. * @package Tree
  46. * @version //autogentag//
  47. */
  48. class ezcTreeVisitorXHTML implements ezcTreeVisitor
  49. {
  50. /**
  51. * Holds all the edges of the graph.
  52. *
  53. * @var array(string=>array(string))
  54. */
  55. protected $edges = array();
  56. /**
  57. * Holds the root ID.
  58. *
  59. * @var string
  60. */
  61. protected $root = null;
  62. /**
  63. * Whether the XML ID has been set.
  64. *
  65. * @var bool
  66. */
  67. private $treeIdSet;
  68. /**
  69. * Holds the options for this class
  70. *
  71. * @var ezcTreeVisitorXHTMLOptions
  72. */
  73. public $options;
  74. /**
  75. * Constructs a new ezcTreeVisitorXHTML visualizer.
  76. *
  77. * @param ezcTreeVisitorXHTMLOptions $options
  78. */
  79. public function __construct( ezcTreeVisitorXHTMLOptions $options = null )
  80. {
  81. if ( $options === null )
  82. {
  83. $this->options = new ezcTreeVisitorXHTMLOptions;
  84. }
  85. else
  86. {
  87. $this->options = $options;
  88. }
  89. }
  90. /**
  91. * Formats a node's data.
  92. *
  93. * It is just a simple method, that provide an easy way to change the way
  94. * on how data is formatted when this class is extended. The data is passed
  95. * in the $data argument, and whether the node should be highlighted is
  96. * passed in the $highlight argument.
  97. *
  98. * @param mixed $data
  99. * @param bool $highlight
  100. * @return string
  101. */
  102. protected function formatData( $data, $highlight )
  103. {
  104. $data = htmlspecialchars( $data );
  105. return $highlight ? "<div class=\"highlight\">$data</div>" : $data;
  106. }
  107. /**
  108. * Visits the node and sets the the member variables according to the node
  109. * type and contents.
  110. *
  111. * @param ezcTreeVisitable $visitable
  112. * @return bool
  113. */
  114. public function visit( ezcTreeVisitable $visitable )
  115. {
  116. if ( $visitable instanceof ezcTree )
  117. {
  118. }
  119. if ( $visitable instanceof ezcTreeNode )
  120. {
  121. if ( $this->root === null )
  122. {
  123. $this->root = $visitable->id;
  124. }
  125. $parent = $visitable->fetchParent();
  126. if ( $parent )
  127. {
  128. $this->edges[$parent->id][] = array( $visitable->id, $visitable->data, $visitable->fetchPath() );
  129. }
  130. }
  131. return true;
  132. }
  133. /**
  134. * Formats the path to the node
  135. *
  136. * @param array $child
  137. */
  138. protected function formatPath( $child )
  139. {
  140. $path = $child[2]->nodes;
  141. if ( !$this->options->displayRootNode )
  142. {
  143. array_shift( $path );
  144. }
  145. if ( $this->options->selectedNodeLink )
  146. {
  147. $slice = array_slice( $path, -1 );
  148. $path = htmlspecialchars( $this->options->basePath . '/' . array_pop( $slice ) );
  149. }
  150. else
  151. {
  152. $path = htmlspecialchars( $this->options->basePath . '/' . join( '/', $path ) );
  153. }
  154. return $path;
  155. }
  156. /**
  157. * Loops over the children of the node with ID $id.
  158. *
  159. * This methods loops over all the node's children and adds the correct
  160. * layout for each node depending on the state that is collected in the
  161. * $level and $levelLast variables.
  162. *
  163. * @param string $id
  164. * @param int $level
  165. * @param array(int=>bool) $levelLast
  166. *
  167. * @return string
  168. */
  169. protected function doChildren( $id, $level = 0, $levelLast = array() )
  170. {
  171. $text = '';
  172. $children = $this->edges[$id];
  173. $numChildren = count( $children );
  174. if ( $numChildren > 0 )
  175. {
  176. $text .= str_repeat( ' ', $level + 1 );
  177. $idPart = '';
  178. if ( !$this->treeIdSet )
  179. {
  180. $idPart = $this->options->xmlId ? " id=\"{$this->options->xmlId}\"" : '';
  181. $this->treeIdSet = true;
  182. }
  183. $text .= "<ul{$idPart}>\n";
  184. foreach ( $children as $child )
  185. {
  186. $text .= str_repeat( ' ', $level + 2 );
  187. $path = $this->formatPath( $child );
  188. $data = $this->formatData( $child[1], in_array( $child[0], $this->options->highlightNodeIds ) );
  189. $linkStart = $linkEnd = '';
  190. if ( $this->options->addLinks )
  191. {
  192. $linkStart = "<a href=\"{$path}\">";
  193. $linkEnd = "</a>";
  194. }
  195. $highlightPart = '';
  196. if ( in_array( $child[0], $this->options->subtreeHighlightNodeIds ) )
  197. {
  198. $highlightPart = ' class="highlight"';
  199. }
  200. if ( isset( $this->edges[$child[0]] ) )
  201. {
  202. $text .= "<li{$highlightPart}>{$linkStart}{$data}{$linkEnd}\n";
  203. $text .= $this->doChildren( $child[0], $level + 2, $levelLast );
  204. $text .= str_repeat( ' ', $level + 2 );
  205. $text .= "</li>\n";
  206. }
  207. else
  208. {
  209. $text .= "<li{$highlightPart}>{$linkStart}{$data}{$linkEnd}</li>\n";
  210. }
  211. }
  212. $text .= str_repeat( ' ', $level + 1 );
  213. $text .= "</ul>\n";
  214. }
  215. return $text;
  216. }
  217. /**
  218. * Returns the XHTML representation of a tree.
  219. *
  220. * @return string
  221. * @ignore
  222. */
  223. public function __toString()
  224. {
  225. $tree = '';
  226. $this->treeIdSet = false;
  227. if ( $this->options->displayRootNode )
  228. {
  229. $idPart = $this->options->xmlId ? " id=\"{$this->options->xmlId}\"" : '';
  230. $tree .= "<ul{$idPart}>\n";
  231. $tree .= "<li>{$this->root}</li>\n";
  232. $this->treeIdSet = true;
  233. }
  234. $tree .= $this->doChildren( $this->root );
  235. if ( $this->options->displayRootNode )
  236. {
  237. $tree .= "</ul>\n";
  238. }
  239. return $tree;
  240. }
  241. }
  242. ?>