require_once ("element.inc.php"); require_once ("timer.inc.php"); require_once ("i18n.inc.php"); /** * Zgriff auf Gruppen \n * Abfragen, ändern und hinzufügen von Gruppen sowie auf die in der Gruppe gespeicherten Werte (Texte, Bilder) \n * \n * Gruppen sind eine Zusammenfassung von mehreren Elementen, also z.B. Text und Bild. * * \author Claus Muus * \date $Date$ */ class Group implements ArrayAccess { const ID_REQUEST_NAME = "cms_id"; ///< Request Variable die automatisch ausgewertet wird und dessen Wert als parent ID der Seite genommen wird private $parent_id = 0; ///< ID der Parent Gruppe private $id = 0; ///< ID der Gruppe private $online_id = 0; ///< ID der online stehenden Gruppe die zu dieser gehört private $link_id = 0; ///< Gibt bei einer Linkverfolgung die id der Gruppe an, auf die der Link verweist private $link_name = ""; ///< Gibt bei einer Linkverfolgung den Namen der Gruppe an, auf die der Link verweist private $link_group_name = ""; ///< name der verlinkten Gruppe private $has_ticket = false; ///< Gibt an ob diese Gruppe ein Ticket hat (nicht das Server Ticket) protected $list = NULL; ///< Liste der diese Gruppe angehört private $name = ""; ///< Name der Gruppe protected $edit_mode = Base::MODE_NONE; ///< Editier Modus dieser Gruppe private $edit_right = Base::MODE_NONE; ///< Editier Recht für diese Gruppe private $edit_groups = ""; ///< Gruppen die diese Gruppe editieren dürfen private $status = Base::STATUS_ERASED; ///< Status dieser Gruppe protected $url = ""; ///< URL dieser Gruppe protected $placeholders = array (); ///< Platzhalter die gesetzt wurden private $elementObjs = array (); ///< Element Objekte die bereits erzeugt wurden protected $group_number = 0; ///< Numer der Gruppe protected static $group_counter = 0; ///< Fortlaufende Numer der Gruppe protected static $site_number = 0; ///< Zähler über alle abgerufenen Seiten private static $checkInform = false; ///< speichert ob bereits informAboutChanges() aufgerufen wurde /** * Initialesiert das Objekt \n * Wird keine ID angegeben so wird nur ein lehres Objekt erzeugt das keine Entsprechung in der Datenbank hat * * \param values Ein assoziatives Array das Folgende optionalen Eigenschaften der Gruppe setzt: * \param parent_id ID der parent Gruppe. Ist beim erstellen neuer Gruppen erforderlich * \param id ID der Gruppe * \param link_id ID der Gruppe auf die diese Gruppe verweist. * \param link_name Name der Gruppe auf die diese Gruppe verweist. * \param list @ref Liste Objekt in dem diese Gruppe eingebunden ist * \param name Name der Gruppe * \param url URL unter welcher die Gruppe angezeigt wird * \param edit_groups Usergruppen die diese Gruppe angehört (siehe auch @ref User::getEditRight ) * \param edit_mode Editiermodus in dem diese Gruppe sich befinden soll */ public function __construct ($values=array ()) { if (!Setting::checkDb ()) { Header ("Location: " . Setting::get ("config", "cmsPath")); exit; } $db = new Database (); $this->checkTimer (); $this->parent_id = (isset ($values['parent_id']) && Base::is_int ($values['parent_id'])) ? $values['parent_id'] : $this->parent_id; $this->id = (isset ($values['id']) && Base::is_int ($values['id'])) ? $values['id'] : $this->id; $this->link_id = (isset ($values['link_id']) && Base::is_int ($values['link_id'])) ? $values['link_id'] : $this->link_id; $this->link_name = (isset ($values['link_name']) && is_string ($values['link_name'])) ? $values['link_name'] : $this->link_name; $this->list = (isset ($values['list']) && $values['list'] instanceof Liste) ? $values['list'] : $this->list; $this->name = (isset ($values['name']) && is_string ($values['name'])) ? self::trimmName ($values['name']) : $this->name; $this->url = (isset ($values['url']) && is_string ($values['url'])) ? $values['url'] : $this->url; $this->edit_groups = (isset ($values['edit_groups']) && is_string ($values['edit_groups'])) ? $values['edit_groups'] : $this->edit_groups; if ($this->id && $db->query ("SELECT parent_group_id, online_group_id, name, status, edit_groups, url, ticket_id FROM `{prefix}group` WHERE id={$this->id} AND ({$this->parent_id}=0 OR parent_group_id={$this->parent_id})")) { $this->parent_id = $db['parent_group_id']; $this->online_id = $db['online_group_id'] ? $db['online_group_id'] : $this->id; $this->name = $db['name']; $this->status = $db['status']; $this->has_ticket = ($db['ticket_id'] && ($db['ticket_id'] == Ticket::selected ())); $url = $db['url']; if ($this->link_id) { $this->url = $db['url']; // Gruppe ist ein link if ($db->query ("SELECT name, edit_groups FROM `{prefix}group` WHERE id={$this->link_id} AND ''='{$this->link_name}' OR parent_group_id={$this->link_id} AND name='{$this->link_name}'")) { //$this->link_parent_id = $db['parent_group_id']; $this->link_group_name = $db['name']; // Gruppe übernimmt daher die Editierrechte seiner Quelle $this->edit_groups = $db['edit_groups']; } } else if (self::editMode ()) { // Editierrechte speichern if (isset ($values['edit_groups'])) { $db->query ("UPDATE `{prefix}group` SET edit_groups='{$this->edit_groups}' WHERE id={$this->online_id} OR online_group_id={$this->online_id}"); } else { $this->edit_groups = $db['edit_groups']; } // update url if ($this->url) { $url = Database::escape ($this->url); $db->query ("UPDATE `{prefix}group` SET url='{$url}' WHERE id={$this->online_id} OR online_group_id={$this->online_id}"); } else { $this->url = $url; } } else { $this->url = $db['url']; } } else { $this->id = 0; } // Wenn eingeloggt if (User::get ("id")) { // Edit Mode für Main-Dot initialesieren self::initEditMode (0, Ticket::selected () ? Base::MODE_VIEW : Base::MODE_ONLINE); $this->edit_right = User::getEditRight ($this->edit_groups); if ($this->id) { $this->group_number = $this->online_id; } else { self::$group_counter ++; $this->group_number = 0 . self::$group_counter; } if ($this->link_id) { $this->group_number = $this->link_id . "_" . $this->id; } } $this->edit_mode = (isset ($values['edit_mode']) && Base::is_int ($values['edit_mode'])) ? $values['edit_mode'] : self::getEditMode (); self::informAboutChanges (); } /** * Gibt den Wert für einige Objekt Variablen zurück * * \param name Name der abgefragten Objekt Variable. Definierte namen sind: * - id: Online ID der Gruppe * - offline_id: Offline ID der Gruppe * - child: Ein String in der Form "cms_id=12345" zur Verwendung in Links als Verweis auf unterseiten * - childName: Der name der child Variable. Default ist "cms_id" * - editMode: true wenn diese Gruppe im Editiermodus ist, sonst false * - hasSub: Prüft ob die Gruppe Untergruppen hat * - hasNext: Prüft ob in der Parent Liste weitere Gruppen folgen * - alle privaten Objekt Variablen * * \return Wert der abgefragten Objekt Variable */ public function __get ($name) { switch ($name) { case "id": return $this->online_id; case "offline_id": return $this->id; case "child": return $this->child (); case "childId": return $this->childId (); case "childName": return self::ID_REQUEST_NAME; case "editMode": return $this->edit_mode & Base::MODE_EDIT; case "hasSub": return $this->hasSub (); case "hasNext": return $this->list->hasNext; default: if (isset ($this->$name)) { return $this->$name; } else { Base::error ("Undefined property: Group::\$$name"); } } } /** * Setz den Wert einiger Objekt Variablen * * \param name Name der Objekt Variable die gesetzt werden soll. Definierte namen sind: * - editMode: Der Editiermodus der Gruppe */ public function __set ($name, $value) { switch ($name) { case "edit_mode": $this->edit_mode = (Base::is_int ($value)) ? $value : Base::MODE_NONE; $this->elementObjs = array (); break; } } /** * Prüft ob ein Element gesetzt ist \n * Bsp.: if ($group['name']) * * \param name Name des Elementes * * \return true wenn das Elementes gesetzt ist, sonst false */ public function offsetExists ($name) { return $this->element ($name)->exists (); } /** * Liest den Wert eins Elements \n * Bsp.: $text = $group['name'] * * \param name Name des Elementes * * \return Wert des Elementes */ public function offsetGet ($name) { return $this->element ($name)->getValue (false, false); } /** * Setzt den Wert eins Elements \n * Bsp.: $group['name'] = "text" * * \param name Name des Elementes * \param text Text der dem Element zugewiesen werden soll * * \return bei Erfolg Wert des Elementes, sonst false */ public function offsetSet ($name, $text) { if (!$this->has_ticket) { $last_online_id = $this->online_id; if ($this->create ()) { $db = new Database (); $history = new History ("group set value"); $history->groupStart (); $this->status = Base::STATUS_OFFLINE; $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET status={$this->status} WHERE id={$this->id}"); $history->store ($this->id, "group"); if ($this->online_id != $last_online_id) { $this->move (0); } $status = $this->element ($name)->setValue ($text); if ($this->list) { $this->list->updateGroups (); } $history->groupEnd (); return $status ? $text : false; } } else { return $this->element ($name)->setValue ($text) ? $text : false; } return false; } /** * Löscht ein Element * Bsp.: unset ($group['name']) * * \param name Name des Elementes das gelöscht werden soll */ public function offsetUnset ($name) { $this->element ($name)->del (); } /** * Entfernd aus einem Namen alle für Gruppennamen unerlaupten Zeichen * * \param name Name der Normiert werdn soll * * \return Normierter Gruppenname */ public static function trimmName ($name) { return preg_replace ("/^[^a-zA-Z_\/]+|[^a-zA-Z0-9- _\/]/s", "", $name); } /** * Erzeugt eine Positions ID vor der angegebenen Position \n * Wurde keine ID angegeben wird eine ID fürs Ende der aktuellen Liste zurück gegeben * * \param before_id ID der Gruppe vor der die aktuelle Gruppe eingefügt werden soll, oder 0 um am Ende einzufügen * * \return ID der neuen Position */ protected function newSequence ($before_id=0) { if ($this->parent_id && $this->name) { $db = new Database (); $sequence = 0; if ($before_id && Base::is_int ($before_id) && $db->query ("SELECT s.sequence FROM `{prefix}group` g, {prefix}sequence s WHERE g.id=$before_id AND s.id=sequence_id")) { $sequence = $db['sequence']; if ($db->query ("SELECT s.id, s.sequence FROM `{prefix}group` g, {prefix}sequence s WHERE parent_group_id={$this->parent_id} AND name='{$this->name}' AND s.id=sequence_id AND s.sequence>=$sequence")) { foreach ($db->result as $row) { $db->query ("UPDATE {prefix}sequence SET sequence=sequence+1 WHERE id={$row['id']}"); } } } else if ($db->query ("SELECT MAX(s.sequence) AS max_sequence FROM `{prefix}group` g, {prefix}sequence s WHERE parent_group_id={$this->parent_id} AND name='{$this->name}' AND s.id=sequence_id")) { // Es wird am ende eingefügt $sequence = $db['max_sequence'] + 1; } $db->query ("INSERT INTO {prefix}sequence (sequence) VALUES ($sequence)"); return $db->rowid; } return 0; } /** * Liefert ein Element Objekt zum angegebenen Namen * * \param name Name des Elementes * \param id ID des Elementes * * \return Element Objekt zum angegebenen Namen */ public function element ($name, $id=0) { if (!isset ($this->elementObjs[$name])) { $this->elementObjs[$name] = new Element (array ('group_id' => $this->link_id ? $this->link_id : $this->online_id, 'group_name' => $this->link_id ? $this->link_group_name : $this->name, 'name' => $name, 'id' => $id, 'edit_mode' => $this->edit_mode)); } return $this->elementObjs[$name]; } /** * Macht die Gruppe zur ersten Gruppe auf einer Seite oder Erzeugt diese wenn noch keine existiert. Diese ist nicht Editierbar * * \return ID der gruppe wenn erfolgreich, sonst 0 */ public function createTop () { $db = new Database (); if ($db->query ("SELECT id, status FROM `{prefix}group` WHERE parent_group_id={$this->parent_id} AND name='{$this->name}'")) { $this->id = $db['id']; $this->status = $db['status']; $this->online_id = $this->id; $this->has_ticket = false; } if ($this->name && $this->edit_mode & Base::MODE_EDIT) { if (!$this->id && self::editMode ()) { $url = Database::escape ($this->url); $db->query ("INSERT INTO `{prefix}group` (parent_group_id, link_group_name, name, status, url) VALUES ({$this->parent_id}, '', '{$this->name}', ".Base::STATUS_ERASED.", '{$url}')"); $this->id = $db->rowid; $this->status = Base::STATUS_ERASED; $this->online_id = $this->id; $this->has_ticket = false; } if ($this->status != Base::STATUS_ONLINE) { $this->status = Base::STATUS_ONLINE; $history = new History ("group create top"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET status={$this->status} WHERE id={$this->id}"); $history->store ($this->id, "group"); } $this->elementObjs = array (); } return $this->id; } /** * Erzeugt eine neue Gruppe falls diese bisher nur ein Platzhalter ist, oder für das aktuelle Ticket noch keine existiert. * * \return ID der Gruppe wenn erfolgreich, sonst 0 */ public function create () { if (!Ticket::id ()) { return 0; } if (!$this->has_ticket && $this->parent_id && $this->name) { // Neuen Eintrag anlegen $db = new Database (); $history = new History ("group no changes"); $history->groupStart (); if ($this->id && $db->query ("SELECT link_group_id, link_group_name, status, sequence_id, url FROM `{prefix}group` WHERE id={$this->id}")) { // Kopie des sichtbaren $link_group_id = $db['link_group_id']; $link_group_name = $db['link_group_name']; $sequence_id = $db['sequence_id']; $url = Database::escape ($db['url']); $this->status = $db['status'] | (Base::STATUS_REMOVED); // $this->status = $db['status'] & (~ Base::STATUS_ONLINE); } else { // neuer Eintrag $url = Database::escape ($this->url); $db->query ("INSERT INTO `{prefix}group` (parent_group_id, name, status, url) VALUES ({$this->parent_id}, '{$this->name}', ".Base::STATUS_ERASED.", '$url')"); $this->online_id = $db->rowid; $link_group_id = 0; $link_group_name = ""; $sequence_id = 0; $this->status = Base::STATUS_ERASED; $history->store ($this->online_id, "group"); } $db->query ("INSERT INTO `{prefix}group` (parent_group_id, link_group_id, link_group_name, online_group_id, name, status, sequence_id, url, ticket_id) VALUES ({$this->parent_id}, $link_group_id, '$link_group_name', {$this->online_id}, '{$this->name}', {$this->status}, $sequence_id, '$url', ".Ticket::id ().")"); $this->id = $db->rowid; $this->has_ticket = true; $history->store ($this->id, "group"); $this->elementObjs = array (); $history->groupEnd (); } return $this->id; } /** * Verschiebt diese Gruppe an die Position vor der angegebenen Gruppe * * \param before_id ID der Gruppe vor der eingefügt werden soll, oder 0 um am Ende einzufügen * \param parent_id ID der Parent Gruppe, zu der die Liste gehört, in die am Ende eingefügt werden soll, sofern keine before_id angegeben wurde (optional) * \param name Name der Parent Gruppe, zu der die Liste gehört, in die eingefügt werden soll, sofern keine before_id angegeben wurde (optional) */ public function move ($before_id, $parent_id=0, $name="") { if ($before_id != $this->id && Base::is_int ($before_id) && $this->create ()) { $db = new Database (); if ($db->query ("SELECT parent_group_id, name, url FROM `{prefix}group` WHERE id=$before_id OR ($before_id=0 AND parent_group_id=$parent_id AND name='$name')")) { $this->parent_id = $db['parent_group_id']; $this->name = $db['name']; $this->url = $db['url']; } else { if ($parent_id && $name) { $this->parent_id = $parent_id; $this->name = $name; } if ($db->query ("SELECT url FROM `{prefix}group` WHERE id=$parent_id")) { $this->url = $db['url']; } } $sequence_id = $this->newSequence ($before_id); $this->status = Base::STATUS_OFFLINE; $url = Database::escape ($this->url); $history = new History ("group move"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET parent_group_id={$this->parent_id}, name='{$this->name}', sequence_id=$sequence_id, status={$this->status}, url='{$url}' WHERE id={$this->id}"); $history->store ($this->id, "group"); } } /** * Kopiert die angegebene Gruppe, sofern eine angegeben wurde. Wurde keine ID angegeben wird für die aktuelle Gruppe nur eine ID erzeugt wenn sie bisher noch keine ID hatte * * \param id ID der zu kopierenden Gruppe * \param recursive wenn true dann wird rekursiv kopiert */ public function set ($id=0, $recursive=true, $parentlist=array ()) { if (empty ($parentlist[$id]) && $this->create ()) { $parentlist[$this->id] = true; if ($id != $this->id && $id && Base::is_int ($id)) { // Es soll eine Kopie eingefügt werden $db = new Database (); $history = new History ("group set"); $history->groupStart (); $history->storeOld ($this->id, "group"); // Offline setzen $this->status = Base::STATUS_OFFLINE; $db->query ("UPDATE `{prefix}group` SET status={$this->status} WHERE id={$this->id}"); if ($db->query ("SELECT link_group_id, link_group_name, ticket_id, status FROM `{prefix}group` WHERE (id=$id OR (online_group_id=$id AND (ticket_id=".Ticket::SERVER_ID." OR ticket_id=".Ticket::selected ()."))) AND link_group_id!=0 ORDER BY ticket_id DESC LIMIT 1")) { // Wenn quelle ein Link ist nur Link kopieren if (!($db['status'] & (Base::STATUS_ERASED | Base::STATUS_ARCHIVED))) { $link_id = $db['link_group_id']; $link_name = $db['link_group_name']; $db->query ("UPDATE `{prefix}group` SET link_group_id=$link_id, link_group_name='$link_name' WHERE id={$this->id}"); } } else { $childs = array (); if ($recursive && $db->query ("SELECT online_group_id FROM `{prefix}group` WHERE id=$id")) { $online_id = $db['online_group_id'] ? $db['online_group_id'] : $id; // Untereintraege kopieren foreach (self::getChildList ($online_id) as $row) { if (preg_match ("/^\//", $row['name'])) { // Diese Quell-Gruppe ist auf einer neuen Seite // Wenn die neue Quell-Seite nicht den selben Namen wie die vorhergehende Quell-Seite hat, // kann sie nur mit kopiert werden, wenn die vorhergehende Quell-Seite den selben Namen wie die vorhergehende Ziel-Seite hat // Name der vorhergehenden Quell Seite suchen $src_name = ""; $pid = $id; while ($db->query ("SELECT parent_group_id, name FROM `{prefix}group` WHERE id=$pid")) { if (preg_match ("/^\//", $db['name'])) { $src_name = $db['name']; break; } $pid = $db['parent_group_id']; } // name der vorhergehenden Ziel-Seite suchen $dest_name = ""; $pid = $this->id; while ($db->query ("SELECT parent_group_id, name FROM `{prefix}group` WHERE id=$pid")) { if (preg_match ("/^\//", $db['name'])) { $dest_name = $db['name']; break; } $pid = $db['parent_group_id']; } if ($src_name == $row['name']) { // Diese Ziel-Seite muss den Namen der vorhergehenden Ziel-Seite bekommen $row['name'] = $dest_name; } else { // nur kopieren wenn die vorhergehende Quell-Seite den selben Namen wie die vorhergehende Ziel-Seite hat if ($dest_name != $src_name) { // Seite darf nicht mitkopiert werden, da der neue Name nicht erkannt werden konnte continue; } } } // Gruppe kopieren $group = new Group (array ('parent_id' => $this->online_id, 'name' => $row['name'])); $group->set ($row['id'], true, $parentlist); $group->move (0, $this->online_id, $row['name']); $childs[$row['online_group_id']] = $group->online_id; } // Daten kopieren if ($db->query ("SELECT id, name, ticket_id, status FROM {prefix}element WHERE group_id=$online_id AND (ticket_id=0 OR ticket_id=".Ticket::SERVER_ID." OR ticket_id=".Ticket::selected ().") ORDER BY ticket_id")) { $elements = array (); foreach ($db as $row) { if (!($row['status'] & (Base::STATUS_ERASED | Base::STATUS_ARCHIVED))) { if (empty ($elements[$row['name']]) || $row['status'] & Base::STATUS_ONLINE) { $elements[$row['name']] = $row; } } else { unset ($elements[$row['name']]); } } foreach ($elements as $row) { $this->element ($row['name'])->setCopy ($row['id']); if ($childs) { // Links auf childs anpassen $text = $this->element ($row['name'])->getValue (); foreach ($childs as $src_id => $dest_id) { $text = preg_replace ("/".self::ID_REQUEST_NAME."=$src_id/", self::ID_REQUEST_NAME."=$dest_id", $text); } $this->element ($row['name'])->setValue ($text); } } } } } $history->store ($this->id, "group"); $history->groupEnd (); } } } /** * Macht diese Gruppe zu einem Link auf die angegebene Gruppe * * \param id ID der Gruppe auf die verlinkt werden soll. Wenn der Name mit angegeben wird, verweist die ID auf eine Liste * \param name Name der Liste auf die verlinkt werden soll */ public function setLink ($id, $name="") { if ($name == "" && $id != $this->id && $id != $this->online_id && Base::is_int ($id) && $this->create ()) { $db = new Database (); if ($db->query ("SELECT online_group_id FROM `{prefix}group` WHERE id={$id} AND online_group_id!=0")) { $id = $db['online_group_id']; } $this->status = Base::STATUS_OFFLINE; $history = new History ("group set link"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET link_group_id=$id, status={$this->status} WHERE id={$this->id}"); $history->store ($this->id, "group"); } if ($name != "" && ($id != $this->parent_id || $name != $this->name) && Base::is_int ($id) && $this->create ()) { $db = new Database (); $this->status = Base::STATUS_OFFLINE; $history = new History ("group set link"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET link_group_id=$id, link_group_name='$name', status={$this->status} WHERE id={$this->id}"); $history->store ($this->id, "group"); } } // Achtung: Durch diese einfache (nicht rekusieve) Form des Loeschens koennen Weisen entstehen // Beim Rekusievem Löschen könnten hingegen tote Links in Texten oder von Einträgen entstehen, // was jedoch in jedem fall geprüft werden sollte und eventuell ein Löschen verhindern müsste. /** * Löscht die Gruppe */ public function del () { if (!($this->status & Base::STATUS_ERASED) && $this->create ()) { $db = new Database (); $history = new History ("group delete"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET status=".Base::STATUS_ERASED." WHERE id={$this->id}"); $this->status = Base::STATUS_ERASED; $history->store ($this->id, "group"); } } /** * Stellt den Zustand wieder her, der geherscht hatte bevor diese Gruppe erstellt/bearbeitet wurde * - Das ist der Zustand als die Gruppe angelegt wurde * - Diese Änderung wirkt sich nicht direkt auf den online Zustand aus */ public function remove () { $history = History::getList ($this->id, "group", true, 0, "group no changes"); if ($history) { History::restore ($history[0]['id']); } else { $db = new Database (); $this->status |= Base::STATUS_REMOVED; $db->query ("UPDATE `{prefix}group` SET status=status|".Base::STATUS_REMOVED." WHERE id={$this->id}"); } } /** * Verschiebt die Gruppe in das Archiv */ public function archive () { if (!($this->status & Base::STATUS_ARCHIVED) && $this->create ()) { $db = new Database (); $history = new History ("group archive"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET status=".Base::STATUS_ARCHIVED." WHERE id={$this->id}"); $this->status = Base::STATUS_ARCHIVED; $history->store ($this->id, "group"); } } /** * setzt die Gruppe offline und löscht alle anderen Zustände (online, archive, erased) */ public function offline () { if ($this->status && $this->create ()) { $db = new Database (); $history = new History ("group offline"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET status=".Base::STATUS_OFFLINE." WHERE id={$this->id}"); $this->status = Base::STATUS_OFFLINE; $history->store ($this->id, "group"); } } /** * setzt die Gruppe online und löscht alle anderen Zustände (offline, archive, erased) */ public function online () { if ($this->status && $this->create ()) { $db = new Database (); $history = new History ("group online"); $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET status=".Base::STATUS_ONLINE." WHERE id={$this->id}"); $this->status = Base::STATUS_ONLINE; $history->store ($this->id, "group"); } } /** * Diese Gruppe und alle untergruppen online stellen, oder diese Gruppe offline Stellen * * \param status Status der gesetzt werden soll (Base::STATUS_ONLINE, Base::STATUS_OFFLINE) * * \return Der neue Status der Gruppe */ public function setStatus ($status) { $db = new Database (); // online stellen if ($status == Base::STATUS_ONLINE && $this->id) { $history = new History ("group set online"); $history->groupStart (); $statusChanged = false; if(!($this->status & Base::STATUS_ONLINE)) { // bei den Einträgen (zu dieser online_id) die bisher online waren, das online Attribut entfernen if ($db->query ("SELECT id FROM `{prefix}group` WHERE online_group_id={$this->online_id} AND status&".Base::STATUS_ONLINE)) { foreach ($db->result as $row) { $id = $row['id']; $history->storeOld ($id, "group"); $db->query ("UPDATE `{prefix}group` SET status=status&".(~ Base::STATUS_ONLINE)." WHERE id=$id"); $history->store ($id, "group"); } } // aenderungen an diesem Eintrag nach online uebernehmen $this->status |= Base::STATUS_ONLINE; if ($db->query ("SELECT parent_group_id, link_group_id, link_group_name, name, edit_groups, sequence_id, url FROM `{prefix}group` WHERE id={$this->id}")) { $parent_id = $db['parent_group_id']; $link_id = $db['link_group_id']; $link_name = $db['link_group_name']; $name = $db['name']; $edit_groups = $db['edit_groups']; $sequence_id = $db['sequence_id']; $url = Database::escape ($db['url']); if (!$db->query ("SELECT id FROM `{prefix}group` WHERE id={$this->online_id}")) { $db->query ("INSERT INTO `{prefix}group` (id, parent_group_id, name, status, edit_groups, url) VALUES ({$this->online_id}, $parent_id, '$name', ".Base::STATUS_ERASED.", '$edit_groups', '$url')"); } $history->storeOld ($this->online_id, "group"); $db->query ("UPDATE `{prefix}group` SET parent_group_id=$parent_id, link_group_id=$link_id, link_group_name='$link_name', name='$name', status={$this->status}, sequence_id=$sequence_id WHERE id={$this->online_id}"); $history->store ($this->online_id, "group"); } // Eintrag online makieren $history->storeOld ($this->id, "group"); $db->query ("UPDATE `{prefix}group` SET status={$this->status} WHERE id={$this->id}"); $history->store ($this->id, "group"); $statusChanged = true; } // Daten online stellen $elementChanged = false; if ($db->query ("SELECT DISTINCT id, name FROM {prefix}element WHERE group_id={$this->online_id} AND (ticket_id=".Ticket::SERVER_ID." OR ticket_id=".Ticket::id ().")")) { foreach ($db as $row) { if ($this->element ($row['name'], $row['id'])->setStatus ($status)) { $elementChanged = true; } } } if (!$statusChanged && $elementChanged) { $history->storeOld ($this->id, "group"); $history->store ($this->id, "group"); } // Untereintraege online stellen if ($this->online_id) { foreach (self::getChildList ($this->online_id, "", true) as $row) { // edit_groups von parent nehmen falls es bisher nicht gesetzt wurde (z.B. bei im Text eingebettete Bilder) $edit_groups = $row['edit_groups'] ? $row['edit_groups'] : $this->edit_groups; if (User::getEditRight ($edit_groups) & Base::MODE_ONLINE) { $group = new Group (array ('id' => $row['id'], 'edit_groups' => $edit_groups)); $group->setStatus ($status); } } } $history->groupEnd (); } // offline stellen if ($status == Base::STATUS_OFFLINE && $db->query ("SELECT status FROM `{prefix}group` WHERE id={$this->online_id}")) { if($db['status'] & Base::STATUS_ONLINE) { $history = new History ("group set offline"); $this->status &= (~ Base::STATUS_ONLINE); // Eintrag offline stellen $history->storeOld ($this->online_id, "group"); $db->query ("UPDATE `{prefix}group` SET status=status&".(~ Base::STATUS_ONLINE)." WHERE id={$this->online_id}"); $history->store ($this->online_id, "group"); // bei den Einträgen (zu dieser online_id) die bisher online waren, das online Attribut entfernen if ($db->query ("SELECT id FROM `{prefix}group` WHERE online_group_id={$this->online_id} AND status&".Base::STATUS_ONLINE)) { foreach ($db->result as $row) { $id = $row['id']; $history->storeOld ($id, "group"); $db->query ("UPDATE `{prefix}group` SET status=status&".(~ Base::STATUS_ONLINE)." WHERE id=$id"); $history->store ($id, "group"); } } } } return $this->status; } /** * Liefert den Status der onlinegruppe * * \param id ID der Gruppe * * \return Status der onlinegruppe */ public static function getOnlineGroupStatus ($id) { $db = new Database (); if ($id && Base::is_int ($id) && $db->query ("SELECT g2.status FROM `{prefix}group` g1, `{prefix}group` g2 WHERE g1.id={$id} AND g2.id=g1.online_group_id")) { return $db['status']; } return Base::MODE_NONE; } /** * Liefert die Timer-id des Timers der für die angegebene Gruppe gesetzt ist * * \param id ID der Gruppe zu der der Timer gesucht wird * * \return ID des Timers wenn einer gesetzt ist, sonst 0 */ public static function getTimer ($id) { $db = new Database (); if ($id && Base::is_int ($id) && $db->query ("SELECT timer_id FROM `{prefix}group` WHERE id=$id")) { return ($db['timer_id'] > 0) ? $db['timer_id'] : -$db['timer_id']; } return 0; } /** * Setzt einen Timer auf eine Gruppe * * \param id ID der Gruppe auf der der Timer gesetzt werden soll * \param id ID des Timers */ public static function setTimer ($id, $timer_id) { $db = new Database (); if ($id && Base::is_int ($id) && Base::is_int ($timer_id)) { $history = new History ("group set timer"); $history->storeOld ($id, "group"); $db->query ("UPDATE `{prefix}group` SET timer_id=$timer_id WHERE id=$id"); $history->store ($id, "group"); } } /** * Löscht einen Timer aus eine Gruppe oder komplett * * \param id ID der Gruppe aus der der Timer gelöscht werden soll * \param complete wenn true dann wird der angegebene Timer aus allen Gruppen gelöscht in denen er gesetzt wurde */ public static function delTimer ($id, $complete=false) { $db = new Database (); if ($id && Base::is_int ($id)) { $history = new History ("group del timer"); if ($complete && $db->query ("SELECT timer_id FROM `{prefix}group` WHERE id=$id")) { $timer_id = $db['timer_id']; if ($db->query ("SELECT id FROM `{prefix}group` WHERE timer_id=$timer_id")) { foreach ($db->result as $row) { $history->storeOld ($row['id'], "group"); $db->query ("UPDATE `{prefix}group` SET timer_id=0 WHERE id={$row['id']}"); $history->store ($row['id'], "group"); } } Timer::del ($timer_id); } else { $history->storeOld ($id, "group"); $db->query ("UPDATE `{prefix}group` SET timer_id=0 WHERE id=$id"); $history->store ($id, "group"); } } } /** * Prüft ob ein Timer abgelaufen ist und führt gegebenen falls alle an ihn gebundenen Aktionen aus */ private function checkTimer () { if (Setting::get ("group", "checktimer time", 0)+60 < time ()) { Setting::set ("group", "checktimer time", time (), false); $db = new Database (); $history = new History ("execute timer"); $history->groupStart (); foreach (Timer::getExpiredList () as $timer) { $timer_id = $timer['id']; if ($db->query ("SELECT id, timer_id FROM `{prefix}group` WHERE timer_id=$timer_id OR timer_id=-$timer_id")) { foreach ($db as $row) { $group = new Group ($row['id']); $group->setStatus (($row['timer_id']>0) ? Base::STATUS_ONLINE : Base::STATUS_OFFLINE); self::delTimer ($row['id']); } } Timer::del ($timer_id); } $history->groupEnd (); } } /** * Holt id und Name der parent Gruppe * * \param id Id des Eintrages */ public static function getParent ($id) { $db = new Database (); if ($id && Base::is_int ($id) && (self::editMode () && $db->query ("SELECT parent_group_id, name FROM `{prefix}group` WHERE online_group_id=$id") || $db->query ("SELECT parent_group_id, name FROM `{prefix}group` WHERE id=$id"))) { return array ('id' => $db['parent_group_id'], 'name' => $db['name']); } return array (); } /** * Liefert einen url Query-string für Verweise auf unterseiten * * \param name name der child Seite (optional) */ public function child ($name="") { return self::ID_REQUEST_NAME . "=" . (Base::is_int ($name) ? $name : $this->childId ($name)); } /** * Liefert die parentId für eine child Gruppe, bzw die id der child Gruppe wenn $createNew gesetzt ist. Wird kein name angegeben so ist dies die onlineId dieser Gruppe,\n * Wird ein name angegeben so wird eine Untergruppe angelegt, welche die Namen verwaltet. Dies wird z.B. von links in Texten verwendet.\n * Es wird nur im Editirmodus oder wenn $createNew gesetzt ist eine neue Untergruppe mit dem gegebenem Namen angelegt. * * \param name name des child Eintrages (optional) * \param createNew erzeuge einen neuen Eintrag am Ende der child Liste (optional) */ public function childId ($name="", $createNew=false) { $online_id = $this->link_id ? $this->link_id : $this->online_id; if (!$name || !$this->online_id) { return $online_id; } $db = new Database (); if (!$createNew && $db->query ("SELECT id, online_group_id FROM `{prefix}group` WHERE parent_group_id=$online_id AND name='/$name' AND (ticket_id=0 OR ticket_id=".Ticket::SERVER_ID." OR ticket_id=".Ticket::selected ().") AND !(status&".(Base::STATUS_ERASED | Base::STATUS_ARCHIVED | Base::STATUS_REMOVED).") AND ({$this->edit_mode}!=0 OR status&".Base::STATUS_ONLINE.") ORDER BY ticket_id DESC")) { return $db['online_group_id'] ? $db['online_group_id'] : $db['id']; } else if ($createNew || ($this->edit_mode & Base::MODE_EDIT)) { $child = new Group (array ('parent_id' => $online_id, 'name' => "/$name", 'url' => $this->url)); //$child->create (); $child->offline (); return $createNew ? $child->online_id : $online_id; } else { return 0; } } /** * Liste aller Gruppen zur angegebenen parent Gruppe holen * * \param parent_id Id der parent Gruppe * \param name name der gesuchten Gruppen * \param all auch geloeschte/archivierte Gruppen */ public static function getChildList ($parent_id, $name="", $all=false, $edit_mode=false) { $name = (is_string ($name)) ? self::trimmName ($name) : ""; $parent_id = (Base::is_int ($parent_id)) ? $parent_id : -1; $edit_mode = (Base::is_int ($edit_mode) && $edit_mode!==false) ? $edit_mode : (Base::MODE_VIEW | Base::MODE_EDIT); $groups = array (); $db = new Database (); // Nur online Eintraege weden aus Performance Gruenden gesondert behandelt if ((self::getEditMode () & $edit_mode) || $all) { // Sowohl online als auch offline Eintraege, und wenn $all gesetzt ist auch geloeschte if ($db->query ("SELECT g2.id, g2.link_group_id, g2.link_group_name, g2.name, g2.status, g2.edit_groups, g2.ticket_id, g2.online_group_id, g2.parent_group_id, g2.url, s.sequence FROM `{prefix}group` g1, `{prefix}group` g2 LEFT JOIN {prefix}sequence s ON s.id=g2.sequence_id WHERE g1.parent_group_id=$parent_id AND ('$name'='' OR g1.name='$name') AND (g1.ticket_id=0 OR g1.ticket_id=".Ticket::SERVER_ID." OR g1.ticket_id=".Ticket::selected ().") AND ((g2.id=g1.id) OR (g2.online_group_id=g1.id AND g2.parent_group_id!=g1.parent_group_id AND (g2.ticket_id=".Ticket::SERVER_ID." OR g2.ticket_id=".Ticket::selected ()."))) ORDER BY ticket_id")) { foreach ($db as $row) { if ($row['online_group_id']) { // die onlineId wieder aus der Liste entfernen, da dieser Eintrag die bearbeitete Version des bestehenden Eintrages ist unset ($groups[$row['online_group_id']]); foreach ($groups as $group) { if ($group['online_group_id'] == $row['online_group_id']) { // die id wieder aus der Liste entfernen, da die ticket_id dieses Eintarges eine höhere Priorität als der bestehenden Eintrages hat unset ($groups[$group['id']]); } } } if (($all && !($row['status'] & Base::STATUS_REMOVED)) || !($row['status'] & (Base::STATUS_REMOVED | Base::STATUS_ERASED | Base::STATUS_ARCHIVED)) && $row['parent_group_id'] == $parent_id){ // Eintrag in Liste aufnehmen $groups[$row['id']] = $row; } } } usort ($groups, array ("Group", "groupSequenceCmp")); } else { // Nur online Eintraege if ($db->query ("SELECT g.id, link_group_id, link_group_name, name, status, edit_groups, ticket_id, online_group_id, parent_group_id, url, s.sequence FROM `{prefix}group` g, {prefix}sequence s WHERE parent_group_id=$parent_id AND ('$name'='' OR name='$name') AND ticket_id=0 AND status=".Base::STATUS_ONLINE." AND s.id=sequence_id ORDER BY sequence")) { $groups = $db->result; } } return $groups; } /** * Alle Gruppen/Elemente die unter dem gegebenen Ticket bearbeitet wurden * * \param ticket_id Id des Tickets oder 0 für alle (optional) */ public static function getEditList ($ticket_id=NULL) { $ticket_id = (Base::is_int ($ticket_id)) ? $ticket_id : Ticket::selected (); $groups = array (); $db = new Database (); // geänderte Gruppen if ($db->query ("SELECT g1.id, g1.name, g1.status, g1.edit_groups, g1.url, g2.id AS online_id, h.time, h.ticket_id, h.id AS history_id, u.realname AS username FROM `{prefix}group` g1 LEFT JOIN {prefix}history h ON h.row_id=g1.id AND h.table_name='group' AND h.ticket_id=$ticket_id AND h.status='".History::STATUS_ACTIVE."' LEFT JOIN `{prefix}user` u ON h.user_id=u.id, `{prefix}group` g2 WHERE ($ticket_id=0 OR g1.ticket_id=$ticket_id) AND g2.id=g1.online_group_id AND (!(g1.status&".(Base::STATUS_ERASED | Base::STATUS_ARCHIVED | Base::STATUS_REMOVED).") OR (g2.status&".Base::STATUS_ONLINE."))")) { foreach ($db as $row) { if (User::getEditRight ($row['edit_groups']) && (Base::MODE_VIEW | Base::MODE_EDIT | Base::MODE_ONLINE)) { $groups[$row['history_id']] = $row; } } } // geänderte Elemente (von online stehenden Gruppen) if ($db->query ("SELECT e.id AS element_id, g.name, e.name AS element_name, e.status, g.edit_groups, g.url, g.id, g.online_group_id AS online_id, h.time, h.ticket_id, h.id AS history_id, u.realname AS username FROM `{prefix}element` e LEFT JOIN {prefix}history h ON h.row_id=e.id AND h.table_name='element' AND h.ticket_id=$ticket_id AND h.status='".History::STATUS_ACTIVE."' LEFT JOIN `{prefix}user` u ON h.user_id=u.id, `{prefix}group` g WHERE ($ticket_id=0 OR e.ticket_id=$ticket_id) AND e.group_id=g.online_group_id AND (!(e.status&".Base::STATUS_ONLINE.") AND (g.status&".Base::STATUS_ONLINE."))")) { foreach ($db as $row) { if (User::getEditRight ($row['edit_groups']) && (Base::MODE_VIEW | Base::MODE_EDIT | Base::MODE_ONLINE)) { $groups[$row['history_id']] = $row; } } } ksort ($groups); return $groups; } /** * Informationen zur Bearbeitung der aktuellen Gruppe * * \return Array mit Infos (username, time) */ public function getEditInfo () { $ticket_id = Ticket::selected (); $db = new Database (); if ($db->query ("SELECT h.time, u.realname AS username FROM {prefix}history h LEFT JOIN `{prefix}user` u ON h.user_id=u.id WHERE h.row_id={$this->id} AND h.table_name='group' AND h.ticket_id=$ticket_id AND h.status='".History::STATUS_ACTIVE."'")) { return $db[0]; } return array (); } /** * Volltextsuche über alle angegebenen Gruppen und Elemente * * \param search text to search or array witch 'search' and url like expression (e.g. array ('search'=>"foo", 'url'=>"%lang=en%")) * \param elements Elemente in denen gesucht werden soll. Ein Array aus Gruppen und Elementen (Bsp.: array ('group1' => 'element1', 'group2' => array ('element1', 'element2'))) * \param max_rows Maximale Anzahl von Ergebniszeilen * \param snippet_len Länge der Textschnipsel um die Treffer * \param snippet_repeat Maximale Anzahl von Treffern pro Ergebniszeile * * \return Array mit den Treffern als assoziatives Array mit den Feldern (head, snippets, text, url) */ public static function search ($search, $elements, $max_rows=20, $snippet_len=50, $snippet_repeat=5) { $result = array (); $db = new Database (); $edit_mode = self::getEditMode () & (Base::MODE_VIEW | Base::MODE_EDIT); $repeat = $snippet_repeat / count ($search); $urlExp = (is_array ($search)) ? "LIKE '".Database::escape ($search['url'])."'" : ""; $search = (is_array ($search)) ? $search['search'] : $search; $search = html_entity_decode ($search, ENT_QUOTES, "UTF-8"); $search = preg_replace ("/^ +| +$/", "", $search); $search = preg_replace ("/ +/", " ", $search); $dbSearch = Database::escape ($search); foreach ($elements as $group => $elemente) { if (!is_array ($elemente)) { $elemente = array ($elemente); } foreach ($elemente as $element) { $group = Liste::trimmName ($group); $element = Element::trimmName ($element); if ($db->query ("SELECT DISTINCT e.text, g.url, g.parent_group_id FROM `{prefix}group` g, {prefix}element e WHERE g.name='$group' AND g.id=e.group_id AND e.name='$element' AND MATCH(e.text) AGAINST('$dbSearch') AND g.url!='' $urlExp AND g.status=".Base::STATUS_ONLINE." AND g.ticket_id=0 AND e.status=".Base::STATUS_ONLINE." AND e.ticket_id=0 LIMIT $max_rows")) { foreach ($db->result as $row) { // nur wenn alle parents online stehen in suchergebnis aufnehmen $parentId = $row['parent_group_id']; for ($i=0; $i<20 && $parentId && $db->query ("SELECT parent_group_id, status, name, id FROM `{prefix}group` WHERE id=$parentId"); $i++) { if (!($db[0]['status']&Base::STATUS_ONLINE)) { break; } $parentId = $db[0]['parent_group_id']; } if (!($db[0]['status']&Base::STATUS_ONLINE)) { continue; } // Überschrift suchen $row['head'] = strip_tags (preg_replace ("/.*?