1 <?php
2
3 4 5 6 7
8
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
33
34 class rex_navigation
35 {
36 use rex_factory_trait;
37
38 private $depth;
39 private $open;
40 private $path = [];
41 private $classes = [];
42 private $linkclasses = [];
43 private $filter = [];
44 private $callbacks = [];
45
46 private $current_article_id = -1;
47 private $current_category_id = -1;
48
49 private function __construct()
50 {
51
52 }
53
54 55 56
57 public static function factory()
58 {
59 $class = self::getFactoryClass();
60 return new $class();
61 }
62
63 64 65 66 67 68 69 70 71 72
73 public function get($category_id = 0, $depth = 3, $open = false, $ignore_offlines = false)
74 {
75 if (!$this->_setActivePath()) {
76 return false;
77 }
78
79 $this->depth = $depth;
80 $this->open = $open;
81 if ($ignore_offlines) {
82 $this->addFilter('status', 1, '==');
83 }
84
85 return $this->_getNavigation($category_id);
86 }
87
88 89 90
91 public function show($category_id = 0, $depth = 3, $open = false, $ignore_offlines = false)
92 {
93 echo $this->get($category_id, $depth, $open, $ignore_offlines);
94 }
95
96 97 98 99 100 101 102 103 104
105 public function getBreadcrumb($startPageLabel, $includeCurrent = false, $category_id = 0)
106 {
107 if (!$this->_setActivePath()) {
108 return false;
109 }
110
111 $path = $this->path;
112
113 $i = 1;
114 $lis = '';
115
116 if ($startPageLabel) {
117 $lis .= '<li class="rex-lvl' . $i . '"><a href="' . rex_getUrl(rex_article::getSiteStartArticleId()) . '">' . rex_escape($startPageLabel) . '</a></li>';
118 ++$i;
119
120
121 if (isset($path[0]) && $path[0] == rex_article::getSiteStartArticleId()) {
122 unset($path[0]);
123 }
124 }
125
126 $show = !$category_id;
127 foreach ($path as $pathItem) {
128 if (!$show) {
129 if ($pathItem == $category_id) {
130 $show = true;
131 } else {
132 continue;
133 }
134 }
135
136 $cat = rex_category::get($pathItem);
137 $lis .= '<li class="rex-lvl' . $i . '"><a href="' . $cat->getUrl() . '">' . rex_escape($cat->getName()) . '</a></li>';
138 ++$i;
139 }
140
141 if ($includeCurrent) {
142 if ($art = rex_article::get($this->current_article_id)) {
143 if (!$art->isStartArticle()) {
144 $lis .= '<li class="rex-lvl' . $i . '">' . rex_escape($art->getName()) . '</li>';
145 }
146 } else {
147 $cat = rex_category::get($this->current_article_id);
148 $lis .= '<li class="rex-lvl' . $i . '">' . rex_escape($cat->getName()) . '</li>';
149 }
150 }
151
152 return '<ul class="rex-breadcrumb">' . $lis . '</ul>';
153 }
154
155 156 157
158 public function showBreadcrumb($startPageLabel = false, $includeCurrent = false, $category_id = 0)
159 {
160 echo $this->getBreadcrumb($startPageLabel, $includeCurrent, $category_id);
161 }
162
163 public function setClasses($classes)
164 {
165 $this->classes = $classes;
166 }
167
168 public function setLinkClasses($classes)
169 {
170 $this->linkclasses = $classes;
171 }
172
173 174 175 176 177 178 179 180
181 public function addFilter($metafield = 'id', $value = '1', $type = '=', $depth = '')
182 {
183 $this->filter[] = ['metafield' => $metafield, 'value' => $value, 'type' => $type, 'depth' => $depth];
184 }
185
186 187 188 189 190 191
192 public function addCallback($callback, $depth = '')
193 {
194 if ($callback != '') {
195 $this->callbacks[] = ['callback' => $callback, 'depth' => $depth];
196 }
197 }
198
199 private function _setActivePath()
200 {
201 $article_id = rex_article::getCurrentId();
202 if ($OOArt = rex_article::get($article_id)) {
203 $path = trim($OOArt->getPath(), '|');
204
205 $this->path = [];
206 if ($path != '') {
207 $this->path = explode('|', $path);
208 }
209
210 $this->current_article_id = $article_id;
211 $this->current_category_id = $OOArt->getCategoryId();
212 return true;
213 }
214
215 return false;
216 }
217
218 private function checkFilter(rex_category $category, $depth)
219 {
220 foreach ($this->filter as $f) {
221 if ($f['depth'] == '' || $f['depth'] == $depth) {
222 $mf = $category->getValue($f['metafield']);
223 $va = $f['value'];
224 switch ($f['type']) {
225 case '<>':
226 case '!=':
227 if ($mf == $va) {
228 return false;
229 }
230 break;
231 case '>':
232 if ($mf <= $va) {
233 return false;
234 }
235 break;
236 case '<':
237 if ($mf >= $va) {
238 return false;
239 }
240 break;
241 case '=>':
242 case '>=':
243 if ($mf < $va) {
244 return false;
245 }
246 break;
247 case '=<':
248 case '<=':
249 if ($mf > $va) {
250 return false;
251 }
252 break;
253 case 'regex':
254 if (!preg_match($va, $mf)) {
255 return false;
256 }
257 break;
258 case '=':
259 case '==':
260 default:
261
262 if ($mf != $va) {
263 return false;
264 }
265 }
266 }
267 }
268 return true;
269 }
270
271 private function checkCallbacks(rex_category $category, $depth, &$li, &$a)
272 {
273 foreach ($this->callbacks as $c) {
274 if ($c['depth'] == '' || $c['depth'] == $depth) {
275 $callback = $c['callback'];
276 if (is_string($callback)) {
277 $callback = explode('::', $callback, 2);
278 if (count($callback) < 2) {
279 $callback = $callback[0];
280 }
281 }
282 if (is_array($callback) && count($callback) > 1) {
283 list($class, $method) = $callback;
284 if (is_object($class)) {
285 $result = $class->$method($category, $depth, $li, $a);
286 } else {
287 $result = $class::$method($category, $depth, $li, $a);
288 }
289 } else {
290 $result = $callback($category, $depth, $li, $a);
291 }
292 if (!$result) {
293 return false;
294 }
295 }
296 }
297 return true;
298 }
299
300 protected function _getNavigation($category_id, $depth = 1)
301 {
302 if ($category_id < 1) {
303 $nav_obj = rex_category::getRootCategories();
304 } else {
305 $nav_obj = rex_category::get($category_id)->getChildren();
306 }
307
308 $lis = [];
309 foreach ($nav_obj as $nav) {
310 $li = [];
311 $a = [];
312 $li['class'] = [];
313 $a['class'] = [];
314 $a['href'] = [$nav->getUrl()];
315 if ($this->checkFilter($nav, $depth) && $this->checkCallbacks($nav, $depth, $li, $a)) {
316 $li['class'][] = 'rex-article-' . $nav->getId();
317
318 if ($nav->getId() == $this->current_category_id) {
319 $li['class'][] = 'rex-current';
320 $a['class'][] = 'rex-current';
321 } elseif (in_array($nav->getId(), $this->path)) {
322 $li['class'][] = 'rex-active';
323 $a['class'][] = 'rex-active';
324 } else {
325 $li['class'][] = 'rex-normal';
326 }
327 if (isset($this->linkclasses[($depth - 1)])) {
328 $a['class'][] = $this->linkclasses[($depth - 1)];
329 }
330 if (isset($this->classes[($depth - 1)])) {
331 $li['class'][] = $this->classes[($depth - 1)];
332 }
333 $li_attr = [];
334 foreach ($li as $attr => $v) {
335 $li_attr[] = $attr . '="' . implode(' ', $v) . '"';
336 }
337 $a_attr = [];
338 foreach ($a as $attr => $v) {
339 $a_attr[] = $attr . '="' . implode(' ', $v) . '"';
340 }
341 $l = '<li ' . implode(' ', $li_attr) . '>';
342 $l .= '<a ' . implode(' ', $a_attr) . '>' . rex_escape($nav->getName()) . '</a>';
343 ++$depth;
344 if (($this->open ||
345 $nav->getId() == $this->current_category_id ||
346 in_array($nav->getId(), $this->path))
347 && ($this->depth >= $depth || $this->depth < 0)
348 ) {
349 $l .= $this->_getNavigation($nav->getId(), $depth);
350 }
351 --$depth;
352 $l .= '</li>';
353 $lis[] = $l;
354 }
355 }
356 if (count($lis) > 0) {
357 return '<ul class="rex-navi' . $depth . ' rex-navi-depth-' . $depth . ' rex-navi-has-' . count($lis) . '-elements">' . implode('', $lis) . '</ul>';
358 }
359 return '';
360 }
361 }
362