* @copyright 2014 ManiaControl Team * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 */ class SettingManager implements CallbackListener { /* * Constants */ const TABLE_SETTINGS = 'mc_settings'; const CB_SETTING_CHANGED = 'SettingManager.SettingChanged'; /* * Private Properties */ private $maniaControl = null; private $storedSettings = array(); /** * Construct a new Setting Manager * * @param ManiaControl $maniaControl */ public function __construct(ManiaControl $maniaControl) { $this->maniaControl = $maniaControl; $this->initTables(); $this->maniaControl->callbackManager->registerCallbackListener(CallbackManager::CB_AFTERINIT, $this, 'handleAfterInit'); } /** * Initialize the necessary Database Tables * * @return bool */ private function initTables() { $mysqli = $this->maniaControl->database->mysqli; $defaultType = "'" . Setting::TYPE_STRING . "'"; $typeSet = Setting::getTypeSet(); $settingTableQuery = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_SETTINGS . "` ( `index` int(11) NOT NULL AUTO_INCREMENT, `class` varchar(100) NOT NULL, `setting` varchar(150) NOT NULL, `type` set({$typeSet}) NOT NULL DEFAULT {$defaultType}, `value` varchar(100) NOT NULL, `default` varchar(100) NOT NULL, `changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`index`), UNIQUE KEY `settingId` (`class`,`setting`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Settings and Configurations' AUTO_INCREMENT=1;"; $result = $mysqli->query($settingTableQuery); if ($mysqli->error) { trigger_error($mysqli->error, E_USER_ERROR); } return $result; } /** * Handle After Init Callback */ public function handleAfterInit() { $this->deleteUnusedSettings(); } /** * Delete all unused Settings that haven't been initialized during the current Startup * * @return bool */ private function deleteUnusedSettings() { $mysqli = $this->maniaControl->database->mysqli; $settingQuery = "DELETE FROM `" . self::TABLE_SETTINGS . "` WHERE `changed` < NOW() - INTERVAL 1 HOUR;"; $result = $mysqli->query($settingQuery); if ($mysqli->error) { trigger_error($mysqli->error); return false; } if ($result) { $this->storedSettings = array(); return true; } return false; } /** * Get a Setting by its Index * * @param int $settingIndex * @param mixed $defaultValue * @return Setting */ public function getSettingByIndex($settingIndex, $defaultValue = null) { $mysqli = $this->maniaControl->database->mysqli; $settingQuery = "SELECT * FROM `" . self::TABLE_SETTINGS . "` WHERE `index` = {$settingIndex};"; $result = $mysqli->query($settingQuery); if ($mysqli->error) { trigger_error($mysqli->error); return null; } if ($result->num_rows <= 0) { $result->close(); return $defaultValue; } /** @var Setting $setting */ $setting = $result->fetch_object(Setting::CLASS_NAME, array(true)); $result->close(); return $setting; } /** * Set a Setting for the given Object * * @param mixed $object * @param string $settingName * @param mixed $value * @return Setting */ public function setSetting($object, $settingName, $value) { $className = ClassUtil::getClass($object); $setting = $this->getSetting($object, $settingName); if ($setting) { $setting->value = $value; if (!$this->saveSetting($setting)) { return null; } } else { $setting = $this->initSetting($object, $settingName, $value); } $this->storedSettings[$className . $settingName] = $setting; // Trigger Settings Changed Callback $this->maniaControl->callbackManager->triggerCallback(self::CB_SETTING_CHANGED, $setting); return $setting; } /** * Get Setting by Name for the given Object * * @param mixed $object * @param string $settingName * @param mixed $default * @return Setting */ public function getSetting($object, $settingName, $default = null) { $settingClass = ClassUtil::getClass($object); // Retrieve from Storage if possible if (isset($this->storedSettings[$settingClass . $settingName])) { return $this->storedSettings[$settingClass . $settingName]; } // Fetch setting $mysqli = $this->maniaControl->database->mysqli; $settingQuery = "SELECT * FROM `" . self::TABLE_SETTINGS . "` WHERE `class` = '" . $mysqli->escape_string($settingClass) . "' AND `setting` = '" . $mysqli->escape_string($settingName) . "';"; $result = $mysqli->query($settingQuery); if ($mysqli->error) { trigger_error($mysqli->error); return null; } if ($result->num_rows <= 0) { if ($default === null) { return null; } $setting = $this->initSetting($object, $settingName, $default); return $setting; } /** @var Setting $setting */ $setting = $result->fetch_object(Setting::CLASS_NAME, array(true)); $result->free(); // Store setting $this->storedSettings[$settingClass . $settingName] = $setting; return $setting; } /** * Initialize a Setting for the given Object * * @param mixed $object * @param string $settingName * @param mixed $defaultValue * @return Setting */ public function initSetting($object, $settingName, $defaultValue) { $setting = new Setting(); $setting->class = ClassUtil::getClass($object); $setting->setting = $settingName; $setting->type = Setting::getValueType($defaultValue); $setting->value = $defaultValue; $setting->default = $defaultValue; $saved = $this->saveSetting($setting); if ($saved) { return $setting; } return null; } /** * Save the given Setting in the Database * * @param Setting $setting * @return bool */ public function saveSetting(Setting &$setting) { $mysqli = $this->maniaControl->database->mysqli; $settingQuery = "INSERT INTO `" . self::TABLE_SETTINGS . "` ( `class`, `setting`, `type`, `value`, `default` ) VALUES ( ?, ?, ?, @value := ?, @value ) ON DUPLICATE KEY UPDATE `index` = LAST_INSERT_ID(`index`), `type` = VALUES(`type`), `value` = IF(`default` = VALUES(`default`), `value`, VALUES(`default`)), `default` = VALUES(`default`), `changed` = NOW();"; $settingStatement = $mysqli->prepare($settingQuery); if ($mysqli->error) { trigger_error($mysqli->error); return false; } $formattedValue = $setting->getFormattedValue(); $settingStatement->bind_param('ssss', $setting->class, $setting->setting, $setting->type, $formattedValue); $settingStatement->execute(); if ($settingStatement->error) { trigger_error($settingStatement->error); $settingStatement->close(); return false; } $setting->index = $settingStatement->insert_id; $settingStatement->close(); return true; } /** * Get the Setting Value directly * * @param mixed $object * @param string $settingName * @param mixed $default * @return mixed */ public function getSettingValue($object, $settingName, $default = null) { $setting = $this->getSetting($object, $settingName, $default); if ($setting) { return $setting->value; } return null; } /** * Reset a Setting to its Default Value * * @param mixed $object * @param string $settingName * @return bool */ public function resetSetting($object, $settingName = null) { if ($object instanceof Setting) { $className = $object->class; $settingName = $object->setting; } else { $className = ClassUtil::getClass($object); } $mysqli = $this->maniaControl->database->mysqli; $settingQuery = "UPDATE `" . self::TABLE_SETTINGS . "` SET `value` = `default` WHERE `class` = '" . $mysqli->escape_string($className) . "' AND `setting` = '" . $mysqli->escape_string($settingName) . "';"; $result = $mysqli->query($settingQuery); if ($mysqli->error) { trigger_error($mysqli->error); return false; } if (isset($this->storedSettings[$className . $settingName])) { unset($this->storedSettings[$className . $settingName]); } return $result; } /** * Delete a Setting * * @param mixed $object * @param string $settingName * @return bool */ public function deleteSetting($object, $settingName = null) { if ($object instanceof Setting) { $className = $object->class; $settingName = $object->setting; } else { $className = ClassUtil::getClass($object); } $mysqli = $this->maniaControl->database->mysqli; $settingQuery = "DELETE FROM `" . self::TABLE_SETTINGS . "` WHERE `class` = '" . $mysqli->escape_string($className) . "' AND `setting` = '" . $mysqli->escape_string($settingName) . "';"; $result = $mysqli->query($settingQuery); if ($mysqli->error) { trigger_error($mysqli->error); return false; } if (isset($this->storedSettings[$className . $settingName])) { unset($this->storedSettings[$className . $settingName]); } return $result; } /** * Get all Settings for the given Class * * @param mixed $object * @return array */ public function getSettingsByClass($object) { $className = ClassUtil::getClass($object); $mysqli = $this->maniaControl->database->mysqli; $query = "SELECT * FROM `" . self::TABLE_SETTINGS . "` WHERE `class` = '" . $mysqli->escape_string($className) . "' ORDER BY `setting` ASC;"; $result = $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); return null; } $settings = array(); while ($setting = $result->fetch_object(Setting::CLASS_NAME, array(true))) { $settings[$setting->index] = $setting; } $result->free(); return $settings; } /** * Get all Settings * * @return array */ public function getSettings() { $mysqli = $this->maniaControl->database->mysqli; $query = "SELECT * FROM `" . self::TABLE_SETTINGS . "` ORDER BY `class` ASC, `setting` ASC;"; $result = $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); return null; } $settings = array(); while ($setting = $result->fetch_object(Setting::CLASS_NAME, array(true))) { $settings[$setting->index] = $setting; } $result->free(); return $settings; } /** * Get all Setting Classes * * @param bool $hidePluginClasses * @return array */ public function getSettingClasses($hidePluginClasses = false) { $mysqli = $this->maniaControl->database->mysqli; $query = "SELECT DISTINCT `class` FROM `" . self::TABLE_SETTINGS . "` ORDER BY `class` ASC;"; $result = $mysqli->query($query); if ($mysqli->error) { trigger_error($mysqli->error); return null; } $settingClasses = array(); while ($row = $result->fetch_object()) { if (!$hidePluginClasses || !PluginManager::isPluginClass($row->class)) { array_push($settingClasses, $row->class); } } $result->free(); return $settingClasses; } }