Subversion Repositories oidplus

Rev

Rev 1086 | Rev 1172 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * OIDplus 2.0
  5.  * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
  6.  *
  7.  * Licensed under the Apache License, Version 2.0 (the "License");
  8.  * you may not use this file except in compliance with the License.
  9.  * You may obtain a copy of the License at
  10.  *
  11.  *     http://www.apache.org/licenses/LICENSE-2.0
  12.  *
  13.  * Unless required by applicable law or agreed to in writing, software
  14.  * distributed under the License is distributed on an "AS IS" BASIS,
  15.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16.  * See the License for the specific language governing permissions and
  17.  * limitations under the License.
  18.  */
  19.  
  20. namespace ViaThinkSoft\OIDplus;
  21.  
  22. // phpcs:disable PSR1.Files.SideEffects
  23. \defined('INSIDE_OIDPLUS') or die;
  24. // phpcs:enable PSR1.Files.SideEffects
  25.  
  26. // OIDplusConfig contains settings that are stored in the database.
  27. // Not to be confused with OIDplusBaseConfig which is the basic ("static")
  28. // configuration stored in userdata/baseconfig/config.inc.php,
  29. // e.g. database access credentials.
  30. class OIDplusConfig extends OIDplusBaseClass implements OIDplusGetterSetterInterface {
  31.  
  32.         /*public*/ const PROTECTION_EDITABLE = 0;
  33.         /*public*/ const PROTECTION_READONLY = 1;
  34.         /*public*/ const PROTECTION_HIDDEN   = 2;
  35.  
  36.         protected $configTableReadOnce = false; // this ensures that all $values and $descriptions were read
  37.  
  38.         protected $values = array();
  39.         protected $descriptions = array();
  40.         protected $protectSettings = array();
  41.         protected $visibleSettings = array();
  42.         protected $validateCallbacks = array();
  43.  
  44.         /**
  45.          * @param string $name
  46.          * @param string $description
  47.          * @param string $init_value
  48.          * @param int $protection
  49.          * @param $validateCallback
  50.          * @return void
  51.          * @throws OIDplusException
  52.          */
  53.         public function prepareConfigKey(string $name, string $description, string $init_value, int $protection, $validateCallback) {
  54.                 // Check if the protection flag is valid
  55.                 switch ($protection) {
  56.                         case OIDplusConfig::PROTECTION_EDITABLE:
  57.                                 $protected = 0;
  58.                                 $visible   = 1;
  59.                                 break;
  60.                         case OIDplusConfig::PROTECTION_READONLY:
  61.                                 $protected = 1;
  62.                                 $visible   = 1;
  63.                                 break;
  64.                         case OIDplusConfig::PROTECTION_HIDDEN:
  65.                                 $protected = 1;
  66.                                 $visible   = 0;
  67.                                 break;
  68.                         default:
  69.                                 throw new OIDplusException(_L('Invalid protection flag, use OIDplusConfig::PROTECTION_* constants'));
  70.                 }
  71.  
  72.                 // Check length limitations given by the database tables
  73.                 if (strlen($name) > 50) {
  74.                         throw new OIDplusException(_L('Config key name "%1" is too long (max %2).',$name,50));
  75.                 }
  76.                 if (strlen($description) > 255) {
  77.                         throw new OIDplusException(_L('Description for config key "%1" is too long (max %2).',$name,255));
  78.                 }
  79.  
  80.                 // Read all values and descriptions from the database once.
  81.                 $this->buildConfigArray();
  82.  
  83.                 // Figure out if we need to create/update something at database level
  84.                 if (!isset($this->values[$name])) {
  85.                         // Case A: The config setting does not exist in the database. So we create it now.
  86.                         try {
  87.                                 OIDplus::db()->query("insert into ###config (name, description, value, protected, visible) values (?, ?, ?, ?, ?)", array($name, $description, $init_value, $protected, $visible));
  88.                         } catch (\Exception $e) {
  89.                                 // After a software update that introduced a new config setting,
  90.                                 // there will be a race-condition at this place, because
  91.                                 // jsTree and content are loading simultaneously!
  92.                                 // So we ignore the error here.
  93.                         }
  94.                         $this->values[$name] = $init_value;
  95.                         $this->descriptions[$name] = $description;
  96.                         $this->protectSettings[$name] = $protected;
  97.                         $this->visibleSettings[$name] = $visible;
  98.                 } else {
  99.                         // Case B: The config setting exists ...
  100.                         if ($this->descriptions[$name] != $description) {
  101.                                 // ... but the human readable description is different.
  102.                                 // We want to give the plugin authors the possibility to automatically update the config descriptions for their plugins
  103.                                 // So we just edit the description
  104.                                 OIDplus::db()->query("update ###config set description = ? where name = ?", array($description, $name));
  105.                                 $this->descriptions[$name] = $description;
  106.                         }
  107.                         if ($this->protectSettings[$name] != $protected) {
  108.                                 OIDplus::db()->query("update ###config set protected = ? where name = ?", array($protected, $name));
  109.                                 $this->protectSettings[$name] = $protected;
  110.                         }
  111.                         if ($this->visibleSettings[$name] != $visible) {
  112.                                 OIDplus::db()->query("update ###config set visible = ? where name = ?", array($visible, $name));
  113.                                 $this->visibleSettings[$name] = $visible;
  114.                         }
  115.                 }
  116.  
  117.                 // Register the validation callback
  118.                 if (!is_null($validateCallback)) {
  119.                         $this->validateCallbacks[$name] = $validateCallback;
  120.                 }
  121.         }
  122.  
  123.         /**
  124.          * @return void
  125.          * @throws OIDplusException
  126.          */
  127.         public function clearCache() {
  128.                 $this->configTableReadOnce = false;
  129.                 $this->buildConfigArray();
  130.         }
  131.  
  132.         /**
  133.          * @return void
  134.          * @throws OIDplusException
  135.          */
  136.         protected function buildConfigArray() {
  137.                 if ($this->configTableReadOnce) return;
  138.  
  139.                 $this->values = array();
  140.                 $this->descriptions = array();
  141.                 $this->protectSettings = array();
  142.                 $this->visibleSettings = array();
  143.                 $res = OIDplus::db()->query("select name, description, protected, visible, value from ###config");
  144.                 while ($row = $res->fetch_object()) {
  145.                         $this->values[$row->name] = $row->value;
  146.                         $this->descriptions[$row->name] = $row->description;
  147.                         $this->protectSettings[$row->name] = $row->protected;
  148.                         $this->visibleSettings[$row->name] = $row->visible;
  149.                 }
  150.  
  151.                 $this->configTableReadOnce = true;
  152.         }
  153.  
  154.         /**
  155.          * @param string $name
  156.          * @param mixed|null $default
  157.          * @return mixed|null
  158.          * @throws OIDplusException
  159.          */
  160.         public function getValue(string $name, $default=null) {
  161.                 // Read all config settings once and write them in array $this->values
  162.                 $this->buildConfigArray();
  163.  
  164.                 // Now we can see if our desired attribute is available
  165.                 if (isset($this->values[$name])) {
  166.                         return $this->values[$name];
  167.                 } else {
  168.                         return $default;
  169.                 }
  170.         }
  171.  
  172.         /**
  173.          * @param string $name
  174.          * @return bool
  175.          * @throws OIDplusException
  176.          */
  177.         public function exists(string $name): bool {
  178.                 return !is_null($this->getValue($name, null));
  179.         }
  180.  
  181.         /**
  182.          * @param string $name
  183.          * @param mixed $value
  184.          * @return void
  185.          * @throws OIDplusException
  186.          */
  187.         public function setValue(string $name, $value) {
  188.                 // Read all config settings once and write them in array $this->values
  189.                 $this->buildConfigArray();
  190.  
  191.                 if (isset($this->values[$name])) {
  192.                         // Avoid unnecessary database writes
  193.                         if ($this->values[$name] == $value) return;
  194.                 } else {
  195.                         throw new OIDplusException(_L('Config value "%1" cannot be written because it was not prepared!', $name));
  196.                 }
  197.  
  198.                 // Give plugins the possibility to stop the process by throwing an Exception (e.g. if the value is invalid)
  199.                 // Required is that the plugin previously prepared the config setting using prepareConfigKey()
  200.                 if (isset($this->validateCallbacks[$name])) {
  201.                         $this->validateCallbacks[$name]($value);
  202.                 }
  203.  
  204.                 // Now change the value in the database
  205.                 OIDplus::db()->query("update ###config set value = ? where name = ?", array($value, $name));
  206.                 $this->values[$name] = $value;
  207.         }
  208.  
  209.         /**
  210.          * @param string $name
  211.          * @param string $value
  212.          * @return void
  213.          * @throws OIDplusException
  214.          */
  215.         public function setValueNoCallback(string $name, string $value) {
  216.                 // Read all config settings once and write them in array $this->values
  217.                 $this->buildConfigArray();
  218.  
  219.                 if (isset($this->values[$name])) {
  220.                         // Avoid unnecessary database writes
  221.                         if ($this->values[$name] == $value) return;
  222.                 } else {
  223.                         throw new OIDplusException(_L('Config value "%1" cannot be written because it was not prepared!', $name));
  224.                 }
  225.  
  226.                 // Now change the value in the database
  227.                 OIDplus::db()->query("update ###config set value = ? where name = ?", array($value, $name));
  228.                 $this->values[$name] = $value;
  229.         }
  230.  
  231.         /**
  232.          * @param string $name
  233.          * @return void
  234.          * @throws OIDplusException
  235.          */
  236.         public function delete(string $name) {
  237.                 if ($this->configTableReadOnce) {
  238.                         if (isset($this->values[$name])) {
  239.                                 OIDplus::db()->query("delete from ###config where name = ?", array($name));
  240.                         }
  241.                 } else {
  242.                         // We do not know if the value exists.
  243.                         // buildConfigArray() would do many reads which are unnecessary.
  244.                         // So we just do a MySQL command to delete the stuff:
  245.                         OIDplus::db()->query("delete from ###config where name = ?", array($name));
  246.                 }
  247.  
  248.                 unset($this->values[$name]);
  249.                 unset($this->descriptions[$name]);
  250.                 unset($this->validateCallbacks[$name]);
  251.                 unset($this->protectSettings[$name]);
  252.                 unset($this->visibleSettings[$name]);
  253.         }
  254.  
  255. }
  256.