├── .github
└── workflows
│ └── publish-to-redaxo.yml
├── LICENSE
├── README.md
├── fragments
└── navigation_array
│ └── navigation.php
├── lib
└── NavigationArray
│ └── BuildArray.php
└── package.yml
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |