name = $name; $this->type = $type; $this->pluginName = $pluginName; $this->setDefaultValue($defaultValue); } /** * Get the name of the setting. * @return string */ public function getName() { return $this->name; } /** * Get the PHP type of the setting. * @return string */ public function getType() { return $this->type; } /** * @internal * @ignore * @param $callback */ public function setConfigureCallback($callback) { $this->configureCallback = $callback; $this->config = null; } /** * @return mixed */ public function getDefaultValue() { return $this->defaultValue; } /** * Sets/overwrites the current default value * @param string $defaultValue */ public function setDefaultValue($defaultValue) { $this->defaultValue = $defaultValue; } /** * @internal * @param Storage $storage */ public function setStorage(Storage $storage) { $this->storage = $storage; } /** * @internal * @ignore * @return FieldConfig * @throws Exception */ public function configureField() { if (!$this->config) { $this->config = new FieldConfig(); if ($this->configureCallback) { call_user_func($this->configureCallback, $this->config); } $this->setUiControlIfNeeded($this->config); $this->checkType($this->config); } return $this->config; } /** * Set whether setting is writable or not. For example to hide setting from the UI set it to false. * * @param bool $isWritable */ public function setIsWritableByCurrentUser($isWritable) { $this->hasWritePermission = (bool) $isWritable; } /** * Returns `true` if this setting is writable for the current user, `false` if otherwise. In case it returns * writable for the current user it will be visible in the Plugin settings UI. * * @return bool */ public function isWritableByCurrentUser() { return (bool) $this->hasWritePermission; } /** * Saves (persists) the value for this setting in the database if a value has been actually set. */ public function save() { $this->storage->save(); } /** * Returns the previously persisted setting value. If no value was set, the default value * is returned. * * @return mixed */ public function getValue() { return $this->storage->getValue($this->name, $this->defaultValue, $this->type); } /** * Sets and persists this setting's value overwriting any existing value. * * Before a value is actually set it will be made sure the current user is allowed to change the value. The value * will be first validated either via a system built-in validate method or via a set {@link FieldConfig::$validate} * custom method. Afterwards the value will be transformed via a possibly specified {@link FieldConfig::$transform} * method. Before storing the actual value, the value will be converted to the actually specified {@link $type}. * * @param mixed $value * @throws \Exception If the current user is not allowed to change the value of this setting. */ public function setValue($value) { $this->checkHasEnoughWritePermission(); $config = $this->configureField(); $this->validateValue($value); if ($config->transform && $config->transform instanceof \Closure) { $value = call_user_func($config->transform, $value, $this); } if (isset($this->type)) { settype($value, $this->type); } $this->storage->setValue($this->name, $value); } private function validateValue($value) { $config = $this->configureField(); if ($config->validate && $config->validate instanceof \Closure) { call_user_func($config->validate, $value, $this); } elseif (is_array($config->availableValues)) { if (is_bool($value) && $value) { $value = '1'; } elseif (is_bool($value)) { $value = '0'; } // TODO move error message creation to a subclass, eg in MeasurableSettings we do not want to mention plugin name $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingsValueNotAllowed', array(strip_tags($config->title), $this->pluginName)); if (is_array($value) && $this->type === FieldConfig::TYPE_ARRAY) { foreach ($value as $val) { if (!array_key_exists($val, $config->availableValues)) { throw new \Exception($errorMsg); } } } else { if (!array_key_exists($value, $config->availableValues)) { throw new \Exception($errorMsg); } } } elseif ($this->type === FieldConfig::TYPE_INT || $this->type === FieldConfig::TYPE_FLOAT) { if (!is_numeric($value)) { $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingsValueNotAllowed', array(strip_tags($config->title), $this->pluginName)); throw new \Exception($errorMsg); } } elseif ($this->type === FieldConfig::TYPE_BOOL) { if (!in_array($value, array(true, false, '0', '1', 0, 1), true)) { $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingsValueNotAllowed', array(strip_tags($config->title), $this->pluginName)); throw new \Exception($errorMsg); } } } /** * @throws \Exception */ private function checkHasEnoughWritePermission() { if (!$this->isWritableByCurrentUser()) { $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingChangeNotAllowed', array($this->name, $this->pluginName)); throw new \Exception($errorMsg); } } private function setUiControlIfNeeded(FieldConfig $field) { if (!isset($field->uiControl)) { $defaultControlTypes = array( FieldConfig::TYPE_INT => FieldConfig::UI_CONTROL_TEXT, FieldConfig::TYPE_FLOAT => FieldConfig::UI_CONTROL_TEXT, FieldConfig::TYPE_STRING => FieldConfig::UI_CONTROL_TEXT, FieldConfig::TYPE_BOOL => FieldConfig::UI_CONTROL_CHECKBOX, FieldConfig::TYPE_ARRAY => FieldConfig::UI_CONTROL_MULTI_SELECT, ); if (isset($defaultControlTypes[$this->type])) { $field->uiControl = $defaultControlTypes[$this->type]; } else { $field->uiControl = FieldConfig::UI_CONTROL_TEXT; } } } private function checkType(FieldConfig $field) { if ($field->uiControl === FieldConfig::UI_CONTROL_MULTI_SELECT && $this->type !== FieldConfig::TYPE_ARRAY) { throw new Exception('Type must be an array when using a multi select'); } $types = array( FieldConfig::TYPE_INT, FieldConfig::TYPE_FLOAT, FieldConfig::TYPE_STRING, FieldConfig::TYPE_BOOL, FieldConfig::TYPE_ARRAY ); if (!in_array($this->type, $types)) { throw new Exception('Type does not exist'); } } }