/admin/class_modul_votings_admin.php

Nachdem nun sowohl das Modul installiert wurde als auch die Beans definiert sind, kann mit der Admin-Ansicht des Moduls begonnen werden.


class class_modul_votings_admin extends class_admin implements interface_admin {
public function __construct() {
$arrModul["name"] = "modul_votings";
$arrModul["author"] = "sidler @ mulchprod.de";
$arrModul["moduleId"] = _votings_modul_id_;
$arrModul["table"] = _dbprefix_."votings_voting";
$arrModul["table2"] = _dbprefix_."votings_answer";
$arrModul["modul"] = "votings";
parent::__construct($arrModul);
}


Wie üblich definiert der Konstruktor Metadaten, die teilweise optional sind, der Vollständigkeit halber aber gepflegt werden sollten. Die Metadaten werden unter Anderem für das Laden der Zugehörigen Texte verwendet, spätestens hierfür sollten diese gepflegt werden.


public function action($strAction = "") {
$strReturn = "";
if($strAction == "")
$strAction = "list";

try {
if($strAction == "list")
$strReturn = $this->actionList();
else if($strAction == "newVoting")
$strReturn = $this->actionNewVoting("new");
else if($strAction == "editVoting")
$strReturn = $this->actionNewVoting("edit");
else if($strAction == "saveVoting") {
if($this->validateForm()) {
$strReturn = $this->actionSaveVoting();
if($strReturn == "")
$this->adminReload(getLinkAdminHref($this->arrModule["modul"]));
}
else {
if($this->getParam("mode") == "new")
$strReturn = $this->actionNewVoting("new");
else
$strReturn = $this->actionNewVoting("edit");
}
}
else if($strAction == "deleteVoting") {
$strReturn = $this->actionDeleteVoting();
if($strReturn == "")
$this->adminReload(getLinkAdminHref($this->arrModule["modul"]));
}
[ ... ]action parts for the answers [ ... ]
}
catch (class_exception $objException) {
$objException->processException();
$strReturn = "An internal error occured: ".$objException->getMessage();
}
$this->strOutput = $strReturn;
}


Der action() Block steuert die Admin-Klasse und ruft die einzelnen Methoden auf, je nach angeforderter Aktion. Die action() Methode wird dabei vom Framework aufgerufen, übergeben wird die auszuführende Aktion. Wird keine Aktion übergeben, so kann hier eine default-Aktion gesetzt werden, im obigen Beispiel wäre das die Aktion „list“, was der Listenansicht der verfügbaren Votings entspricht ( actionList() ).


public function getOutputContent() {
return $this->strOutput;
}


Das Ergebnis der Ausführung wird in diesem Fall nicht als Rückgabewert der action()-Methode erwartet, sondern wird zu einem späteren Zeitpunkt über die Methode getOutputContent() geladen.

public function getOutputModuleNavi() {
$arrReturn = array();
$arrReturn[] = array("right", getLinkAdmin("right", "change", "&changemodule=".$this->arrModule["modul"], $this->getText("module_permissions"), "", "", true, "adminnavi"));
$arrReturn[] = array("", "");
$arrReturn[] = array("view", getLinkAdmin($this->arrModule["modul"], "list", "", $this->getText("module_list"), "", "", true, "adminnavi"));
$arrReturn[] = array("", "");
$arrReturn[] = array("edit", getLinkAdmin($this->arrModule["modul"], "newVoting", "", $this->getText("module_create"), "", "", true, "adminnavi"));
return $arrReturn;
}


Der Aufbau der Modul-Navigation (im Standard-Skin die Navigation am linken Rand) erfolgt über den Rückgabewert der Methode getOutputModuleNavi(). Der Rückgabewert ist dabei ein zweidimensionales Array. Jeder Eintrag des Arrays ist wieder ein Array, welches sowohl das benötigte Recht, als auch den Link dazu speichert. Das Framework prüft dann selbstständig, ob der aktuelle Benutzer das angegebene Recht besitzt und blendet dann, wenn gegeben, den Link als Navigationspunkt ein.
Um logische Trenner in der Navigation auszugeben, kann ein Array mit leeren Werten zurückgegeben werden: $arrReturn[] = array("", "");
Siehe hierzu auch http://apidocs.kajona.de/v3.3.0/modul_system/class_admin.html#getOutputModuleNavi

protected function getRequiredFields() {
$strAction = $this->getAction();
$arrReturn = array();
if($strAction == "saveVoting") {
$arrReturn["voting_title"] = "string";
}
if($strAction == "saveAnswer") {
$arrReturn["answer_title"] = "string";
}
return $arrReturn;
}


Die Methode getRequiredFields() kann zu Validierung von Formulareingaben genutzt werden – die Validierung erfolgt dann vom Framework automatisch. Um die Validierung zu nutzen, muss Kajona jedoch wissen, bei welcher Aktion welche Felder geprüft werden sollen. Hier wären es also das Feld „voting_title“ bei der Aktion „saveVoting“ sowie das Feld „answer_title“ beim Ausführen von „saveAnswer“. Die Methode gibt also, je nach Aktion, ein anderes Array nach dem Schema „Feld = Datentyp“ zurück.
Die Validierung an sich wird hier in der bereits beschriebenen action()-Methode durch $this->validateForm() ausgelöst, welche einen bool-Wert zurückliefert.
Die fehlerhaften Felder können dann direkt und formatiert an entsprechender Stelle über den Aufruf von $this->objToolkit->getValidationErrors($this); ausgegeben werden.
Siehe hierzu auch

Der nun folgende, durchaus lange Block der actionList() Methode, sorgt für die tabellarische Darstellung der Votings. Hier kommt auch ein wenig die Arbeitsweise des Admin-Toolkits zur Geltung.


private function actionList() {
$strReturn = "";
if($this->objRights->rightView($this->getModuleSystemid($this->arrModule["modul"]))) {
$strVotings = "";
$arrVotings = class_modul_votings_voting::getVotings();
$intI = 0;


Zu Beginn werden die Rechte geprüft – am Modul an sich. Sind diese vorhanden, wird vom Voting-Bean die Liste an verfügbaren Votings angefragt, welche dann iterativ verarbeitet werden.

foreach($arrVotings as $objOneVoting) {
if($this->objRights->rightView($objOneVoting->getSystemid())) {
$strAction = "";
if($this->objRights->rightEdit($objOneVoting->getSystemid())) {
$strAction .= $this->objToolkit->listButton(getLinkAdmin($this->arrModule["modul"], "editVoting", "&systemid=".$objOneVoting->getSystemid(), "", $this->getText("voting_edit"), "icon_pencil.gif"));

$strAction .= $this->objToolkit->listButton(getLinkAdmin($this->arrModule["modul"], "listAnswers", "&systemid=".$objOneVoting->getSystemid(), "", $this->getText("voting_listAnswers"), "icon_book.gif"));

}


In der Schleife wird für jedes Voting überprüft, ob der Anwender die Rechte zum Anzeigen besitzt. Nur dann wird das Voting ausgegeben. Kontextsensitiv werden dann die einzelnen, möglichen Aktion gesammelt – ebenfalls wieder abhängig von den Rechten des Anwenders. Im obigen Abschnitt wären das die Aktion zum Editieren („editVoting“) sowie zum Auflisten der zugehörigen Antworten („listAnswers“). Der Button wird dabei über die Toolkit-Methode listButton() sowie über Helferfunktionen zusammengesetzt.
Siehe hierzu auch

if($this->objRights->rightDelete($objOneVoting->getSystemid()))
$strAction .= $this->objToolkit->listDeleteButton(
$objOneVoting->getStrTitle(), $this->getText("voting_delete_question"),
getLinkAdminHref($this->arrModule["modul"], "deleteVoting", "&systemid=".$objOneVoting->getSystemid()."&voting_delete_final=1&peClose=".$this->getParam("pe"))
);
if($this->objRights->rightEdit($objOneVoting->getSystemid()))
$strAction .= $this->objToolkit->listStatusButton($objOneVoting->getSystemid());
if($this->objRights->rightRight($objOneVoting->getSystemid()))
$strAction .= $this->objToolkit->listButton(getLinkAdmin("right", "change", "&systemid=".$objOneVoting->getSystemid(), "", $this->getText("voting_permissions"), getRightsImageAdminName($objOneVoting->getSystemid())));

$strVotings .= $this->objToolkit->listRow2Image(getImageAdmin("icon_question.gif"), uniStrTrim($objOneVoting->getStrTitle(), 80), $strAction, $intI++);


Die Zeile eines einzelnen Votings wird mit dem vorangegangen Aufruf per listRow2Image() hinzugefügt – eine Zeile mit Bild und zwei Inhaltselementen: Name des Votings sowie die Aktionen.

}
}

if($this->objRights->rightEdit($this->getModuleSystemid($this->arrModule["modul"])))
$strVotings .= $this->objToolkit->listRow2Image("", "", getLinkAdmin($this->arrModule["modul"], "newVoting", "", $this->getText("module_create"), $this->getText("module_create"), "icon_blank.gif"), $intI++);


Eine Zeile zum Anlegen neuer Votings ergänzt die gesamte Liste.


if(uniStrlen($strVotings) != 0)
$strVotings = $this->objToolkit->listHeader().$strVotings.$this->objToolkit->listFooter();

if(count($arrVotings) == 0)
$strVotings.= $this->getText("list_empty");

$strReturn .= $strVotings;
}
else
$strReturn = $this->getText("error_permissions");

return $strReturn;
}


Um ein neues Voting zu erstellen oder ein bestehendes zu Bearbeiten, wird von der action()-Methode die Methode actionNewVoting() mit einem entsprechenden Parameter aufgerufen.


private function actionNewVoting($strMode = "new") {
$strReturn = "";
if($strMode == "new") {
//Form to create new votings
if($this->objRights->rightEdit($this->getModuleSystemid($this->arrModule["modul"]))) {
$strReturn .= $this->objToolkit->getValidationErrors($this);
$strReturn .= $this->objToolkit->formHeader(getLinkAdminHref($this->arrModule["modul"], "saveVoting"));
$strReturn .= $this->objToolkit->formInputTextArea("voting_title", $this->getText("voting_title"), $this->getParam("voting_title"));
$strReturn .= $this->objToolkit->formDateSingle("voting_start", $this->getText("voting_start"), new class_date());
$strReturn .= $this->objToolkit->formDateSingle("voting_end", $this->getText("voting_end"), null);
$strReturn .= $this->objToolkit->formInputHidden("systemid", "");
$strReturn .= $this->objToolkit->formInputHidden("mode", "new");
$strReturn .= $this->objToolkit->formInputHidden("peClose", $this->getParam("pe"));
$strReturn .= $this->objToolkit->formInputSubmit($this->getText("button_save"));
$strReturn .= $this->objToolkit->formClose();
$strReturn .= $this->objToolkit->setBrowserFocus("votings_title");
}
else
$strReturn .= $this->getText("error_permissions");
}


Bei einem neu anzulegenden Voting werden die Rechte auf Modul-Ebene geprüft, das Formular wird leer aufgebaut. Der Element-Name „voting_title“ entspricht dem von der Methode getRequiredFields() zurückgegebenen Wert, eine Prüfung auf Validität kann also erfolgen. Mögliche Fehler werden durch den Aufruf von $this->objToolkit->getValidationErrors() vor dem Formular ausgegeben.

elseif ($strMode == "edit") {
//Rights
if($this->objRights->rightEdit($this->getSystemid())) {
$objVoting = new class_modul_votings_voting($this->getSystemid());
$strReturn .= $this->objToolkit->getValidationErrors($this);
$strReturn .= $this->objToolkit->formHeader(getLinkAdminHref($this->arrModule["modul"], "saveVoting"));
$strReturn .= $this->objToolkit->formInputTextArea("voting_title", $this->getText("voting_title"), $objVoting->getStrTitle());
$strReturn .= $this->objToolkit->formDateSingle("voting_start", $this->getText("voting_start"), $objVoting->getLongDateStart() != 0 ? new class_date($objVoting->getLongDateStart()) : null);
$strReturn .= $this->objToolkit->formDateSingle("voting_end", $this->getText("voting_end"), $objVoting->getLongDateEnd() != 0 ? new class_date($objVoting->getLongDateEnd()) : null);

$strReturn .= $this->objToolkit->formInputHidden("systemid", $this->getSystemid());
$strReturn .= $this->objToolkit->formInputHidden("mode", "edit");
$strReturn .= $this->objToolkit->formInputHidden("peClose", $this->getParam("pe"));
$strReturn .= $this->objToolkit->formInputSubmit($this->getText("button_save"));
$strReturn .= $this->objToolkit->formClose();
$strReturn .= $this->objToolkit->setBrowserFocus("votings_title");
}
else
$strReturn .= $this->getText("error_permissions");
}
return $strReturn;
}


Beim Editieren eines vorhandenen Votings werden die Rechte direkt am Voting geprüft, die Felder werden mit den Werten des bestehenden Votings vorbelegt. Der komplette Aufbau der Formulare erfolgt per Toolkit-Funktionen.

private function actionSaveVoting() {
$strReturn = "";
$objVoting = null;
if($this->getParam("mode") == "new" && $this->objRights->rightEdit($this->getModuleSystemid($this->arrModule["modul"]))) {
$objVoting = new class_modul_votings_voting();
}
elseif($this->getParam("mode") == "edit" && $this->objRights->rightEdit($this->getSystemid())) {
$objVoting = new class_modul_votings_voting($this->getSystemid());
}
if($objVoting != null) {
$objVoting->setStrTitle($this->getParam("voting_title"));
//parse passed dates
$objStartDate = new class_date("0");
$objStartDate->generateDateFromParams("voting_start", $this->getAllParams());
$objEndDate = new class_date("0");
$objEndDate->generateDateFromParams("voting_end", $this->getAllParams());
$objVoting->setLongDateStart($objStartDate->getLongTimestamp());
$objVoting->setLongDateEnd($objEndDate->getLongTimestamp());
if(!$objVoting->updateObjectToDb( $this->getModuleSystemid($this->arrModule["modul"])))
throw new class_exception("Error updating object to db", class_exception::$level_ERROR);
}
else
$strReturn .= $this->getText("error_permissions");

return $strReturn;
}

Während des Speicherns des Votings wird lediglich beim Initialisieren des Objektes zwischen neuen und bestehenden Objekten unterschieden. Das Verarbeiten der per Formular übermittelten Datum-Werte erfolgt hier automatisch von der Date-Klasse durch den Aufruf von generateDateFromParams(). Beim Speichern wird nicht zwischen neuen und bestehenden Objekten unterschieden, um die Unterschiede kümmert sich ja das Framework.
Siehe hierzu auch

private function actionDeleteVoting() {
$strReturn = "";
if($this->objRights->rightDelete($this->getSystemid())) {
if($this->getParam("voting_delete_final") == "") {
$objFaq = new class_modul_votings_voting($this->getSystemid());
$strName = $objFaq->getStrTitle();
$strReturn .= $this->objToolkit->warningBox($strName
."<br /><a href=\"".http://www.kajona.de/index.php."?admin=1&amp;module=".$this->arrModule["modul"]."&amp;action=deleteVoting&amp;systemid="
.$this->getSystemid().($this->getParam("pe") == "" ? "" : "&amp;peClose=".$this->getParam("pe"))."&amp;voting_delete_final=1\">"
.$this->getText("voting_delete_question"));
}
elseif($this->getParam("voting_delete_final") == "1") {
$objVoting = new class_modul_votings_voting($this->getSystemid());
if(!$objVoting->deleteVoting())
throw new class_exception("Error deleting object from db", class_exception::$level_ERROR);
}
}
else
$strReturn .= $this->getText("error_permissions");

return $strReturn;
}


Die Methode actionDeleteVoting() wird von der action() Methode dann aufgerufen, wenn ein Voting gelöscht werden soll. Die im ersten Teil der Methode erzeugte Warnmeldung wird nur über den Portal-Editor aufgerufen. Im Backend jedoch wird der Dialog zum Löschen des Datensatzes bereits in der Methode actionList() erzeugt. Der zweite Teil führt dann das wirkliche Löschen durch – wie erwartet durch den entsprechenden Aufruf am Voting-Bean.


[ ... Answer-Functions ... ]
}


Die Methoden zum Verwalten der Antworten sind analog zu denen der Votings und werden deshalb nicht erneut betrachtet.
Lediglich beim Speichern einer Antwort gibt es einen relevanter Unterschied:


if(!$objAnswer->updateObjectToDb( $this->getParam("votingid") ) )


Als Paramter des updateObjectToDb()-Aufrufes wird die ID des zugehörigen Votings mit übergeben. Hierrüber baut das Framework dann die Zuordnung Antwort zu Voting selbstständig auf.