Nav.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <?php
  2. namespace Luracast\Restler\UI;
  3. use Luracast\Restler\CommentParser;
  4. use Luracast\Restler\Data\Text;
  5. use Luracast\Restler\Restler;
  6. use Luracast\Restler\Routes;
  7. use Luracast\Restler\Scope;
  8. use Luracast\Restler\Util;
  9. /**
  10. * Utility class for automatically creating data to build an navigation interface
  11. * based on available routes that are accessible by the current user
  12. *
  13. * @category Framework
  14. * @package Restler
  15. * @author R.Arul Kumaran <arul@luracast.com>
  16. * @copyright 2010 Luracast
  17. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  18. * @link http://luracast.com/products/restler/
  19. *
  20. */
  21. class Nav
  22. {
  23. protected static $tree = array();
  24. public static $root = 'home';
  25. /**
  26. * @var array all paths beginning with any of the following will be excluded
  27. * from documentation. if an empty string is given it will exclude the root
  28. */
  29. public static $excludedPaths = array('');
  30. /**
  31. * @var array prefix additional menu items with one of the following syntax
  32. * [$path => $text]
  33. * [$path]
  34. * [$path => ['text' => $text, 'url' => $url, 'trail'=> $trail]]
  35. */
  36. public static $prepends = array();
  37. /**
  38. * @var array suffix additional menu items with one of the following syntax
  39. * [$path => $text]
  40. * [$path]
  41. * [$path => ['text' => $text, 'url' => $url, 'trail'=> $trail]]
  42. */
  43. public static $appends = array();
  44. public static $addExtension = true;
  45. protected static $extension = '';
  46. protected static $activeTrail = '';
  47. protected static $url;
  48. public static function get($for = '', $activeTrail = null)
  49. {
  50. if (empty(static::$tree)) {
  51. /** @var Restler $restler */
  52. $restler = Scope::get('Restler');
  53. if (static::$addExtension)
  54. static::$extension = isset($restler->responseFormat)
  55. ? '.' . $restler->responseFormat->getExtension()
  56. : '.html';
  57. static::$url = $restler->getBaseUrl();
  58. if (empty(static::$url))
  59. static::$url = '';
  60. static::$activeTrail = $activeTrail = empty($activeTrail)
  61. ? (empty($restler->url) || $restler->url == 'index'
  62. ? static::$root
  63. : $restler->url
  64. )
  65. : $activeTrail;
  66. if (static::$addExtension)
  67. static::$extension = isset($restler->responseFormat)
  68. ? '.' . $restler->responseFormat->getExtension()
  69. : '.html';
  70. static::addUrls(static::$prepends);
  71. $map = Routes::findAll(
  72. static::$excludedPaths,
  73. array('POST', 'DELETE', 'PUT', 'PATCH'),
  74. $restler->getRequestedApiVersion()
  75. );
  76. foreach ($map as $path => $data) {
  77. foreach ($data as $item) {
  78. $access = $item['access'];
  79. $route = $item['route'];
  80. $url = $route['url'];
  81. if ($access && !Text::contains($url, '{')) {
  82. $label = Util::nestedValue(
  83. $route,
  84. 'metadata',
  85. CommentParser::$embeddedDataName,
  86. 'label'
  87. );
  88. if (!empty($url)) {
  89. $url .= static::$extension;
  90. }
  91. static::add($url, $label);
  92. }
  93. }
  94. }
  95. static::addUrls(static::$appends);
  96. } elseif (empty($activeTrail)) {
  97. $activeTrail = static::$activeTrail;
  98. }
  99. $tree = static::$tree;
  100. $activeTrail = explode('/', $activeTrail);
  101. $nested = & static::nested($tree, $activeTrail);
  102. if (is_array($nested)) {
  103. $nested['active'] = true;
  104. }
  105. if (!empty($for)) {
  106. $for = explode('/', $for);
  107. $tree = static::nested($tree, $for)['children'];
  108. }
  109. return array_filter($tree);
  110. }
  111. protected static function & nested(array & $tree, array $parts)
  112. {
  113. if (!empty($parts)) {
  114. $part = array_shift($parts);
  115. if (empty($tree[$part])) {
  116. return $tree[$part];
  117. } elseif (empty($parts)) {
  118. return static::nested($tree[$part], $parts);
  119. } elseif (!empty($tree[$part]['children'])) {
  120. return static::nested($tree[$part]['children'], $parts);
  121. }
  122. } else {
  123. return $tree;
  124. }
  125. $value = null;
  126. return $value;
  127. }
  128. public static function addUrls(array $urls)
  129. {
  130. foreach ($urls as $url => $label) {
  131. $trail = null;
  132. if (is_array($label)) {
  133. if (isset($label['trail'])) {
  134. $trail = $label['trail'];
  135. }
  136. if (isset($label['url'])) {
  137. $url = $label['url'];
  138. $label = isset($label['label']) ? $label['label'] : null;
  139. } else {
  140. $url = current(array_keys($label));
  141. $label = current($label);
  142. }
  143. }
  144. if (is_numeric($url)) {
  145. $url = $label;
  146. $label = null;
  147. }
  148. static::add($url, $label, $trail);
  149. }
  150. return static::$tree;
  151. }
  152. public static function add($url, $label = null, $trail = null)
  153. {
  154. $r = parse_url($url);
  155. if (is_null($trail)) {
  156. $trail = isset($r['path']) ? $r['path'] : static::$root;
  157. }
  158. //remove / prefix and / suffixes and any extension
  159. $trail = strtok(trim($trail, '/'), '.');
  160. $parts = explode('/', $trail);
  161. if (count($parts) == 1 && empty($parts[0]))
  162. $parts = array(static::$root);
  163. if (isset($r['fragment'])) {
  164. $parts[] = $r['fragment'];
  165. if (is_null($label)) {
  166. $label = Text::title($r['fragment']);
  167. }
  168. }
  169. if (empty($r['scheme'])) {
  170. //relative url found
  171. if (empty($url)) {
  172. $label = Text::title(static::$root);
  173. $url = static::$url;
  174. } else {
  175. $url = static::$url . '/' . ltrim($url, '/');
  176. }
  177. }
  178. if (is_null($label)) {
  179. $label = Text::title(strtok(end($parts), '.'));
  180. }
  181. $r['url'] = $url;
  182. $r['path'] = $trail;
  183. $r['parts'] = $parts;
  184. $r['label'] = $label;
  185. static::build($r);
  186. return $r;
  187. }
  188. public static function build(array $r)
  189. {
  190. $p = & static::$tree;
  191. $parts = $r['parts'];
  192. $last = count($parts) - 1;
  193. foreach ($parts as $i => $part) {
  194. if ($i == $last) {
  195. $p[$part]['text'] = $r['label'];
  196. $p[$part]['href'] = $r['url'];
  197. $p[$part]['class'] = Text::slug($part);
  198. /* dynamically do it at run time instead
  199. if ($r['path'] == static::$activeTrail)
  200. $p[$part]['active'] = true;
  201. */
  202. } elseif (!isset($p[$part])) {
  203. $p[$part] = array();
  204. $p[$part]['text'] = Text::title($part);
  205. $p[$part]['href'] = '#';
  206. $p[$part]['children'] = array();
  207. }
  208. $p = & $p[$part]['children'];
  209. }
  210. }
  211. }