Guest User

Untitled

a guest
Feb 21st, 2018
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.54 KB | None | 0 0
  1. <?php
  2.  
  3. /**
  4. * Klasse zum Erstellen von Navigationen, v0.1.
  5. *
  6. * @package redaxo\structure
  7. */
  8.  
  9. /*
  10. * Beispiel-Konfiguration einer Haupt-Navigation:
  11. *
  12. * $it = rex_navigation_iterator::factory()
  13. * ->ignoreOfflines(true)
  14. * ;
  15. *
  16. * foreach($it as $navItem) {
  17. * list($ooObj, $depth, $nth, $count) = $navItem;
  18. *
  19. * if ($nth == 1) {
  20. * if ($depth == 1) {
  21. * $class = "nav navbar-nav";
  22. * } else {
  23. * $class = "dropdown";
  24. * }
  25. * echo '<ul class="'. $class .'">';
  26. * }
  27. *
  28. * echo "<li class='rex-navi-depth-". $depth ." rex-nav-". $nth ."nth-child'>";
  29. * echo "<a href='". $ooObj->getUrl() ."'>". $ooObj->getName() ."</a>";
  30. * echo "</li>\n";
  31. *
  32. * if ($nth == $count) {
  33. * echo '</ul>';
  34. * }
  35. * }
  36. *
  37. * Bespiel-Konfiguration einer Seiten-Navigation
  38. *
  39. * $it = rex_navigation_iterator::factory()
  40. * ->startCategory(27)
  41. * ->depthLimit(3)
  42. * ->ignoreOfflines(true)
  43. *
  44. * foreach($it as $navItem) {
  45. * list($ooObj, $depth, $nth, $count) = $navItem;
  46. *
  47. * if ($nth == 1) {
  48. * if ($depth == 1) {
  49. * $class = "nav side-nav";
  50. * } else {
  51. * $class = "";
  52. * }
  53. * echo '<ul class="'. $class .'">';
  54. * }
  55. *
  56. * echo "<li class='rex-navi-depth-". $depth ." rex-nav-". $nth ."nth-child'>";
  57. * echo "<a href='". $ooObj->getUrl() ."'>". $ooObj->getName() ."</a>";
  58. * echo "</li>\n";
  59. *
  60. * if ($nth == $count) {
  61. * echo '</ul>';
  62. * }
  63. * }
  64. *
  65. * Bespiel-Konfiguration einer Breadcrumb-Navigation
  66. *
  67. * $it = rex_navigation_iterator::factory()
  68. * ->activePath(true)
  69. * ->ignoreOfflines(true)
  70. *
  71. * echo '<ul class="breadcrumb-nav">';
  72. * echo '<li><a href="' . rex_getUrl(rex_article::getSiteStartArticleId()) . '">STARTSEITE</a></li>';
  73. * foreach($it as $navItem) {
  74. * list($ooObj, $depth, $nth, $count) = $navItem;
  75. *
  76. * echo "<li>";
  77. * echo "<a href='". $ooObj->getUrl() ."'>". $ooObj->getName() ."</a>";
  78. * echo "</li>\n";
  79. * }
  80. * echo '</ul>';
  81. */
  82.  
  83. class rex_navigation_iterator implements IteratorAggregate
  84. {
  85. use rex_factory_trait;
  86.  
  87. private $startCategory = 0;
  88. private $ignoreOfflines = false;
  89. private $activePath = false;
  90. private $depthLimit = -1; // Wieviele Ebene tief, ab der Startebene
  91. private $path = [];
  92. private $filter = [];
  93.  
  94. private $current_category_id = -1; // Aktuelle Katgorie
  95.  
  96. private function __construct()
  97. {
  98. // nichts zu tun
  99. }
  100.  
  101. /**
  102. * @return static
  103. */
  104. public static function factory()
  105. {
  106. $class = self::getFactoryClass();
  107. return new $class();
  108. }
  109.  
  110. /**
  111. * @param int $categoryId Id der Wurzelkategorie, -1 für alle Kategorien (default)
  112. *
  113. * @return $this
  114. */
  115. public function startCategory($categoryId) {
  116. $this->startCategory = $categoryId;
  117.  
  118. return $this;
  119. }
  120.  
  121. /**
  122. * @param int $limit Anzahl der Ebenen die angezeigt werden sollen, -1 kein Limit (default)
  123. *
  124. * @return $this
  125. */
  126. public function depthLimit($limit) {
  127. $this->depthLimit = $limit;
  128.  
  129. return $this;
  130. }
  131.  
  132. /**
  133. * @param bool $ignoreOfflines FALSE, wenn offline Elemente angezeigt werden (default), sonst TRUE
  134. *
  135. * @return $this
  136. */
  137. public function ignoreOfflines($ignoreOfflines) {
  138. $this->ignoreOfflines = $ignoreOfflines;
  139.  
  140. return $this;
  141. }
  142.  
  143. /**
  144. * @param bool $activePath True, wenn nur Elemente der aktiven Kategorie angezeigt werden sollen, sonst FALSE (default)
  145. *
  146. * @return $this
  147. */
  148. public function activePath($activePath) {
  149. $this->activePath = $activePath;
  150.  
  151. return $this;
  152. }
  153.  
  154. /**
  155. * Fügt einen Filter hinzu.
  156. *
  157. * @param string $metafield Datenbankfeld der Kategorie
  158. * @param mixed $value Wert für den Vergleich
  159. * @param string $type Art des Vergleichs =/</.
  160. * @param int|string $depth "" wenn auf allen Ebenen, wenn definiert, dann wird der Filter nur auf dieser Ebene angewendet
  161. */
  162. public function addFilter($metafield = 'id', $value = '1', $type = '=', $depth = '')
  163. {
  164. $this->filter[] = ['metafield' => $metafield, 'value' => $value, 'type' => $type, 'depth' => $depth];
  165. }
  166.  
  167. public function getIterator()
  168. {
  169. $this->_setActivePath();
  170.  
  171. if ($this->ignoreOfflines) {
  172. $this->addFilter('status', 1, '==');
  173. }
  174.  
  175. yield from ($this->_getNavigation($this->startCategory));
  176. }
  177.  
  178. private function _setActivePath()
  179. {
  180. $article_id = rex_article::getCurrentId();
  181. if (!$OOArt = rex_article::get($article_id)) {
  182. throw new Exception("Unable to determine current article-id");
  183. }
  184.  
  185. $path = trim($OOArt->getPath(), '|');
  186.  
  187. $this->path = [];
  188. if ($path != '') {
  189. $this->path = explode('|', $path);
  190. }
  191.  
  192. $this->current_category_id = $OOArt->getCategoryId();
  193. }
  194.  
  195. private function checkFilter(rex_category $category, $depth)
  196. {
  197. foreach ($this->filter as $f) {
  198. if ($f['depth'] == '' || $f['depth'] == $depth) {
  199. $mf = $category->getValue($f['metafield']);
  200. $va = $f['value'];
  201. switch ($f['type']) {
  202. case '<>':
  203. case '!=':
  204. if ($mf == $va) {
  205. return false;
  206. }
  207. break;
  208. case '>':
  209. if ($mf <= $va) {
  210. return false;
  211. }
  212. break;
  213. case '<':
  214. if ($mf >= $va) {
  215. return false;
  216. }
  217. break;
  218. case '=>':
  219. case '>=':
  220. if ($mf < $va) {
  221. return false;
  222. }
  223. break;
  224. case '=<':
  225. case '<=':
  226. if ($mf > $va) {
  227. return false;
  228. }
  229. break;
  230. case 'regex':
  231. if (!preg_match($va, $mf)) {
  232. return false;
  233. }
  234. break;
  235. case '=':
  236. case '==':
  237. default:
  238. // =
  239. if ($mf != $va) {
  240. return false;
  241. }
  242. }
  243. }
  244. }
  245. return true;
  246. }
  247.  
  248. protected function _getNavigation($category_id, $depth = 1)
  249. {
  250. if ($category_id < 1) {
  251. $nav_obj = rex_category::getRootCategories();
  252. } else {
  253. $nav_obj = rex_category::get($category_id)->getChildren();
  254. }
  255.  
  256. $checked = [];
  257. foreach ($nav_obj as $nav) {
  258. if ($this->checkFilter($nav, $depth)) {
  259. $checked[] = $nav;
  260. }
  261. }
  262.  
  263. $nth = 1;
  264. foreach($checked as $nav) {
  265. if (!$this->activePath || $this->activePath && ($nav->getId() == $this->current_category_id || in_array($nav->getId(), $this->path))
  266. ) {
  267. yield [$nav, $depth, $nth, count($checked)];
  268.  
  269. ++$depth;
  270. if ($this->depthLimit >= $depth || $this->depthLimit < 0) {
  271. yield from ($this->_getNavigation($nav->getId(), $depth));
  272. }
  273. --$depth;
  274.  
  275. $nth++;
  276. }
  277. }
  278. }
  279. }
Add Comment
Please, Sign In to add comment