Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Steur <thomas.steur@gmail.com>2016-03-10 00:55:45 +0300
committerThomas Steur <thomas.steur@gmail.com>2016-04-11 05:11:33 +0300
commitb52ae4e7e488e0474d67c54578e1d6c1aa066bff (patch)
treef94b02f774cbc24faaa18f29ee1e19fef8b338af /core/Settings/Storage/Backend
parent6ba622a68a26792af8cc22131f488f7ff5189d2c (diff)
refs #7983 let plugins add or remove fields to websites and better settings api
Diffstat (limited to 'core/Settings/Storage/Backend')
-rw-r--r--core/Settings/Storage/Backend/BackendInterface.php47
-rw-r--r--core/Settings/Storage/Backend/Cache.php78
-rw-r--r--core/Settings/Storage/Backend/MeasurableSettingsTable.php167
-rw-r--r--core/Settings/Storage/Backend/Null.php44
-rw-r--r--core/Settings/Storage/Backend/PluginSettingsTable.php175
-rw-r--r--core/Settings/Storage/Backend/SitesTable.php122
6 files changed, 633 insertions, 0 deletions
diff --git a/core/Settings/Storage/Backend/BackendInterface.php b/core/Settings/Storage/Backend/BackendInterface.php
new file mode 100644
index 0000000000..624493460e
--- /dev/null
+++ b/core/Settings/Storage/Backend/BackendInterface.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Settings\Storage\Backend;
+
+/**
+ * Interface for a storage backend. Any new storage backend must implement this interface.
+ */
+interface BackendInterface
+{
+
+ /**
+ * Get an id that identifies the current storage. Eg `Plugin_$pluginName_Settings` could be a storage id
+ * for plugin settings. It's kind of like a cache key and the value will be actually used for this by a cache
+ * decorator.
+ *
+ * @return string
+ */
+ public function getStorageId();
+
+ /**
+ * Saves (persists) the current setting values in the database. Always all values that belong to a group of
+ * settings or backend needs to be passed. Usually existing values will be deleted and new values will be saved
+ * @param array $values An array of key value pairs where $settingName => $settingValue.
+ * Eg array('settingName1' > 'settingValue1')
+ */
+ public function save($values);
+
+ /**
+ * Deletes all saved settings.
+ * @return void
+ */
+ public function delete();
+
+ /**
+ * Loads previously saved setting values and returns them (if some were saved)
+ *
+ * @return array An array of key value pairs where $settingName => $settingValue.
+ * Eg array('settingName1' > 'settingValue1')
+ */
+ public function load();
+}
diff --git a/core/Settings/Storage/Backend/Cache.php b/core/Settings/Storage/Backend/Cache.php
new file mode 100644
index 0000000000..f3150d77ee
--- /dev/null
+++ b/core/Settings/Storage/Backend/Cache.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Settings\Storage\Backend;
+
+use Piwik\Settings\Storage;
+use Piwik\Tracker;
+use Piwik\Cache as PiwikCache;
+
+/**
+ * Loads settings from tracker cache instead of database. If not yet present in tracker cache will cache it.
+ *
+ * Can be used as a decorator in combination with any other storage backend.
+ */
+class Cache implements BackendInterface
+{
+ /**
+ * @var BackendInterface
+ */
+ private $backend;
+
+ public function __construct(BackendInterface $backend)
+ {
+ $this->backend = $backend;
+ }
+
+ /**
+ * Saves (persists) the current setting values in the database.
+ */
+ public function save($values)
+ {
+ $this->backend->save($values);
+ self::clearCache();
+ }
+
+ public function getStorageId()
+ {
+ return $this->backend->getStorageId();
+ }
+
+ public function delete()
+ {
+ $this->backend->delete();
+ self::clearCache();
+ }
+
+ public function load()
+ {
+ $cacheId = $this->getStorageId();
+ $cache = self::buildCache();
+
+ if ($cache->contains($cacheId)) {
+ return $cache->fetch($cacheId);
+ }
+
+ $settings = $this->backend->load();
+ $cache->save($cacheId, $settings);
+
+ return $settings;
+ }
+
+ public static function clearCache()
+ {
+ Tracker\Cache::deleteTrackerCache();
+ self::buildCache()->flushAll();
+ }
+
+ public static function buildCache()
+ {
+ return PiwikCache::getEagerCache();
+ }
+}
diff --git a/core/Settings/Storage/Backend/MeasurableSettingsTable.php b/core/Settings/Storage/Backend/MeasurableSettingsTable.php
new file mode 100644
index 0000000000..22452288c8
--- /dev/null
+++ b/core/Settings/Storage/Backend/MeasurableSettingsTable.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Settings\Storage\Backend;
+
+use Piwik\Common;
+use Piwik\Db;
+use Exception;
+
+/**
+ * Measurable settings backend. Stores all settings in a "site_setting" database table.
+ *
+ * If a value that needs to be stored is an array, will insert a new row for each value of this array.
+ */
+class MeasurableSettingsTable implements BackendInterface
+{
+ /**
+ * @var int
+ */
+ private $idSite;
+
+ /**
+ * @var string
+ */
+ private $pluginName;
+
+ /**
+ * @var Db\AdapterInterface
+ */
+ private $db;
+
+ public function __construct($idSite, $pluginName)
+ {
+ if (empty($pluginName)) {
+ throw new Exception('No plugin name given for MeasurableSettingsTable backend');
+ }
+
+ if (empty($idSite)) {
+ throw new Exception('No idSite given for MeasurableSettingsTable backend');
+ }
+
+ $this->idSite = (int) $idSite;
+ $this->pluginName = $pluginName;
+ }
+
+ private function initDbIfNeeded()
+ {
+ if (!isset($this->db)) {
+ // we need to avoid db creation on instance creation, especially important in tracker mode
+ // the db might be never actually used when values are eg fetched from a cache
+ $this->db = Db::get();
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getStorageId()
+ {
+ return 'MeasurableSettings_' . $this->idSite . '_' . $this->pluginName;
+ }
+
+ /**
+ * Saves (persists) the current setting values in the database.
+ */
+ public function save($values)
+ {
+ $this->initDbIfNeeded();
+
+ $table = $this->getTableName();
+
+ $this->delete();
+
+ foreach ($values as $name => $value) {
+ if (!is_array($value)) {
+ $value = array($value);
+ }
+
+ foreach ($value as $val) {
+ if (!isset($val)) {
+ continue;
+ }
+
+ if (is_bool($val)) {
+ $val = (int) $val;
+ }
+
+ $sql = "INSERT INTO $table (`idsite`, `plugin_name`, `setting_name`, `setting_value`) VALUES (?, ?, ?, ?)";
+ $bind = array($this->idSite, $this->pluginName, $name, $val);
+
+ $this->db->query($sql, $bind);
+ }
+ }
+ }
+
+ public function load()
+ {
+ $this->initDbIfNeeded();
+
+ $table = $this->getTableName();
+
+ $sql = "SELECT `setting_name`, `setting_value` FROM " . $table . " WHERE idsite = ? and plugin_name = ?";
+ $bind = array($this->idSite, $this->pluginName);
+
+ $settings = $this->db->fetchAll($sql, $bind);
+
+ $flat = array();
+ foreach ($settings as $setting) {
+ $name = $setting['setting_name'];
+
+ if (array_key_exists($name, $flat)) {
+ if (!is_array($flat[$name])) {
+ $flat[$name] = array($flat[$name]);
+ }
+ $flat[$name][] = $setting['setting_value'];
+ } else {
+ $flat[$name] = $setting['setting_value'];
+ }
+ }
+
+ return $flat;
+ }
+
+ private function getTableName()
+ {
+ return Common::prefixTable('site_setting');
+ }
+
+ public function delete()
+ {
+ $this->initDbIfNeeded();
+
+ $table = $this->getTableName();
+ $sql = "DELETE FROM $table WHERE `idsite` = ? and plugin_name = ?";
+ $bind = array($this->idSite, $this->pluginName);
+
+ $this->db->query($sql, $bind);
+ }
+
+ /**
+ * @internal
+ * @param int $idSite
+ * @throws \Exception
+ */
+ public static function removeAllSettingsForSite($idSite)
+ {
+ $query = sprintf('DELETE FROM %s WHERE idsite = ?', Common::prefixTable('site_setting'));
+ Db::query($query, array($idSite));
+ }
+
+ /**
+ * @internal
+ * @param string $pluginName
+ * @throws \Exception
+ */
+ public static function removeAllSettingsForPlugin($pluginName)
+ {
+ $query = sprintf('DELETE FROM %s WHERE plugin_name = ?', Common::prefixTable('site_setting'));
+ Db::query($query, array($pluginName));
+ }
+}
diff --git a/core/Settings/Storage/Backend/Null.php b/core/Settings/Storage/Backend/Null.php
new file mode 100644
index 0000000000..cc64c55654
--- /dev/null
+++ b/core/Settings/Storage/Backend/Null.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Settings\Storage\Backend;
+
+use Piwik\Settings\Storage;
+
+/**
+ * Static / temporary storage where a value shall never be persisted. Meaning it will use the default value
+ * for each request until configured differently. Useful for tests etc.
+ */
+class Null implements BackendInterface
+{
+ private $storageId;
+
+ public function __construct($storageId)
+ {
+ $this->storageId = $storageId;
+ }
+
+ public function load()
+ {
+ return array();
+ }
+
+ public function getStorageId()
+ {
+ return $this->storageId;
+ }
+
+ public function delete()
+ {
+ }
+
+ public function save($values)
+ {
+ }
+}
diff --git a/core/Settings/Storage/Backend/PluginSettingsTable.php b/core/Settings/Storage/Backend/PluginSettingsTable.php
new file mode 100644
index 0000000000..87476ff8fb
--- /dev/null
+++ b/core/Settings/Storage/Backend/PluginSettingsTable.php
@@ -0,0 +1,175 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Settings\Storage\Backend;
+
+use Piwik\Common;
+use Piwik\Db;
+use Exception;
+
+/**
+ * Plugin settings backend. Stores all settings in a "plugin_setting" database table.
+ *
+ * If a value that needs to be stored is an array, will insert a new row for each value of this array.
+ */
+class PluginSettingsTable implements BackendInterface
+{
+ /**
+ * @var string
+ */
+ private $pluginName;
+
+ /**
+ * @var string
+ */
+ private $userLogin;
+
+ /**
+ * @var Db\AdapterInterface
+ */
+ private $db;
+
+ public function __construct($pluginName, $userLogin)
+ {
+ 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;
+ }
+
+ private function initDbIfNeeded()
+ {
+ if (!isset($this->db)) {
+ // we do not want to create a db connection on backend creation
+ $this->db = Db::get();
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getStorageId()
+ {
+ return 'PluginSettings_' . $this->pluginName . '_User_' . $this->userLogin;
+ }
+
+ /**
+ * Saves (persists) the current setting values in the database.
+ */
+ public function save($values)
+ {
+ $this->initDbIfNeeded();
+
+ $table = $this->getTableName();
+
+ $this->delete();
+
+ foreach ($values as $name => $value) {
+
+ if (!is_array($value)) {
+ $value = array($value);
+ }
+
+ foreach ($value as $val) {
+ if (!isset($val)) {
+ continue;
+ }
+
+ if (is_bool($val)) {
+ $val = (int) $val;
+ }
+
+ $sql = "INSERT INTO $table (`plugin_name`, `user_login`, `setting_name`, `setting_value`) VALUES (?, ?, ?, ?)";
+ $bind = array($this->pluginName, $this->userLogin, $name, $val);
+
+ $this->db->query($sql, $bind);
+ }
+ }
+ }
+
+ public function load()
+ {
+ $this->initDbIfNeeded();
+
+ $sql = "SELECT `setting_name`, `setting_value` FROM " . $this->getTableName() . " WHERE plugin_name = ? and user_login = ?";
+ $bind = array($this->pluginName, $this->userLogin);
+
+ $settings = $this->db->fetchAll($sql, $bind);
+
+ $flat = array();
+ foreach ($settings as $setting) {
+ $name = $setting['setting_name'];
+
+ if (array_key_exists($name, $flat)) {
+ if (!is_array($flat[$name])) {
+ $flat[$name] = array($flat[$name]);
+ }
+ $flat[$name][] = $setting['setting_value'];
+ } else {
+ $flat[$name] = $setting['setting_value'];
+ }
+ }
+
+ return $flat;
+ }
+
+ private 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);
+ }
+
+ /**
+ * Unsets all settings for a user. The settings will be removed from the database. Used when
+ * a user is deleted.
+ *
+ * @internal
+ * @param string $userLogin
+ * @throws \Exception If the `$userLogin` is empty. Otherwise we would delete most plugin settings
+ */
+ public static function removeAllUserSettingsForUser($userLogin)
+ {
+ if (empty($userLogin)) {
+ throw new Exception('No userLogin specified. Cannot remove all settings for this user');
+ }
+
+ $table = Common::prefixTable('plugin_setting');
+ Db::get()->query(sprintf('DELETE FROM %s WHERE user_login = ?', $table), array($userLogin));
+ }
+
+ /**
+ * Unsets all settings for a plugin. The settings will be removed from the database. Used when
+ * a plugin is uninstalled.
+ *
+ * @internal
+ * @param string $pluginName
+ * @throws \Exception If the `$userLogin` is empty.
+ */
+ public static function removeAllSettingsForPlugin($pluginName)
+ {
+ $table = Common::prefixTable('plugin_setting');
+ Db::get()->query(sprintf('DELETE FROM %s WHERE plugin_name = ?', $table), array($pluginName));
+ }
+}
diff --git a/core/Settings/Storage/Backend/SitesTable.php b/core/Settings/Storage/Backend/SitesTable.php
new file mode 100644
index 0000000000..81de89b100
--- /dev/null
+++ b/core/Settings/Storage/Backend/SitesTable.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Settings\Storage\Backend;
+
+use Piwik\Plugins\SitesManager\Model;
+use Piwik\Site;
+use Exception;
+
+/**
+ * Backend for an existing site. Stores all settings in the "site" database table.
+ */
+class SitesTable implements BackendInterface
+{
+ /**
+ * @var int
+ */
+ private $idSite;
+
+ private $commaSeparatedArrayFields = array(
+ 'sitesearch_keyword_parameters',
+ 'sitesearch_category_parameters',
+ 'excluded_user_agents',
+ 'excluded_parameters',
+ 'excluded_ips'
+ );
+
+ // these fields are standard fields of a site and cannot be adjusted via a setting
+ private $allowedNames = array(
+ 'ecommerce', 'sitesearch', 'sitesearch_keyword_parameters',
+ 'sitesearch_category_parameters', 'exclude_unknown_urls',
+ 'excluded_ips', 'excluded_parameters',
+ 'excluded_user_agents', 'keep_url_fragment', 'urls'
+ );
+
+ public function __construct($idSite)
+ {
+ if (empty($idSite)) {
+ throw new Exception('No idSite given for Measurable backend');
+ }
+
+ $this->idSite = (int) $idSite;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getStorageId()
+ {
+ return 'SitesTable_' . $this->idSite;
+ }
+
+ /**
+ * Saves (persists) the current setting values in the database.
+ */
+ public function save($values)
+ {
+ $model = $this->getModel();
+
+ foreach ($values as $key => $value) {
+ if (!in_array($key, $this->allowedNames)) {
+ unset($values[$key]);
+ continue;
+ }
+
+ if (is_array($value) && in_array($key, $this->commaSeparatedArrayFields)) {
+ $values[$key] = implode(',', $value);
+ } elseif (is_bool($value)) {
+ $values[$key] = (int) $value;
+ }
+ }
+
+ if (!empty($values['urls'])) {
+ $urls = array_unique($values['urls']);
+ $values['main_url'] = array_shift($urls);
+
+ $model->deleteSiteAliasUrls($this->idSite);
+ foreach ($urls as $url) {
+ $model->insertSiteUrl($this->idSite, $url);
+ }
+ }
+
+ unset($values['urls']);
+
+ $model->updateSite($values, $this->idSite);
+ Site::clearCacheForSite($this->idSite);
+ }
+
+ public function load()
+ {
+ if (!empty($this->idSite)) {
+ $site = Site::getSite($this->idSite);
+
+ $urls = $this->getModel();
+ $site['urls'] = $urls->getSiteUrlsFromId($this->idSite);
+
+ foreach ($this->commaSeparatedArrayFields as $field) {
+ if (!empty($site[$field]) && is_string($site[$field])) {
+ $site[$field] = explode(',', $site[$field]);
+ }
+ }
+
+ return $site;
+ }
+ }
+
+ private function getModel()
+ {
+ return new Model();
+ }
+
+ public function delete()
+ {
+ }
+
+}