| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Settings\Storage\Backend; |
|
|
| use Piwik\Common; |
| use Piwik\Db; |
| use Exception; |
|
|
| |
| |
| |
| |
| |
| class PluginSettingsTable extends BaseSettingsTable |
| { |
| |
| |
| |
| private $pluginName; |
|
|
| |
| |
| |
| private $userLogin; |
|
|
| public function __construct($pluginName, $userLogin) |
| { |
| parent::__construct(); |
|
|
| if (empty($pluginName)) { |
| throw new Exception('No plugin name given for PluginSettingsTable backend'); |
| } |
|
|
| if ($userLogin === false || $userLogin === null) { |
| throw new Exception('Invalid user login name given for PluginSettingsTable backend'); |
| } |
|
|
| $this->pluginName = $pluginName; |
| $this->userLogin = $userLogin; |
| } |
|
|
| |
| |
| |
| public function getStorageId() |
| { |
| return 'PluginSettings_' . $this->pluginName . '_User_' . $this->userLogin; |
| } |
|
|
| |
| |
| |
| |
| public function save($values) |
| { |
| $this->initDbIfNeeded(); |
|
|
| $valuesKeep = array(); |
|
|
| foreach ($values as $name => $value) { |
| if (!isset($value)) { |
| continue; |
| } |
| if (is_array($value) || is_object($value)) { |
| $jsonEncoded = 1; |
| $value = json_encode($value); |
| } else { |
| $jsonEncoded = 0; |
| if (is_bool($value)) { |
| |
| |
| $value = (int) $value; |
| } |
| } |
|
|
| $valuesKeep[] = array($this->pluginName, $this->userLogin, $name, $value, $jsonEncoded); |
| } |
|
|
| $columns = self::getColumns(); |
|
|
| $table = $this->getTableName(); |
| $lockKey = $this->getStorageId(); |
| $this->lock->execute($lockKey, function () use ($valuesKeep, $table, $columns) { |
| $this->delete(); |
| |
| if (!empty($valuesKeep)) { |
| Db\BatchInsert::tableInsertBatchSql($table, $columns, $valuesKeep); |
| } |
| }); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function saveValue(string $settingName, $value): void |
| { |
| $this->initDbIfNeeded(); |
|
|
| if (empty($settingName)) { |
| throw new Exception('No setting name given for PluginSettingsTable backend'); |
| } |
|
|
| $table = $this->getTableName(); |
| $lockKey = $this->getStorageId(); |
| $columns = self::getColumns(); |
|
|
| $this->lock->execute($lockKey, function () use ($table, $columns, $settingName, $value) { |
| $this->deleteValueWithoutLock($settingName); |
|
|
| if (is_null($value)) { |
| return; |
| } |
|
|
| [$storedValue, $jsonEncoded] = $this->encodeValueForStorage($value); |
| Db\BatchInsert::tableInsertBatchSql( |
| $table, |
| $columns, |
| [[$this->pluginName, $this->userLogin, $settingName, $storedValue, $jsonEncoded]] |
| ); |
| }); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function loadValue(string $settingName, $defaultValue = null) |
| { |
| $this->initDbIfNeeded(); |
| if (empty($settingName)) { |
| throw new Exception('No setting name given for PluginSettingsTable backend'); |
| } |
|
|
| $table = $this->getTableName(); |
|
|
| $sql = "SELECT `setting_name`, `setting_value`, `json_encoded` |
| FROM `$table` |
| WHERE plugin_name = ? and user_login = ? and setting_name = ?"; |
| $bind = [$this->pluginName, $this->userLogin, $settingName]; |
|
|
| try { |
| $rows = $this->db->fetchAll($sql, $bind); |
| } catch (\Exception $e) { |
| if ($this->jsonEncodedMissingError($e)) { |
| $sql = "SELECT `setting_name`, `setting_value` |
| FROM `$table` |
| WHERE plugin_name = ? and user_login = ? and setting_name = ?"; |
| $rows = $this->db->fetchAll($sql, $bind); |
| } else { |
| throw $e; |
| } |
| } |
|
|
| if (empty($rows)) { |
| return $defaultValue; |
| } |
|
|
| $flat = $this->flattenSettingsRows($rows); |
| return array_key_exists($settingName, $flat) ? $flat[$settingName] : $defaultValue; |
| } |
|
|
| |
| |
| |
| public function deleteValue(string $settingName): void |
| { |
| $this->initDbIfNeeded(); |
|
|
| if (empty($settingName)) { |
| throw new Exception('No setting name given for PluginSettingsTable backend'); |
| } |
|
|
| $lockKey = $this->getStorageId(); |
| $this->lock->execute($lockKey, function () use ($settingName) { |
| $this->deleteValueWithoutLock($settingName); |
| }); |
| } |
|
|
|
|
| private function jsonEncodedMissingError(Exception $e) |
| { |
| return strpos($e->getMessage(), 'json_encoded') !== false; |
| } |
|
|
| public function load() |
| { |
| $this->initDbIfNeeded(); |
|
|
| $sql = "SELECT `setting_name`, `setting_value`, `json_encoded` FROM `" . $this->getTableName() . "` WHERE plugin_name = ? and user_login = ?"; |
| $bind = array($this->pluginName, $this->userLogin); |
|
|
| try { |
| $settings = $this->db->fetchAll($sql, $bind); |
| } catch (\Exception $e) { |
| |
| |
| if ($this->jsonEncodedMissingError($e)) { |
| $sql = "SELECT `setting_name`, `setting_value` FROM `" . $this->getTableName() . "` WHERE plugin_name = ? and user_login = ?"; |
| $settings = $this->db->fetchAll($sql, $bind); |
| } else { |
| throw $e; |
| } |
| } |
|
|
| return $this->flattenSettingsRows($settings); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public function loadValuesForUsers(array $settingNames): array |
| { |
| $this->initDbIfNeeded(); |
| if (empty($settingNames)) { |
| return []; |
| } |
|
|
| $table = $this->getTableName(); |
| $placeholders = Common::getSqlStringFieldsArray($settingNames); |
| $sql = "SELECT user_login, setting_name, setting_value, json_encoded |
| FROM `$table` |
| WHERE plugin_name = ? |
| AND setting_name IN ($placeholders) |
| AND user_login <> ''"; |
| $bind = array_merge([$this->pluginName], $settingNames); |
|
|
| try { |
| $rows = $this->db->fetchAll($sql, $bind); |
| } catch (\Exception $e) { |
| if ($this->jsonEncodedMissingError($e)) { |
| $sql = "SELECT user_login, setting_name, setting_value |
| FROM `$table` |
| WHERE plugin_name = ? |
| AND setting_name IN ($placeholders) |
| AND user_login <> ''"; |
| $rows = $this->db->fetchAll($sql, $bind); |
| } else { |
| throw $e; |
| } |
| } |
|
|
| $valuesByUser = []; |
| foreach ($rows as $row) { |
| $jsonEncoded = isset($row['json_encoded']) ? (bool) $row['json_encoded'] : false; |
| $value = $this->decodeValueFromStorage( |
| $row['setting_value'], |
| $jsonEncoded |
| ); |
| $valuesByUser[$row['user_login']][$row['setting_name']] = $value; |
| } |
| return $valuesByUser; |
| } |
|
|
| protected function getTableName() |
| { |
| return Common::prefixTable('plugin_setting'); |
| } |
|
|
| public function delete() |
| { |
| $this->initDbIfNeeded(); |
|
|
| $table = $this->getTableName(); |
| $sql = "DELETE FROM `$table` WHERE `plugin_name` = ? and `user_login` = ?"; |
| $bind = array($this->pluginName, $this->userLogin); |
|
|
| $this->db->query($sql, $bind); |
| } |
|
|
| private function deleteValueWithoutLock(string $settingName): void |
| { |
| $this->initDbIfNeeded(); |
|
|
| $table = $this->getTableName(); |
| $sql = "DELETE FROM `$table` |
| WHERE `plugin_name` = ? and `user_login` = ? and `setting_name` = ?"; |
| $bind = [$this->pluginName, $this->userLogin, $settingName]; |
|
|
| $this->db->query($sql, $bind); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public static function removeAllUserSettingsForUser($userLogin) |
| { |
| if (empty($userLogin)) { |
| throw new Exception('No userLogin specified. Cannot remove all settings for this user'); |
| } |
|
|
| try { |
| $table = Common::prefixTable('plugin_setting'); |
| Db::get()->query(sprintf('DELETE FROM `%s` WHERE user_login = ?', $table), array($userLogin)); |
| } catch (Exception $e) { |
| if ($e->getCode() != 42) { |
| |
| throw $e; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public static function removeAllSettingsForPlugin($pluginName) |
| { |
| try { |
| $table = Common::prefixTable('plugin_setting'); |
| Db::get()->query(sprintf('DELETE FROM `%s` WHERE plugin_name = ?', $table), array($pluginName)); |
| } catch (Exception $e) { |
| if ($e->getCode() != 42) { |
| |
| throw $e; |
| } |
| } |
| } |
|
|
| |
| |
| |
| private static function getColumns(): array |
| { |
| return ['plugin_name', 'user_login', 'setting_name', 'setting_value', 'json_encoded']; |
| } |
|
|
| |
| |
| |
| |
| private function encodeValueForStorage($value): array |
| { |
| if (is_array($value) || is_object($value)) { |
| return [json_encode($value), 1]; |
| } |
|
|
| if (is_bool($value)) { |
| return [(int) $value, 0]; |
| } |
|
|
| return [$value, 0]; |
| } |
|
|
| |
| |
| |
| |
| private function decodeValueFromStorage($value, bool $jsonEncoded) |
| { |
| if ($jsonEncoded) { |
| return json_decode($value, true); |
| } |
| return $value; |
| } |
|
|
| |
| |
| |
| private function flattenSettingsRows(array $settings): array |
| { |
| $flat = []; |
| foreach ($settings as $setting) { |
| $name = $setting['setting_name']; |
| $jsonEncoded = isset($setting['json_encoded']) ? (bool) $setting['json_encoded'] : false; |
| $value = $this->decodeValueFromStorage($setting['setting_value'], $jsonEncoded); |
| if (array_key_exists($name, $flat) && !$jsonEncoded) { |
| $flat[$name] = (array) $flat[$name]; |
| $flat[$name][] = $value; |
| } else { |
| $flat[$name] = $value; |
| } |
| } |
| return $flat; |
| } |
| } |
|
|