0251 / 590 837 15
info@a-coding-project.de
;

Überarbeitung Settings-Komponente (CMS)

Unser CMS ContentLion ist ja zum Großteil objektorientiert – Nur zum Großteil! Denn auf die Settings wird derzeit über die Funktionen getSetting und setSetting zugegriffen. Da in Kürze Erweiterungen in Richtung Multi-Domain Benutzung und Order bzw. Seitenspezische Einstellungen anstehen, ist jetzt der passende Augenblick, die Settings einmal zu überarbeiten.

Die alten Funktionen waren in der Datei /system/settings.php gespeicher, die am Ende des Beitrags gelöscht werden kann. Für jede Abfrage auf die Settings wurde eine Datenabfrage generiert. Bei Settings die häufiger gebraucht werden (root oder host) kann dies zu kleinen Performance-Problemen führen, weshalb ich in den neuen Settings extra darauf geachtet habe, dass wir jeden Setting nur einmal auslesen müssen.

Du erinnerst dich bestimmt, dass es neben den globalen Einstellungen auch Einstellungen für Plugins oder Skins geben kann. Hier werden die Spalten areaType und area verwendet -> default ist beides global. In der neuen Settings-Klasse gibt es eine statisches Array mit dem Namen instances. Hier werden alle Instanzen der Settings-Klasse gespeichert. Als keys werden areaType unda rea genommen, so dass wir sicherstellen können, dass für jeden areaType und für jede area nur eine Instanz vorhanden ist.

Die Hauptinstanz, die für alle Settings ist, wird über die Funktion getInstance zurückgegeben. Sie erstellt auch ein neues Settings-Objekt, falls noch keins vorhanden ist:

    public static function getInstance(){
      if(!isset(self::$instances["global"]["global"])){
        $res = new Settings();
        self::$instances["global"]["global"] = $res;
      }
      else{
        $res = self::$instances["global"]["global"];
      }
      return $res;
    }

Diese
Über diese Instanz kann man (gleich) schonmal die globalen Einstellungen auslesen. Möchte man nun eine Skinspezifische einstellung auslesen, kann man über specify eine passende Instanz bekommen:

    public function specify($areaType = "global",$area = "global"){
      if(!isset($this->$instances[$areaType][$area])){
        $res = new Settings();
        $res->parent = $this;
        $res->setAreaType($areaType);
        $res->setArea($area);
        $this->instances[$areaType][$area] = $res;
      }
      else{
        $res = $this->instances[$areaType][$area];
      }
      return $res;
    }

In dieser wwerden areaType und die area gespeichert. Außerdem gibt es einen verweis auf die übergeordnete Klasse, so dass wenn keine spezifische Einstellung erstellt wurde einfach auf die globalen Einstellungen zurückgegriffen werden kann.

In der Funktion get und der privaten Funktion getFromDB kann man sich nun die jeweilige Einstellung heraussuchen. Der Quelltext ähnelt dem der alten getSetting():

    public function get($property){
      $res = null;
      if(isset($this->properties[$property])){
        $res = $this->properties[$property];
      }
      else{
        $res = $this->getFromDB($property);
        if(!$res && $this->parent != null){
          $res = $this->parent->get($property);
        }
        $this->properties[$property] = $res;
      }

      return $res;
    }

    protected function getFromDB($property){
      $area     = $GLOBALS['db']->EscapeString($this->area);
      $areaType = $GLOBALS['db']->EscapeString($this->areaType);
      $property = $GLOBALS['db']->EscapeString($property);
      $sql      = "";
      if(isset($_SESSION['user'])){
       $sql = "SELECT value FROM {'dbprefix'}settings WHERE role = '".$_SESSION['user']->role->ID."' AND area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' UNION ";
      }
      $sql .= "SELECT value FROM {'dbprefix'}settings WHERE role = '3' AND area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."'";
      return $GLOBALS['db']->ReadField($sql);
    }

Die Funktion set ist ungefähr der Inhalt der alten setSetting:

    public function set($property,$value){
      $area     = $GLOBALS['db']->EscapeString($this->area);
      $areaType = $GLOBALS['db']->EscapeString($this->areaType);
      $property = $GLOBALS['db']->EscapeString($this->property);
      $value    = $GLOBALS['db']->EscapeString($this->value);
      $role     = $GLOBALS['db']->EscapeString($this->role);
      $allUserData = $GLOBALS['db']->ReadRow("SELECT * FROM  {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '3'");
      if($GLOBALS['db']->EscapeString($allUserData->value) != $value or $role == 3){
        $exists = $GLOBALS['db']->ReadField("SELECT COUNT(*) FROM {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."'") > 0;
        if($exists){
          $res = $GLOBALS['db']->Execute("UPDATE {'dbprefix'}settings SET value = '".$value."' WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."'");
        }
        else{
          $res = $GLOBALS['db']->Execute("INSERT INTO {'dbprefix'}settings (value,area,areaType,property,role,description,type) VALUES ('".$value."', '".$area."', '".$areaType."', '".$property."', '".$role."','".$allUserData->description."','".$allUserData->type."')");
        }
      }
      else{
        $GLOBALS['db']->Execute("DELETE FROM {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."'") ;
      }
      return $res;
    }

Jetzt kommt der spaßige Teil der Änderung: Alle getSetting und setSetting-Aufrufe müssen an die neue Funktion angepasst werden. Für die globalen Einstellungen kann man zum Beispiel so den host bekommen: Settings::getInstance()->get(„host“).

Ich hoffe, ich habe in alle entsprechenden Aufrufe im Source geändert. Am besten ihr installiert ContentLion einmal neu, damit auch beim Update keine Datei vergessen wird.

Hier ist nochmal fürs Copy & Paste der komplette Code der neuen Settings-Klasse:

<?PHP
  class Settings{

    protected $area              = "global";
    protected $areaType          = "global";
    protected $parent            = null;
    protected $properties        = array();
    protected static $instances  = array();

    public function get($property){
      $res = null;
      if(isset($this->properties[$property])){
        $res = $this->properties[$property];
      }
      else{
        $res = $this->getFromDB($property);
        if(!$res && $this->parent != null){
          $res = $this->parent->get($property);
        }
        $this->properties[$property] = $res;
      }

      return $res;
    }

    protected function getFromDB($property){
      $area     = $GLOBALS['db']->EscapeString($this->area);
      $areaType = $GLOBALS['db']->EscapeString($this->areaType);
      $property = $GLOBALS['db']->EscapeString($property);
      $sql      = "";
      if(isset($_SESSION['user'])){
       $sql = "SELECT value FROM {'dbprefix'}settings WHERE role = '".$_SESSION['user']->role->ID."' AND area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' UNION ";
      }
      $sql .= "SELECT value FROM {'dbprefix'}settings WHERE role = '3' AND area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."'";
      return $GLOBALS['db']->ReadField($sql);
    }

    public function set($property,$value){
      $area     = $GLOBALS['db']->EscapeString($this->area);
      $areaType = $GLOBALS['db']->EscapeString($this->areaType);
      $property = $GLOBALS['db']->EscapeString($this->property);
      $value    = $GLOBALS['db']->EscapeString($this->value);
      $role     = $GLOBALS['db']->EscapeString($this->role);
      $allUserData = $GLOBALS['db']->ReadRow("SELECT * FROM  {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '3'");
      if($GLOBALS['db']->EscapeString($allUserData->value) != $value or $role == 3){
        $exists = $GLOBALS['db']->ReadField("SELECT COUNT(*) FROM {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."'") > 0;
        if($exists){
          $res = $GLOBALS['db']->Execute("UPDATE {'dbprefix'}settings SET value = '".$value."' WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."'");
        }
        else{
          $res = $GLOBALS['db']->Execute("INSERT INTO {'dbprefix'}settings (value,area,areaType,property,role,description,type) VALUES ('".$value."', '".$area."', '".$areaType."', '".$property."', '".$role."','".$allUserData->description."','".$allUserData->type."')");
        }
      }
      else{
        $GLOBALS['db']->Execute("DELETE FROM {'dbprefix'}settings WHERE area = '".$area."' AND areaType = '".$areaType."' AND property = '".$property."' AND role = '".$role."'") ;
      }
      return $res;
    }

    public function setArea($area){
      $this->area = $area;
    }

    public function setAreaType($area){
      $this->areaType = $area;
    }

    public static function getInstance(){
      if(!isset(self::$instances["global"]["global"])){
        $res = new Settings();
        self::$instances["global"]["global"] = $res;
      }
      else{
        $res = self::$instances["global"]["global"];
      }
      return $res;
    }

    public function specify($areaType = "global",$area = "global"){
      if(!isset($this->$instances[$areaType][$area])){
        $res = new Settings();
        $res->parent = $this;
        $res->setAreaType($areaType);
        $res->setArea($area);
        $this->instances[$areaType][$area] = $res;
      }
      else{
        $res = $this->instances[$areaType][$area];
      }
      return $res;
    }

  }
?>

Alle weiteren Änderungen findest du in den Revisonen 47, 48, 49 und 50.