diff options
author | Thomas Steur <tsteur@users.noreply.github.com> | 2018-05-03 22:37:39 +0300 |
---|---|---|
committer | Benaka <diosmosis@users.noreply.github.com> | 2018-05-03 22:37:39 +0300 |
commit | 94ba5d292a0bde8a3b2056e698cfcb3e9ea7c1af (patch) | |
tree | 0cc5deab197195dd092ddf1c528cc5b438ddd942 /core/Settings | |
parent | 19000f9e263e28be2703fedc9d2b77b7d962539b (diff) |
Added new setting field to configure multiple values (#12807)
* Added new setting field to configure multiple values
* remove not needed comment
* better spacing between rows
* make fields wider
* fix ui test
* rename multipair to multituple
* rename variable
* fix it was not possible to persist nested arrays
* only catch error when using old version
* catch exception
* better implementation
* require higher version
* trying to fix json_encoded columm missing in db during updater
* silence errors
* hard code the query
* fix user login cannot be null
* fail if query fails
Diffstat (limited to 'core/Settings')
-rw-r--r-- | core/Settings/FieldConfig.php | 5 | ||||
-rw-r--r-- | core/Settings/FieldConfig/MultiPair.php | 89 | ||||
-rw-r--r-- | core/Settings/Setting.php | 5 | ||||
-rw-r--r-- | core/Settings/Storage/Backend/MeasurableSettingsTable.php | 54 | ||||
-rw-r--r-- | core/Settings/Storage/Backend/PluginSettingsTable.php | 54 |
5 files changed, 174 insertions, 33 deletions
diff --git a/core/Settings/FieldConfig.php b/core/Settings/FieldConfig.php index e7b819b34e..3132032dc8 100644 --- a/core/Settings/FieldConfig.php +++ b/core/Settings/FieldConfig.php @@ -70,6 +70,11 @@ class FieldConfig const UI_CONTROL_SINGLE_EXPANDABLE_SELECT = 'expandable-select'; /** + * Lets a user configure two form fields next to each other, and add multiple entries of those two pairs. + */ + const UI_CONTROL_MULTI_TUPLE = 'multituple'; + + /** * Generates a hidden form field. To use this field assign it to the `$uiControl` property. */ const UI_CONTROL_HIDDEN = 'hidden'; diff --git a/core/Settings/FieldConfig/MultiPair.php b/core/Settings/FieldConfig/MultiPair.php new file mode 100644 index 0000000000..ede9477e3f --- /dev/null +++ b/core/Settings/FieldConfig/MultiPair.php @@ -0,0 +1,89 @@ +<?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\FieldConfig; + +/** + * Lets you configure a multi pair field. + * + * Usage: + * + * $field->uiControl = FieldConfig::UI_CONTROL_MULTI_PAIR; + * $field1 = new FieldConfig\MultiPair('Index', 'index', FieldConfig::UI_CONTROL_TEXT); + * $field2 = new FieldConfig\MultiPair('Value', 'value', FieldConfig::UI_CONTROL_TEXT); + * $field->uiControlAttributes['field1'] = $field1->toArray(); + * $field->uiControlAttributes['field2'] = $field2->toArray(); + * + * @api + */ +class MultiPair +{ + /** + * The name of the key the index should have eg "dimension" will make an index array(array('dimension' => '...')) + * @var string + */ + public $key = ''; + + /** + * Describes what HTML element should be used to manipulate the setting through Piwik's UI. + * + * See {@link Piwik\Plugin\Settings} for a list of supported control types. + * + * @var string + */ + public $uiControl = null; + + /** + * Defines a custom template file for a UI control. This file should render a UI control and expose the value in a + * "formField.value" angular model. For an example see "plugins/CorePluginsAdmin/angularjs/form-field/field-text.html" + * + * @var string + */ + public $customUiControlTemplateFile = ''; + + /** + * This setting's display name, for example, `'Refresh Interval'`. + * + * Be sure to escape any user input as HTML can be used here. + * + * @var string + */ + public $title = ''; + + /** + * The list of all available values for this setting. If null, the setting can have any value. + * + * If supplied, this field should be an array mapping available values with their prettified + * display value. Eg, if set to `array('nb_visits' => 'Visits', 'nb_actions' => 'Actions')`, + * the UI will display **Visits** and **Actions**, and when the user selects one, Piwik will + * set the setting to **nb_visits** or **nb_actions** respectively. + * + * @var null|array + */ + public $availableValues = null; + + public function __construct($title, $key, $uiControl = 'text') + { + $this->title = $title; + $this->key = $key; + $this->uiControl = $uiControl; + } + + public function toArray() + { + return array( + 'key' => $this->key, + 'title' => $this->title, + 'uiControl' => $this->uiControl, + 'templateFile' => $this->customUiControlTemplateFile, + 'availableValues' => $this->availableValues, + ); + } + +} diff --git a/core/Settings/Setting.php b/core/Settings/Setting.php index 9bcf683e0d..0dc84e3952 100644 --- a/core/Settings/Setting.php +++ b/core/Settings/Setting.php @@ -321,6 +321,11 @@ class Setting throw new Exception('Type must be an array when using a multi select'); } + if ($field->uiControl === FieldConfig::UI_CONTROL_MULTI_TUPLE && + $this->type !== FieldConfig::TYPE_ARRAY) { + throw new Exception('Type must be an array when using a multi pair'); + } + $types = array( FieldConfig::TYPE_INT, FieldConfig::TYPE_FLOAT, diff --git a/core/Settings/Storage/Backend/MeasurableSettingsTable.php b/core/Settings/Storage/Backend/MeasurableSettingsTable.php index e91a7ac9cd..181505ff20 100644 --- a/core/Settings/Storage/Backend/MeasurableSettingsTable.php +++ b/core/Settings/Storage/Backend/MeasurableSettingsTable.php @@ -12,6 +12,7 @@ namespace Piwik\Settings\Storage\Backend; use Piwik\Common; use Piwik\Db; use Exception; +use Piwik\Version; /** * Measurable settings backend. Stores all settings in a "site_setting" database table. @@ -78,43 +79,64 @@ class MeasurableSettingsTable implements BackendInterface $this->delete(); foreach ($values as $name => $value) { - if (!is_array($value)) { - $value = array($value); + if (!isset($value)) { + continue; } - foreach ($value as $val) { - if (!isset($val)) { - continue; - } - - if (is_bool($val)) { - $val = (int) $val; + if (is_array($value) || is_object($value)) { + $jsonEncoded = 1; + $value = json_encode($value); + } else { + $jsonEncoded = 0; + if (is_bool($value)) { + // we are currently not storing booleans as json as it could result in trouble with the UI and regress + // preselecting the correct value + $value = (int) $value; } + } - $sql = "INSERT INTO $table (`idsite`, `plugin_name`, `setting_name`, `setting_value`) VALUES (?, ?, ?, ?)"; - $bind = array($this->idSite, $this->pluginName, $name, $val); + $sql = "INSERT INTO $table (`idsite`, `plugin_name`, `setting_name`, `setting_value`, `json_encoded`) VALUES (?, ?, ?, ?, ?)"; + $bind = array($this->idSite, $this->pluginName, $name, $value, $jsonEncoded); - $this->db->query($sql, $bind); - } + $this->db->query($sql, $bind); } } + private function jsonEncodedMissingError(Exception $e) + { + return strpos($e->getMessage(), 'json_encoded') !== false; + } + public function load() { $this->initDbIfNeeded(); $table = $this->getTableName(); - $sql = "SELECT `setting_name`, `setting_value` FROM " . $table . " WHERE idsite = ? and plugin_name = ?"; + $sql = "SELECT `setting_name`, `setting_value`, `json_encoded` FROM " . $table . " WHERE idsite = ? and plugin_name = ?"; $bind = array($this->idSite, $this->pluginName); - $settings = $this->db->fetchAll($sql, $bind); + try { + $settings = $this->db->fetchAll($sql, $bind); + } catch (\Exception $e) { + // we catch an exception since json_encoded might not be present before matomo is updated to 3.5.0+ but the updater + // may run this query + if ($this->jsonEncodedMissingError($e)) { + $sql = "SELECT `setting_name`, `setting_value` FROM " . $table . " WHERE idsite = ? and plugin_name = ?"; + $settings = $this->db->fetchAll($sql, $bind); + } else { + throw $e; + } + + } $flat = array(); foreach ($settings as $setting) { $name = $setting['setting_name']; - if (array_key_exists($name, $flat)) { + if (!empty($setting['json_encoded'])) { + $flat[$name] = json_decode($setting['setting_value'], true); + } elseif (array_key_exists($name, $flat)) { if (!is_array($flat[$name])) { $flat[$name] = array($flat[$name]); } diff --git a/core/Settings/Storage/Backend/PluginSettingsTable.php b/core/Settings/Storage/Backend/PluginSettingsTable.php index 0f49d6b68e..126460a8af 100644 --- a/core/Settings/Storage/Backend/PluginSettingsTable.php +++ b/core/Settings/Storage/Backend/PluginSettingsTable.php @@ -12,6 +12,7 @@ namespace Piwik\Settings\Storage\Backend; use Piwik\Common; use Piwik\Db; use Exception; +use Piwik\Version; /** * Plugin settings backend. Stores all settings in a "plugin_setting" database table. @@ -77,42 +78,61 @@ class PluginSettingsTable implements BackendInterface $this->delete(); foreach ($values as $name => $value) { - - if (!is_array($value)) { - $value = array($value); + if (!isset($value)) { + continue; } - foreach ($value as $val) { - if (!isset($val)) { - continue; - } - - if (is_bool($val)) { - $val = (int) $val; + if (is_array($value) || is_object($value)) { + $jsonEncoded = 1; + $value = json_encode($value); + } else { + $jsonEncoded = 0; + if (is_bool($value)) { + // we are currently not storing booleans as json as it could result in trouble with the UI and regress + // preselecting the correct value + $value = (int) $value; } + } - $sql = "INSERT INTO $table (`plugin_name`, `user_login`, `setting_name`, `setting_value`) VALUES (?, ?, ?, ?)"; - $bind = array($this->pluginName, $this->userLogin, $name, $val); + $sql = "INSERT INTO $table (`plugin_name`, `user_login`, `setting_name`, `setting_value`, `json_encoded`) VALUES (?, ?, ?, ?, ?)"; + $bind = array($this->pluginName, $this->userLogin, $name, $value, $jsonEncoded); - $this->db->query($sql, $bind); - } + $this->db->query($sql, $bind); } } + private function jsonEncodedMissingError(Exception $e) + { + return strpos($e->getMessage(), 'json_encoded') !== false; + } + public function load() { $this->initDbIfNeeded(); - $sql = "SELECT `setting_name`, `setting_value` FROM " . $this->getTableName() . " WHERE plugin_name = ? and user_login = ?"; + $sql = "SELECT `setting_name`, `setting_value`, `json_encoded` FROM " . $this->getTableName() . " WHERE plugin_name = ? and user_login = ?"; $bind = array($this->pluginName, $this->userLogin); - $settings = $this->db->fetchAll($sql, $bind); + try { + $settings = $this->db->fetchAll($sql, $bind); + } catch (\Exception $e) { + // we catch an exception since json_encoded might not be present before matomo is updated to 3.5.0+ but the updater + // may run this query + 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; + } + } $flat = array(); foreach ($settings as $setting) { $name = $setting['setting_name']; - if (array_key_exists($name, $flat)) { + if (!empty($setting['json_encoded'])) { + $flat[$name] = json_decode($setting['setting_value'], true); + } elseif (array_key_exists($name, $flat)) { if (!is_array($flat[$name])) { $flat[$name] = array($flat[$name]); } |