├── package.yml
├── .github
└── workflows
│ └── publish-to-redaxo.yml
├── fragments
└── navigation_array
│ └── navigation.php
├── LICENSE
├── lib
└── NavigationArray
│ └── BuildArray.php
└── README.md
/package.yml:
--------------------------------------------------------------------------------
1 | package: navigation_array
2 | version: '5.3.3'
3 | author: 'Friends Of REDAXO'
4 | supportpage: https://github.com/FriendsOfREDAXO/navigation_array
5 | info: 'REDAXO AddOn:Navigation Array'
6 |
7 | requires:
8 | redaxo: '^5.15.0'
9 | php:
10 | version: '>=8.1'
11 |
--------------------------------------------------------------------------------
/.github/workflows/publish-to-redaxo.yml:
--------------------------------------------------------------------------------
1 | name: Publish release
2 |
3 | on:
4 | release:
5 | types:
6 | - published
7 |
8 | jobs:
9 | redaxo_publish:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v3
13 | - uses: FriendsOfREDAXO/installer-action@v1
14 | with:
15 | myredaxo-username: ${{ secrets.MYREDAXO_USERNAME }}
16 | myredaxo-api-key: ${{ secrets.MYREDAXO_API_KEY }}
17 | description: ${{ github.event.release.body }}
18 |
19 |
--------------------------------------------------------------------------------
/fragments/navigation_array/navigation.php:
--------------------------------------------------------------------------------
1 | getVar('navigationArray') as $categoryArray): ?>
2 |
3 |
4 | = $categoryArray['catName'] ?>
5 |
6 |
7 |
8 | subfragment('navigation_array/navigation.php', ['navigationArray' => $categoryArray['children']]);
10 | ?>
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Friends Of REDAXO
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/NavigationArray/BuildArray.php:
--------------------------------------------------------------------------------
1 | start = $start;
33 | $this->depth = $depth;
34 | $this->ignoreOfflines = $ignoreOfflines;
35 | $this->level = $level;
36 | }
37 |
38 | /**
39 | * Set categories to exclude from the navigation (int or array of ints with category ids).
40 | *
41 | * @param int|array $excludedCategories
42 | * @return $this
43 | */
44 | public function setExcludedCategories(int|array $excludedCategories): self
45 | {
46 | if (is_int($excludedCategories)) {
47 | $excludedCategories = [$excludedCategories];
48 | }
49 |
50 | if (!is_array($excludedCategories)) {
51 | $message = 'Excluded categories must be an integer or an array of integers.';
52 | rex_logger::logError(E_USER_ERROR, $message, __FILE__, __LINE__);
53 | throw new rex_exception($message);
54 | }
55 |
56 | $this->excludedCategories = $excludedCategories;
57 | return $this;
58 | }
59 |
60 | /**
61 | * Set ID of the category to start with (default: -1, yrewrite mountID or root category).
62 | *
63 | * @param int $start
64 | * @return $this
65 | */
66 | public function setStart(int $start): self
67 | {
68 | $this->start = $start;
69 | return $this;
70 | }
71 |
72 | /**
73 | * Set how many levels should the navigation show (default: 4).
74 | *
75 | * @param int $depth
76 | * @return $this
77 | */
78 | public function setDepth(int $depth): self
79 | {
80 | $this->depth = $depth;
81 | return $this;
82 | }
83 |
84 | /**
85 | * Set whether offline categories should be ignored (default: true).
86 | *
87 | * @param int $ignore 1 for true, 0 for false
88 | * @return $this
89 | */
90 | public function setIgnore(int $ignore): self
91 | {
92 | $this->ignoreOfflines = (bool)$ignore;
93 | return $this;
94 | }
95 |
96 | /**
97 | * @param int $lvl
98 | * @return $this
99 | */
100 | public function setLevel(int $lvl): self
101 | {
102 | $this->level = $lvl;
103 | return $this;
104 | }
105 |
106 | /**
107 | * Create a new instance of BuildArray.
108 | *
109 | * @return self
110 | */
111 | public static function create(): self
112 | {
113 | return new self();
114 | }
115 |
116 | /**
117 | * Generate the navigation array.
118 | *
119 | * @return array
120 | */
121 | public function generate(): array
122 | {
123 | $result = [];
124 | $currentCat = rex_category::getCurrent();
125 | $currentCatpath = $currentCat ? $currentCat->getPathAsArray() : [];
126 | $currentCat_id = $currentCat ? $currentCat->getId() : 0;
127 |
128 | $this->initializeStartCategory();
129 |
130 | foreach ($this->startCats as $cat) {
131 | if ($this->isPermitted($cat)) {
132 | $result[] = $this->processCategory($cat, $currentCatpath, $currentCat_id);
133 | }
134 | }
135 | return array_filter($result);
136 | }
137 |
138 | /**
139 | * Set a callback to filter categories.
140 | *
141 | * @param callable $callback
142 | * @return $this
143 | */
144 | public function setCategoryFilterCallback(callable $callback): self
145 | {
146 | $this->categoryFilterCallback = $callback;
147 | return $this;
148 | }
149 |
150 | /**
151 | * Set a callback to add custom data to the category array.
152 | *
153 | * @param callable $callback
154 | * @return $this
155 | */
156 | public function setCustomDataCallback(callable $callback): self
157 | {
158 | $this->customDataCallback = $callback;
159 | return $this;
160 | }
161 |
162 | /**
163 | * Generate the navigation array as JSON.
164 | *
165 | * @return string
166 | */
167 | public function toJson(): string
168 | {
169 | $array = $this->generate();
170 | return json_encode($array, JSON_PRETTY_PRINT);
171 | }
172 |
173 | /**
174 | * Initialize the start category based on the provided start value
175 | * or fallback to yrewrite domain or root categories
176 | *
177 | * @return void
178 | */
179 | private function initializeStartCategory(): void
180 | {
181 | // Erster Schritt: Startwert ermitteln, falls es -1 (Default) ist
182 | if ($this->start == -1) {
183 | // YRewrite Domain-Startpunkt versuchen zu holen
184 | if (rex_addon::get('yrewrite')->isAvailable()) {
185 | $domain = rex_yrewrite::getDomainByArticleId(rex_article::getCurrentId(), rex_clang::getCurrentId());
186 | $this->start = ($domain !== null) ? $domain->getMountId() : 0;
187 | } else {
188 | // Fallback auf Root-Kategorien
189 | $this->start = 0;
190 | }
191 | }
192 |
193 | // Zweiter Schritt: Kategorien basierend auf dem ermittelten Startwert laden
194 | // Arrays von Kategorie-IDs
195 | if (is_array($this->start)) {
196 | $this->startCats = [];
197 | foreach ($this->start as $startCatId) {
198 | $startCat = rex_category::get($startCatId);
199 | if ($startCat) {
200 | $this->startCats[] = $startCat;
201 | }
202 | }
203 | return;
204 | }
205 |
206 | // Spezifische Kategorie-ID (nicht 0)
207 | if ($this->start != 0) {
208 | $startCat = rex_category::get($this->start);
209 | if ($startCat) {
210 | $this->startCats = $startCat->getChildren($this->ignoreOfflines);
211 | return;
212 | }
213 | }
214 |
215 | // Fallback auf Root-Kategorien
216 | $this->startCats = rex_category::getRootCategories($this->ignoreOfflines);
217 | }
218 |
219 | /**
220 | * Check if the category is permitted by ycom.
221 | *
222 | * @param rex_category $cat
223 | * @return bool
224 | */
225 | private function isCategoryPermitted(rex_category $cat): bool
226 | {
227 | // Erst prüfen, ob das ycom-Addon überhaupt installiert und aktiviert ist
228 | if (!rex_addon::get('ycom')->isAvailable()) {
229 | return true;
230 | }
231 |
232 | // Dann prüfen, ob das auth-Plugin verfügbar ist
233 | $ycom_check = rex_addon::get('ycom')->getPlugin('auth')->isAvailable();
234 | return !$ycom_check || $cat->isPermitted();
235 | }
236 |
237 | /**
238 | * Check if category meets all navigation requirements
239 | * Prüft ob die Kategorie alle Anforderungen erfüllt (YCom, Ausschlüsse, Filter)
240 | *
241 | * @param rex_category $cat
242 | * @return bool
243 | */
244 | private function isPermitted(rex_category $cat): bool
245 | {
246 | // Prüfe YCom Berechtigungen
247 | if (!$this->isCategoryPermitted($cat)) {
248 | return false;
249 | }
250 |
251 | // Prüfe ob Kategorie ausgeschlossen ist
252 | if (in_array($cat->getId(), $this->excludedCategories)) {
253 | return false;
254 | }
255 |
256 | // Prüfe Category Filter Callback
257 | if (is_callable($this->categoryFilterCallback) && !call_user_func($this->categoryFilterCallback, $cat)) {
258 | return false;
259 | }
260 |
261 | return true;
262 | }
263 |
264 | /**
265 | * @param rex_category $cat
266 | * @param array $currentCatpath
267 | * @param int $currentCat_id
268 | * @return array
269 | */
270 | private function processCategory(rex_category $cat, array $currentCatpath, int $currentCat_id): array
271 | {
272 | $catId = $cat->getId();
273 |
274 | // Base category data
275 | $categoryArray = [
276 | 'catId' => $catId,
277 | 'parentId' => $cat->getParentId(),
278 | 'level' => $this->level,
279 | 'catName' => $cat->getName(),
280 | 'url' => $cat->getUrl(),
281 | 'path' => $cat->getPathAsArray(),
282 | 'active' => in_array($catId, $currentCatpath) || $currentCat_id == $catId,
283 | 'current' => $currentCat_id == $catId,
284 | ];
285 |
286 | // Process children only if we haven't reached the maximum depth
287 | $children = [];
288 | if ($this->level < $this->depth) {
289 | $childCats = $cat->getChildren($this->ignoreOfflines);
290 | if ($childCats) {
291 | $this->level++; // Increment level for children
292 | foreach ($childCats as $child) {
293 | if ($this->isPermitted($child)) {
294 | $children[] = $this->processCategory($child, $currentCatpath, $currentCat_id);
295 | }
296 | }
297 | $this->level--; // Restore level after processing children
298 | }
299 | }
300 |
301 | $categoryArray['hasChildren'] = !empty($children);
302 | $categoryArray['children'] = $children;
303 |
304 | // Add custom data if callback is set
305 | if (is_callable($this->customDataCallback)) {
306 | $customData = call_user_func($this->customDataCallback, $cat);
307 | if (is_array($customData)) {
308 | $categoryArray = array_merge($categoryArray, $customData);
309 | }
310 | }
311 |
312 | return $categoryArray;
313 | }
314 |
315 | /**
316 | * Get category information either for current category or by ID
317 | *
318 | * @param int|null $categoryId Optional category ID
319 | * @return array
320 | */
321 | public function getCategory(?int $categoryId = null): array
322 | {
323 | // Kategorie ermitteln (entweder durch ID oder current)
324 | $cat = null;
325 | if ($categoryId !== null) {
326 | $cat = rex_category::get($categoryId);
327 | } else {
328 | $cat = rex_category::getCurrent();
329 | }
330 |
331 | if (!$cat) {
332 | return [];
333 | }
334 |
335 | // YCom-Berechtigungen prüfen
336 | $hasYcomPermissions = $this->isCategoryPermitted($cat);
337 |
338 | // Filter-Status prüfen
339 | $isFilterPermitted = true;
340 | if (is_callable($this->categoryFilterCallback)) {
341 | $isFilterPermitted = call_user_func($this->categoryFilterCallback, $cat);
342 | }
343 |
344 | $catId = $cat->getId();
345 | $path = $cat->getPathAsArray();
346 | $currentCat = rex_category::getCurrent();
347 | $currentCatpath = $currentCat ? $currentCat->getPathAsArray() : [];
348 | $currentCat_id = $currentCat ? $currentCat->getId() : 0;
349 |
350 | // Kinder mit processCategory verarbeiten
351 | $children = [];
352 | $childCategories = $cat->getChildren($this->ignoreOfflines);
353 | if ($childCategories) {
354 | foreach ($childCategories as $childCat) {
355 | if ($this->isPermitted($childCat)) {
356 | $children[] = $this->processCategory($childCat, $currentCatpath, $currentCat_id);
357 | }
358 | }
359 | }
360 |
361 | $categoryArray = [
362 | 'catId' => $catId,
363 | 'parentId' => $cat->getParentId(),
364 | 'catName' => $cat->getName(),
365 | 'url' => $cat->getUrl(),
366 | 'hasChildren' => !empty($children),
367 | 'children' => $children, // Kinder aus processCategory
368 | 'path' => $path,
369 | 'pathCount' => count($path),
370 | 'active' => in_array($catId, $currentCatpath) || $currentCat_id == $catId,
371 | 'current' => $currentCat_id == $catId,
372 | 'cat' => $cat,
373 | 'ycom_permitted' => $hasYcomPermissions,
374 | 'filter_permitted' => $isFilterPermitted,
375 | 'is_permitted' => $hasYcomPermissions && $isFilterPermitted
376 | ];
377 |
378 | // Custom Data hinzufügen wenn ein Callback definiert ist
379 | if (is_callable($this->customDataCallback)) {
380 | $customData = call_user_func($this->customDataCallback, $cat);
381 | if (is_array($customData)) {
382 | $categoryArray = array_merge($categoryArray, $customData);
383 | }
384 | }
385 |
386 | return $categoryArray;
387 | }
388 |
389 | /**
390 | * Walk through the navigation and apply a callback to each item.
391 | *
392 | * @param callable $callback The callback function to apply to each item.
393 | * It will receive the item (category array) and the level as arguments.
394 | * @return void
395 | */
396 | public function walk(callable $callback): void
397 | {
398 | $this->initializeStartCategory();
399 |
400 | $currentCat = rex_category::getCurrent();
401 | $currentCatpath = $currentCat ? $currentCat->getPathAsArray() : [];
402 | $currentCat_id = $currentCat ? $currentCat->getId() : 0;
403 |
404 | foreach ($this->startCats as $cat) {
405 | if ($this->isPermitted($cat)) {
406 | // Start mit Level 0 für die Root-Kategorien
407 | $this->walkRecursive($cat, $callback, $currentCatpath, $currentCat_id, 0);
408 | }
409 | }
410 | }
411 |
412 | /**
413 | * Recursive helper function for the walk method.
414 | *
415 | * @param rex_category $cat
416 | * @param callable $callback
417 | * @param array $currentCatpath
418 | * @param int $currentCat_id
419 | * @param int $level
420 | * @return void
421 | */
422 | private function walkRecursive(rex_category $cat, callable $callback, array $currentCatpath, int $currentCat_id, int $level): void
423 | {
424 | // Prüfe zuerst, ob wir die maximale Tiefe überschritten haben
425 | if ($level > $this->depth) {
426 | return;
427 | }
428 |
429 | $item = $this->processCategory($cat, $currentCatpath, $currentCat_id);
430 | if (!empty($item)) {
431 | call_user_func($callback, $item, $level);
432 | }
433 |
434 | // Hole Kindkategorien nur wenn wir noch nicht die maximale Tiefe erreicht haben
435 | if ($level < $this->depth) {
436 | $childCats = $cat->getChildren($this->ignoreOfflines);
437 | if (!empty($childCats)) {
438 | foreach ($childCats as $child) {
439 | if ($this->isPermitted($child)) {
440 | $this->walkRecursive($child, $callback, $currentCatpath, $currentCat_id, $level + 1);
441 | }
442 | }
443 | }
444 | }
445 | }
446 | }
447 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # REDAXO Navigation Array
2 |
3 | Navigation Array ist eine PHP-Klasse für die einfache Erstellung einer Navigationsstruktur als Array. Diese Klasse bietet flexible Möglichkeiten, Navigationsdaten auszulesen, zu filtern und zu verarbeiten, insbesondere durch die Nutzung der `walk()`-Methode.
4 |
5 | ## Erklärung der Klasse
6 |
7 | Die `FriendsOfRedaxo\NavigationArray\BuildArray` Klasse bietet folgende Hauptfunktionalitäten:
8 |
9 | * **Erstellung eines Navigationsarrays:** Generiert ein verschachteltes Array, das die Kategorien und ihre Hierarchie darstellt.
10 | * **Filterung von Kategorien:** Ermöglicht das Herausfiltern von Kategorien basierend auf benutzerdefinierten Kriterien.
11 | * **Hinzufügen benutzerdefinierter Daten:** Fügt zusätzliche Informationen zu jedem Kategorie-Array hinzu.
12 | * **Rekursive Navigationstraversierung:** Die `walk()`-Methode erlaubt es, die Navigationsstruktur rekursiv zu durchlaufen und dabei individuelle Operationen auszuführen.
13 | * **Abrufen von Kategorieinformationen:** Mit der `getCategory()`-Methode können detaillierte Informationen zu einzelnen Kategorien abgerufen werden.
14 |
15 | ### Kernfunktionen
16 |
17 | - Berücksichtigung von Offline-Artikeln und YCom-Rechten.
18 | - Frei wählbare Startkategorie.
19 | - Festlegbare Tiefe der Navigation.
20 | - Filterung und Manipulation von Kategorien über Callbacks.
21 |
22 | ### Features
23 |
24 | - `getCategory`-Methode zum Abrufen von Kategorieinformationen (inkl. Kindkategorien).
25 | - `walk()`-Methode für einfache, rekursive Navigationstraversierung.
26 | - Mitgelieferte Fragmente für die HTML-Ausgabe der Navigation (siehe Beispiele unten).
27 |
28 | ## Auslesen der Daten
29 |
30 | ### Array-Struktur
31 |
32 | Das generierte Array enthält alle Kategorien und Unterkategorien bis zur angegebenen Tiefe. Offline-Kategorien und Rechte aus YCom werden vorher entfernt.
33 |
34 | ```php
35 | array:7 [
36 | 0 => array:11 [▶]
37 | 1 => array:11 [▶]
38 | 2 => array:11 [▶]
39 | 3 => array:11 [▶]
40 | 4 => array:11 [
41 | "catId" => 43
42 | "parentId" => 0
43 | "level" => 0
44 | "catName" => "Kontakt"
45 | "url" => "/kontakt/"
46 | "hasChildren" => true
47 | "children" => array:2 [
48 | 0 => array:11 [
49 | "catId" => 178
50 | "parentId" => 43
51 | "level" => 1
52 | "catName" => "Kontaktformular"
53 | "url" => "/kontakt/kontaktformular/"
54 | "hasChildren" => false
55 | "children" => []
56 | "path" => array:1 [▶]
57 | "active" => false
58 | "current" => false
59 | ]
60 | 1 => array:11 [▶]
61 | ]
62 | "path" => []
63 | "active" => true
64 | "current" => true
65 | ]
66 | 5 => array:11 [▶]
67 | 6 => array:11 [▶]
68 | ]
69 | ```
70 |
71 | ### Array generieren
72 |
73 | #### Aufruf mit Konstruktor
74 |
75 | ```php
76 | // define namespace
77 | use FriendsOfRedaxo\NavigationArray\BuildArray;
78 | // create object
79 | $navigationObject = new BuildArray(-1, 3);
80 | // generate navigation array
81 | $navigationArray = $navigationObject->generate();
82 | ```
83 |
84 | #### Aufruf mit Methoden
85 |
86 | ```php
87 | // define namespace
88 | use FriendsOfRedaxo\NavigationArray\BuildArray;
89 | // create navigation array
90 | $navigationArray = BuildArray::create()
91 | ->setStart(-1)
92 | ->setDepth(4)
93 | ->setIgnore(true)
94 | ->setCategoryFilterCallback(CategoryFilter())
95 | ->setCustomDataCallback(CustomData())
96 | ->generate();
97 | ```
98 |
99 | ## Erstellen von Navigationen
100 |
101 | ### Verwendung der `walk()`-Methode
102 |
103 | Die `walk()`-Methode ermöglicht es, die Navigation rekursiv zu durchlaufen und dabei eine Callback-Funktion auf jedes Element anzuwenden. Dies ist ideal für benutzerdefinierte Ausgaben oder Manipulationen der Navigationsdaten.
104 |
105 | #### Verwendung
106 |
107 | ```php
108 | public function walk(callable $callback): void
109 | ```
110 |
111 | #### Parameter
112 |
113 | - `$callback`: Eine `callable`-Funktion, die für jedes Navigationselement aufgerufen wird. Die Funktion erhält zwei Parameter:
114 | - `$item`: Das aktuelle Navigationselement (als `array`).
115 | - `$level`: Die aktuelle Ebene der Navigation (als `int`).
116 |
117 | #### Beispiel: Verschachtelte HTML-Liste mit `walk()`
118 |
119 | ```php
120 | setDepth(3)
129 | ->setExcludedCategories([32,34])
130 | ->setCategoryFilterCallback(function(rex_category $cat){
131 | return true;
132 | })
133 | ->setCustomDataCallback(function(rex_category $cat){
134 | return [
135 | 'css_id' => 'cat-'.$cat->getId(),
136 | 'description' => $cat->getValue('description')
137 | ];
138 | });
139 |
140 | $items = []; // Sammle alle Items
141 | $navigation->walk(function ($item, $level) use (&$items) {
142 | $items[] = ['item' => $item, 'level' => $level];
143 | });
144 |
145 | // Verarbeite die Items
146 | for ($i = 0; $i < count($items); $i++) {
147 | $currentItem = $items[$i];
148 | $level = $currentItem['level'];
149 | $item = $currentItem['item'];
150 |
151 | // Prüfe auf Leveländerungen
152 | if ($level > $currentLevel) {
153 | $htmlNavigation .= "\n" . str_repeat(' ', $level) . '';
154 | } elseif ($level < $currentLevel) {
155 | // Schließe übergeordnete Level
156 | $diff = $currentLevel - $level;
157 | for ($j = 0; $j < $diff; $j++) {
158 | $htmlNavigation .= '' . "\n" . str_repeat(' ', $currentLevel - $j - 1) . '
';
159 | if ($j < $diff - 1) {
160 | $htmlNavigation .= '';
161 | }
162 | }
163 | } elseif ($i > 0) {
164 | // Auf gleichem Level: Schließe vorheriges li
165 | $htmlNavigation .= '';
166 | }
167 |
168 | $htmlNavigation .= "\n" . str_repeat(' ', $level);
169 | $activeClass = $item['active'] ? ' class="active"' : '';
170 | $htmlNavigation .= '';
171 | $htmlNavigation .= '';
172 | $htmlNavigation .= $item['catName'];
173 | $htmlNavigation .= '';
174 |
175 | $currentLevel = $level;
176 | }
177 |
178 | // Schließe verbleibende offene Tags
179 | if ($currentLevel >= 0) {
180 | for ($i = $currentLevel; $i >= 0; $i--) {
181 | $htmlNavigation .= '' . "\n" . str_repeat(' ', $i) . '';
182 | }
183 | }
184 |
185 | echo $htmlNavigation;
186 | ```
187 |
188 | #### Beispiel: Logausgabe der Navigation mit `walk()`
189 |
190 | ```php
191 | setDepth(2);
195 |
196 | $navigation->walk(function ($item, $level) {
197 | echo str_repeat(" ", $level) . "Kategorie: " . $item['catName'] . ", Level: " . $level . ", URL: " . $item['url'] . "
";
198 | });
199 | ```
200 |
201 | #### Beispiel: Einfache Navigation mit `walk()` und REDAXO Fragment
202 |
203 | Hier ein Beispiel, wie du die `walk()`-Methode in Verbindung mit einem REDAXO-Fragment für eine einfache Navigation verwenden kannst.
204 |
205 | **1. Fragment (`simple_navigation.php`)**:
206 | Erstelle eine Fragmentdatei im Verzeichnis `fragments/navigation_array` mit folgendem Inhalt:
207 |
208 | ```php
209 | getVar('items');
211 | $level = $this->getVar('level', 0);
212 | $activeClass = $this->getVar('activeClass', 'active');
213 |
214 | if (empty($items)) {
215 | return '';
216 | }
217 | $output = '';
218 | foreach ($items as $item) {
219 | $active = $item['active'] ? ' class="'.$activeClass.'"' : '';
220 | $output .= '- '.$item['catName'].'';
221 | if(isset($item['children']) && !empty($item['children'])){
222 |
223 | $output .= $this->subfragment('navigation_array/simple_navigation.php', [
224 | 'items' => $item['children'],
225 | 'level' => $level +1,
226 | 'activeClass' => $activeClass
227 | ]);
228 | }
229 | $output .='
';
230 | }
231 | $output .= '
';
232 | echo $output;
233 | ?>
234 | ```
235 |
236 | **2. Aufruf im Template:**
237 | In deinem REDAXO-Template kannst du die Navigation wie folgt erstellen:
238 | ```php
239 | setDepth(3);
243 | $htmlNavigation = '';
244 | $items = [];
245 | $navigation->walk(function ($item, $level) use (&$items) {
246 | $items[] = $item;
247 | });
248 |
249 |
250 | $fragment = new rex_fragment();
251 | $fragment->setVar('items', $items);
252 | $fragment->setVar('activeClass', 'active');
253 | echo $fragment->parse('navigation_array/simple_navigation.php');
254 | ```
255 |
256 | Dieses Beispiel zeigt, wie du mit der `walk()`-Methode ein Array der Navigation erzeugen kannst und dieses dann mit einem REDAXO-Fragment in eine einfache Navigation umwandeln kannst. Die Rekursion wird nun über die Fragments realisiert, um einen wiederverwendbaren Code zu erhalten.
257 |
258 | #### Beispiel: Breadcrumb mit `walk()`
259 |
260 | Hier ist ein modernes Breadcrumb-Beispiel mit der `walk()`-Methode:
261 |
262 | ```php
263 | setDepth(10);
267 | $breadcrumbItems = [];
268 |
269 | $navarray->walk(function ($item, $level) use (&$breadcrumbItems) {
270 | if ($item['active']) {
271 | $liclass = '';
272 | if ('REX_ARTICLE_ID' == $item['catId']) {
273 | $liclass = ' class="disabled"';
274 | $item['url'] = '';
275 | }
276 | $breadcrumbItems[] = '' . $item['catName'] . '';
277 | }
278 | });
279 | echo '';
280 | echo ' ';
281 | echo implode("\n", $breadcrumbItems);
282 | echo '
';
283 |
284 | ```
285 |
286 | Dieses Beispiel zeigt, wie du die `walk()` Methode nutzen kannst um einen Breadcrumb zu generieren, und dabei von den bereitgestellten Informationen Gebrauch machst.
287 |
288 | ### Vergleich: `walk()` vs. Eigene Iteration (Gleiche Ausgabe)
289 |
290 | Um die Vorteile der `walk()`-Methode zu verdeutlichen, zeigen wir hier, wie man die gleiche verschachtelte Navigation mit beiden Methoden erstellt. Dies ermöglicht einen direkten Code-Vergleich.
291 |
292 | #### Mit `walk()`-Methode
293 |
294 | ```php
295 | setDepth(3);
299 | $htmlOutput = '';
300 |
301 | $navigation->walk(function($item, $level) use (&$htmlOutput) {
302 | $htmlOutput .= str_repeat(" ", $level) . '' . $item['catName'] . '
';
303 | });
304 |
305 | echo $htmlOutput;
306 | ```
307 |
308 | #### Mit eigener Iterationsfunktion
309 |
310 | ```php
311 | ' . $item['catName'] . '
';
318 | if ($item['hasChildren']) {
319 | $output .= myCustomNavigation($item['children'], $level + 1);
320 | }
321 | }
322 | return $output;
323 | }
324 |
325 | $navigation = BuildArray::create()->setDepth(3)->generate();
326 | echo myCustomNavigation($navigation);
327 | ```
328 |
329 | **Analyse:**
330 |
331 | * **Klarheit:** Beide Code-Beispiele erzeugen *exakt* die gleiche HTML-Ausgabe.
332 | * **Code-Kürze:** Die `walk()`-Methode erfordert *deutlich weniger* Code und ist lesbarer, da die Rekursionslogik intern gehandhabt wird.
333 | * **Wartbarkeit:** Der Code mit `walk()` ist einfacher zu warten, da die Rekursionslogik gekapselt ist.
334 | * **Flexibilität:** Die `walk()`-Methode ermöglicht es, die Logik der Ausgabe in einem Callback zu definieren, was die Flexibilität erhöht.
335 |
336 | Dieser direkte Vergleich zeigt, dass die `walk()`-Methode eine prägnantere, klarere und wartungsfreundlichere Möglichkeit bietet, die Navigationsdaten zu verarbeiten.
337 |
338 | ## Weitere Beispiele
339 |
340 | Neben der Nutzung von `walk()`, können auch die generierten Arrays direkt für die Ausgabe genutzt werden.
341 |
342 | ### Fragmente
343 |
344 | Mit Fragmenten wird die Logik sauber vom Code getrennt. Das Fragment `navigation.php` kann kopiert, angepasst und in `project` oder `theme`-Ordner abgelegt werden.
345 |
346 | ```php
347 | // Festlegen des Namespace
348 | use FriendsOfRedaxo\NavigationArray\BuildArray;
349 |
350 | // Navigation Array erstellen
351 | $navigationObject = new BuildArray(-1, 3);
352 | $navigationArray = $navigationObject->generate();
353 |
354 | //Fragmente laden Navigation Array und Klasse für aktive Elemente übergeben
355 | $fragment = new rex_fragment();
356 | $fragment->setVar('navigationArray', $navigationArray);
357 | $fragment->setVar('activeClass', 'active');
358 |
359 | // Navigation ausgeben
360 |
365 | ```
366 |
367 | ### Weitere PHP-Funktionen (Auswahl)
368 |
369 | Hier sind weitere Beispiele für spezifische HTML-Ausgaben
370 |
371 | #### Beispiel erweiterte Navigation mit Callback
372 |
373 | ```php
374 | setCustomDataCallback(function($cat) {
379 | return ['navtype' => $cat->getValue('cat_navigationstyp')];
380 | })
381 | ->generate();
382 |
383 | $mainnavigation_items = [];
384 |
385 | function createNavigationItems($navi) {
386 | $items = [];
387 | $class_active = $navi['active'] ? 'active' : '';
388 | $class_current = $navi['current'] ? ' current' : '';
389 | $class_has_child = $navi['children'] ? ' has-child' : '';
390 |
391 | $items[] = "{$navi['catName']}";
392 |
393 | if ($navi['children']) {
394 | $items[] = '';
395 | $items[] = '';
396 |
397 | foreach ($navi['children'] as $nav_child) {
398 | $items[] = createNavigationItems($nav_child);
399 | }
400 |
401 | $items[] = '
';
402 | }
403 |
404 | $items[] = '';
405 |
406 | return implode($items);
407 | }
408 |
409 | foreach ($mainnavi_array as $navi) {
410 | $navtype_arr = explode('|', $navi['navtype']);
411 |
412 | if (in_array('main', $navtype_arr)) {
413 | $mainnavigation_items[] = createNavigationItems($navi);
414 | }
415 | }
416 |
417 | $mainnavigation = '' . implode($mainnavigation_items) . '
';
418 | ```
419 |
420 | #### Beispiel: Bootstrap 5 Navigation
421 |
422 | ```php
423 | ';
450 | $sub[] = bsnavi5($cat['children']);
451 | $sub[] = '';
452 | $subnavi = join("\n", $sub);
453 | }
454 |
455 | $catname = $cat['catName'];
456 | if ($cat['active'] == true) {
457 | $active = ' active';
458 | }
459 |
460 | $catname = '' . $catname . '';
461 | $output[] = '' . $catname . $subnavi . '';
462 | }
463 | return implode("\n", $output);
464 | }
465 |
466 |
467 | $NavigationArray = BuildArray::create()->setDepth(4)->generate();
468 | ?>
469 |
470 |
477 |