Seite 1 von 25

Modul :: NavigationUniversell

Verfasst: Mi 11. Jul 2007, 17:49
von kummer
hi all

hier noch ein modul, welches ich schon länger in betrieb habe. es handelt sich dabei um ein navigationsmodul, welches alle gänigen menus abbilden können sollte (sowohl splitted wie normale).

die neuste version (1.2.2) steht hier zum download zur verfügung: http://www.editio.ch/cms/front_content. ... uleView=45

folgender code ist in einer datei beliebiger bezeichnung im verzeichnis 'contenido/classes' abzulegen:

Code: Alles auswählen

<?php


/**
 * @author Andreas Kummer
 * @copyright Copyright &copy; 2007 atelierQ
 */

class aQnavigation {

	/**
	 * Konstruktor der Klasse.
	 * @param Integer  Primärschlüssel der Startkategorie.
	 */
	function aQnavigation($startId) {

		global $client, $lang, $idcat, $db;

		$this->startId = $startId;

		$this->client = $client;
		$this->lang = $lang;
		
		$this->idcat = (isset($_GET['pretend'])) ? ($_GET['pretend']) : ($idcat);

		$this->before = '';
		$this->beforeEach = '';
		$this->between = '';
		$this->after = '';

		$this->excludeItemsStartingWith = '__';

		$this->db = $db;

		$this->setStartIds();

		$this->getNavigation();
	}

	/**
	 * Auslesen der Navigationsstruktur aus der Datenbank.
	 */
	function getNavigation() {

		global $cfg, $auth;

		if ($this->startId != $this->id[0]) {
			/*
			 * Wenn die StartId nicht identisch ist mit der höchsten Ebene der
			 * aktuell selektierten Kategorie, dann liegt die gewählte Kategorie
			 * folgerichtig ausserhalb des für die Navigation gewählten Baumes.
			 * In diesem Fall ist nur die Hauptnavigation einzublenden.
			 */
			$this->id[0] = $this->startId;
			for ($i = 1; $i <= 3; $i++) {
				$this->id[$i] = -1;
			}
		}

		if ($auth->auth['uid'] == '' || !$this->isNumeric($auth->auth['uid'])) {
			/*
			 * Login nicht erfolgt
			 */
			$user = 0;
		} else {
			/*
			 * Benutzer ist eingeloggt
			 */
			$user = $auth->auth['uid'];
		}

		$this->db->query("" .
		"SELECT DISTINCT " .
		"a.idcat, " .
		"a.parentid, " .
		"a.preid, " .
		"a.postid, " .
		"a.parentid, " .
		"b.name, " .
		"b.idlang, " .
		"IF (b.visible = 1 && (b.public = 1 || c.idfrontendpermission IS NOT NULL), 1, 0) AS visible " .
		"FROM {$cfg['tab']['cat']} AS a " .
		"LEFT JOIN {$cfg['tab']['cat_lang']} AS b ON a.idcat = b.idcat " .
		"LEFT JOIN {$cfg['tab']['frontendpermissions']} AS c ON (c.item = b.idcatlang AND c.idlang = b.idlang AND plugin ='category') " .
		"LEFT JOIN {$cfg['tab']['frontendgroupmembers']} AS d ON c.idfrontendgroup = d.idfrontendgroup " .
		"WHERE " .
		"	a.idclient = {$this->client} " .
		"   AND (" .
		"      a.parentid = {$this->id[0]} " .
		"      OR a.parentid = {$this->id[1]} " .
		"      OR a.parentid = {$this->id[2]} " .
		"      OR a.parentid = {$this->id[3]} " .
		"   ) " .
		"	AND (" .
		"		d.idfrontenduser = {$user} " .
		"		OR d.idfrontenduser IS NULL" .
		"	)" .
		"");

		$this->navigationTree = array ();

		$this->firstId[0] = 0;
		$this->firstId[1] = 0;
		$this->firstId[2] = 0;
		$this->firstId[3] = 0;

		while ($this->db->next_record()) {

			for ($i = 0; $i <= 3; $i++) {
				if (($this->firstId[$i] == 0 && $this->db->f('parentid') == $this->id[$i] && $this->db->f('preid') == 0 && $this->db->f('idlang') == $this->lang) || ($this->firstId[$i] == 0 && $this->db->f('parentid') == $this->id[$i] && $this->db->f('preid') == 0 && $this->db->f('idlang') == null)) {
					$this->firstId[$i] = $this->db->f('idcat');
				}
			}
			/*
			 * Das Einfügen in den Navigationsbaum darf nur erfolgen, wenn noch kein Eintrag existiert
			 * oder - wenn bereits einer existiert - der neue Eintrag der aktuell gewählten Sprache
			 * entspricht.
			 */
			if (!isset ($this->navigationTree[$this->db->f('parentid')][$this->db->f('idcat')]) || $this->db->f('idlang') == $this->lang) {
				$this->navigationTree[$this->db->f('parentid')][$this->db->f('idcat')] = array (
					'preid' => $this->db->f('preid'
				), 'postid' => $this->db->f('postid'), 'visible' => $this->db->f('visible'), 'name' => $this->db->f('name'), 'idlang' => $this->db->f('idlang'));
			}
		}

	}

	/**
	 * Ausgabe der Navigation an die Standardausgabe.
	 * @param String  Navigationstyp
	 */
	function showNavigation($type, $next = -1) {

		static $first;
		static $output = array (
			false,
			false,
			false,
			false,
			false,
			false,
			false
		);

		$returnValue = "";

		if ($next == 0) {
			if ($output[$type]) {
				return $this->after[$type];
			} else {
				return false;
			}
		}

		if ($next == -1) {
			$returnValue .= $this->before[$type];
			$next = $this->firstId[$type];
			$first[$type] = true;
		}

		$parentId = $this->id[$type];

		$link = 'front_content.php?idcat=' . $next;

		if ($this->navigationTree[$parentId][$next]['visible'] == 1 && $this->navigationTree[$parentId][$next]['idlang'] == $this->lang && $this->isVisble($this->navigationTree[$parentId][$next]['name'])) {
			if (!$first[$type]) {
				$returnValue .= $this->between[$type];
			}

			if (strstr($this->navigationTree[$parentId][$next]['name'], '$$$') == true) {
				$name = explode('$$$', $this->navigationTree[$parentId][$next]['name']);
				$name1 = $name[0];
				$name2 = $name[1];
			} else {
				$name1 = $this->navigationTree[$parentId][$next]['name'];
				$name2 = '';
			}

			$sub = (isset ($this->sub[$type])) ? ($this->sub[$type]) : ('');

			if ($this->isSelected($next)) {
				$returnValue .= $this->beforeSelected[$type];
				$returnValue .= str_replace('{sub}', $sub, str_replace('{name2}', $name2, str_replace('{name1}', $name1, str_replace('{link}', $link, ($sub == '') ? ($this->maskSelected[$type]) : ($this->maskSelectedSub[$type])))));
			} else {
				$returnValue .= $this->beforeEach[$type];
				$returnValue .= str_replace('{sub}', $sub, str_replace('{name2}', $name2, str_replace('{name1}', $name1, str_replace('{link}', $link, $this->maskNormal[$type]))));
			}
			$first[$type] = false;
			$output[$type] = true;
		}
		elseif (!$output && $this->navigationTree[$parentId][$next]['postid'] == 0) {
			/*
			 * Die Navigation enthält nichts.
			 */
		}

		return $returnValue . $this->showNavigation($type, $this->navigationTree[$parentId][$next]['postid']);
	}

	function setExcludeStart($start) {
		$this->excludeItemsStartingWith = $start;
	}

	function isVisble($name) {
		if (substr($name, 0, strlen($this->excludeItemsStartingWith)) == $this->excludeItemsStartingWith) {
			return false;
		}
		return true;
	}

	/**
	 * Ausgabe vor der Navigation
	 * @param String  Ausgabe vor der Navigation.
	 */
	function before($level, $text) {
		$this->before[$level] = $text;
	}

	/**
	 * Ausgabe vor jedem Eintrag
	 * @param String  Ausgabe vor jedem Eintrag.
	 */
	function beforeEach($level, $text) {
		$this->beforeEach[$level] = $text;
	}

	/**
	 * Ausgabe vor jedem selektierten Menueintrag
	 * @param String  Ausgabe vor jedem selektierten Menueintrag.
	 */
	function beforeSelected($level, $text) {
		$this->beforeSelected[$level] = $text;
	}

	/**
	 * Ausgabe zwischen zwei Hauptmenupunkten
	 * @param String  Ausgabe zwischen zwei Hauptmenupunkten.
	 */
	function between($level, $text) {
		$this->between[$level] = $text;
	}

	/**
	 * Ausgabe nach der Navigation
	 * @param String  Ausgabe nach der Navigation.
	 */
	function after($level, $text) {
		$this->after[$level] = $text;
	}

	function maskNormal($level, $text) {
		$this->maskNormal[$level] = $text;
	}

	function maskNormalSub($level, $text) {
		$this->maskNormalSub[$level] = $text;
	}

	function maskSelected($level, $text) {
		$this->maskSelected[$level] = $text;
	}

	function maskSelectedSub($level, $text) {
		$this->maskSelectedSub[$level] = $text;
	}

	function setSub($level, $content) {
		$this->sub[$level] = $content;
	}

	/**
	 * Gibt das Level der Kategorie zurück.
	 * @param Integer  Primärschlüssel der Kategorie.
	 * @return Integer Level der spezifizierten Kategorie.
	 */
	function getLevel($idcat) {

		global $cfg;

		if (empty ($idcat)) {
			return 0;
		}

		$this->db->query("" .
		"SELECT level FROM {$cfg['tab']['cat_tree']} " .
		"WHERE " .
		"   idcat = $idcat" .
		"");
		if ($this->db->next_record()) {
			return $this->db->f('level');
		} else {
			return 0;
		}
	}

	/**
	 * Gib die Tiefe relativ zum Hauptmenu an.
	 * @param Integer  Primärschlüssel der Kategorie
	 * @return Integer Level relativ zum Hauptmenu
	 */
	function getNetLevel($idcat) {

		return $this->getLevel($idcat) - $this->getLevel($this->startId);
	}

	/**
	 * Ermittlung des jeweils ersten Kategorieeintrages jeder Ebene. Die
	 * Speicherung dieser Daten erfolgt in das Klassenattribut id.
	 */
	function setStartIds() {

		$id = $this->idcat;

		$level = $this->getNetLevel($id);
		$this->id[$level] = $id;

		while ($level > 0) {
			$this->id[$level -1] = $this->getParentId($id);
			$id = $this->id[$level -1];
			$level = $this->getNetLevel($id);
		}

		if (empty ($this->id)) {
			$this->id[0] = $this->startId;
		}
		for ($i = 1; $i <= 3; $i++) {
			if (empty ($this->id[$i])) {
				$this->id[$i] = -1;
			}
		}
		ksort($this->id);
	}

	/**
	 * Ermittlung des Elternelementes der Kategorie mit dem Primärschlüssel
	 * idcat
	 * @param Integer  Primärschlüssel des Kindelementes, dessen Elternelement
	 * ermittelt werden soll.
	 * @return Integer Primärschlüssel des Elternelementes.
	 */
	function getParentId($idcat) {

		global $cfg;

		$this->db->query("" .
		"SELECT parentid FROM {$cfg['tab']['cat']} " .
		"WHERE " .
		"   idcat = $idcat " .
		"");
		if ($this->db->next_record()) {
			return $this->db->f('parentid');
		} else {
			return 0;
		}
	}

	/**
	 * Anzeige, ob eine Navigationsebene Elemente enthält oder nicht.
	 * @param Integer  Navigationsstufe.
	 * @return Boolean True, wenn die Navigationsstufe leer ist (keine Elemente
	 * enhält). Sonst false.
	 */
	function navigationEmpty($level) {

		if ($this->firstId[$level] == 0) {
			return true;
		}

		return false;
	}

	/**
	 * Anzeige, ob eine Kategorie selektiert ist oder nicht. Eine Kategorie gilt
	 * als selektiert, wenn sie die aktuelle Kategorie ist oder ein direktes
	 * oder indirektes Elternelement der aktuellen Kategorie.
	 * @param Integer  Primärschlüssel der Kategorie, deren Status gefragt ist.
	 * @return Boolean True, wenn die gefragte Kategorie mit der aktuellen
	 * Kategorie übereinstimmt oder ein direktes oder indirektes Elternelement
	 * der aktuellen Kategorie darstellt.
	 */
	function isSelected($idcat) {

		return in_array($idcat, $this->id);
	}

	function isNumeric($parameter) {
		return !preg_match("/[^0-9]/", $parameter);
	}
}

?>
das navigationsmodul sieht dann - je nach aufgabe - etwas weniger komplex aus. nur als beispiel:

Code: Alles auswählen

<?php

cInclude('classes', 'atelierq.navigation.class.inc.php');

$cApiClient = new cApiClient($client);
$aQnavigation = new aQnavigation($cApiClient->getProperty('navigation', 'idcat_servicenavigation'));

$aQnavigation->between(1, '');
$aQnavigation->maskNormal(1, '<div><a target="_self" href="{link}">{name1}</a></div>');
$aQnavigation->maskSelected(1, '<div><a target="_self" href="{link}">›{name1}</a></div>');

$aQnavigation->between(0, '');
$aQnavigation->maskNormal(0, '<div><a target="_self" href="{link}">{name1}</a></div>');
$aQnavigation->maskNormalSub(0, '<div><a target="_self" href="{link}">{name1}</a></div>{sub}');
$aQnavigation->maskSelected(0, '<div><a target="_self" href="{link}">›{name1}</a></div>');
$aQnavigation->maskSelectedSub(0, '<div><a target="_self" href="{link}">›{name1}</a></div>{sub}');

$aQnavigation->setSub(0, $aQnavigation->showNavigation(1));

/*
 * hier erfolgt die ausgabe an den browser
 */
echo $aQnavigation->showNavigation(0);
?> 
bei der instantiierung der klasse übergibt man die idcat der übergeordneten kategorie an. in diesem fall - da das für die ganze website typsischerweise identisch ist - als systemeigenschaft.

bei jedem methodenaufruf ist der ebenenindex zu bezeichnen (im beispiel 0 für die oberste ebene und 1 für die zweitoberste ebene). dann hat man methoden für die maskenangabe normal (maskNormal) sowie selektiert (maskSelected). innerhalb dieser hat man platzhalter, die dann dynamsich gesetzt werden. link ist der link (front_content.php? usw.) und name1 für den kategorienbezeichner.

sowohl die maskNormal wie auch die maskSelected kann submenus enthalten. dafür sind die methoden maskNormalSub und maskSelectedSub, die einen zusätzlich platzhalter sub enthalten. an dessen stelle wird dann die subnavigation ausgegeben.

das modul scheint auf den ersten blick etwas komplex in der anwendung. tatsächlich lässt sich damit jedwedes menu abbilden. die submenus können - müssen jedoch nicht - an der selben stelle ausgegeben werden. in unserem beispiel werden sie zusammen dargestellt. der aufruf der methode $aQnavigation->showNavigation(1) kann jedoch auch in einem anderen modul erfolgen.

viel spass damit!

gruss,
andreas

Verfasst: Mi 11. Jul 2007, 17:58
von kummer
zwei dinge habe ich noch vergessen zu erwähnen:

(1) kategorien, die mit zwei underscores beginnen (also __meineKategorie) werden nicht angezeigt werden. auf diese weise ist es möglich, kategorien für artikellisten an beliebigen stellen zu haben.

(2) wenn innerhalb eines kategoriebezeichners drei dollarzeichen (also z.b. meine$$$kategorie) auftreten, ist im platzhalter {name1} meine und im platzhalter {name2} kategorie enthalten. damit lässt sich ein kategoriebezeichner gegebenenfalls auch in zwei spans oder divs aufteilen. ist z.b. nummerierungen sinnvoll.

Verfasst: Fr 13. Jul 2007, 09:26
von der_allgaeuer
Hallo Kummer,
habe das alles (fast alles) gelesen und getestet.
Funktioniert aber nicht - es kommt überhaupt keine Ausgabe :(

Ich habe die Klasse nicht unter einem beliebigen Dateinamen abgespeichert sondern unter atelierq.navigation.class.inc.php. Ich denke, das nuss auch so sein, oder?
Dann habe ich den Quellcode 'navigationsmodul' in die Ausgabe eines neuen Moduls kopiert, aber leider so keine Ausgabe.

Kannst Du mir sagen, wo's bei mir fehlt? (... hmm bei meinem Modul natürlich :? )

Danke
mfg Hubert

Verfasst: Fr 13. Jul 2007, 09:31
von kummer
hast du eine property im mandanten angelegt mit der id der hauptnavigation?

Verfasst: Fr 13. Jul 2007, 09:42
von der_allgaeuer
kummer hat geschrieben:hast du eine property im mandanten angelegt mit der id der hauptnavigation?
ne, hab ich nicht.
mit welchen Werten muss ich da eine anlegen (Typ, Name, Wert)?
(mein Baum heißt "Hauptnavigation" und hat idcat=1)

Verfasst: Fr 13. Jul 2007, 09:46
von kummer
in deinem fall der wert 1. typ = navigation, name = idcat_servicenavigation

Verfasst: Fr 13. Jul 2007, 13:21
von der_allgaeuer
kummer hat geschrieben:in deinem fall der wert 1. typ = navigation, name = idcat_servicenavigation
... und es funktioniert. :)
Jetzt muß ich noch testen - bis zum Ende

aber schon mal danke
Gruss Hubert

Verfasst: Fr 13. Jul 2007, 13:31
von matt.loker
Ich hätte da mal eine Frage.

Kann man mit diesem Modul auch 2 verschiedene Menustrukturen gleichzeitig verwirklichen? also z.B. die ersten 2 Menuebenen als normales Listing und die 3. und 4. Ebene sind gesplitete Menus.

grüsse

Verfasst: Fr 13. Jul 2007, 13:33
von kummer
die bezeichnung der property ist möglicherweise etwas unglücklich gewählt. im prinzip kann jeder wählen was er will. dann muss man einfach eine entsprechende anpassung im modul vornehmen:

Code: Alles auswählen

$cApiClient->getProperty('navigation', 'idcat_servicenavigation')
ist dann durch die entsprechende property zu ersetzen. im übrigen kann man auch gleich den wert an diese stelle schreiben, da sich die id der hauptnavigation in aller regel nicht verändern wird.

Verfasst: Fr 13. Jul 2007, 13:38
von kummer
matt.loker hat geschrieben:Ich hätte da mal eine Frage.

Kann man mit diesem Modul auch 2 verschiedene Menustrukturen gleichzeitig verwirklichen? also z.B. die ersten 2 Menuebenen als normales Listing und die 3. und 4. Ebene sind gesplitete Menus.

grüsse
kein problem. du hast alle freiheiten.

du kannst ja für jede ebene separat masken spezifizieren, nach belieben verschachteln oder - ist auch möglich - auf verschiedene module verteilen. in den weiteren modulen ist dann nur noch der aufruf von showNavigation notwendig. man muss einfach beachten, dass die klasseninstatiierung in demjenigen modul erfolgt, welches als erstes ausgeführt werden wird. sonst funktioniert es nicht.

Verfasst: Fr 13. Jul 2007, 16:12
von matt.loker
hab dein skript versucht einzubinden, aber ich bekomme nur eine fehlermeldung. Hab aber alles so gemacht wie es hier angesprochen wurde. was könnte ich den falsch machen - so viel kann man doch nicht falsch machen

Verfasst: Fr 13. Jul 2007, 16:31
von der_allgaeuer
matt.loker hat geschrieben:hab dein skript versucht einzubinden, aber ich bekomme nur eine fehlermeldung. Hab aber alles so gemacht wie es hier angesprochen wurde. was könnte ich den falsch machen - so viel kann man doch nicht falsch machen
Ich will versuchen Dir zu helfen -
was hast Du denn bisher gemacht? Ein bischen mehr solltest Du schon mitteilen :?

Verfasst: Fr 13. Jul 2007, 16:42
von matt.loker
ja entschuldige - ich hatte das script zwischenzeitlich mal gelöscht gehabt und habe die fehlermeldung nicht ganz aus dem kopf wiedergeben können.

also ich versuch mal meinen ablauf wiederzugeben.
ich habe eine datei atelierq.navigation.class.inc.php in contenido/classes erstellt. als nächstes habe ich ein modul "Atelierq Navigation" angelegt und als letztes habe ich eine property "Typ=navigation, Name=idcat_servicenavigation und Wert=1" im Mandanten angelegt.

Danach habe ich in meinem Standardtemplate die Hauptnavi "Hauptnavigation" durch "Atelierq Navigation" ausgetauscht.

Wenn ich dann auf meine Seite gehe, sehe ich eine fehlermeldung

Code: Alles auswählen

<b>Parse error</b>:  parse error, unexpected T_STRING in <b>/srv/www/vhosts/smoco.de/httpdocs/contenido/contenido/classes/atelierq.navigation.class.inc.php</b> on line <b>392</b>

Verfasst: Fr 13. Jul 2007, 16:54
von der_allgaeuer
nee,
da weiss ich jetzt auch nicht weiter.
Ich denke, da muss Dir doch kummer weiter helfen.

Ich hab im Prinzip nichts anderes gemacht. Bei mir funktioniert es super und ich kann es auch nach allen denkbaren Möglichkeiten einbauen.

Schade Leider :(

Verfasst: Fr 13. Jul 2007, 18:27
von kummer
matt.loker hat geschrieben:ja entschuldige - ich hatte das script zwischenzeitlich mal gelöscht gehabt und habe die fehlermeldung nicht ganz aus dem kopf wiedergeben können.

also ich versuch mal meinen ablauf wiederzugeben.
ich habe eine datei atelierq.navigation.class.inc.php in contenido/classes erstellt. als nächstes habe ich ein modul "Atelierq Navigation" angelegt und als letztes habe ich eine property "Typ=navigation, Name=idcat_servicenavigation und Wert=1" im Mandanten angelegt.

Danach habe ich in meinem Standardtemplate die Hauptnavi "Hauptnavigation" durch "Atelierq Navigation" ausgetauscht.

Wenn ich dann auf meine Seite gehe, sehe ich eine fehlermeldung

Code: Alles auswählen

<b>Parse error</b>:  parse error, unexpected T_STRING in <b>/srv/www/vhosts/smoco.de/httpdocs/contenido/contenido/classes/atelierq.navigation.class.inc.php</b> on line <b>392</b>
du hast alles richtig gemacht. im abgebildeten code hat das php-ausgangstag gefehlt (habe ich inzwischen hineingeflickt, ganz zuunterst an der klasse). das wird vermutlich bei dir einen fehler ausgelöst haben. ich habe es auch fehlerhaft in betrieb, ohne dass problem auftreten. komisch eigentlich.

du kannst es ja nun noch einmal versuchen. sollte so wie du es gemacht hast funktionieren.

gruss,
andreas