questlab/www/analytics/core/Plugin/Settings.php
2016-04-10 18:55:57 +02:00

308 lines
9.1 KiB
PHP

<?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\Plugin;
use Piwik\Piwik;
use Piwik\Settings\Setting;
use Piwik\Settings\Storage;
use Piwik\Settings\StorageInterface;
use Piwik\Tracker\SettingsStorage;
/**
* Base class of all plugin settings providers. Plugins that define their own configuration settings
* can extend this class to easily make their settings available to Piwik users.
*
* Descendants of this class should implement the {@link init()} method and call the
* {@link addSetting()} method for each of the plugin's settings.
*
* For an example, see the {@link Piwik\Plugins\ExampleSettingsPlugin\ExampleSettingsPlugin} plugin.
*
* @api
*/
abstract class Settings
{
const TYPE_INT = 'integer';
const TYPE_FLOAT = 'float';
const TYPE_STRING = 'string';
const TYPE_BOOL = 'boolean';
const TYPE_ARRAY = 'array';
const CONTROL_RADIO = 'radio';
const CONTROL_TEXT = 'text';
const CONTROL_TEXTAREA = 'textarea';
const CONTROL_CHECKBOX = 'checkbox';
const CONTROL_PASSWORD = 'password';
const CONTROL_MULTI_SELECT = 'multiselect';
const CONTROL_SINGLE_SELECT = 'select';
/**
* An array containing all available settings: Array ( [setting-name] => [setting] )
*
* @var Settings[]
*/
private $settings = array();
private $introduction;
protected $pluginName;
/**
* @var StorageInterface
*/
protected $storage;
/**
* Constructor.
*/
public function __construct($pluginName = null)
{
if (!empty($pluginName)) {
$this->pluginName = $pluginName;
} else {
$classname = get_class($this);
$parts = explode('\\', $classname);
if (3 <= count($parts)) {
$this->pluginName = $parts[2];
}
}
$this->storage = Storage\Factory::make($this->pluginName);
$this->init();
}
/**
* @ignore
*/
public function getPluginName()
{
return $this->pluginName;
}
/**
* @ignore
* @return Setting
*/
public function getSetting($name)
{
if (array_key_exists($name, $this->settings)) {
return $this->settings[$name];
}
}
/**
* Implemented by descendants. This method should define plugin settings (via the
* {@link addSetting()}) method and set the introduction text (via the
* {@link setIntroduction()}).
*/
abstract protected function init();
/**
* Sets the text used to introduce this plugin's settings in the _Plugin Settings_ page.
*
* @param string $introduction
*/
protected function setIntroduction($introduction)
{
$this->introduction = $introduction;
}
/**
* Returns the introduction text for this plugin's settings.
*
* @return string
*/
public function getIntroduction()
{
return $this->introduction;
}
/**
* Returns the settings that can be displayed for the current user.
*
* @return Setting[]
*/
public function getSettingsForCurrentUser()
{
$settings = array_filter($this->getSettings(), function (Setting $setting) {
return $setting->isWritableByCurrentUser();
});
$settings2 = $settings;
uasort($settings, function ($setting1, $setting2) use ($settings2) {
/** @var Setting $setting1 */ /** @var Setting $setting2 */
if ($setting1->getOrder() == $setting2->getOrder()) {
// preserve order for settings having same order
foreach ($settings2 as $setting) {
if ($setting1 === $setting) {
return -1;
}
if ($setting2 === $setting) {
return 1;
}
}
return 0;
}
return $setting1->getOrder() > $setting2->getOrder() ? -1 : 1;
});
return $settings;
}
/**
* Returns all available settings. This will include settings that are not available
* to the current user (such as settings available only to the Super User).
*
* @return Setting[]
*/
public function getSettings()
{
return $this->settings;
}
/**
* Makes a new plugin setting available.
*
* @param Setting $setting
* @throws \Exception If there is a setting with the same name that already exists.
* If the name contains non-alphanumeric characters.
*/
protected function addSetting(Setting $setting)
{
$name = $setting->getName();
if (!ctype_alnum(str_replace('_', '', $name))) {
$msg = sprintf('The setting name "%s" in plugin "%s" is not valid. Only underscores, alpha and numerical characters are allowed', $setting->getName(), $this->pluginName);
throw new \Exception($msg);
}
if (array_key_exists($name, $this->settings)) {
throw new \Exception(sprintf('A setting with name "%s" does already exist for plugin "%s"', $setting->getName(), $this->pluginName));
}
$this->setDefaultTypeAndFieldIfNeeded($setting);
$this->addValidatorIfNeeded($setting);
$setting->setStorage($this->storage);
$setting->setPluginName($this->pluginName);
$this->settings[$name] = $setting;
}
/**
* Saves (persists) the current setting values in the database.
*/
public function save()
{
$this->storage->save();
SettingsStorage::clearCache();
/**
* Triggered after a plugin settings have been updated.
*
* **Example**
*
* Piwik::addAction('Settings.MyPlugin.settingsUpdated', function (Settings $settings) {
* $value = $settings->someSetting->getValue();
* // Do something with the new setting value
* });
*
* @param Settings $settings The plugin settings object.
*/
Piwik::postEvent(sprintf('Settings.%s.settingsUpdated', $this->pluginName), array($this));
}
/**
* Removes all settings for this plugin from the database. Useful when uninstalling
* a plugin.
*/
public function removeAllPluginSettings()
{
Piwik::checkUserHasSuperUserAccess();
$this->storage->deleteAllValues();
SettingsStorage::clearCache();
}
private function getDefaultType($controlType)
{
$defaultTypes = array(
static::CONTROL_TEXT => static::TYPE_STRING,
static::CONTROL_TEXTAREA => static::TYPE_STRING,
static::CONTROL_PASSWORD => static::TYPE_STRING,
static::CONTROL_CHECKBOX => static::TYPE_BOOL,
static::CONTROL_MULTI_SELECT => static::TYPE_ARRAY,
static::CONTROL_RADIO => static::TYPE_STRING,
static::CONTROL_SINGLE_SELECT => static::TYPE_STRING,
);
return $defaultTypes[$controlType];
}
private function getDefaultCONTROL($type)
{
$defaultControlTypes = array(
static::TYPE_INT => static::CONTROL_TEXT,
static::TYPE_FLOAT => static::CONTROL_TEXT,
static::TYPE_STRING => static::CONTROL_TEXT,
static::TYPE_BOOL => static::CONTROL_CHECKBOX,
static::TYPE_ARRAY => static::CONTROL_MULTI_SELECT,
);
return $defaultControlTypes[$type];
}
private function setDefaultTypeAndFieldIfNeeded(Setting $setting)
{
$hasControl = !is_null($setting->uiControlType);
$hasType = !is_null($setting->type);
if ($hasControl && !$hasType) {
$setting->type = $this->getDefaultType($setting->uiControlType);
} elseif ($hasType && !$hasControl) {
$setting->uiControlType = $this->getDefaultCONTROL($setting->type);
} elseif (!$hasControl && !$hasType) {
$setting->type = static::TYPE_STRING;
$setting->uiControlType = static::CONTROL_TEXT;
}
}
private function addValidatorIfNeeded(Setting $setting)
{
if (!is_null($setting->validate) || is_null($setting->availableValues)) {
return;
}
$pluginName = $this->pluginName;
$setting->validate = function ($value) use ($setting, $pluginName) {
$errorMsg = Piwik::translate('CoreAdminHome_PluginSettingsValueNotAllowed',
array($setting->title, $pluginName));
if (is_array($value) && $setting->type == Settings::TYPE_ARRAY) {
foreach ($value as $val) {
if (!array_key_exists($val, $setting->availableValues)) {
throw new \Exception($errorMsg);
}
}
} else {
if (!array_key_exists($value, $setting->availableValues)) {
throw new \Exception($errorMsg);
}
}
};
}
}