Dca-rules

Aus Contao Community Documentation


Erweiterungs-Übersicht
Name des Entwicklers David Molineus http://www.netzmacht.de
Version der Erweiterung 1.0.0-rc3
Kompatibilität mit Contao Version 2.11.0 - 3.0.1
Link zum Extension Repository https://contao.org/de/extension-list/view/dca-rules.html
Link zum Tracker https://github.com/dmolineus/dca-rules/


Allgemeines

Die Erweiterung dca-rules ist als Hilfswerkzeug für die Entwicklung von DataContainern konzipiert. Es stellt allgemeine Callbacks für die Generierung von Operationen, Global Operationen, für die Rechteüberprüfung sowie der Ausgabe der Labeln in der Listenansicht. Diese können mit Regeln konfiguriert werden, sodass diese über die DCA-Dateien erstellt werden können ohne neue Callbacks zu definieren. Damit wird die Erzeugung redundanter Callbacks bei der Entwicklung von DataContainern reduziert.

Vorgehensweise ohne dca-rules

Um den Einsatz von den DCA-Regeln zu verdeutlichen, soll hier ein Beispiel erläutert werden. Es ist eine Erweiterung geplant, die es angemeldeten Benutzern im Frontend ermöglicht, Artikel mit Rückmeldungen zu versehen, z.B. dass sie eine Überarbeitung benötigen. Diese sollen dem Nutzer zugeordnet werden und von Redakteuren im Backend bearbeitet werden können. Backend-Redakteure ohne Bearbeitungsrechte sollen, die Feedbacks einsehen können. Hat der Benutzer Zugriff aus das Member Modul, soll außerdem ein Button zum entsprechenden Benutzer angezeigt werden. Gelöscht werden sollen die Feedbacks hingegen nur vom Administrator.

Aufbau der tl_feedback

Man erstellt also einen DataContainer tl_feedback.php, der die entsprechenden Felder id, pid, tstamp, created, memberid, userid, status, type, message beinhaltet. Pid ist hierbei die ID der Artikel, memberid die ID des Nutzers, der das Feedback abgegeben hat, userid die ID des bearbeiteten Benutzers. Außerdem wird in created die Timestamp gespeichert, als das Feedback abgegeben wurde, während tstamp bei jeder Änderung aktualisiert wird.

Benötigte Operationen

Nach den Anforderungen, müssen folgende Operationen erstellt werden:

  • Feedback bearbeiten (wenn Rechte vorhanden)
  • Benutzer anzeigen (wenn Zugriff aus Modul member)
  • Feedback löschen (nur Admin)
  • Feedback anzeigen (alle Benutzer mit Zugriff auf Modul)

Dies bedeutet außerdem, dass die Zugriffsrechte überprüft werden müssen:

  • Bearbeiten nur Redakteure mit Lösch-Rechten
  • Löschen Aktion nur Administrator

DataContainer Klasse

Nach dem gewöhnlichen Weg, würde man jetzt für die Buttons edit, member, delete Callbacks definieren, sowie einen onload_callback checkPermission, welches die Zugriffsrechte überprüft. Im unten dargestellten Code-Beispiel ist dies kurz verdeutlicht. Das Problem hierbei ist, dass man immer wieder die gleichen Callbacks definiert, sobald die Zugriffsrechte mal eingeschränkt sind.

class Feedback extends Backend
{
    public function __construct()
    {
        parent::__construct();
        $this->import('BackendUser', 'User');
    }
 
    public function checkPermission()
    {
        $act = \Input::get('act');
        if(($act == 'delete' || $act == 'deletAll') && !$this->user->isAdmin)
        {
            $this->log('Hacking attempt');
            $this->redirect('contao/main.php?act=error');
        }
 
        // check user permission ...
    }
 
    public function generateDeleteButton($arrRow, $strHref, $strLabel, $strTitle, $strIcon, $strAttributes)
    {
        if(!$this->User->isAdmin)
        {
            return '';
        }
 
        return '<a href="">....</a>';
    }
}

Vorgehensweise mit dca-rules

An dieser Stelle setzt dca-rules an und bietet eine leicht zu konfigurierbare Schnittstelle, die solche Aufgaben löst. Außerdem ist sie leicht erweiterbar, sodass selbst bei komplexeren Beispielen immer noch auf die Regeln zurückgegriffen werden kann.

Verwendung der vordefinierten Callbacks

Daher bietet die Erweiterung vordefinierte Callbacks, die anstelle der neu entwickelten aufgerufen werden. Zusätzlich werden diese noch mit Regeln definiert. Zur Zeit stehen folgende Callbacks zur Verfügung. Bei den Button Callbacks handelt es sich um magische Callbacks, die um den Buttonnamen ergänzt werden müssen. Dies ist erforderlich, damit der allgemeine Callback nur bei dem entsprechenden Button ausgeführt wird.

  • checkPermission
  • generateButton*
  • generateGlobalButton*
  • generateLabel

Damit diese verwendet werden können, muss die DataContainer Klasse die mitgelieferte Klasse Netzmacht\Utils\DataContainer erweitern. Diese basiert selbst auf der Backend Klasse. Außerdem benötigt sie den Namen der Tabelle. Dieser kann automatisch generiert werden, wenn die erstellte Klassen der Namenskonvention folgt. Aus der Tabelle tl_feedback wird der DataContainer Feedback. Entscheidet man sich für einen anderen Namen, muss lediglich die Variable $strTable definiert werden:

class Feedback extends Netzmacht\Utils\DataContainer
{
    // protected $strTable = 'tl_feedback';
}

Wird nun der DataContainer verwendet, können die mitgelieferten Callbacks wie gewohnt in der DCA-Datei definiert:

$GLOBALS['TL_DCA']['tl_feedback']['config']['onload_callback'][] = array('Feedback', 'checkPermission');

Verwendung von Regeln

Neben den Callbacks werden nun die Regeln definiert. Diese werden in folgenden Variablen gespeichert:

$GLOBALS['TL_DCA']['tl_feedback']['config']['permission_rules'] = array(); // Regeln für checkPermission
$GLOBALS['TL_DCA']['tl_feedback']['list']['operation']['button']['button_rules'] = array(); // Regeln für generateButton
$GLOBALS['TL_DCA']['tl_feedback']['list']['gobal_operation']['button']['button_rules'] = array(); // Regeln für generateGlobalButton
$GLOBALS['TL_DCA']['tl_feedback']['list']['label']['label_rules'] = array(); // Regeln für generateLabel

Anhand des oben genannten Beispiels definieren wir zwei Regeln zur Rechteüberprüfung. Zum einem verwenden wir hasAccess um den Zugriffsrechte für die Bearbeiten Funktion zu überprüfen, sowie isAdmin um die LöschFunktionen einzugrenzen.

$GLOBALS['TL_DCA']['tl_feedback']['config']['permission_rules'] = array('isAdmin', 'hasAccess');

Dies würde allerdings dazu führen, dass die isAdmin Regel auf alle Aktionen angewandt wird. Sprich das Modul wäre nur für Administratoren nutzbar. Daher bietet dca-rules eine Möglichkeit Attribute zu definieren. Dabei wird folgende Syntax verwendet:

$rule = array('rule:attribute'); // setzt attribute=true
$rule = array('rule:attribute=2'); // setzt attribute=2. Boolean und Numeric werden entsprechend konvertiert
$rule = array('rule:attribute=$value'); // Zugriff auf eine in der Feedback definierte Variable $this->value
$rule = array('rule:attribute=[one,two,three]'); // Ein Array array('one', 'two', 'three')
$rule = array('rule:attribute=[true,2,false,$value,2.3, 'hallo']'); // Werte des Array werden ebenso konvertiert: array(true, 2, false, $this->value, 2.3, 'hallo');
$rule = array('rule:a=2:b=3:c:4');  // Mehrere Attribute können durch einen Doppelpunkt getrennt werden
$rule = array('rule:error=&.errors.1'); // accessing language vars of current table
$rule = array('rule:error=&MSC.yes'); // accessing language var $GLOBALS['TL_LANG']['MSC']['yes']

Permission Regeln

Die Permission Rules bieten alle die Möglichkeit über das act Attribute die Regel nur auf die definierten Aktionen anzuwenden. Dabei können diese als Arrray definiert werden. Demzufolge erweitert man das obige Beispiel. Außerdem soll überorpft werden, ob der Benutzer Zugriff aus das Modul hat. Daher übergeben wir den Modulnamen:

$GLOBALS['TL_DCA']['tl_feedback']['config']['permission_rules'] = array('isAdmin:act=[delete,deleteAll]', 'hasAccess:module=feedback');

Dadurch sind die Einschränkungen schon recht weit umgesetzt. Allerdings bekämen jetzt alle Redakteure Zugriff die Beabeiten-Funktion. Um diese einzuschränken, wendet man nochmals die Regel hasAccess die mit den Attributen permission und action beliebige BackendUser::hasAccess(action, permission) Überprüfungen machen kann. Diese nuss natürlich vorher auch in der tl_user(_group) und über TL_PERMISSION definiert werden. Das soll an dieser Stelle nicht näher behandelt werden. Es wird davon ausgegangen, dass der Zugriff feedback mit dem Wert edit definiert ist. Die Regel hasAccess wird nun nur auf die Aktionen edit und editAll angewandt:

$GLOBALS['TL_DCA']['tl_feedback']['config']['permission_rules'] = array
(
    'isAdmin:act=[delete,deleteAll]', 'hasAccess:module=feedback', 'hasAccess:act=[edit,editAll]:permission=feedback:action=edit'
);

Das ist alles! Damit hat man in einer Zeile in der DCA-Datei die Rechteüberprüfung vorgenommen.

Button Regeln

Das gleiche Prinzip wird bei den Button-Regeln angewandt. Diese folgen der gleichen Syntax und dem gleichen Prinzip wie die Permission Regeln. Allerdings benötigen sie noch die Regel generate, die zur Ausgabe dient. Diese muss mit angegeben werden, was den Vorteil hat, das man auch nach der Ausgabe noch Manipulationen vornehmen kann. Doch weiter an dem genannten Beispiel mit den Buttons edit,member,delete,show.

Wie bei der Rechteübergabe, werden die Regeln nun definiert. Wichtigste Helfer, sind hierbei auch wieder die Regeln isAdmin sowie hasAccess. Die Konfigurationen de Buttons sind unten aufgeführt. den show Button muss man nicht definieren, da ja die Zugriffsbeschränkung mit dem Zugriff des Modules bereits erreicht ist.

$GLOBALS['TL_DCA']['tl_feedback']['list']['operations']['edit'] = array
(
    // normale button konfiguration, zusätzlich
    'button_callback' 		=> array('Feedback', 'generateButtonEdit'),
    'button_rules'  		=> array('hasAccess:permission=feedback:action=edit', 'generate'),
);
 
$GLOBALS['TL_DCA']['tl_feedback']['list']['operations']['member'] = array
(
    // normale button konfiguration, zusätzlich
    'button_callback' 		=> array('Feedback', 'generateButtonMember'),
    'button_rules' 		=> array('hasAccess:module=member', 'generate'),
);
 
$GLOBALS['TL_DCA']['tl_feedback']['list']['operations']['delete'] = array
(
    // normale button konfiguration, zusätzlich
    'button_callback' 		=> array('Feedback', 'generateButtonDelete'),
    'button_rules' 		=> array('isAdmin', 'generate'),
);

Label Regeln

Die Label Regeln dienen dazu die Aufgabe der einzelnen Felder zu bestimmen. Sie dienen dazu einzelne Werte der Ausgabe anders zu formatieren. An dem oben genannten Beispiel gibt es die Spalte created. Die Übersicht soll im mode=1 erfolgen. Dabei wird der Timestamp nicht konvertiert. Dies erledigt Contao nur bei der tstamp Spalte automatisch. Außerdem soll ausgegeben werden, ob das Feedback bereits einem bearbeitenden Nutzer zugewiesen wurde. Hierbei soll lediglich ja/nein und nicht der Beutzername ausgegeben werden. Für beide Fälle bringt dca-rules wieder Regeln mit. Während alle anderen Regeln immer einen Abbruch der Überprüfung erreichen können, werden die LabelRegeln immer durchgeführt.

Diese werden folgendermaßen konfiguriert:

$GLOBALS['TL_DCA']['tl_feedback']['list']['label'] = array
(
    'fields' 				=> array('id', 'created', 'userid'),
    'showColumns' 			=> true,
    'label_callback' 			=> array('Feedback', 'generateLabel'),
    'label_rules' 			=> array(),			
);

Wir erzeugen also eine Listenansicht, die tabellarisch ausgegeben wird mit den Spalten id, created und userid. Statt der Userid werden wir eine ja/nein ausgabe machen. Auch hier wird der bereits vorhandene Callback aufgerufen.

Was man bei den Regeln für Label beachten muss, dass die Werte von Contao in einem Array $values nach dem Index der oben aufgelisteten Felder überliefert bekommt. in $vlaues[0] steht also die ID, nd $values[1] der Timestamp usw. Dazu gibt es auch ein Array mit den unbearbeiten Werten $row['id']. Manchmal konvertiert Contao den Wert bereits in eine Ausgabe. Beispielsweise bei einen Boolean Wert. So wird hier entweder ein - für eine leere Angabe, oder die Spaltenbezeichnung angegeben. Aus diesem Grund verwenden die Label Regeln sowohl ein Attribute index wie auch field, um zwischen den beiden Werten wählen zu können. Der Index ist immer erforderlich, da er die Position der Ausgabe entscheidet.

Für den hier beschriebenen Fall stehen zwei Regeln zur Verfügung: parseDate und yesNo. Dabei wird der yesNo Regel sowohl der Index als auch das Feld übergeben. Das Feld wird dann anhand des Attributes condition überprüft. Da "ja" ausgeben werden soll, wenn der Wert > 0 ist, muss die Überprüfung noch auf false gesetzt werden:

$GLOBALS['TL_DCA']['tl_feedback']['list']['label'] = array
(
    'label_rules' 			=> array('parseDate:index=1', 'yesNo:index=2:field=created:condition=0:is=false'),			
);

Dadurch könenn wir so gut wie alle Aktionen der Tabelle lösen ohne einen einzigen Callback geschrieben zu haben!

Vorhandene Regeln

Nachdem anhand des Beispiels die Funktionsweise erläutert wurde, gibt es hier eine Übersicht der vordefinierten Regeln. Auf den jeweiligen Unterseiten ist die Verwendungsweise der Regeln näher erläutert:

Permission Regeln

  • generic
  • hasAccess
  • isAllowed
  • isAdmin
  • forbidden

Button Regeln

  • disableIcon
  • toggleIcon
  • referer
  • hasAccess
  • isAllowed
  • isAdmin

Label Regeln

  • parseDate (index,field,format= einen Timestamp parsen
  • yesNo (index,field,codition,is) ja/nein ausgeben

Eigene Regeln definieren

Neben den vordefinierten Regeln können auch eigene Regeln definiert werden. Diese werden als Methoden in dem DataContainer definiert und folgen folgenden Konventionen. Die Button Regeln werden sowohl für die globale als auch lokale Buttons verwendet. Bei globalen ist $arrRow=null.

protected function permissionRule*($objDc, &$arrAttributes, &$strError);
protected function buttonRule*(&$strButton, &$strHref, &$strLabel, &$strTitle, &$strIcon, &$strAttributes, &$arrAttributes, $arrRow=null);
protected function labelRule*(&$arrRow, &$strLabel, &$objDc, &$arrValues, &$arrAttributes);

Da die Variablen per Referenz übergeben werden, können sie so von einer Regel zur nächsten weitergereicht werden. Möchte eine Regel beispielsweise das Icon ersetzen, so muss lediglich die icon Variable neu gesetzt werden.

protected function buttonRuleChangeIcon(&$strButton, &$strHref, &$strLabel, &$strTitle, &$strIcon, &$strAttributes, &$arrAttributes, $arrRow=null)
{
    $strIcon = (isset($arrAttribute['icon']) ? $arrAttribute['icon'] : 'change.gif';
}

Sollen Attribute weitergereicht werden, so ist es erforderlich, diese als solche zu kennzeichnen. Damit wird verhindert, dass sich die einzelnen Regeln ungewollt gegenseitig beinflussen, aber dennoch Anweisungen an nächste Regeln gesetzt werden können. Dazu muss unter $arrAttributes['__set__'] das entsprechende Feld hinzugefügt werden. Sinnvoll ist dies beispielsweise, wenn eine Regel die Ausgabe beeinflussen möchte:

protected function buttonRuleReferer(&$strButton, &$strHref, &$strLabel, &$strTitle, &$strIcon, &$strAttributes, &$arrAttributes, $arrRow=null)
{
    $strHref = $this->getReferer(true);
 
    // do not use addToUrl() instead use plain href
    $arrAttributes['plain'] = true;
    $arrAttributes['__set__'][] = 'plain';
 
    return true;
}
Ansichten
Meine Werkzeuge

Contao Community Documentation

Pelle: gibt's ein besseres Wort für "beschränkt"?
Thomas: "Kunde"

Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge