Instantly share code, notes, and snippets.
Forked from staabm/navigation_iterator.php
Created
May 27, 2018 18:16
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save skerbis/1074a8ce3d2354414c8a78f0a2ff26a6 to your computer and use it in GitHub Desktop.
redaxo navigation iterator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Klasse zum Erstellen von Navigationen, v0.1. | |
* | |
* @package redaxo\structure | |
*/ | |
/* | |
* Beispiel-Konfiguration einer Haupt-Navigation: | |
* | |
* $it = rex_navigation_iterator::factory() | |
* ->ignoreOfflines(true) | |
* ; | |
* | |
* foreach($it as $navItem) { | |
* list($ooObj, $depth, $nth, $count) = $navItem; | |
* | |
* if ($nth == 1) { | |
* if ($depth == 1) { | |
* $class = "nav navbar-nav"; | |
* } else { | |
* $class = "dropdown"; | |
* } | |
* echo '<ul class="'. $class .'">'; | |
* } | |
* | |
* echo "<li class='rex-navi-depth-". $depth ." rex-nav-". $nth ."nth-child'>"; | |
* echo "<a href='". $ooObj->getUrl() ."'>". $ooObj->getName() ."</a>"; | |
* echo "</li>\n"; | |
* | |
* if ($nth == $count) { | |
* echo '</ul>'; | |
* } | |
* } | |
* | |
* Bespiel-Konfiguration einer Seiten-Navigation | |
* | |
* $it = rex_navigation_iterator::factory() | |
* ->startCategory(27) | |
* ->depthLimit(3) | |
* ->ignoreOfflines(true) | |
* | |
* foreach($it as $navItem) { | |
* list($ooObj, $depth, $nth, $count) = $navItem; | |
* | |
* if ($nth == 1) { | |
* if ($depth == 1) { | |
* $class = "nav side-nav"; | |
* } else { | |
* $class = ""; | |
* } | |
* echo '<ul class="'. $class .'">'; | |
* } | |
* | |
* echo "<li class='rex-navi-depth-". $depth ." rex-nav-". $nth ."nth-child'>"; | |
* echo "<a href='". $ooObj->getUrl() ."'>". $ooObj->getName() ."</a>"; | |
* echo "</li>\n"; | |
* | |
* if ($nth == $count) { | |
* echo '</ul>'; | |
* } | |
* } | |
* | |
* Bespiel-Konfiguration einer Breadcrumb-Navigation | |
* | |
* $it = rex_navigation_iterator::factory() | |
* ->activePath(true) | |
* ->ignoreOfflines(true) | |
* | |
* echo '<ul class="breadcrumb-nav">'; | |
* echo '<li><a href="' . rex_getUrl(rex_article::getSiteStartArticleId()) . '">STARTSEITE</a></li>'; | |
* foreach($it as $navItem) { | |
* list($ooObj, $depth, $nth, $count) = $navItem; | |
* | |
* echo "<li>"; | |
* echo "<a href='". $ooObj->getUrl() ."'>". $ooObj->getName() ."</a>"; | |
* echo "</li>\n"; | |
* } | |
* echo '</ul>'; | |
*/ | |
class rex_navigation_iterator implements IteratorAggregate | |
{ | |
use rex_factory_trait; | |
private $startCategory = 0; | |
private $ignoreOfflines = false; | |
private $activePath = false; | |
private $depthLimit = -1; // Wieviele Ebene tief, ab der Startebene | |
private $path = []; | |
private $filter = []; | |
private $current_category_id = -1; // Aktuelle Katgorie | |
private function __construct() | |
{ | |
// nichts zu tun | |
} | |
/** | |
* @return static | |
*/ | |
public static function factory() | |
{ | |
$class = self::getFactoryClass(); | |
return new $class(); | |
} | |
/** | |
* @param int $categoryId Id der Wurzelkategorie, -1 für alle Kategorien (default) | |
* | |
* @return $this | |
*/ | |
public function startCategory($categoryId) { | |
$this->startCategory = $categoryId; | |
return $this; | |
} | |
/** | |
* @param int $limit Anzahl der Ebenen die angezeigt werden sollen, -1 kein Limit (default) | |
* | |
* @return $this | |
*/ | |
public function depthLimit($limit) { | |
$this->depthLimit = $limit; | |
return $this; | |
} | |
/** | |
* @param bool $ignoreOfflines FALSE, wenn offline Elemente angezeigt werden (default), sonst TRUE | |
* | |
* @return $this | |
*/ | |
public function ignoreOfflines($ignoreOfflines) { | |
$this->ignoreOfflines = $ignoreOfflines; | |
return $this; | |
} | |
/** | |
* @param bool $activePath True, wenn nur Elemente der aktiven Kategorie angezeigt werden sollen, sonst FALSE (default) | |
* | |
* @return $this | |
*/ | |
public function activePath($activePath) { | |
$this->activePath = $activePath; | |
return $this; | |
} | |
/** | |
* Fügt einen Filter hinzu. | |
* | |
* @param string $metafield Datenbankfeld der Kategorie | |
* @param mixed $value Wert für den Vergleich | |
* @param string $type Art des Vergleichs =/</. | |
* @param int|string $depth "" wenn auf allen Ebenen, wenn definiert, dann wird der Filter nur auf dieser Ebene angewendet | |
*/ | |
public function addFilter($metafield = 'id', $value = '1', $type = '=', $depth = '') | |
{ | |
$this->filter[] = ['metafield' => $metafield, 'value' => $value, 'type' => $type, 'depth' => $depth]; | |
} | |
public function getIterator() | |
{ | |
$this->_setActivePath(); | |
if ($this->ignoreOfflines) { | |
$this->addFilter('status', 1, '=='); | |
} | |
yield from ($this->_getNavigation($this->startCategory)); | |
} | |
private function _setActivePath() | |
{ | |
$article_id = rex_article::getCurrentId(); | |
if (!$OOArt = rex_article::get($article_id)) { | |
throw new Exception("Unable to determine current article-id"); | |
} | |
$path = trim($OOArt->getPath(), '|'); | |
$this->path = []; | |
if ($path != '') { | |
$this->path = explode('|', $path); | |
} | |
$this->current_category_id = $OOArt->getCategoryId(); | |
} | |
private function checkFilter(rex_category $category, $depth) | |
{ | |
foreach ($this->filter as $f) { | |
if ($f['depth'] == '' || $f['depth'] == $depth) { | |
$mf = $category->getValue($f['metafield']); | |
$va = $f['value']; | |
switch ($f['type']) { | |
case '<>': | |
case '!=': | |
if ($mf == $va) { | |
return false; | |
} | |
break; | |
case '>': | |
if ($mf <= $va) { | |
return false; | |
} | |
break; | |
case '<': | |
if ($mf >= $va) { | |
return false; | |
} | |
break; | |
case '=>': | |
case '>=': | |
if ($mf < $va) { | |
return false; | |
} | |
break; | |
case '=<': | |
case '<=': | |
if ($mf > $va) { | |
return false; | |
} | |
break; | |
case 'regex': | |
if (!preg_match($va, $mf)) { | |
return false; | |
} | |
break; | |
case '=': | |
case '==': | |
default: | |
// = | |
if ($mf != $va) { | |
return false; | |
} | |
} | |
} | |
} | |
return true; | |
} | |
protected function _getNavigation($category_id, $depth = 1) | |
{ | |
if ($category_id < 1) { | |
$nav_obj = rex_category::getRootCategories(); | |
} else { | |
$nav_obj = rex_category::get($category_id)->getChildren(); | |
} | |
$checked = []; | |
foreach ($nav_obj as $nav) { | |
if ($this->checkFilter($nav, $depth)) { | |
$checked[] = $nav; | |
} | |
} | |
$nth = 1; | |
foreach($checked as $nav) { | |
if (!$this->activePath || $this->activePath && ($nav->getId() == $this->current_category_id || in_array($nav->getId(), $this->path)) | |
) { | |
yield [$nav, $depth, $nth, count($checked)]; | |
++$depth; | |
if ($this->depthLimit >= $depth || $this->depthLimit < 0) { | |
yield from ($this->_getNavigation($nav->getId(), $depth)); | |
} | |
--$depth; | |
$nth++; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Diese Navigation funktioniert nur mit 1 Ebene. Ab 2 Ebenen werden die
<li><ul>
Elemente falsch geschachtelt.<ul>
muss innerhalb vom<li>
stehen.