diff --git a/CHANGELOG.md b/CHANGELOG.md index cbe224bc10003e3a15b47316a97ce2fdaec7d68b..007d94b312c1310d65afec0db3de7ff639b7277f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,9 +18,12 @@ This is a changelog for Piwik platform developers. All changes for our HTTP API' * The method `Piwik\Plugin\Controller::getEvolutionHtml` has been removed without a replacement as it should be no longer needed. The evolution is generated by ViewDataTables directly * The `core:plugin` console command has been removed in favor of the new `plugin:list`, `plugin:activate` and `plugin:deactivate` commands as anounced in Piwik 2.11 * The visibility of private properties and methods in `Piwik\Plugins\Login\Controller` were changed to `protected` -* Controller actions are now case sensitive. This means the URL and events have to use the same case as the name of the action defined in a controller. +* Controller actions are now case sensitive. This means the URL and events have to use the same case as the name of the action defined in a controller. * The "User Menu" was removed and should be replaced by "Admin Menu". Change `configureUserMenu(MenuUser $menu)` to `configureAdminMenu(MenuAdmin $menu)` in your `Menu.php`. * The method `Piwik\Menu\MenuAdmin::addSettingsItem()` was removed, use `Piwik\Menu\MenuAdmin::addManageItem()` instead. +* The class `Piwik\Plugin\Settings` has been splitted to `Piwik\Settings\Plugin\SystemSettings` and `Piwik\Settings\Plugin\UserSettings`. +* The creation of settings has slightly changed to improve performance. It is now possible to create new settings via the method `$this->makeSetting()` see `Piwik\Plugins\ExampleSettingsPlugin\SystemSettings` for an example. +* It is no possible to define an introduction text for settings. ### New APIs * Multiple widgets for one report can now be created via the `Report::configureWidgets()` method via the new classes `Piwik\Widget\ReportWidgetFactory` and `Piwik\Widget\ReportWidgetConfig` @@ -29,6 +32,7 @@ This is a changelog for Piwik platform developers. All changes for our HTTP API' * The new class `Piwik\Category\Subcategory` let you change the name and order of menu items * New HTTP API method `API.getWidgetMetadata` to get a list of available widgets * New HTTP API method `API.getReportPagesMetadata` to get a list of all available pages that exist including the widgets they include +* New HTTP API method `SitesManager.getSiteSettings` to get a list of all available settings for a specific site * The JavaScript AjaxHelper has a new method `ajaxHelper.withTokenInUrl()` to easily send a token along a XHR. Within the Controller the existence of this token can be checked via `$this->checkTokenInUrl();` to prevent CSRF attacks. ### New features diff --git a/core/API/DataTableManipulator/ReportTotalsCalculator.php b/core/API/DataTableManipulator/ReportTotalsCalculator.php index 7906077b1e2d27bb2512bb273092fe51d8358310..e1e467d0c1ebcdf79c81e35a97730dcbfb17ca7b 100644 --- a/core/API/DataTableManipulator/ReportTotalsCalculator.php +++ b/core/API/DataTableManipulator/ReportTotalsCalculator.php @@ -13,7 +13,7 @@ use Piwik\DataTable; use Piwik\Metrics; use Piwik\Period; use Piwik\Plugin\Report; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * This class is responsible for setting the metadata property 'totals' on each dataTable if the report @@ -212,7 +212,7 @@ class ReportTotalsCalculator extends DataTableManipulator private function findFirstLevelReport() { - $reports = new Reports(); + $reports = new ReportsProvider(); foreach ($reports->getAllReports() as $report) { $actionToLoadSubtables = $report->getActionToLoadSubTables(); if ($actionToLoadSubtables == $this->apiMethod diff --git a/core/API/DataTablePostProcessor.php b/core/API/DataTablePostProcessor.php index c6424ea79356cb3b6f93f756147449e74c9088a5..c2fdd1569c0c46e113ce7d77e5761c89fd424f68 100644 --- a/core/API/DataTablePostProcessor.php +++ b/core/API/DataTablePostProcessor.php @@ -19,7 +19,7 @@ use Piwik\DataTable\Filter\PivotByDimension; use Piwik\Metrics\Formatter; use Piwik\Plugin\ProcessedMetric; use Piwik\Plugin\Report; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * Processes DataTables that should be served through Piwik's APIs. This processing handles @@ -72,7 +72,7 @@ class DataTablePostProcessor $this->apiMethod = $apiMethod; $this->setRequest($request); - $this->report = Reports::factory($apiModule, $apiMethod); + $this->report = ReportsProvider::factory($apiModule, $apiMethod); $this->apiInconsistencies = new Inconsistencies(); $this->setFormatter(new Formatter()); } diff --git a/core/DataTable/Filter/PivotByDimension.php b/core/DataTable/Filter/PivotByDimension.php index bbc72f46d9a6806eb338b2914b1dd0de83df979b..f668afb0b977be452db7961c79df4621d57a50d9 100644 --- a/core/DataTable/Filter/PivotByDimension.php +++ b/core/DataTable/Filter/PivotByDimension.php @@ -21,7 +21,7 @@ use Piwik\Period; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugin\Segment; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Site; /** @@ -329,7 +329,7 @@ class PivotByDimension extends BaseFilter { list($module, $method) = explode('.', $report); - $this->thisReport = Reports::factory($module, $method); + $this->thisReport = ReportsProvider::factory($module, $method); if (empty($this->thisReport)) { throw new Exception("Unable to find report '$report'."); } diff --git a/core/DataTable/Renderer/Xml.php b/core/DataTable/Renderer/Xml.php index b01f5596a25a8b0538fdce790ba6687f1f4dd84e..31e56a4fde01f138205c0663789ec4d20c770cdc 100644 --- a/core/DataTable/Renderer/Xml.php +++ b/core/DataTable/Renderer/Xml.php @@ -176,9 +176,9 @@ class Xml extends Renderer } // render the array item - if (is_array($value)) { + if (is_array($value) || $value instanceof \stdClass) { $result .= $prefixLines . $prefix . "\n"; - $result .= $this->renderArray($value, $prefixLines . "\t"); + $result .= $this->renderArray((array) $value, $prefixLines . "\t"); $result .= $prefixLines . $suffix . "\n"; } elseif ($value instanceof DataTable || $value instanceof Map @@ -198,6 +198,7 @@ class Xml extends Renderer } } else { $xmlValue = self::formatValueXml($value); + if (strlen($xmlValue) != 0) { $result .= $prefixLines . $prefix . $xmlValue . $suffix . "\n"; } else { diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php index 07cb1490d08862fe450afec00b8c7e325ed6a86a..61532c47efa8bffe399d4b71b5aff778fd38a39a 100644 --- a/core/Db/Schema/Mysql.php +++ b/core/Db/Schema/Mysql.php @@ -76,11 +76,21 @@ class Mysql implements SchemaInterface ) ENGINE=$engine DEFAULT CHARSET=utf8 ", + 'plugin_setting' => "CREATE TABLE {$prefixTables}plugin_setting ( + `plugin_name` VARCHAR(60) NOT NULL, + `setting_name` VARCHAR(255) NOT NULL, + `setting_value` LONGTEXT NOT NULL, + `user_login` VARCHAR(100) NOT NULL DEFAULT '', + INDEX(plugin_name, user_login) + ) ENGINE=$engine DEFAULT CHARSET=utf8 + ", + 'site_setting' => "CREATE TABLE {$prefixTables}site_setting ( idsite INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `plugin_name` VARCHAR(60) NOT NULL, `setting_name` VARCHAR(255) NOT NULL, `setting_value` LONGTEXT NOT NULL, - PRIMARY KEY(idsite, setting_name) + INDEX(idsite, plugin_name) ) ENGINE=$engine DEFAULT CHARSET=utf8 ", diff --git a/core/Http/ControllerResolver.php b/core/Http/ControllerResolver.php index e0fe7d98e36c45fd093f83c9dde39a7e9b924917..b9e71b0f11df044c41e685fa676061ffd26fa115 100644 --- a/core/Http/ControllerResolver.php +++ b/core/Http/ControllerResolver.php @@ -12,9 +12,9 @@ use DI\FactoryInterface; use Exception; use Piwik\Plugin; use Piwik\Plugin\Controller; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Session; -use Piwik\Plugin\Widgets; +use Piwik\Plugin\WidgetsProvider; /** * Resolves the controller that will handle the request. @@ -29,11 +29,11 @@ class ControllerResolver private $abstractFactory; /** - * @var Widgets + * @var WidgetsProvider */ private $widgets; - public function __construct(FactoryInterface $abstractFactory, Widgets $widgets) + public function __construct(FactoryInterface $abstractFactory, WidgetsProvider $widgets) { $this->abstractFactory = $abstractFactory; $this->widgets = $widgets; @@ -100,7 +100,7 @@ class ControllerResolver private function createReportController($module, $action, array &$parameters) { - $report = Reports::factory($module, $action); + $report = ReportsProvider::factory($module, $action); if (!$report) { return null; diff --git a/core/Measurable/Measurable.php b/core/Measurable/Measurable.php index d80c1f032330dc707fe5734201f1f4090e4087b0..6223a6931f6371420f75cce09076fdeb158247c8 100644 --- a/core/Measurable/Measurable.php +++ b/core/Measurable/Measurable.php @@ -9,7 +9,6 @@ namespace Piwik\Measurable; -use Exception; use Piwik\Site; /** @@ -17,16 +16,4 @@ use Piwik\Site; */ class Measurable extends Site { - - public function getSettingValue($name) - { - $settings = new MeasurableSettings($this->id, $this->getType()); - $setting = $settings->getSetting($name); - - if (!empty($setting)) { - return $setting->getValue(); // Calling `getValue` makes sure we respect read permission of this setting - } - - throw new Exception(sprintf('Setting %s does not exist', $name)); - } } diff --git a/core/Measurable/MeasurableSetting.php b/core/Measurable/MeasurableSetting.php deleted file mode 100644 index 91e0970442fb950516ab94a8fdec7b40e721f069..0000000000000000000000000000000000000000 --- a/core/Measurable/MeasurableSetting.php +++ /dev/null @@ -1,70 +0,0 @@ -<?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\Measurable; - -use Piwik\Piwik; - -/** - * Describes a Type setting for a website, mobile app, ... - * - * See {@link \Piwik\Plugin\Settings}. - */ -class MeasurableSetting extends \Piwik\Settings\Setting -{ - /** - * By default the value of the type setting is only readable by users having at least view access to one site - * - * @var bool - * @since 2.14.0 - */ - public $readableByCurrentUser = false; - - /** - * By default the value of the type setting is only writable by users having at least admin access to one site - * @var bool - * @internal - */ - public $writableByCurrentUser = false; - - /** - * Constructor. - * - * @param string $name The persisted name of the setting. - * @param string $title The display name of the setting. - */ - public function __construct($name, $title) - { - parent::__construct($name, $title); - - $this->writableByCurrentUser = Piwik::isUserHasSomeAdminAccess(); - $this->readableByCurrentUser = Piwik::isUserHasSomeViewAccess(); - } - - /** - * 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 $this->writableByCurrentUser; - } - - /** - * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. - * - * @return bool - */ - public function isReadableByCurrentUser() - { - return $this->readableByCurrentUser; - } -} diff --git a/core/Measurable/MeasurableSettings.php b/core/Measurable/MeasurableSettings.php deleted file mode 100644 index 7d627e0a2ca542cb00713d6d83115772286069da..0000000000000000000000000000000000000000 --- a/core/Measurable/MeasurableSettings.php +++ /dev/null @@ -1,103 +0,0 @@ -<?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\Measurable; - -use Piwik\Db; -use Piwik\Piwik; -use Piwik\Plugin\Settings; -use Piwik\Measurable\Settings\Storage; -use Piwik\Settings\Setting; -use Piwik\Measurable\Type\TypeManager; - -class MeasurableSettings extends Settings -{ - - /** - * @var int - */ - private $idSite = null; - - /** - * @var string - */ - private $idType = null; - - /** - * @param int $idSite The id of a site. If you want to get settings for a not yet created site just pass an empty value ("0") - * @param string $idType If no typeId is given, the type of the site will be used. - * - * @throws \Exception - */ - public function __construct($idSite, $idType) - { - $this->idSite = $idSite; - $this->idType = $idType; - $this->storage = new Storage(Db::get(), $this->idSite); - $this->pluginName = 'MeasurableSettings'; - - $this->init(); - } - - protected function init() - { - $typeManager = new TypeManager(); - $type = $typeManager->getType($this->idType); - $type->configureMeasurableSettings($this); - - /** - * This event is posted when generating settings for a Measurable (website). You can add any Measurable settings - * that you wish to be shown in the Measurable manager (websites manager). If you need to add settings only for - * eg MobileApp measurables you can use eg `$type->getId() === Piwik\Plugins\MobileAppMeasurable\Type::ID` and - * add only settings if the condition is true. - * - * @since Piwik 2.14.0 - * @deprecated will be removed in Piwik 3.0.0 - * - * @param MeasurableSettings $this - * @param \Piwik\Measurable\Type $type - * @param int $idSite - */ - Piwik::postEvent('Measurable.initMeasurableSettings', array($this, $type, $this->idSite)); - } - - public function addSetting(Setting $setting) - { - if ($this->idSite && $setting instanceof MeasurableSetting) { - $setting->writableByCurrentUser = Piwik::isUserHasAdminAccess($this->idSite); - } - - parent::addSetting($setting); - } - - public function save() - { - Piwik::checkUserHasAdminAccess($this->idSite); - - $typeManager = new TypeManager(); - $type = $typeManager->getType($this->idType); - - /** - * Triggered just before Measurable settings are about to be saved. You can use this event for example - * to validate not only one setting but multiple ssetting. For example whether username - * and password matches. - * - * @since Piwik 2.14.0 - * @deprecated will be removed in Piwik 3.0.0 - * - * @param MeasurableSettings $this - * @param \Piwik\Measurable\Type $type - * @param int $idSite - */ - Piwik::postEvent('Measurable.beforeSaveSettings', array($this, $type, $this->idSite)); - - $this->storage->save(); - } - -} - diff --git a/core/Measurable/Settings/Storage.php b/core/Measurable/Settings/Storage.php deleted file mode 100644 index df9748af5e98c7b3f84230b11689bf4e84e2933d..0000000000000000000000000000000000000000 --- a/core/Measurable/Settings/Storage.php +++ /dev/null @@ -1,104 +0,0 @@ -<?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\Measurable\Settings; - -use Piwik\Db; -use Piwik\Common; -use Piwik\Settings\Setting; - -/** - * Storage for site settings - */ -class Storage extends \Piwik\Settings\Storage -{ - private $idSite = null; - - /** - * @var Db - */ - private $db = null; - - private $toBeDeleted = array(); - - public function __construct(Db\AdapterInterface $db, $idSite) - { - $this->db = $db; - $this->idSite = $idSite; - } - - protected function deleteSettingsFromStorage() - { - $table = $this->getTableName(); - $sql = "DELETE FROM $table WHERE `idsite` = ?"; - $bind = array($this->idSite); - - $this->db->query($sql, $bind); - } - - public function deleteValue(Setting $setting) - { - $this->toBeDeleted[$setting->getName()] = true; - parent::deleteValue($setting); - } - - public function setValue(Setting $setting, $value) - { - $this->toBeDeleted[$setting->getName()] = false; // prevent from deleting this setting, we will create/update it - parent::setValue($setting, $value); - } - - /** - * Saves (persists) the current setting values in the database. - */ - public function save() - { - $table = $this->getTableName(); - - foreach ($this->toBeDeleted as $name => $delete) { - if ($delete) { - $sql = "DELETE FROM $table WHERE `idsite` = ? and `setting_name` = ?"; - $bind = array($this->idSite, $name); - - $this->db->query($sql, $bind); - } - } - - $this->toBeDeleted = array(); - - foreach ($this->settingsValues as $name => $value) { - $value = serialize($value); - - $sql = "INSERT INTO $table (`idsite`, `setting_name`, `setting_value`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `setting_value` = ?"; - $bind = array($this->idSite, $name, $value, $value); - - $this->db->query($sql, $bind); - } - } - - protected function loadSettings() - { - $sql = "SELECT `setting_name`, `setting_value` FROM " . $this->getTableName() . " WHERE idsite = ?"; - $bind = array($this->idSite); - - $settings =$this->db->fetchAll($sql, $bind); - - $flat = array(); - foreach ($settings as $setting) { - $flat[$setting['setting_name']] = unserialize($setting['setting_value']); - } - - return $flat; - } - - private function getTableName() - { - return Common::prefixTable('site_setting'); - } -} diff --git a/core/Measurable/Type.php b/core/Measurable/Type.php index e9457a660fb618218842e9f5a8319db2e423bbd7..5d24f044090b5e75e687da71790b62ef7dcbd242 100644 --- a/core/Measurable/Type.php +++ b/core/Measurable/Type.php @@ -55,8 +55,5 @@ class Type return $this->howToSetupUrl; } - public function configureMeasurableSettings(MeasurableSettings $settings) - { - } } diff --git a/core/Measurable/Type/TypeManager.php b/core/Measurable/Type/TypeManager.php index af40d9c6249e27d0ca5acd3d55d651bf1b9cd110..a514abbbdcee54de8fe8cafae262e15f5710cf47 100644 --- a/core/Measurable/Type/TypeManager.php +++ b/core/Measurable/Type/TypeManager.php @@ -8,6 +8,7 @@ */ namespace Piwik\Measurable\Type; +use Piwik\Container\StaticContainer; use Piwik\Plugin\Manager as PluginManager; use Piwik\Measurable\Type; @@ -18,7 +19,14 @@ class TypeManager */ public function getAllTypes() { - return PluginManager::getInstance()->findComponents('Type', '\\Piwik\\Measurable\\Type'); + $components = PluginManager::getInstance()->findComponents('Type', '\\Piwik\\Measurable\\Type'); + + $instances = array(); + foreach ($components as $component) { + $instances[] = StaticContainer::get($component); + } + + return $instances; } /** diff --git a/core/Menu/MenuAbstract.php b/core/Menu/MenuAbstract.php index 777d97b523736b34a1eec8d5025e518dae2aec30..25e6ce0f531e68a1f4dde2c1c56152c0ca055a80 100644 --- a/core/Menu/MenuAbstract.php +++ b/core/Menu/MenuAbstract.php @@ -8,6 +8,7 @@ */ namespace Piwik\Menu; +use Piwik\Container\StaticContainer; use Piwik\Plugins\SitesManager\API; use Piwik\Singleton; use Piwik\Plugin\Manager as PluginManager; @@ -71,7 +72,12 @@ abstract class MenuAbstract extends Singleton return self::$menus; } - self::$menus = PluginManager::getInstance()->findComponents('Menu', 'Piwik\\Plugin\\Menu'); + $components = PluginManager::getInstance()->findComponents('Menu', 'Piwik\\Plugin\\Menu'); + + self::$menus = array(); + foreach ($components as $component) { + self::$menus[] = StaticContainer::get($component); + } return self::$menus; } diff --git a/core/Notification/Manager.php b/core/Notification/Manager.php index bdf1f130dd4882a99e8947068525bd0655c8f4ba..4ae3acde4218bb5fda83947b653ec99d465a42fd 100644 --- a/core/Notification/Manager.php +++ b/core/Notification/Manager.php @@ -129,6 +129,10 @@ class Manager private static function removeOldestNotificationsIfThereAreTooMany() { + if (!self::isSessionEnabled()) { + return; + } + $maxNotificationsInSession = 30; $session = static::getSession(); diff --git a/core/Plugin.php b/core/Plugin.php index 852e09522e51abe52f8bb031b8a4c3eaa3f2209f..91d5a8a8ad5a21275a5eab3b8f7b587edbdd0660 100644 --- a/core/Plugin.php +++ b/core/Plugin.php @@ -324,7 +324,7 @@ class Plugin * given subclass. If the requested file exists but does not extend this class * a warning will be shown to advice a developer to extend this certain class. * - * @return \stdClass|null Null if the requested component does not exist or an instance of the found + * @return string|null Null if the requested component does not exist or an instance of the found * component. */ public function findComponent($componentName, $expectedSubclass) @@ -369,7 +369,7 @@ class Plugin $this->cache->save($cacheId, $classname); } - return StaticContainer::get($classname); + return $classname; } public function findMultipleComponents($directoryWithinPlugin, $expectedSubclass) diff --git a/core/Plugin/API.php b/core/Plugin/API.php index c54e10a82bb6c72d31746bdb2a43b7d327ba730a..0f48816af36743645855809d914282c7ef37c2f3 100644 --- a/core/Plugin/API.php +++ b/core/Plugin/API.php @@ -85,6 +85,16 @@ abstract class API unset(self::$instances[$class]); } + /** + * Used in tests only + * @ignore + * @deprecated + */ + public static function unsetAllInstances() + { + self::$instances = array(); + } + /** * Sets the singleton instance. For testing purposes. * @ignore diff --git a/core/Plugin/Controller.php b/core/Plugin/Controller.php index 74691e577cc50aba4a0d609104cb3e5b5ba959cf..ad4addf85cfafe8e72d6ea6de136d5df1f4820ee 100644 --- a/core/Plugin/Controller.php +++ b/core/Plugin/Controller.php @@ -33,7 +33,7 @@ use Piwik\Piwik; use Piwik\Plugins\CoreAdminHome\CustomLogo; use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; use Piwik\Plugins\LanguagesManager\LanguagesManager; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\SettingsPiwik; use Piwik\Site; use Piwik\Url; @@ -314,7 +314,7 @@ abstract class Controller protected function renderReport($apiAction, $controllerAction = false) { if (empty($controllerAction) && is_string($apiAction)) { - $report = Reports::factory($this->pluginName, $apiAction); + $report = ReportsProvider::factory($this->pluginName, $apiAction); if (!empty($report)) { $apiAction = $report; diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php index 2b552f48e0e34c66240d868469cadd834eccc8f1..b4904517478488d2a6e1e628bc8eeb7c3272a7e4 100644 --- a/core/Plugin/Manager.php +++ b/core/Plugin/Manager.php @@ -12,8 +12,11 @@ namespace Piwik\Plugin; use Piwik\Application\Kernel\PluginList; use Piwik\Cache; use Piwik\Columns\Dimension; +use Piwik\Common; use Piwik\Config as PiwikConfig; use Piwik\Config; +use Piwik\Db; +use Piwik\Settings\Storage as SettingsStorage; use Piwik\Container\StaticContainer; use Piwik\EventDispatcher; use Piwik\Filesystem; @@ -398,7 +401,8 @@ class Manager } $this->loadAllPluginsAndGetTheirInfo(); - \Piwik\Settings\Manager::cleanupPluginSettings($pluginName); + SettingsStorage\Backend\PluginSettingsTable::removeAllSettingsForPlugin($pluginName); + SettingsStorage\Backend\MeasurableSettingsTable::removeAllSettingsForPlugin($pluginName); $this->executePluginDeactivate($pluginName); $this->executePluginUninstall($pluginName); diff --git a/core/Plugin/Menu.php b/core/Plugin/Menu.php index 384c3a199a0552f0adc3a93b2265505db58a2592..99275a5aeb0e1c0a24e284f337f727eff514247c 100644 --- a/core/Plugin/Menu.php +++ b/core/Plugin/Menu.php @@ -236,7 +236,7 @@ class Menu } $reportAction = lcfirst(substr($action, 4)); - if (Reports::factory($module, $reportAction)) { + if (ReportsProvider::factory($module, $reportAction)) { return; } diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php index c98d38e849931a9ba04c93e638288b38eb8fdf32..38e4857498b5da40495c842d287decb8c7c5e49f 100644 --- a/core/Plugin/Report.php +++ b/core/Plugin/Report.php @@ -20,7 +20,7 @@ use Piwik\Cache as PiwikCache; use Piwik\Piwik; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\ViewDataTable\Factory as ViewDataTableFactory; use Exception; use Piwik\Widget\WidgetsList; @@ -699,7 +699,7 @@ class Report list($subtableReportModule, $subtableReportAction) = $this->getSubtableApiMethod(); - $subtableReport = Reports::factory($subtableReportModule, $subtableReportAction); + $subtableReport = ReportsProvider::factory($subtableReportModule, $subtableReportAction); if (empty($subtableReport)) { return null; } diff --git a/core/Plugin/Reports.php b/core/Plugin/ReportsProvider.php similarity index 99% rename from core/Plugin/Reports.php rename to core/Plugin/ReportsProvider.php index 56d69e5453c4219c550f0c580eb3c85ee98575cb..021ca891fecfc4d51e3a6f5c57cb6c0106866354 100644 --- a/core/Plugin/Reports.php +++ b/core/Plugin/ReportsProvider.php @@ -16,7 +16,7 @@ use Piwik\Cache as PiwikCache; /** * Get reports that are defined by plugins. */ -class Reports +class ReportsProvider { /** diff --git a/core/Plugin/Settings.php b/core/Plugin/Settings.php deleted file mode 100644 index c26581e4b1ece96fd983f2285964ec8ceb09b0eb..0000000000000000000000000000000000000000 --- a/core/Plugin/Settings.php +++ /dev/null @@ -1,308 +0,0 @@ -<?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); - } - } - }; - } -} diff --git a/core/Plugin/SettingsProvider.php b/core/Plugin/SettingsProvider.php new file mode 100644 index 0000000000000000000000000000000000000000..5cc05bd32c136c1f7bb9f4f64ff1e154da8ac5d8 --- /dev/null +++ b/core/Plugin/SettingsProvider.php @@ -0,0 +1,215 @@ +<?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\CacheId; +use Piwik\Container\StaticContainer; +use Piwik\Plugin; +use Piwik\Cache as PiwikCache; +use Piwik\Settings\Measurable\MeasurableSettings; +use \Piwik\Settings\Plugin\UserSettings; +use \Piwik\Settings\Plugin\SystemSettings; + +/** + * 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. + */ +class SettingsProvider +{ + /** + * @var Plugin\Manager + */ + private $pluginManager; + + public function __construct(Plugin\Manager $pluginManager) + { + $this->pluginManager = $pluginManager; + } + + /** + * + * Get user settings implemented by a specific plugin (if implemented by this plugin). + * @param string $pluginName + * @return SystemSettings|null + */ + public function getSystemSettings($pluginName) + { + $plugin = $this->getLoadedAndActivated($pluginName); + + if ($plugin) { + $settings = $plugin->findComponent('SystemSettings', 'Piwik\\Settings\\Plugin\\SystemSettings'); + + if ($settings) { + return StaticContainer::get($settings); + } + } + } + + /** + * Get user settings implemented by a specific plugin (if implemented by this plugin). + * @param string $pluginName + * @return UserSettings|null + */ + public function getUserSettings($pluginName) + { + $plugin = $this->getLoadedAndActivated($pluginName); + + if ($plugin) { + $settings = $plugin->findComponent('UserSettings', 'Piwik\\Settings\\Plugin\\UserSettings'); + + if ($settings) { + return StaticContainer::get($settings); + } + } + } + + /** + * Returns all available system settings. A plugin has to specify a file named `SystemSettings.php` containing a + * class named `SystemSettings` that extends `Piwik\Settings\Plugin\SystemSettings` in order to be considered as + * a system setting. Otherwise the settings for a plugin won't be available. + * + * @return SystemSettings[] An array containing array([pluginName] => [setting instance]). + */ + public function getAllSystemSettings() + { + $cacheId = CacheId::languageAware('AllSystemSettings'); + $cache = PiwikCache::getTransientCache(); + + if (!$cache->contains($cacheId)) { + $pluginNames = $this->pluginManager->getActivatedPlugins(); + $byPluginName = array(); + + foreach ($pluginNames as $plugin) { + $component = $this->getSystemSettings($plugin); + + if (!empty($component)) { + $byPluginName[$plugin] = $component; + } + } + + $cache->save($cacheId, $byPluginName); + } + + return $cache->fetch($cacheId); + } + + /** + * Returns all available user settings. A plugin has to specify a file named `UserSettings.php` containing a class + * named `UserSettings` that extends `Piwik\Settings\Plugin\UserSettings` in order to be considered as a plugin + * setting. Otherwise the settings for a plugin won't be available. + * + * @return UserSettings[] An array containing array([pluginName] => [setting instance]). + */ + public function getAllUserSettings() + { + $cacheId = CacheId::languageAware('AllUserSettings'); + $cache = PiwikCache::getTransientCache(); + + if (!$cache->contains($cacheId)) { + $pluginNames = $this->pluginManager->getActivatedPlugins(); + $byPluginName = array(); + + foreach ($pluginNames as $plugin) { + $component = $this->getUserSettings($plugin); + + if (!empty($component)) { + $byPluginName[$plugin] = $component; + } + } + + $cache->save($cacheId, $byPluginName); + } + + return $cache->fetch($cacheId); + } + + /** + * @api + * + * Get measurable settings for a specific plugin. + * + * @param string $pluginName The name of a plugin. + * @param int $idSite The ID of a site. If a site is about to be created pass idSite = 0. + * @param string|null $idType If null, idType will be detected automatically if the site already exists. Only + * needed to set a value when idSite = 0 (this is the case when a site is about) + * to be created. + * + * @return MeasurableSettings|null Returns null if no MeasurableSettings implemented by this plugin or when plugin + * is not loaded and activated. Returns an instance of the settings otherwise. + */ + public function getMeasurableSettings($pluginName, $idSite, $idType = null) + { + $plugin = $this->getLoadedAndActivated($pluginName); + + if ($plugin) { + $component = $plugin->findComponent('MeasurableSettings', 'Piwik\\Settings\\Measurable\\MeasurableSettings'); + + if ($component) { + return StaticContainer::getContainer()->make($component, array( + 'idSite' => $idSite, + 'idMeasurableType' => $idType + )); + } + } + } + + /** + * @api + * + * Get all available measurable settings implemented by loaded and activated plugins. + * + * @param int $idSite The ID of a site. If a site is about to be created pass idSite = 0. + * @param string|null $idMeasurableType If null, idType will be detected automatically if the site already exists. + * Only needed to set a value when idSite = 0 (this is the case when a site + * is about) to be created. + * + * @return MeasurableSettings[] + */ + public function getAllMeasurableSettings($idSite, $idMeasurableType = null) + { + $pluginNames = $this->pluginManager->getActivatedPlugins(); + $byPluginName = array(); + + foreach ($pluginNames as $plugin) { + $component = $this->getMeasurableSettings($plugin, $idSite, $idMeasurableType); + + if (!empty($component)) { + $byPluginName[$plugin] = $component; + } + } + + return $byPluginName; + } + + private function getLoadedAndActivated($pluginName) + { + if (!$this->pluginManager->isPluginLoaded($pluginName)) { + return; + } + + try { + if (!$this->pluginManager->isPluginActivated($pluginName)) { + return; + } + + $plugin = $this->pluginManager->getLoadedPlugin($pluginName); + } catch (\Exception $e) { + // we are not allowed to use possible settings from this plugin, plugin is not active + return; + } + + return $plugin; + } + +} diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php index 5ca7e2e9badbc900653c6931b7140198028a6174..3b7bcf4ff807b0f11ea9dd471c9e032726527b8c 100644 --- a/core/Plugin/ViewDataTable.php +++ b/core/Plugin/ViewDataTable.php @@ -13,7 +13,7 @@ use Piwik\Common; use Piwik\DataTable; use Piwik\Period; use Piwik\Piwik; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\View; use Piwik\View\ViewInterface; use Piwik\ViewDataTable\Config as VizConfig; @@ -192,7 +192,7 @@ abstract class ViewDataTable implements ViewInterface $this->requestConfig->apiMethodToRequestDataTable = $apiMethodToRequestDataTable; - $report = Reports::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); + $report = ReportsProvider::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); if (!empty($report)) { /** @var Report $report */ diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php index da2c60c18eb53b744717df577843e4a1fe42d8db..e19da81d9a619d66af96f8d94e6fa923d3672204 100644 --- a/core/Plugin/Visualization.php +++ b/core/Plugin/Visualization.php @@ -23,7 +23,7 @@ use Piwik\Period; use Piwik\Piwik; use Piwik\Plugins\API\API as ApiApi; use Piwik\Plugins\PrivacyManager\PrivacyManager; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\View; use Piwik\ViewDataTable\Manager as ViewDataTableManager; use Piwik\Plugin\Manager as PluginManager; @@ -169,7 +169,7 @@ class Visualization extends ViewDataTable parent::__construct($controllerAction, $apiMethodToRequestDataTable, $params); - $this->report = Reports::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); + $this->report = ReportsProvider::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); } public function render() diff --git a/core/Plugin/Widgets.php b/core/Plugin/WidgetsProvider.php similarity index 99% rename from core/Plugin/Widgets.php rename to core/Plugin/WidgetsProvider.php index e67f2bce6199de676d1ad6483bc04ec9b6f30f63..8fe015411b4f3d60cbb5c94e8f3f73cf59d26401 100644 --- a/core/Plugin/Widgets.php +++ b/core/Plugin/WidgetsProvider.php @@ -19,7 +19,7 @@ use Piwik\Widget\WidgetContainerConfig; /** * Get widgets that are defined by plugins. */ -class Widgets +class WidgetsProvider { /** * @var Plugin\Manager diff --git a/core/Scheduler/TaskLoader.php b/core/Scheduler/TaskLoader.php index 60b9e328b6042ce1a85ac464883bee2f1d477289..95c3394cfb2172f6de7e6841a51cfd552f58db4d 100644 --- a/core/Scheduler/TaskLoader.php +++ b/core/Scheduler/TaskLoader.php @@ -8,6 +8,7 @@ namespace Piwik\Scheduler; +use Piwik\Container\StaticContainer; use Piwik\Plugin\Manager as PluginManager; use Piwik\Plugin\Tasks; @@ -27,6 +28,7 @@ class TaskLoader $pluginTasks = PluginManager::getInstance()->findComponents('Tasks', 'Piwik\Plugin\Tasks'); foreach ($pluginTasks as $pluginTask) { + $pluginTask = StaticContainer::get($pluginTask); $pluginTask->schedule(); foreach ($pluginTask->getScheduledTasks() as $task) { diff --git a/core/Settings/FieldConfig.php b/core/Settings/FieldConfig.php new file mode 100644 index 0000000000000000000000000000000000000000..4c75fc1719e650dfb31ed2ad434a0ae31072d537 --- /dev/null +++ b/core/Settings/FieldConfig.php @@ -0,0 +1,208 @@ +<?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; + +/** + * Lets you configure a form field. + * + * @api + */ +class FieldConfig +{ + /** + * Shows a radio field + */ + const UI_CONTROL_RADIO = 'radio'; + + /** + * Shows a text field + */ + const UI_CONTROL_TEXT = 'text'; + + /** + * Shows a text area + */ + const UI_CONTROL_TEXTAREA = 'textarea'; + + /** + * Shows a checkbox + */ + const UI_CONTROL_CHECKBOX = 'checkbox'; + + /** + * Shows a password field + */ + const UI_CONTROL_PASSWORD = 'password'; + + /** + * Shows a select field where a user can select multiple values. The type "Array" is required for this ui control. + */ + const UI_CONTROL_MULTI_SELECT = 'multiselect'; + + /** + * Shows a select field + */ + const UI_CONTROL_SINGLE_SELECT = 'select'; + + /** + * Generates a hidden form field + */ + const UI_CONTROL_HIDDEN = 'hidden'; + + /** + * Expects an integer value + */ + const TYPE_INT = 'integer'; + + /** + * Expects a float value + */ + const TYPE_FLOAT = 'float'; + + /** + * Expects a string + */ + const TYPE_STRING = 'string'; + + /** + * Expects a boolean + */ + const TYPE_BOOL = 'boolean'; + + /** + * Expects an array containing multiple values + */ + const TYPE_ARRAY = 'array'; + + /** + * 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; + + /** + * Name-value mapping of HTML attributes that will be added HTML form control, eg, + * `array('size' => 3)`. Attributes will be escaped before outputting. + * + * @var array + */ + public $uiControlAttributes = array(); + + /** + * 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. + * + * The setting value will be validated if this field is set. If the value is not one of the + * available values, an error will be triggered. + * + * _Note: If a custom validator is supplied (see {@link $validate}), the setting value will + * not be validated._ + * + * @var null|array + */ + public $availableValues = null; + + /** + * Text that will appear above this setting's section in the _Plugin Settings_ admin page. + * + * @var null|string + */ + public $introduction = null; + + /** + * Text that will appear directly underneath the setting title in the _Plugin Settings_ admin + * page. If set, should be a short description of the setting. + * + * @var null|string + */ + public $description = null; + + /** + * Text that will appear next to the setting's section in the _Plugin Settings_ admin page. If set, + * it should contain information about the setting that is more specific than a general description, + * such as the format of the setting value if it has a special format. + * + * Be sure to escape any user input as HTML can be used here. + * + * @var null|string + */ + public $inlineHelp = null; + + /** + * A closure that does some custom validation on the setting before the setting is persisted. + * + * The closure should take two arguments: the setting value and the {@link Setting} instance being + * validated. If the value is found to be invalid, the closure should throw an exception with + * a message that describes the error. + * + * **Example** + * + * $setting->validate = function ($value, Setting $setting) { + * if ($value > 60) { + * throw new \Exception('The time limit is not allowed to be greater than 60 minutes.'); + * } + * } + * + * @var null|\Closure + */ + public $validate = null; + + /** + * A closure that transforms the setting value. If supplied, this closure will be executed after + * the setting has been validated. + * + * _Note: If a transform is supplied, the setting's {@link $type} has no effect. This means the + * transformation function will be responsible for casting the setting value to the appropriate + * data type._ + * + * **Example** + * + * $setting->transform = function ($value, Setting $setting) { + * if ($value > 30) { + * $value = 30; + * } + * + * return (int) $value; + * } + * + * @var null|\Closure + */ + public $transform = null; + + /** + * 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 = ''; + + /** + * Here you can define conditions so that certain form fields will be only shown when a certain condition + * is true. This condition is supposed to be evaluated on the client side dynamically. This way you can hide + * for example some fields depending on another field. For example if SiteSearch is disabled, fields to enter + * site search keywords is not needed anymore and can be disabled. + * + * For example 'sitesearch', or 'sitesearch && !use_sitesearch_default' where 'sitesearch' and 'use_sitesearch_default' + * are both values of fields. + * + * @var string + */ + public $condition; + +} diff --git a/core/Settings/Manager.php b/core/Settings/Manager.php deleted file mode 100644 index e757e44d6007e1c89e72244676b542dd8f4d14c9..0000000000000000000000000000000000000000 --- a/core/Settings/Manager.php +++ /dev/null @@ -1,157 +0,0 @@ -<?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; - -use Piwik\Plugin\Manager as PluginManager; - -/** - * Settings manager. - * - */ -class Manager -{ - private static $settings = array(); - private static $numPluginsChecked = 0; - - /** - * Returns all available plugin settings, even settings for inactive plugins. A plugin has to specify a file named - * `Settings.php` containing a class named `Settings` that extends `Piwik\Plugin\Settings` in order to be - * considered as a plugin setting. Otherwise the settings for a plugin won't be available. - * - * @return \Piwik\Plugin\Settings[] An array containing array([pluginName] => [setting instance]). - */ - public static function getAllPluginSettings() - { - $numActivatedPlugins = PluginManager::getInstance()->getNumberOfActivatedPlugins(); - - if (static::$numPluginsChecked != $numActivatedPlugins) { - static::$numPluginsChecked = $numActivatedPlugins; - static::$settings = array(); - } - - if (empty(static::$settings)) { - $settings = PluginManager::getInstance()->findComponents('Settings', 'Piwik\\Plugin\\Settings'); - $byPluginName = array(); - - foreach ($settings as $setting) { - $byPluginName[$setting->getPluginName()] = $setting; - } - - static::$settings = $byPluginName; - } - - return static::$settings; - } - - private static function isActivatedPlugin($pluginName) - { - return PluginManager::getInstance()->isPluginActivated($pluginName); - } - - /** - * Removes all settings made for a specific plugin. Useful while uninstalling a plugin. - * - * @param string $pluginName - */ - public static function cleanupPluginSettings($pluginName) - { - $pluginManager = PluginManager::getInstance(); - - if (!$pluginManager->isPluginLoaded($pluginName)) { - return; - } - - $plugin = $pluginManager->loadPlugin($pluginName); - $settings = $plugin->findComponent('Settings', 'Piwik\\Plugin\\Settings'); - - if (!empty($settings)) { - $settings->removeAllPluginSettings(); - } - } - - /** - * Gets all plugins settings that have at least one settings a user is allowed to change. Only the settings for - * activated plugins are returned. - * - * @return \Piwik\Plugin\Settings[] An array containing array([pluginName] => [setting instance]). - */ - public static function getPluginSettingsForCurrentUser() - { - $settings = static::getAllPluginSettings(); - - $settingsForUser = array(); - foreach ($settings as $pluginName => $setting) { - if (!static::isActivatedPlugin($pluginName)) { - continue; - } - - $forUser = $setting->getSettingsForCurrentUser(); - if (!empty($forUser)) { - $settingsForUser[$pluginName] = $setting; - } - } - - return $settingsForUser; - } - - public static function hasSystemPluginSettingsForCurrentUser($pluginName) - { - $pluginNames = static::getPluginNamesHavingSystemSettings(); - - return in_array($pluginName, $pluginNames); - } - - /** - * Detects whether there are user settings for activated plugins available that the current user can change. - * - * @return bool - */ - public static function hasUserPluginsSettingsForCurrentUser() - { - $settings = static::getPluginSettingsForCurrentUser(); - - foreach ($settings as $setting) { - foreach ($setting->getSettingsForCurrentUser() as $set) { - if ($set instanceof UserSetting) { - return true; - } - } - } - - return false; - } - - public static function getPluginNamesHavingSystemSettings() - { - $settings = static::getPluginSettingsForCurrentUser(); - $plugins = array(); - - foreach ($settings as $pluginName => $setting) { - foreach ($setting->getSettingsForCurrentUser() as $set) { - if ($set instanceof SystemSetting) { - $plugins[] = $pluginName; - } - } - } - - return array_unique($plugins); - } - /** - * Detects whether there are system settings for activated plugins available that the current user can change. - * - * @return bool - */ - public static function hasSystemPluginsSettingsForCurrentUser() - { - $settings = static::getPluginNamesHavingSystemSettings(); - - return !empty($settings); - } -} diff --git a/core/Settings/Measurable/MeasurableProperty.php b/core/Settings/Measurable/MeasurableProperty.php new file mode 100644 index 0000000000000000000000000000000000000000..b49ee046982a8440aa72a2954ce0a306b4088054 --- /dev/null +++ b/core/Settings/Measurable/MeasurableProperty.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\Measurable; + +use Piwik\Container\StaticContainer; +use Piwik\Piwik; +use Piwik\Settings\Storage; +use Exception; + +/** + * Describes a Measurable property for a measurable type such as a website, a mobile app, .... + * + * The difference to {@link MeasurableSetting} is that these fields will be stored in the actual site table whereas + * MeasurableSetting will be stored in a site_settings table. For this reasons MeasurableProperty can be used only + * for some specific fields that already exist in site table such as "ecommerce", "sitesearch" etc. + * + * See {@link \Piwik\Settings\Setting}. + */ +class MeasurableProperty extends \Piwik\Settings\Setting +{ + /** + * @var int + */ + private $idSite = 0; + + 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' + ); + + /** + * Constructor. + * + * @param string $name The persisted name of the setting. + * @param mixed $defaultValue Default value for this setting if no value was specified. + * @param string $type Eg an array, int, ... see TYPE_* constants + * @param string $pluginName The name of the plugin the setting belongs to. + * @param int $idSite The idSite this property belongs to. + * @throws Exception + */ + public function __construct($name, $defaultValue, $type, $pluginName, $idSite) + { + if (!in_array($name, $this->allowedNames)) { + throw new Exception(sprintf('Name "%s" is not allowed to be used with a MeasurableProperty, use a MeasurableSetting instead.', $name)); + } + + parent::__construct($name, $defaultValue, $type, $pluginName); + + $this->idSite = $idSite; + + $storageFactory = StaticContainer::get('Piwik\Settings\Storage\Factory'); + $this->storage = $storageFactory->getSitesTable($idSite); + } + + /** + * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. + * + * @return bool + */ + public function isWritableByCurrentUser() + { + if (isset($this->hasWritePermission)) { + return $this->hasWritePermission; + } + + // performance improvement, do not detect this in __construct otherwise likely rather "big" query to DB. + if ($this->hasSiteBeenCreated()) { + $this->hasWritePermission = Piwik::isUserHasAdminAccess($this->idSite); + } else { + $this->hasWritePermission = Piwik::hasUserSuperUserAccess(); + } + + return $this->hasWritePermission; + } + + private function hasSiteBeenCreated() + { + return !empty($this->idSite); + } +} diff --git a/core/Settings/Measurable/MeasurableSetting.php b/core/Settings/Measurable/MeasurableSetting.php new file mode 100644 index 0000000000000000000000000000000000000000..b03289e44ea710391e5a9334b4058bf7a9e1ba88 --- /dev/null +++ b/core/Settings/Measurable/MeasurableSetting.php @@ -0,0 +1,72 @@ +<?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\Measurable; + +use Piwik\Container\StaticContainer; +use Piwik\Piwik; +use Piwik\Settings\Storage; + +/** + * Describes a Measurable setting for a measurable type such as a website, a mobile app, ... + * + * See {@link \Piwik\Settings\Setting}. + */ +class MeasurableSetting extends \Piwik\Settings\Setting +{ + /** + * @var int + */ + private $idSite = 0; + + /** + * Constructor. + * + * @param string $name The persisted name of the setting. + * @param mixed $defaultValue Default value for this setting if no value was specified. + * @param string $type Eg an array, int, ... see TYPE_* constants + * @param string $pluginName The name of the plugin the setting belongs to + * @param int $idSite The idSite this setting belongs to. + */ + public function __construct($name, $defaultValue, $type, $pluginName, $idSite) + { + parent::__construct($name, $defaultValue, $type, $pluginName); + + $this->idSite = $idSite; + + $storageFactory = StaticContainer::get('Piwik\Settings\Storage\Factory'); + $this->storage = $storageFactory->getMeasurableSettingsStorage($idSite, $this->pluginName); + } + + /** + * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. + * + * @return bool + */ + public function isWritableByCurrentUser() + { + if (isset($this->hasWritePermission)) { + return $this->hasWritePermission; + } + + // performance improvement, do not detect this in __construct otherwise likely rather "big" query to DB. + if ($this->hasSiteBeenCreated()) { + $this->hasWritePermission = Piwik::isUserHasAdminAccess($this->idSite); + } else { + $this->hasWritePermission = Piwik::hasUserSuperUserAccess(); + } + + return $this->hasWritePermission; + } + + private function hasSiteBeenCreated() + { + return !empty($this->idSite); + } +} diff --git a/core/Settings/Measurable/MeasurableSettings.php b/core/Settings/Measurable/MeasurableSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..3d062f994349200b41568151a5c04b878ae48f28 --- /dev/null +++ b/core/Settings/Measurable/MeasurableSettings.php @@ -0,0 +1,141 @@ +<?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\Measurable; + +use Piwik\Db; +use Piwik\Piwik; +use Piwik\Settings\Settings; +use Piwik\Settings\Storage; +use Piwik\Site; +use Exception; + +/** + * Base class of all measurable settings providers. Plugins that define their own configuration settings + * can extend this class to easily make their measurable settings available to Piwik users. + * + * Descendants of this class should implement the {@link init()} method and call the + * {@link makeSetting()} method for each of the measurable's settings. + * + * For an example, see the {@link Piwik\Plugins\ExampleSettingsPlugin\MeasurableSettings} plugin. + * + * $settingsProvider = new Piwik\Plugin\SettingsProvider(); // get this instance via dependency injection + * $measurableSettings = $settingProvider->getMeasurableSettings($yourPluginName, $idsite, $idType = null); + * $measurableSettings->yourSetting->getValue(); + * + * @api + */ +abstract class MeasurableSettings extends Settings +{ + /** + * @var int + */ + protected $idSite; + + /** + * @var string + */ + protected $idMeasurableType; + + /** + * Constructor. + * @param int $idSite If creating settings for a new site that is not created yet, use idSite = 0 + * @param string|null $idMeasurableType If null, idType will be detected from idSite + * @throws Exception + */ + public function __construct($idSite, $idMeasurableType = null) + { + parent::__construct(); + + $this->idSite = (int) $idSite; + + if (!empty($idMeasurableType)) { + $this->idMeasurableType = $idMeasurableType; + } elseif (!empty($idSite)) { + $this->idMeasurableType = Site::getTypeFor($idSite); + } else { + throw new Exception('No idType specified for ' . get_class($this)); + } + + $this->init(); + } + + protected function hasMeasurableType($typeId) + { + return $typeId === $this->idMeasurableType; + } + + /** + * Creates a new measurable setting. + * + * Settings will be displayed in the UI depending on the order of `makeSetting` calls. This means you can define + * the order of the displayed settings by calling makeSetting first for more important settings. + * + * @param string $name The name of the setting that shall be created + * @param mixed $defaultValue The default value for this setting. Note the value will not be converted to the + * specified type. + * @param string $type The PHP internal type the value of this setting should have. + * Use one of FieldConfig::TYPE_* constancts + * @param \Closure $fieldConfigCallback A callback method to configure the field that shall be displayed in the + * UI to define the value for this setting + * @return MeasurableSetting Returns an instance of the created measurable setting. + * @throws Exception + */ + protected function makeSetting($name, $defaultValue, $type, $fieldConfigCallback) + { + $setting = new MeasurableSetting($name, $defaultValue, $type, $this->pluginName, $this->idSite); + $setting->setConfigureCallback($fieldConfigCallback); + + $this->addSetting($setting); + + return $setting; + } + + /** + * @internal + * @param $name + * @param $defaultValue + * @param $type + * @param $configureCallback + * @return MeasurableProperty + * @throws Exception + */ + protected function makeProperty($name, $defaultValue, $type, $configureCallback) + { + $setting = new MeasurableProperty($name, $defaultValue, $type, $this->pluginName, $this->idSite); + $setting->setConfigureCallback($configureCallback); + + $this->addSetting($setting); + + return $setting; + } + + /** + * Saves (persists) the current measurable setting values in the database. + * + * Will trigger an event to notify plugins that a value has been changed. + */ + public function save() + { + parent::save(); + + /** + * Triggered after a plugin settings have been updated. + * + * **Example** + * + * Piwik::addAction('MeasurableSettings.updated', function (MeasurableSettings $settings) { + * $value = $settings->someSetting->getValue(); + * // Do something with the new setting value + * }); + * + * @param Settings $settings The plugin settings object. + */ + Piwik::postEvent('MeasurableSettings.updated', array($this, $this->idSite)); + } +} diff --git a/core/Settings/SystemSetting.php b/core/Settings/Plugin/SystemSetting.php similarity index 50% rename from core/Settings/SystemSetting.php rename to core/Settings/Plugin/SystemSetting.php index 68e780a3e802c246156f055688b4537781925bbc..3c10a4c5f4190f3b03d214d45df8c9a7ccdcb09d 100644 --- a/core/Settings/SystemSetting.php +++ b/core/Settings/Plugin/SystemSetting.php @@ -7,48 +7,38 @@ * */ -namespace Piwik\Settings; +namespace Piwik\Settings\Plugin; use Piwik\Config; +use Piwik\Container\StaticContainer; use Piwik\Piwik; +use Piwik\Settings\Setting; +use Piwik\Settings\Storage; /** - * Describes a system wide setting. Only the Super User can change this type of setting and + * Describes a system wide setting. Only the Super User can change this type of setting by d efault and * the value of this setting will affect all users. * - * See {@link \Piwik\Plugin\Settings}. - * + * See {@link \Piwik\Settings\Setting}. * * @api */ class SystemSetting extends Setting { - /** - * By default the value of the system setting is only readable by SuperUsers but someone the value should be - * readable by everyone. - * - * @var bool - * @since 2.4.0 - */ - public $readableByCurrentUser = false; - - /** - * @var bool - */ - private $writableByCurrentUser = false; - /** * Constructor. * - * @param string $name The persisted name of the setting. - * @param string $title The display name of the setting. + * @param string $name The setting's persisted name. + * @param mixed $defaultValue Default value for this setting if no value was specified. + * @param string $type Eg an array, int, ... see TYPE_* constants + * @param string $pluginName The name of the plugin the system setting belongs to. */ - public function __construct($name, $title) + public function __construct($name, $defaultValue, $type, $pluginName) { - parent::__construct($name, $title); + parent::__construct($name, $defaultValue, $type, $pluginName); - $this->writableByCurrentUser = Piwik::hasUserSuperUserAccess(); - $this->readableByCurrentUser = $this->writableByCurrentUser; + $factory = StaticContainer::get('Piwik\Settings\Storage\Factory'); + $this->storage = $factory->getPluginStorage($this->pluginName, $userLogin = ''); } /** @@ -63,39 +53,19 @@ class SystemSetting extends Setting return false; } - return $this->writableByCurrentUser; - } + if (isset($this->hasWritePermission)) { + return $this->hasWritePermission; + } - /** - * 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->writableByCurrentUser = (bool) $isWritable; - } + // performance improvement, do not detect this in __construct otherwise likely rather "big" query to DB. + $this->hasWritePermission = Piwik::hasUserSuperUserAccess(); - /** - * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. - * - * @return bool - */ - public function isReadableByCurrentUser() - { - return $this->readableByCurrentUser; + return $this->hasWritePermission; } /** - * Returns the display order. System settings are displayed before user settings. - * - * @return int + * @inheritdoc */ - public function getOrder() - { - return 30; - } - public function getValue() { $defaultValue = parent::getValue(); // we access value first to make sure permissions are checked diff --git a/core/Settings/Plugin/SystemSettings.php b/core/Settings/Plugin/SystemSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..1b2fc413ffa2415c89b05554fccf797ce8bdb474 --- /dev/null +++ b/core/Settings/Plugin/SystemSettings.php @@ -0,0 +1,90 @@ +<?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\Plugin; + +use Piwik\Db; +use Piwik\Piwik; +use Piwik\Settings\Settings; +use Piwik\Settings\Storage; + +/** + * Base class of all system settings providers. Plugins that define their own configuration settings + * can extend this class to easily make their system settings available to Piwik users. + * + * Descendants of this class should implement the {@link init()} method and call the + * {@link makeSetting()} method to create a system setting for this plugin. + * + * For an example, see {@link Piwik\Plugins\ExampleSettingsPlugin\SystemSettings}. + * + * $systemSettings = new Piwik\Plugins\ExampleSettingsPlugin\SystemSettings(); // get instance via dependency injection + * $systemSettings->yourSetting->getValue(); + * + * @api + */ +abstract class SystemSettings extends Settings +{ + /** + * Constructor. + */ + public function __construct() + { + parent::__construct(); + + $this->init(); + } + + /** + * Creates a new system setting. + * + * Settings will be displayed in the UI depending on the order of `makeSetting` calls. This means you can define + * the order of the displayed settings by calling makeSetting first for more important settings. + * + * @param string $name The name of the setting that shall be created + * @param mixed $defaultValue The default value for this setting. Note the value will not be converted to the + * specified type. + * @param string $type The PHP internal type the value of this setting should have. + * Use one of FieldConfig::TYPE_* constancts + * @param \Closure $fieldConfigCallback A callback method to configure the field that shall be displayed in the + * UI to define the value for this setting + * @return SystemSetting Returns an instance of the created measurable setting. + */ + protected function makeSetting($name, $defaultValue, $type, $fieldConfigCallback) + { + $setting = new SystemSetting($name, $defaultValue, $type, $this->pluginName); + $setting->setConfigureCallback($fieldConfigCallback); + $this->addSetting($setting); + return $setting; + } + + /** + * Saves (persists) the current setting values in the database. + * + * Will trigger an event to notify plugins that a value has been changed. + */ + public function save() + { + parent::save(); + + /** + * Triggered after system settings have been updated. + * + * **Example** + * + * Piwik::addAction('SystemSettings.updated', function (SystemSettings $settings) { + * if ($settings->getPluginName() === 'PluginName') { + * $value = $settings->someSetting->getValue(); + * // Do something with the new setting value + * } + * }); + * + * @param Settings $settings The plugin settings object. + */ + Piwik::postEvent('SystemSettings.updated', array($this)); + } +} diff --git a/core/Settings/Plugin/UserSetting.php b/core/Settings/Plugin/UserSetting.php new file mode 100644 index 0000000000000000000000000000000000000000..0044eef78fb0e00455e14960c3343976973302b4 --- /dev/null +++ b/core/Settings/Plugin/UserSetting.php @@ -0,0 +1,73 @@ +<?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\Plugin; + +use Piwik\Container\StaticContainer; +use Piwik\Db; +use Piwik\Piwik; +use Exception; +use Piwik\Settings\Setting; +use Piwik\Settings\Storage; + +/** + * Describes a per user setting. Each user will be able to change this setting for themselves, + * but not for other users. + * + * See {@link \Piwik\Settings\Setting}. + */ +class UserSetting extends Setting +{ + /** + * @var null|string + */ + private $userLogin = null; + + /** + * Constructor. + * + * @param string $name The setting's persisted name. + * @param mixed $defaultValue Default value for this setting if no value was specified. + * @param string $type Eg an array, int, ... see TYPE_* constants + * @param string $pluginName The name of the plugin the setting belongs to + * @param string $userLogin The name of the user the value should be set or get for + * @throws Exception + */ + public function __construct($name, $defaultValue, $type, $pluginName, $userLogin) + { + parent::__construct($name, $defaultValue, $type, $pluginName); + + if (empty($userLogin)) { + throw new Exception('No userLogin given to create setting ' . $name); + } + + $this->userLogin = $userLogin; + + $factory = StaticContainer::get('Piwik\Settings\Storage\Factory'); + $this->storage = $factory->getPluginStorage($this->pluginName, $this->userLogin); + } + + /** + * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. + * + * @return bool + */ + public function isWritableByCurrentUser() + { + if (isset($this->hasWritePermission)) { + return $this->hasWritePermission; + } + + // performance improvement, do not detect this in __construct otherwise likely rather "big" query to DB. + $this->hasWritePermission = Piwik::isUserHasSomeViewAccess(); + + return $this->hasWritePermission; + } + +} diff --git a/core/Settings/Plugin/UserSettings.php b/core/Settings/Plugin/UserSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..cda8438d73a2fd17a68f3daa69151eb63a1cc5f5 --- /dev/null +++ b/core/Settings/Plugin/UserSettings.php @@ -0,0 +1,93 @@ +<?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\Plugin; + +use Piwik\Db; +use Piwik\Piwik; +use Piwik\Settings\Settings; +use Piwik\Settings\Storage; + +/** + * 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 {@link Piwik\Plugins\ExampleSettingsPlugin\UserSettings}. + * + * $userSettings = new Piwik\Plugins\ExampleSettingsPlugin\UserSettings(); // get instance via dependency injection + * $userSettings->yourSetting->getValue(); + * + * @api + */ +abstract class UserSettings extends Settings +{ + /** + * Constructor. + */ + public function __construct() + { + parent::__construct(); + + $this->init(); + } + + /** + * Creates a new user setting. + * + * Settings will be displayed in the UI depending on the order of `makeSetting` calls. This means you can define + * the order of the displayed settings by calling makeSetting first for more important settings. + * + * @param string $name The name of the setting that shall be created + * @param mixed $defaultValue The default value for this setting. Note the value will not be converted to the + * specified type. + * @param string $type The PHP internal type the value of this setting should have. + * Use one of FieldConfig::TYPE_* constancts + * @param \Closure $fieldConfigCallback A callback method to configure the field that shall be displayed in the + * UI to define the value for this setting + * @return UserSetting Returns an instance of the created measurable setting. + */ + protected function makeSetting($name, $defaultValue, $type, $configureCallback) + { + $userLogin = Piwik::getCurrentUserLogin(); + + $setting = new UserSetting($name, $defaultValue, $type, $this->pluginName, $userLogin); + $setting->setConfigureCallback($configureCallback); + + $this->addSetting($setting); + return $setting; + } + + /** + * Saves (persists) the current setting values in the database. + * + * Will trigger an event to notify plugins that a value has been changed. + */ + public function save() + { + parent::save(); + + /** + * Triggered after user settings have been updated. + * + * **Example** + * + * Piwik::addAction('UserSettings.updated', function (UserSettings $settings) { + * if ($settings->getPluginName() === 'PluginName') { + * $value = $settings->someSetting->getValue(); + * // Do something with the new setting value + * } + * }); + * + * @param Settings $settings The plugin settings object. + */ + Piwik::postEvent('UserSettings.updated', array($this)); + } +} diff --git a/core/Settings/Setting.php b/core/Settings/Setting.php index bf8947b19674f5507cbaeacf08debdb24f164bd0..efd99c38024f2d0041b8790f3f5e312ef1129249 100644 --- a/core/Settings/Setting.php +++ b/core/Settings/Setting.php @@ -10,168 +10,84 @@ namespace Piwik\Settings; use Piwik\Piwik; -use Piwik\SettingsServer; +use Piwik\Settings\Storage\Storage; +use Exception; /** * Base setting type class. * * @api */ -abstract class Setting +class Setting { - /** - * Describes the setting's PHP data type. When saved, setting values will always be casted to this - * type. - * - * See {@link Piwik\Plugin\Settings} for a list of supported data types. - * - * @var string - */ - public $type = null; /** - * 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. - * + * The name of the setting * @var string */ - public $uiControlType = null; - - /** - * Name-value mapping of HTML attributes that will be added HTML form control, eg, - * `array('size' => 3)`. Attributes will be escaped before outputting. - * - * @var array - */ - public $uiControlAttributes = array(); - - /** - * 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. - * - * The setting value will be validated if this field is set. If the value is not one of the - * available values, an error will be triggered. - * - * _Note: If a custom validator is supplied (see {@link $validate}), the setting value will - * not be validated._ - * - * @var null|array - */ - public $availableValues = null; + protected $name; /** - * Text that will appear above this setting's section in the _Plugin Settings_ admin page. - * - * @var null|string + * Null while not initialized, bool otherwise. + * @var null|bool */ - public $introduction = null; + protected $hasWritePermission = null; /** - * Text that will appear directly underneath the setting title in the _Plugin Settings_ admin - * page. If set, should be a short description of the setting. - * - * @var null|string + * @var Storage */ - public $description = null; + protected $storage; /** - * Text that will appear next to the setting's section in the _Plugin Settings_ admin page. If set, - * it should contain information about the setting that is more specific than a general description, - * such as the format of the setting value if it has a special format. - * - * @var null|string + * @var string */ - public $inlineHelp = null; + protected $pluginName; /** - * A closure that does some custom validation on the setting before the setting is persisted. - * - * The closure should take two arguments: the setting value and the {@link Setting} instance being - * validated. If the value is found to be invalid, the closure should throw an exception with - * a message that describes the error. - * - * **Example** - * - * $setting->validate = function ($value, Setting $setting) { - * if ($value > 60) { - * throw new \Exception('The time limit is not allowed to be greater than 60 minutes.'); - * } - * } - * - * @var null|\Closure + * @var FieldConfig */ - public $validate = null; + protected $config; /** - * A closure that transforms the setting value. If supplied, this closure will be executed after - * the setting has been validated. - * - * _Note: If a transform is supplied, the setting's {@link $type} has no effect. This means the - * transformation function will be responsible for casting the setting value to the appropriate - * data type._ - * - * **Example** - * - * $setting->transform = function ($value, Setting $setting) { - * if ($value > 30) { - * $value = 30; - * } - * - * return (int) $value; - * } - * - * @var null|\Closure + * @var \Closure|null */ - public $transform = null; + protected $configureCallback; /** - * Default value of this setting. - * - * The default value is not casted to the appropriate data type. This means _**you**_ have to make - * sure the value is of the correct type. - * * @var mixed */ - public $defaultValue = null; + protected $defaultValue; /** - * This setting's display name, for example, `'Refresh Interval'`. - * * @var string */ - public $title = ''; - - protected $key; - protected $name; - - /** - * @var StorageInterface - */ - private $storage; - protected $pluginName; + protected $type; /** * Constructor. * * @param string $name The setting's persisted name. Only alphanumeric characters are allowed, eg, * `'refreshInterval'`. - * @param string $title The setting's display name, eg, `'Refresh Interval'`. + * @param mixed $defaultValue Default value for this setting if no value was specified. + * @param string $type Eg an array, int, ... see SettingConfig::TYPE_* constants + * @param string $pluginName The name of the plugin the setting belongs to + * @throws Exception */ - public function __construct($name, $title) + public function __construct($name, $defaultValue, $type, $pluginName) { - $this->key = $name; - $this->name = $name; - $this->title = $title; + if (!ctype_alnum(str_replace('_', '', $name))) { + $msg = sprintf('The setting name "%s" in plugin "%s" is invalid. Only underscores, alpha and numerical characters are allowed', $name, $pluginName); + throw new Exception($msg); + } + + $this->name = $name; + $this->type = $type; + $this->pluginName = $pluginName; + $this->setDefaultValue($defaultValue); } /** - * Returns the setting's persisted name, eg, `'refreshInterval'`. - * + * Get the name of the setting. * @return string */ public function getName() @@ -180,32 +96,47 @@ abstract class Setting } /** - * 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 + * Get the PHP type of the setting. + * @return string */ - public function isWritableByCurrentUser() + public function getType() { - return false; + return $this->type; } /** - * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. - * - * @return bool + * @internal + * @ignore + * @param $callback */ - public function isReadableByCurrentUser() + public function setConfigureCallback($callback) { - return false; + $this->configureCallback = $callback; + $this->config = null; } /** - * Sets the object used to persist settings. - * - * @param StorageInterface $storage + * @return mixed + */ + public function getDefaultValue() + { + return $this->defaultValue; + } + + /** + * Sets/overwrites the current default value + * @param string $defaultValue */ - public function setStorage(StorageInterface $storage) + public function setDefaultValue($defaultValue) + { + $this->defaultValue = $defaultValue; + } + + /** + * @internal + * @param Storage $storage + */ + public function setStorage(Storage $storage) { $this->storage = $storage; } @@ -213,35 +144,52 @@ abstract class Setting /** * @internal * @ignore - * @return StorageInterface + * @return FieldConfig + * @throws Exception */ - public function getStorage() + public function configureField() { - return $this->storage; + 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; } /** - * Sets th name of the plugin the setting belongs to + * Set whether setting is writable or not. For example to hide setting from the UI set it to false. * - * @param string $pluginName + * @param bool $isWritable */ - public function setPluginName($pluginName) + public function setIsWritableByCurrentUser($isWritable) { - $this->pluginName = $pluginName; + $this->hasWritePermission = (bool) $isWritable; } /** - * Returns the previously persisted setting value. If no value was set, the default value - * is returned. + * 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 mixed - * @throws \Exception If the current user is not allowed to change the value of this setting. + * @return bool */ - public function getValue() + public function isWritableByCurrentUser() { - $this->checkHasEnoughReadPermission(); + return (bool) $this->hasWritePermission; + } - return $this->storage->getValue($this); + /** + * Saves (persists) the value for this setting in the database if a value has been actually set. + */ + public function save() + { + $this->storage->save(); } /** @@ -249,40 +197,85 @@ abstract class Setting * is returned. * * @return mixed - * @throws \Exception If the current user is not allowed to change the value of this setting. */ - public function removeValue() + public function getValue() { - $this->checkHasEnoughWritePermission(); - - return $this->storage->deleteValue($this); + 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 ($this->transform && $this->transform instanceof \Closure) { - $value = call_user_func($this->transform, $value, $this); - } elseif (isset($this->type)) { + if ($config->transform && $config->transform instanceof \Closure) { + $value = call_user_func($config->transform, $value, $this); + } + + if (isset($this->type)) { settype($value, $this->type); } - return $this->storage->setValue($this, $value); + $this->storage->setValue($this->name, $value); } private function validateValue($value) { - $this->checkHasEnoughWritePermission(); - - if ($this->validate && $this->validate instanceof \Closure) { - call_user_func($this->validate, $value, $this); + $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); + } } } @@ -291,50 +284,49 @@ abstract class Setting */ private function checkHasEnoughWritePermission() { - // When the request is a Tracker request, allow plugins to write settings - if (SettingsServer::isTrackerApiRequest()) { - return; - } - if (!$this->isWritableByCurrentUser()) { - $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingChangeNotAllowed', array($this->getName(), $this->pluginName)); + $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingChangeNotAllowed', array($this->name, $this->pluginName)); throw new \Exception($errorMsg); } } - /** - * @throws \Exception - */ - private function checkHasEnoughReadPermission() + private function setUiControlIfNeeded(FieldConfig $field) { - // When the request is a Tracker request, allow plugins to read settings - if (SettingsServer::isTrackerApiRequest()) { - return; - } - - if (!$this->isReadableByCurrentUser()) { - $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingReadNotAllowed', array($this->getName(), $this->pluginName)); - throw new \Exception($errorMsg); + 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; + } } } - /** - * Returns the unique string key used to store this setting. - * - * @return string - */ - public function getKey() + private function checkType(FieldConfig $field) { - return $this->key; - } + 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'); + } - /** - * Returns the display order. The lower the return value, the earlier the setting will be displayed. - * - * @return int - */ - public function getOrder() - { - return 100; + $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'); + } } + } diff --git a/core/Settings/Settings.php b/core/Settings/Settings.php new file mode 100644 index 0000000000000000000000000000000000000000..6c076f8cace7d3229f5a08ecfe0235d8568736d3 --- /dev/null +++ b/core/Settings/Settings.php @@ -0,0 +1,107 @@ +<?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; + +/** + * Base class of all settings providers. + * + * @api + */ +abstract class Settings +{ + /** + * An array containing all available settings: Array ( [setting-name] => [setting] ) + * + * @var Setting[] + */ + private $settings = array(); + + protected $pluginName; + + public function __construct() + { + if (!isset($this->pluginName)) { + $classname = get_class($this); + $parts = explode('\\', $classname); + + if (count($parts) >= 3) { + $this->pluginName = $parts[2]; + } else { + throw new \Exception(sprintf('Plugin Settings must have a plugin name specified in %s, could not detect plugin name', $classname)); + } + } + } + + /** + * @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(); + + /** + * Returns the settings that can be displayed for the current user. + * + * @return Setting[] + */ + public function getSettingsWritableByCurrentUser() + { + return array_filter($this->settings, function (Setting $setting) { + return $setting->isWritableByCurrentUser(); + }); + } + + /** + * 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 (isset($this->settings[$name])) { + throw new \Exception(sprintf('A setting with name "%s" does already exist for plugin "%s"', $name, $this->pluginName)); + } + + $this->settings[$name] = $setting; + } + + /** + * Saves (persists) the current setting values in the database. + */ + public function save() + { + foreach ($this->settings as $setting) { + $setting->save(); + } + } + +} diff --git a/core/Settings/Storage.php b/core/Settings/Storage.php deleted file mode 100644 index 131c01b111e87a15baf4d461a814395004167019..0000000000000000000000000000000000000000 --- a/core/Settings/Storage.php +++ /dev/null @@ -1,148 +0,0 @@ -<?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; - -use Piwik\Option; - -/** - * Base setting type class. - * - * @api - */ -class Storage implements StorageInterface -{ - - /** - * Array containing all plugin settings values: Array( [setting-key] => [setting-value] ). - * - * @var array - */ - protected $settingsValues = array(); - - // for lazy loading of setting values - private $settingValuesLoaded = false; - - private $pluginName; - - public function __construct($pluginName) - { - $this->pluginName = $pluginName; - } - - /** - * Saves (persists) the current setting values in the database. - */ - public function save() - { - $this->loadSettingsIfNotDoneYet(); - - Option::set($this->getOptionKey(), serialize($this->settingsValues)); - } - - /** - * Removes all settings for this plugin from the database. Useful when uninstalling - * a plugin. - */ - public function deleteAllValues() - { - $this->deleteSettingsFromStorage(); - - $this->settingsValues = array(); - $this->settingValuesLoaded = false; - } - - protected function deleteSettingsFromStorage() - { - Option::delete($this->getOptionKey()); - } - - /** - * Returns the current value for a setting. If no value is stored, the default value - * is be returned. - * - * @param Setting $setting - * @return mixed - * @throws \Exception If the setting does not exist or if the current user is not allowed to change the value - * of this setting. - */ - public function getValue(Setting $setting) - { - $this->loadSettingsIfNotDoneYet(); - - if (array_key_exists($setting->getKey(), $this->settingsValues)) { - return $this->settingsValues[$setting->getKey()]; - } - - return $setting->defaultValue; - } - - /** - * Sets (overwrites) the value of a setting in memory. To persist the change, {@link save()} must be - * called afterwards, otherwise the change has no effect. - * - * Before the setting is changed, the {@link Piwik\Settings\Setting::$validate} and - * {@link Piwik\Settings\Setting::$transform} closures will be invoked (if defined). If there is no validation - * filter, the setting value will be casted to the appropriate data type. - * - * @param Setting $setting - * @param string $value - * @throws \Exception If the setting does not exist or if the current user is not allowed to change the value - * of this setting. - */ - public function setValue(Setting $setting, $value) - { - $this->loadSettingsIfNotDoneYet(); - - $this->settingsValues[$setting->getKey()] = $value; - } - - /** - * Unsets a setting value in memory. To persist the change, {@link save()} must be - * called afterwards, otherwise the change has no effect. - * - * @param Setting $setting - */ - public function deleteValue(Setting $setting) - { - $this->loadSettingsIfNotDoneYet(); - - $key = $setting->getKey(); - - if (array_key_exists($key, $this->settingsValues)) { - unset($this->settingsValues[$key]); - } - } - - public function getOptionKey() - { - return 'Plugin_' . $this->pluginName . '_Settings'; - } - - private function loadSettingsIfNotDoneYet() - { - if ($this->settingValuesLoaded) { - return; - } - - $this->settingValuesLoaded = true; - $this->settingsValues = $this->loadSettings(); - } - - protected function loadSettings() - { - $values = Option::get($this->getOptionKey()); - - if (!empty($values)) { - return unserialize($values); - } - - return array(); - } -} diff --git a/core/Settings/Storage/Backend/BackendInterface.php b/core/Settings/Storage/Backend/BackendInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..624493460e7eb300b5837780dd6470ffe63324b7 --- /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 0000000000000000000000000000000000000000..f3150d77ee9a733d132ee78313cf9dd67a24d550 --- /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 0000000000000000000000000000000000000000..22452288c8bb5aa1cb8663ba26767b66d8b7492f --- /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 0000000000000000000000000000000000000000..cc64c55654d9c73c6e2af6acbeef5e6cd8df990b --- /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 0000000000000000000000000000000000000000..87476ff8fbd1f8e870608b0f6cf2226c87ffa0e8 --- /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 0000000000000000000000000000000000000000..81de89b10087f0c189af0cacd9c447de3c0ec0e3 --- /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() + { + } + +} diff --git a/core/Settings/Storage/Factory.php b/core/Settings/Storage/Factory.php index 87d54ad3b14c2398c63db7015a602bd35bdf73c7..5c1c6ca6456a40e0c4fa0097c1fe8bfe9e36b534 100644 --- a/core/Settings/Storage/Factory.php +++ b/core/Settings/Storage/Factory.php @@ -9,20 +9,113 @@ namespace Piwik\Settings\Storage; -use Piwik\Settings\Storage; +use Piwik\Settings\Storage\Backend\BackendInterface; use Piwik\SettingsServer; -use Piwik\Tracker\SettingsStorage; +/** + * Factory to create an instance of a storage. The storage can be created with different backends depending on the need. + * + * @package Piwik\Settings\Storage + */ class Factory { - public static function make($pluginName) + // cache prevents multiple loading of storage + private $cache = array(); + + /** + * Get a storage instance for plugin settings. + * + * The storage will hold values that belong to the given plugin name and user login. Be aware that instances + * for a specific plugin and login will be cached during one request for better performance. + * + * @param string $pluginName + * @param string $userLogin Use an empty string if settings should be not for a specific login + * @return Storage + */ + public function getPluginStorage($pluginName, $userLogin) + { + $id = $pluginName . '#' . $userLogin; + + if (!isset($this->cache[$id])) { + $backend = new Backend\PluginSettingsTable($pluginName, $userLogin); + $this->cache[$id] = $this->makeStorage($backend); + } + + return $this->cache[$id]; + } + + /** + * Get a storage instance for measurable settings. + * + * The storage will hold values that belong to the given idSite and plugin name. Be aware that a storage instance + * for a specific site and plugin will be cached during one request for better performance. + * + * @param int $idSite If idSite is empty it will use a backend that never actually persists any value. Pass + * $idSite = 0 to create a storage for a site that is about to be created. + * @param string $pluginName + * @return Storage + */ + public function getMeasurableSettingsStorage($idSite, $pluginName) + { + $id = 'measurableSettings' . (int) $idSite . '#' . $pluginName; + + if (empty($idSite)) { + return $this->getNonPersistentStorage($id . '#nonpersistent'); + } + + if (!isset($this->cache[$id])) { + $backend = new Backend\MeasurableSettingsTable($idSite, $pluginName); + $this->cache[$id] = $this->makeStorage($backend); + } + + return $this->cache[$id]; + } + + /** + * Get a storage instance for settings that will be saved in the "site" table. + * + * The storage will hold values that belong to the given idSite. Be aware that a storage instance for a specific + * site will be cached during one request for better performance. + * + * @param int $idSite If idSite is empty it will use a backend that never actually persists any value. Pass + * $idSite = 0 to create a storage for a site that is about to be created. + * + * @param int $idSite + * @return Storage + */ + public function getSitesTable($idSite) + { + $id = 'sitesTable#' . $idSite; + + if (empty($idSite)) { + return $this->getNonPersistentStorage($id . '#nonpersistent'); + } + + if (!isset($this->cache[$id])) { + $backend = new Backend\SitesTable($idSite); + $this->cache[$id] = $this->makeStorage($backend); + } + + return $this->cache[$id]; + } + + /** + * Get a storage with a backend that will never persist or load any value. + * + * @param string $key + * @return Storage + */ + public function getNonPersistentStorage($key) + { + return new Storage(new Backend\Null($key)); + } + + private function makeStorage(BackendInterface $backend) { if (SettingsServer::isTrackerApiRequest()) { - $storage = new SettingsStorage($pluginName); - } else { - $storage = new Storage($pluginName); + $backend = new Backend\Cache($backend); } - return $storage; + return new Storage($backend); } } diff --git a/core/Settings/Storage/StaticStorage.php b/core/Settings/Storage/StaticStorage.php deleted file mode 100644 index d8a43b6c9aa6bde397495e6bd1dc00db9ab6d96c..0000000000000000000000000000000000000000 --- a/core/Settings/Storage/StaticStorage.php +++ /dev/null @@ -1,34 +0,0 @@ -<?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; - -use Piwik\Settings\Storage; - -/** - * Static / temporary storage where a value will never be persisted meaning it will use the default value - * for each request until configured differently. Useful for tests. - * - * @api - */ -class StaticStorage extends Storage -{ - - protected function loadSettings() - { - return array(); - } - - /** - * Saves (persists) the current setting values in the database. - */ - public function save() - { - } -} diff --git a/core/Settings/Storage/Storage.php b/core/Settings/Storage/Storage.php new file mode 100644 index 0000000000000000000000000000000000000000..b24282068d88b9507d7e032a25d4605226e22ca9 --- /dev/null +++ b/core/Settings/Storage/Storage.php @@ -0,0 +1,117 @@ +<?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; + +use Piwik\Settings\Storage\Backend; + +/** + * A storage stores values for multiple settings. Storing multiple settings here saves having to do + * a "get" for each individual setting. A storage is usually stared between all individual setting instances + * within a plugin. + */ +class Storage +{ + /** + * Array containing all plugin settings values: Array( [setting-key] => [setting-value] ). + * + * @var array + */ + protected $settingsValues = array(); + + // for lazy loading of setting values + private $settingValuesLoaded = false; + + /** + * @var Backend\BackendInterface + */ + private $backend; + + /** + * Defines whether a value has changed since the settings were loaded or not. + * @var bool + */ + private $isDirty = false; + + public function __construct(Backend\BackendInterface $backend) + { + $this->backend = $backend; + } + + /** + * Get the currently used backend for this storage. + * @return Backend\BackendInterface + */ + public function getBackend() + { + return $this->backend; + } + + /** + * Saves (persists) the current setting values in the database if a value has actually changed. + */ + public function save() + { + if ($this->isDirty) { + $this->backend->save($this->settingsValues); + + $this->isDirty = false; + + Backend\Cache::clearCache(); + } + } + + /** + * Returns the current value for a setting. If no value is stored, the default value + * is be returned. + * + * @param string $key The name / key of a setting + * @param mixed $defaultValue Default value that will be used in case no value for this setting exists yet + * @param string $type The PHP internal type the value of the setting should have, see FieldConfig::TYPE_* + * constants. Only an actual value of the setting will be converted to the given type, the + * default value will not be converted. + * @return mixed + */ + public function getValue($key, $defaultValue, $type) + { + $this->loadSettingsIfNotDoneYet(); + + if (array_key_exists($key, $this->settingsValues)) { + settype($this->settingsValues[$key], $type); + return $this->settingsValues[$key]; + } + + return $defaultValue; + } + + /** + * Sets (overwrites) the value of a setting in memory. To persist the change across requests, {@link save()} must be + * called. + * + * @param string $key The name / key of a setting + * @param mixed $value The value that shall be set for the given setting. + */ + public function setValue($key, $value) + { + $this->loadSettingsIfNotDoneYet(); + + $this->isDirty = true; + $this->settingsValues[$key] = $value; + } + + private function loadSettingsIfNotDoneYet() + { + if ($this->settingValuesLoaded) { + return; + } + + $this->settingValuesLoaded = true; + $this->settingsValues = $this->backend->load(); + } +} diff --git a/core/Settings/StorageInterface.php b/core/Settings/StorageInterface.php deleted file mode 100644 index 6a4a76c5ac05778f2c72280ccc59fa078398c264..0000000000000000000000000000000000000000 --- a/core/Settings/StorageInterface.php +++ /dev/null @@ -1,59 +0,0 @@ -<?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; - -/** - * Base type of all Setting storage implementations. - */ -interface StorageInterface -{ - /** - * Gets the current value for this setting. If no value is specified, the default value will be returned. - * - * @param Setting $setting - * - * @return mixed - * - * @throws \Exception In case the setting does not exist or if the current user is not allowed to change the value - * of this setting. - */ - public function getValue(Setting $setting); - - /** - * Removes the value for the given setting. Make sure to call `save()` afterwards, otherwise the removal has no - * effect. - * - * @param Setting $setting - */ - public function deleteValue(Setting $setting); - - /** - * Sets (overwrites) the value for the given setting. Make sure to call `save()` afterwards, otherwise the change - * has no effect. Before the value is saved a possibly define `validate` closure and `filter` closure will be - * called. Alternatively the value will be casted to the specfied setting type. - * - * @param Setting $setting - * @param string $value - * - * @throws \Exception In case the setting does not exist or if the current user is not allowed to change the value - * of this setting. - */ - public function setValue(Setting $setting, $value); - - /** - * Removes all settings for this plugin from the database. Useful when uninstalling - * a plugin. - */ - public function deleteAllValues(); - - /** - * Saves (persists) the current setting values in the database. - */ - public function save(); -} diff --git a/core/Settings/UserSetting.php b/core/Settings/UserSetting.php deleted file mode 100644 index aa3a08c400eb24ba476d54edb5e8bf3a577e84a0..0000000000000000000000000000000000000000 --- a/core/Settings/UserSetting.php +++ /dev/null @@ -1,146 +0,0 @@ -<?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; - -use Piwik\Common; -use Piwik\Piwik; - -/** - * Describes a per user setting. Each user will be able to change this setting for themselves, - * but not for other users. - * - * - * @api - */ -class UserSetting extends Setting -{ - private $userLogin = null; - - /** - * Null while not initialized, bool otherwise. - * @var null|bool - */ - private $hasReadAndWritePermission = null; - - /** - * Constructor. - * - * @param string $name The setting's persisted name. - * @param string $title The setting's display name. - * @param null|string $userLogin The user this setting applies to. Will default to the current user login. - */ - public function __construct($name, $title, $userLogin = null) - { - parent::__construct($name, $title); - - $this->setUserLogin($userLogin); - } - - /** - * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. - * - * @return bool - */ - public function isReadableByCurrentUser() - { - return $this->isWritableByCurrentUser(); - } - - /** - * Returns `true` if this setting can be displayed for the current user, `false` if otherwise. - * - * @return bool - */ - public function isWritableByCurrentUser() - { - if (isset($this->hasReadAndWritePermission)) { - return $this->hasReadAndWritePermission; - } - - $this->hasReadAndWritePermission = Piwik::isUserHasSomeViewAccess(); - - return $this->hasReadAndWritePermission; - } - - /** - * Returns the display order. User settings are displayed after system settings. - * - * @return int - */ - public function getOrder() - { - return 60; - } - - private function buildUserSettingName($name, $userLogin = null) - { - if (empty($userLogin)) { - $userLogin = Piwik::getCurrentUserLogin(); - } - - // the asterisk tag is indeed important here and better than an underscore. Imagine a plugin has the settings - // "api_password" and "api". A user having the login "_password" could otherwise under circumstances change the - // setting for "api" although he is not allowed to. It is not so important at the moment because only alNum is - // currently allowed as a name this might change in the future. - $appendix = '#' . $userLogin . '#'; - - if (Common::stringEndsWith($name, $appendix)) { - return $name; - } - - return $name . $appendix; - } - - /** - * Sets the name of the user this setting will be set for. - * - * @param $userLogin - * @throws \Exception If the current user does not have permission to set the setting value - * of `$userLogin`. - */ - public function setUserLogin($userLogin) - { - if (!empty($userLogin) && !Piwik::hasUserSuperUserAccessOrIsTheUser($userLogin)) { - throw new \Exception('You do not have the permission to read the settings of a different user'); - } - - $this->userLogin = $userLogin; - $this->key = $this->buildUserSettingName($this->name, $userLogin); - } - - /** - * Unsets all settings for a user. The settings will be removed from the database. Used when - * a user is deleted. - * - * @param string $userLogin - * @throws \Exception If the `$userLogin` is empty. - */ - public static function removeAllUserSettingsForUser($userLogin) - { - if (empty($userLogin)) { - throw new \Exception('No userLogin specified'); - } - - $pluginsSettings = Manager::getAllPluginSettings(); - - foreach ($pluginsSettings as $pluginSettings) { - $settings = $pluginSettings->getSettings(); - - foreach ($settings as $setting) { - if ($setting instanceof UserSetting) { - $setting->setUserLogin($userLogin); - $setting->removeValue(); - } - } - - $pluginSettings->save(); - } - } -} diff --git a/core/Site.php b/core/Site.php index 3bc535fc2d0f4e8ec0062c79aa4f779be3a6d326..a45a4a5e2ec691c7c523d51e32e3e7c60231efc2 100644 --- a/core/Site.php +++ b/core/Site.php @@ -418,6 +418,17 @@ class Site self::$infoSites = array(); } + /** + * Clears the site data cache. + * + * See also {@link setSites()} and {@link setSitesFromArray()}. + */ + public static function clearCacheForSite($idSite) + { + $idSite = (int)$idSite; + unset(self::$infoSites[$idSite]); + } + /** * Utility function. Returns the value of the specified field for the * site with the specified ID. diff --git a/core/Tracker/SettingsStorage.php b/core/Tracker/SettingsStorage.php deleted file mode 100644 index a69e03553f5f11db50e29959ccef6295d76ec79e..0000000000000000000000000000000000000000 --- a/core/Tracker/SettingsStorage.php +++ /dev/null @@ -1,58 +0,0 @@ -<?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\Tracker; - -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. - */ -class SettingsStorage extends Storage -{ - protected function loadSettings() - { - $cacheId = $this->getOptionKey(); - $cache = $this->getCache(); - - if ($cache->contains($cacheId)) { - $settings = $cache->fetch($cacheId); - } else { - $settings = parent::loadSettings(); - - $cache->save($cacheId, $settings); - } - - return $settings; - } - - public function save() - { - parent::save(); - self::clearCache(); - } - - private function getCache() - { - return self::buildCache($this->getOptionKey()); - } - - public static function clearCache() - { - Cache::deleteTrackerCache(); - self::buildCache()->flushAll(); - } - - private static function buildCache() - { - return PiwikCache::getEagerCache(); - } -} diff --git a/core/Updates/3.0.0-b1.php b/core/Updates/3.0.0-b1.php index 301bc44a1bc7512622b60ac1084cf7bf55555f33..b7fbd2d0274170ffd870608bd2a2e561052c9b02 100644 --- a/core/Updates/3.0.0-b1.php +++ b/core/Updates/3.0.0-b1.php @@ -11,6 +11,7 @@ namespace Piwik\Updates; use Piwik\Common; use Piwik\Db; +use Piwik\DbHelper; use Piwik\Updater; use Piwik\Updates; use Piwik\Plugins\Dashboard; @@ -30,7 +31,11 @@ class Updates_3_0_0_b1 extends Updates $allGoals = $db->fetchAll(sprintf("SELECT DISTINCT idgoal FROM %s", Common::prefixTable('goal'))); $allDashboards = $db->fetchAll(sprintf("SELECT * FROM %s", Common::prefixTable('user_dashboard'))); - return $this->getDashboardMigrationSqls($allDashboards, $allGoals); + $queries = $this->getDashboardMigrationSqls($allDashboards, $allGoals); + $queries = $this->getPluginSettingsMigrationQueries($queries, $db); + $queries = $this->getSiteSettingsMigrationQueries($queries); + + return $queries; } public function doUpdate(Updater $updater) @@ -38,11 +43,104 @@ class Updates_3_0_0_b1 extends Updates $updater->executeMigrationQueries(__FILE__, $this->getMigrationQueries($updater)); } + /** + * @param $queries + * @param Db $db + * @return mixed + */ + private function getPluginSettingsMigrationQueries($queries, $db) + { + $pluginSettingsTableName = $this->getPluginSettingsTableName(); + $dbSettings = new Db\Settings(); + $engine = $dbSettings->getEngine(); + + $pluginSettingsTable = "CREATE TABLE $pluginSettingsTableName ( + `plugin_name` VARCHAR(60) NOT NULL, + `setting_name` VARCHAR(255) NOT NULL, + `setting_value` LONGTEXT NOT NULL, + `user_login` VARCHAR(100) NOT NULL DEFAULT '', + INDEX(plugin_name, user_login) + ) ENGINE=$engine DEFAULT CHARSET=utf8 + "; + $queries[$pluginSettingsTable] = 1050; + + $optionTable = Common::prefixTable('option'); + $query = 'SELECT `option_name`, `option_value` FROM `' . $optionTable . '` WHERE `option_name` LIKE "Plugin_%_Settings"'; + $options = Db::get()->fetchAll($query); + + foreach ($options as $option) { + $name = $option['option_name']; + $pluginName = str_replace(array('Plugin_', '_Settings'), '', $name); + $values = @unserialize($option['option_value']); + + if (empty($values)) { + continue; + } + + foreach ($values as $settingName => $settingValue) { + if (!is_array($settingValue)) { + $settingValue = array($settingValue); + } + + foreach ($settingValue as $val) { + $queries[$this->createPluginSettingQuery($pluginName, $settingName, $val)] = 1062; + } + } + } + + $queries[$query = sprintf('DELETE FROM `%s` WHERE `option_name` like "Plugin_%%_Settings"', $optionTable)] = false; + + return $queries; + } + + /** + * @param $queries + * @param Db $db + * @return mixed + */ + private function getSiteSettingsMigrationQueries($queries) + { + $table = Common::prefixTable('site_setting'); + + $pluginSettingsTable = "ALTER TABLE $table ADD COLUMN `plugin_name` VARCHAR(60) NOT NULL AFTER `idsite`"; + $queries[$pluginSettingsTable] = 1060; + $queries["ALTER TABLE $table DROP PRIMARY KEY, ADD INDEX(idsite, plugin_name);"] = false; + + // we cannot migrate existing settings as we do not know the related plugin name, but this feature + // (measurablesettings) was not really used anyway. If a migration is somewhere really needed it has to be + // handled in the plugin + $queries[sprintf('DELETE FROM `%s`', $table)] = false; + + return $queries; + } + + private function createPluginSettingQuery($pluginName, $settingName, $settingValue) + { + $table = $this->getPluginSettingsTableName(); + + $login = ''; + if (preg_match('/^.+#(.+)#$/', $settingName, $matches)) { + $login = $matches[1]; + $settingName = str_replace('#' . $login . '#', '', $settingName); + } + + $db = Db::get(); + + $query = sprintf("INSERT INTO %s (plugin_name, setting_name, setting_value, user_login) VALUES ", $table); + $query .= sprintf("(%s, %s, %s, %s)", $db->quote($pluginName), $db->quote($settingName), $db->quote($settingValue), $db->quote($login)); + + return $query; + } + + private function getPluginSettingsTableName() + { + return Common::prefixTable('plugin_setting'); + } + private function getDashboardMigrationSqls($allDashboards, $allGoals) { $sqls = array(); - // update dashboard to use new widgets $oldWidgets = array( array ( diff --git a/core/ViewDataTable/Config.php b/core/ViewDataTable/Config.php index f275aebe587fddfbe1da17bf04af9ce8ff822c58..14a6e13ed5a2cc87bddd4fd4bbdfbcb9c847740e 100644 --- a/core/ViewDataTable/Config.php +++ b/core/ViewDataTable/Config.php @@ -15,7 +15,7 @@ use Piwik\DataTable; use Piwik\DataTable\Filter\PivotByDimension; use Piwik\Metrics; use Piwik\Plugins\API\API; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * Contains base display properties for {@link Piwik\Plugin\ViewDataTable}s. Manipulating these @@ -717,7 +717,7 @@ class Config private function setShouldShowPivotBySubtable() { - $report = Reports::factory($this->controllerName, $this->controllerAction); + $report = ReportsProvider::factory($this->controllerName, $this->controllerAction); if (empty($report)) { $this->show_pivot_by_subtable = false; diff --git a/core/ViewDataTable/Factory.php b/core/ViewDataTable/Factory.php index 543f1280cf02f35eaa492fdf12498e6f1895ca85..846de225c25f2e8b55c972a08e444e6d233563a2 100644 --- a/core/ViewDataTable/Factory.php +++ b/core/ViewDataTable/Factory.php @@ -12,7 +12,7 @@ use Piwik\Common; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * Provides a means of creating {@link Piwik\Plugin\ViewDataTable} instances by ID. @@ -168,7 +168,7 @@ class Factory private static function getReport($apiAction) { list($module, $action) = explode('.', $apiAction); - $report = Reports::factory($module, $action); + $report = ReportsProvider::factory($module, $action); return $report; } diff --git a/core/Widget/WidgetsList.php b/core/Widget/WidgetsList.php index dfeb004277382acd34707f9c88677ecec2127f4e..14c626b0a92c634c469d40ae478795fc594bd2af 100644 --- a/core/Widget/WidgetsList.php +++ b/core/Widget/WidgetsList.php @@ -175,7 +175,7 @@ class WidgetsList { $list = new static; - $widgets = StaticContainer::get('Piwik\Plugin\Widgets'); + $widgets = StaticContainer::get('Piwik\Plugin\WidgetsProvider'); $widgetContainerConfigs = $widgets->getWidgetContainerConfigs(); foreach ($widgetContainerConfigs as $config) { @@ -191,7 +191,7 @@ class WidgetsList } } - $reports = StaticContainer::get('Piwik\Plugin\Reports'); + $reports = StaticContainer::get('Piwik\Plugin\ReportsProvider'); $reports = $reports->getAllReports(); foreach ($reports as $report) { if ($report->isEnabled()) { diff --git a/plugins/API/API.php b/plugins/API/API.php index 528d17e8cf115fc92242e9389b08244e03936d0d..67a86ff386c858071fc0156765ea1f92eef15c17 100644 --- a/plugins/API/API.php +++ b/plugins/API/API.php @@ -25,8 +25,10 @@ use Piwik\Metrics; use Piwik\Period; use Piwik\Period\Range; use Piwik\Piwik; +use Piwik\Plugin\SettingsProvider; use Piwik\Plugins\API\DataTable\MergeDataTables; use Piwik\Plugins\CoreAdminHome\CustomLogo; +use Piwik\Plugins\CorePluginsAdmin\SettingsMetadata; use Piwik\Translation\Translator; use Piwik\Measurable\Type\TypeManager; use Piwik\Version; @@ -54,6 +56,16 @@ require_once PIWIK_INCLUDE_PATH . '/core/Config.php'; */ class API extends \Piwik\Plugin\API { + /** + * @var SettingsProvider + */ + private $settingsProvider; + + public function __construct(SettingsProvider $settingsProvider) + { + $this->settingsProvider = $settingsProvider; + } + /** * Get Piwik version * @return string @@ -113,11 +125,16 @@ class API extends \Piwik\Plugin\API $available = array(); foreach ($types as $type) { + $measurableSettings = $this->settingsProvider->getAllMeasurableSettings($idSite = 0, $type->getId()); + + $settingsMetadata = new SettingsMetadata(); + $available[] = array( 'id' => $type->getId(), 'name' => Piwik::translate($type->getName()), 'description' => Piwik::translate($type->getDescription()), - 'howToSetupUrl' => $type->getHowToSetupUrl() + 'howToSetupUrl' => $type->getHowToSetupUrl(), + 'settings' => $settingsMetadata->formatSettings($measurableSettings) ); } diff --git a/plugins/API/ProcessedReport.php b/plugins/API/ProcessedReport.php index 8a9a96b5370cc2f19feea50d8f91a8be4effaf9e..f5c5cc1a917eeb379449d964c28de5ad59561449 100644 --- a/plugins/API/ProcessedReport.php +++ b/plugins/API/ProcessedReport.php @@ -23,7 +23,7 @@ use Piwik\Metrics\Formatter; use Piwik\Period; use Piwik\Piwik; use Piwik\Plugin\Report; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Site; use Piwik\Timer; use Piwik\Url; @@ -168,7 +168,7 @@ class ProcessedReport $availableReports = array(); - $reports = new Reports(); + $reports = new ReportsProvider(); foreach ($reports->getAllReports() as $report) { $report->configureReportMetadata($availableReports, $parameters); } @@ -291,7 +291,7 @@ class ProcessedReport */ private static function sortReports($a, $b) { - $reports = new Reports(); + $reports = new ReportsProvider(); return $reports->compareCategories($a['category'], $a['subcategory'], $a['order'], $b['category'], $b['subcategory'], $b['order']); } diff --git a/plugins/API/Reports/Get.php b/plugins/API/Reports/Get.php index 61cded3856287cf93ca42407e35ab0dbe68b434e..8adc67b4edda739970b3ae588a16a1eb1f6139ff 100644 --- a/plugins/API/Reports/Get.php +++ b/plugins/API/Reports/Get.php @@ -10,7 +10,7 @@ namespace Piwik\Plugins\API\Reports; use Piwik\Piwik; use Piwik\Plugin\Report; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class Get extends Report { @@ -81,7 +81,7 @@ class Get extends Report */ private function getReportsToMerge() { - $reports = new Reports(); + $reports = new ReportsProvider(); $result = array(); foreach ($reports->getAllReportClasses() as $reportClass) { if ($reportClass == 'Piwik\\Plugins\\API\\Reports\\Get') { diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php index e475f4240c82026d2b1a968e0dd36e01f2a61244..4be588f9fd9b28e2086ed1fcf52f404f1ea7de65 100644 --- a/plugins/Actions/API.php +++ b/plugins/Actions/API.php @@ -22,7 +22,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; use Piwik\Plugins\CustomVariables\API as APICustomVariables; use Piwik\Plugins\Actions\Actions\ActionSiteSearch; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Tracker\Action; use Piwik\Tracker\PageUrl; @@ -56,7 +56,7 @@ class API extends \Piwik\Plugin\API { Piwik::checkUserHasViewAccess($idSite); - $report = Reports::factory("Actions", "get"); + $report = ReportsProvider::factory("Actions", "get"); $archive = Archive::build($idSite, $period, $date, $segment); $requestedColumns = Piwik::getArrayFromApiParameter($columns); diff --git a/plugins/Actions/Reports/GetEntryPageTitles.php b/plugins/Actions/Reports/GetEntryPageTitles.php index 9df1d74450b1e52058b41e397a277e7ebcd956db..5f811121169bfa5d22e8cf78b3664236fe2be1d9 100644 --- a/plugins/Actions/Reports/GetEntryPageTitles.php +++ b/plugins/Actions/Reports/GetEntryPageTitles.php @@ -15,7 +15,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Widget\WidgetsList; @@ -85,8 +85,8 @@ class GetEntryPageTitles extends Base public function getRelatedReports() { return array( - Reports::factory('Actions', 'getPageTitles'), - Reports::factory('Actions', 'getEntryPageUrls') + ReportsProvider::factory('Actions', 'getPageTitles'), + ReportsProvider::factory('Actions', 'getEntryPageUrls') ); } } diff --git a/plugins/Actions/Reports/GetEntryPageUrls.php b/plugins/Actions/Reports/GetEntryPageUrls.php index dfeeb8cf04842f991d3f172fb75282f2ac990541..4714b31a6b4fe6246aa7be48d301cb5a0d30ecaa 100644 --- a/plugins/Actions/Reports/GetEntryPageUrls.php +++ b/plugins/Actions/Reports/GetEntryPageUrls.php @@ -15,7 +15,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Widget\WidgetsList; @@ -83,7 +83,7 @@ class GetEntryPageUrls extends Base public function getRelatedReports() { return array( - Reports::factory('Actions', 'getEntryPageTitles'), + ReportsProvider::factory('Actions', 'getEntryPageTitles'), ); } } diff --git a/plugins/Actions/Reports/GetExitPageTitles.php b/plugins/Actions/Reports/GetExitPageTitles.php index 53f235209d28239999b6c65c593c8fbf7c6f4a90..74ceaf6b17cded42171f0b90b03fff393f548293 100644 --- a/plugins/Actions/Reports/GetExitPageTitles.php +++ b/plugins/Actions/Reports/GetExitPageTitles.php @@ -15,7 +15,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Widget\WidgetsList; @@ -94,8 +94,8 @@ class GetExitPageTitles extends Base public function getRelatedReports() { return array( - Reports::factory('Actions', 'getPageTitles'), - Reports::factory('Actions', 'getExitPageUrls'), + ReportsProvider::factory('Actions', 'getPageTitles'), + ReportsProvider::factory('Actions', 'getExitPageUrls'), ); } } diff --git a/plugins/Actions/Reports/GetExitPageUrls.php b/plugins/Actions/Reports/GetExitPageUrls.php index bc4d29782d3687db6a878edc8cb82c96e5a84382..6ad6865c6c7b74898173476d96ddfa53215a11c0 100644 --- a/plugins/Actions/Reports/GetExitPageUrls.php +++ b/plugins/Actions/Reports/GetExitPageUrls.php @@ -16,7 +16,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Widget\WidgetsList; @@ -98,7 +98,7 @@ class GetExitPageUrls extends Base public function getRelatedReports() { return array( - Reports::factory('Actions', 'getExitPageTitles'), + ReportsProvider::factory('Actions', 'getExitPageTitles'), ); } diff --git a/plugins/Actions/Reports/GetPageTitles.php b/plugins/Actions/Reports/GetPageTitles.php index ed1846ddd6df0e789f0e9b91b8bb5e4177dfd657..5a5e0581e92c45133e7433030ed161ec8576a0e3 100644 --- a/plugins/Actions/Reports/GetPageTitles.php +++ b/plugins/Actions/Reports/GetPageTitles.php @@ -16,7 +16,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Widget\WidgetsList; @@ -82,8 +82,8 @@ class GetPageTitles extends Base public function getRelatedReports() { return array( - Reports::factory('Actions', 'getEntryPageTitles'), - Reports::factory('Actions', 'getExitPageTitles'), + ReportsProvider::factory('Actions', 'getEntryPageTitles'), + ReportsProvider::factory('Actions', 'getExitPageTitles'), ); } } diff --git a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php index 3d50ba4f951e07a7258e3ccc570af1c512ff523e..4b3911780a8534a3767e8241f6213629e3d13bfb 100644 --- a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php +++ b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php @@ -15,7 +15,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetPageTitlesFollowingSiteSearch extends SiteSearchBase { @@ -82,7 +82,7 @@ class GetPageTitlesFollowingSiteSearch extends SiteSearchBase public function getRelatedReports() { return array( - Reports::factory('Actions', 'getPageUrlsFollowingSiteSearch'), + ReportsProvider::factory('Actions', 'getPageUrlsFollowingSiteSearch'), ); } } diff --git a/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php b/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php index 063d3855b5b5ca5a5965464a8e03fb9796b1f7fb..ae1bb8927dd3400fe2e210d74767871a75633d81 100644 --- a/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php +++ b/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\Actions\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Actions\Columns\DestinationPage; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch { @@ -36,7 +36,7 @@ class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch public function getRelatedReports() { return array( - Reports::factory('Actions', 'getPageTitlesFollowingSiteSearch'), + ReportsProvider::factory('Actions', 'getPageTitlesFollowingSiteSearch'), ); } } diff --git a/plugins/AnonymousPiwikUsageMeasurement b/plugins/AnonymousPiwikUsageMeasurement index 3d1160c0980377b140c3ebb987cef4b01ce1b3ac..eb8a1669250ee8d7f889d7cf2e29efcefa7bde83 160000 --- a/plugins/AnonymousPiwikUsageMeasurement +++ b/plugins/AnonymousPiwikUsageMeasurement @@ -1 +1 @@ -Subproject commit 3d1160c0980377b140c3ebb987cef4b01ce1b3ac +Subproject commit eb8a1669250ee8d7f889d7cf2e29efcefa7bde83 diff --git a/plugins/CoreAdminHome/Controller.php b/plugins/CoreAdminHome/Controller.php index 19e0f1c9c1a709b27de59cdc27b532dfd6cbb310..f8031c76e471ed2fbea93f79eaa947476e334a26 100644 --- a/plugins/CoreAdminHome/Controller.php +++ b/plugins/CoreAdminHome/Controller.php @@ -14,7 +14,6 @@ use Piwik\ArchiveProcessor\Rules; use Piwik\Common; use Piwik\Config; use Piwik\Container\StaticContainer; -use Piwik\DataTable\Renderer\Json; use Piwik\Menu\MenuTop; use Piwik\Nonce; use Piwik\Piwik; @@ -24,9 +23,6 @@ use Piwik\Plugins\CustomVariables\CustomVariables; use Piwik\Plugins\LanguagesManager\LanguagesManager; use Piwik\Plugins\PrivacyManager\DoNotTrackHeaderChecker; use Piwik\Plugins\SitesManager\API as APISitesManager; -use Piwik\Settings\Manager as SettingsManager; -use Piwik\Settings\SystemSetting; -use Piwik\Settings\UserSetting; use Piwik\Site; use Piwik\Translation\Translator; use Piwik\UpdateCheck; @@ -35,8 +31,6 @@ use Piwik\View; class Controller extends ControllerAdmin { - const SET_PLUGIN_SETTINGS_NONCE = 'CoreAdminHome.setPluginSettings'; - /** * @var Translator */ @@ -82,175 +76,6 @@ class Controller extends ControllerAdmin return $view->render(); } - public function adminPluginSettings() - { - Piwik::checkUserHasSuperUserAccess(); - - $settings = $this->getPluginSettings(); - - $vars = array( - 'nonce' => Nonce::getNonce(static::SET_PLUGIN_SETTINGS_NONCE), - 'pluginsSettings' => $this->getSettingsByType($settings, 'admin'), - 'firstSuperUserSettingNames' => $this->getFirstSuperUserSettingNames($settings), - 'mode' => 'admin' - ); - - return $this->renderTemplate('pluginSettings', $vars); - } - - /** - * @param \Piwik\Plugin\Settings[] $pluginsSettings - * @return array array([pluginName] => []) - */ - private function getSettingsByType($pluginsSettings, $mode) - { - $byType = array(); - - foreach ($pluginsSettings as $pluginName => $pluginSettings) { - $settings = array(); - - foreach ($pluginSettings->getSettingsForCurrentUser() as $setting) { - if ('admin' === $mode && $setting instanceof SystemSetting) { - $settings[] = $setting; - } elseif ('user' === $mode && $setting instanceof UserSetting) { - $settings[] = $setting; - } - } - - if (!empty($settings)) { - $byType[$pluginName] = array( - 'introduction' => $pluginSettings->getIntroduction(), - 'settings' => $settings - ); - } - } - - return $byType; - } - - public function userPluginSettings() - { - Piwik::checkUserIsNotAnonymous(); - - $settings = $this->getPluginSettings(); - - $vars = array( - 'nonce' => Nonce::getNonce(static::SET_PLUGIN_SETTINGS_NONCE), - 'pluginsSettings' => $this->getSettingsByType($settings, 'user'), - 'firstSuperUserSettingNames' => $this->getFirstSuperUserSettingNames($settings), - 'mode' => 'user' - ); - - return $this->renderTemplate('pluginSettings', $vars); - } - - private function getPluginSettings() - { - $pluginsSettings = SettingsManager::getPluginSettingsForCurrentUser(); - - ksort($pluginsSettings); - - return $pluginsSettings; - } - - /** - * @param \Piwik\Plugin\Settings[] $pluginsSettings - * @return array array([pluginName] => []) - */ - private function getFirstSuperUserSettingNames($pluginsSettings) - { - $names = array(); - foreach ($pluginsSettings as $pluginName => $pluginSettings) { - - foreach ($pluginSettings->getSettingsForCurrentUser() as $setting) { - if ($setting instanceof \Piwik\Settings\SystemSetting) { - $names[$pluginName] = $setting->getName(); - break; - } - } - } - - return $names; - } - - public function setPluginSettings() - { - Piwik::checkUserIsNotAnonymous(); - Json::sendHeaderJSON(); - - $nonce = Common::getRequestVar('nonce', null, 'string'); - - if (!Nonce::verifyNonce(static::SET_PLUGIN_SETTINGS_NONCE, $nonce)) { - return json_encode(array( - 'result' => 'error', - 'message' => $this->translator->translate('General_ExceptionNonceMismatch') - )); - } - - $pluginsSettings = SettingsManager::getPluginSettingsForCurrentUser(); - - try { - - foreach ($pluginsSettings as $pluginName => $pluginSetting) { - foreach ($pluginSetting->getSettingsForCurrentUser() as $setting) { - - $value = $this->findSettingValueFromRequest($pluginName, $setting->getKey()); - - if (!is_null($value)) { - $setting->setValue($value); - } - } - } - - } catch (Exception $e) { - $message = $e->getMessage(); - - if (!empty($setting)) { - $message = $setting->title . ': ' . $message; - } - - $message = html_entity_decode($message, ENT_QUOTES, 'UTF-8'); - return json_encode(array('result' => 'error', 'message' => $message)); - } - - try { - foreach ($pluginsSettings as $pluginSetting) { - $pluginSetting->save(); - } - } catch (Exception $e) { - return json_encode(array( - 'result' => 'error', - 'message' => $this->translator->translate('CoreAdminHome_PluginSettingsSaveFailed')) - ); - } - - Nonce::discardNonce(static::SET_PLUGIN_SETTINGS_NONCE); - return json_encode(array('result' => 'success')); - } - - private function findSettingValueFromRequest($pluginName, $settingKey) - { - $changedPluginSettings = Common::getRequestVar('settings', null, 'array'); - - if (!array_key_exists($pluginName, $changedPluginSettings)) { - return; - } - - $settings = $changedPluginSettings[$pluginName]; - - foreach ($settings as $setting) { - if ($setting['name'] == $settingKey) { - $value = $setting['value']; - - if (is_string($value)) { - return Common::unsanitizeInputValue($value); - } - - return $value; - } - } - } - public function setGeneralSettings() { Piwik::checkUserHasSuperUserAccess(); diff --git a/plugins/CoreAdminHome/CoreAdminHome.php b/plugins/CoreAdminHome/CoreAdminHome.php index 0f9bf6070230ae7c83316517274ff1bd744c0ca1..6010391fdf8ded8d90db9c1fd834a868e9d76c69 100644 --- a/plugins/CoreAdminHome/CoreAdminHome.php +++ b/plugins/CoreAdminHome/CoreAdminHome.php @@ -11,7 +11,8 @@ namespace Piwik\Plugins\CoreAdminHome; use Piwik\Db; use Piwik\Piwik; use Piwik\ProxyHttp; -use Piwik\Settings\UserSetting; +use Piwik\Settings\Plugin\UserSetting; +use Piwik\Settings\Storage\Backend\PluginSettingsTable; /** * @@ -35,7 +36,7 @@ class CoreAdminHome extends \Piwik\Plugin public function cleanupUser($userLogin) { - UserSetting::removeAllUserSettingsForUser($userLogin); + PluginSettingsTable::removeAllUserSettingsForUser($userLogin); } public function getStylesheetFiles(&$stylesheets) @@ -59,7 +60,6 @@ class CoreAdminHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/javascripts/broadcast.js"; $jsFiles[] = "plugins/CoreAdminHome/javascripts/generalSettings.js"; $jsFiles[] = "plugins/CoreHome/javascripts/donate.js"; - $jsFiles[] = "plugins/CoreAdminHome/javascripts/pluginSettings.js"; $jsFiles[] = "plugins/CoreAdminHome/javascripts/protocolCheck.js"; } diff --git a/plugins/CoreAdminHome/Menu.php b/plugins/CoreAdminHome/Menu.php index b0dd0ee2581cb733186001a1dc7174b48a822720..9dcb9b9e66b96c81d374cb964db13cc0526fe8a3 100644 --- a/plugins/CoreAdminHome/Menu.php +++ b/plugins/CoreAdminHome/Menu.php @@ -13,26 +13,9 @@ use Piwik\Menu\MenuAdmin; use Piwik\Menu\MenuTop; use Piwik\Piwik; use Piwik\Plugin; -use Piwik\Settings\Manager as SettingsManager; class Menu extends \Piwik\Plugin\Menu { - public function configureTopMenu(MenuTop $menu) - { - if (Piwik::isUserIsAnonymous()) { - if (Plugin\Manager::getInstance()->isPluginActivated('ScheduledReports')) { - $url = $this->urlForModuleAction('ScheduledReports', 'index'); - } else { - $url = $this->urlForModuleAction('API', 'listAllAPI'); - } - } else { - $url = $this->urlForModuleAction('UsersManager', 'userSettings'); - } - - $menu->registerMenuIcon('CoreAdminHome_Administration', 'icon-configure'); - $menu->addItem('CoreAdminHome_Administration', null, $url, 980, Piwik::translate('CoreAdminHome_Administration')); - } - public function configureAdminMenu(MenuAdmin $menu) { $menu->addDevelopmentItem(null, array(), $order = 40); @@ -43,25 +26,29 @@ class Menu extends \Piwik\Plugin\Menu $menu->addManageItem('General_GeneralSettings', $this->urlForAction('generalSettings'), $order = 6); - - if (SettingsManager::hasSystemPluginsSettingsForCurrentUser()) { - $menu->addManageItem('CoreAdminHome_PluginSettings', - $this->urlForAction('adminPluginSettings'), - $order = 7); - } } if (!Piwik::isUserIsAnonymous()) { $menu->addManageItem('CoreAdminHome_TrackingCode', $this->urlForAction('trackingCodeGenerator'), $order = 25); + } + } - if (SettingsManager::hasUserPluginsSettingsForCurrentUser()) { - $menu->addPersonalItem('CoreAdminHome_PluginSettings', - $this->urlForAction('userPluginSettings'), - $order = 15); + public function configureTopMenu(MenuTop $menu) + { + if (Piwik::isUserIsAnonymous()) { + if (Plugin\Manager::getInstance()->isPluginActivated('ScheduledReports')) { + $url = $this->urlForModuleAction('ScheduledReports', 'index'); + } else { + $url = $this->urlForModuleAction('API', 'listAllAPI'); } + } else { + $url = $this->urlForModuleAction('UsersManager', 'userSettings'); } + + $menu->registerMenuIcon('CoreAdminHome_Administration', 'icon-configure'); + $menu->addItem('CoreAdminHome_Administration', null, $url, 980, Piwik::translate('CoreAdminHome_Administration')); } -} +} \ No newline at end of file diff --git a/plugins/CoreAdminHome/javascripts/pluginSettings.js b/plugins/CoreAdminHome/javascripts/pluginSettings.js deleted file mode 100644 index d6e49de4508583539aa37754eb9e0b6a54c17da1..0000000000000000000000000000000000000000 --- a/plugins/CoreAdminHome/javascripts/pluginSettings.js +++ /dev/null @@ -1,87 +0,0 @@ -/*! - * Piwik - free/libre analytics platform - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - */ - -$(document).ready(function () { - - $submit = $('.pluginsSettingsSubmit'); - - if (!$submit) { - return; - } - - $submit.click(updatePluginSettings); - - function updatePluginSettings() - { - $submit.prop('disabled', true); - - var $nonce = $('[name="setpluginsettingsnonce"]'); - var nonceValue = ''; - - if ($nonce) { - nonceValue = $nonce.val(); - } - - var ajaxHandler = new ajaxHelper(); - ajaxHandler.addParams({ - module: 'CoreAdminHome', - action: 'setPluginSettings', - nonce: nonceValue - }, 'GET'); - ajaxHandler.addParams({settings: getSettings()}, 'POST'); - ajaxHandler.redirectOnSuccess(); - ajaxHandler.setLoadingElement(getLoadingElement()); - ajaxHandler.setErrorElement(getErrorElement()); - ajaxHandler.setCompleteCallback(function () { - $submit.prop('disabled', false); - }); - ajaxHandler.send(); - } - - function getSettings() - { - var $pluginSections = $( "#pluginSettings[data-pluginname]" ); - - var values = {}; - - $pluginSections.each(function (index, pluginSection) { - $pluginSection = $(pluginSection); - - var pluginName = $pluginSection.attr('data-pluginname'); - var serialized = $('input, textarea, select:not([multiple])', $pluginSection).serializeArray(); - - // by default, it does not generate an array - var $multiSelects = $('select[multiple]', $pluginSection); - $multiSelects.each(function (index, multiSelect) { - var name = $(multiSelect).attr('name'); - serialized.push({name: name, value: $(multiSelect).val()}); - }); - - // by default, values of unchecked checkboxes are not send - var $uncheckedNodes = $('input[type=checkbox]:not(:checked)', $pluginSection); - $uncheckedNodes.each(function (index, uncheckedNode) { - var name = $(uncheckedNode).attr('name'); - serialized.push({name: name, value: 0}); - }); - - values[pluginName] = serialized; - }); - - return values; - } - - function getErrorElement() - { - return $('#ajaxErrorPluginSettings'); - } - - function getLoadingElement() - { - return $('#ajaxLoadingPluginSettings'); - } - -}); \ No newline at end of file diff --git a/plugins/CoreAdminHome/lang/en.json b/plugins/CoreAdminHome/lang/en.json index 4a879456613433a2c3227a3bcdd99197dbce3f21..306fe77fd756c6f3aa444006f841cad46cb33fd7 100644 --- a/plugins/CoreAdminHome/lang/en.json +++ b/plugins/CoreAdminHome/lang/en.json @@ -71,6 +71,7 @@ "PluginSettingsIntro": "Here you can change the settings for the following 3rd party plugins:", "PluginSettingsValueNotAllowed": "The value for field \"%1$s\" in plugin \"%2$s\" is not allowed", "PluginSettingsSaveFailed": "Failed to save plugin settings", + "PluginSettingsSaveSuccess": "Plugin settings updated.", "SendPluginUpdateCommunication": "Send an email when a plugin update is available", "SendPluginUpdateCommunicationHelp": "An email will be sent to Super Users when there is a new version available for a plugin.", "StableReleases": "If Piwik is a critical part of your business, we recommend you use the latest stable release. If you use the latest beta and you find a bug or have a suggestion, please %1$ssee here%2$s.", diff --git a/plugins/CoreAdminHome/templates/generalSettings.twig b/plugins/CoreAdminHome/templates/generalSettings.twig index e70d537472ebe2277abe996997cbcd2d1fa1a52c..34f09d9d13ee6c5274f9403ee9e46358f38e2b89 100644 --- a/plugins/CoreAdminHome/templates/generalSettings.twig +++ b/plugins/CoreAdminHome/templates/generalSettings.twig @@ -284,4 +284,9 @@ </p> {% endif %} + <h2 piwik-enriched-headline>{{ 'CoreAdminHome_SystemPluginSettings'|translate }}</h2> + + <div piwik-plugin-settings mode="admin"></div> + + {% endblock %} diff --git a/plugins/CoreAdminHome/templates/pluginSettings.twig b/plugins/CoreAdminHome/templates/pluginSettings.twig deleted file mode 100644 index b160fe847e10a7e54ad2a87cea08490a66f4a9be..0000000000000000000000000000000000000000 --- a/plugins/CoreAdminHome/templates/pluginSettings.twig +++ /dev/null @@ -1,56 +0,0 @@ - -{% extends "admin.twig" %} - -{% set title %} -{% if mode == 'user' -%} - {{ 'CoreAdminHome_PersonalPluginSettings'|translate }} -{%- else -%} - {{ 'CoreAdminHome_SystemPluginSettings'|translate }} -{% endif %} -{% endset %} - -{% block content %} - - {% import 'macros.twig' as piwik %} - {% import 'ajaxMacros.twig' as ajax %} - {% import 'settingsMacros.twig' as settingsMacro %} - - <h2 piwik-enriched-headline>{{ title }}</h2> - - <input type="hidden" name="setpluginsettingsnonce" value="{{ nonce }}"> - - <p> - {{ 'CoreAdminHome_PluginSettingsIntro'|translate }} - {% for pluginName, settings in pluginsSettings %} - <a href="#{{ pluginName|e('html_attr') }}">{{ pluginName }}</a>{% if not loop.last %}, {% endif %} - {% endfor %} - </p> - - {% for pluginName, pluginSettings in pluginsSettings %} - - <h2 id="{{ pluginName|e('html_attr') }}">{{ pluginName }}</h2> - - {% if pluginSettings.introduction %} - <p class="pluginIntroduction"> - {{ pluginSettings.introduction }} - </p> - {% endif %} - - <div id="pluginSettings" data-pluginname="{{ pluginName|e('html_attr') }}"> - - {% for name, setting in pluginSettings.settings %} - {{ settingsMacro.singleSetting(setting, loop.index) }} - {% endfor %} - - </div> - - {% endfor %} - - <hr/> - - {{ ajax.errorDiv('ajaxErrorPluginSettings') }} - {{ ajax.loadingDiv('ajaxLoadingPluginSettings') }} - - <input type="submit" value="{{ 'General_Save'|translate }}" class="pluginsSettingsSubmit submit"/> - -{% endblock %} \ No newline at end of file diff --git a/plugins/CoreConsole/Commands/GenerateReport.php b/plugins/CoreConsole/Commands/GenerateReport.php index 3f9fda4939601849b9cab95117e05f21321f2475..1faa1c9dc6cffc013dc42bb8883bd4832e08acac 100644 --- a/plugins/CoreConsole/Commands/GenerateReport.php +++ b/plugins/CoreConsole/Commands/GenerateReport.php @@ -13,7 +13,7 @@ use Piwik\Columns\Dimension; use Piwik\Piwik; use Piwik\Plugin\Manager; use Piwik\Plugin\Report; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Translate; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -80,7 +80,7 @@ class GenerateReport extends GeneratePluginBase { $order = 1; - $reports = new Reports(); + $reports = new ReportsProvider(); foreach ($reports->getAllReports() as $report) { if ($report->getCategoryId() === $category) { @@ -193,7 +193,7 @@ class GenerateReport extends GeneratePluginBase $category = $input->getOption('category'); - $reports = new Reports(); + $reports = new ReportsProvider(); $categories = array(); foreach ($reports->getAllReports() as $report) { @@ -232,7 +232,7 @@ class GenerateReport extends GeneratePluginBase $dimensions = array(); $dimensionNames = array(); - $reports = new Reports(); + $reports = new ReportsProvider(); foreach ($reports->getAllReports() as $report) { $dimension = $report->getDimension(); diff --git a/plugins/CoreConsole/Commands/GenerateSettings.php b/plugins/CoreConsole/Commands/GenerateSettings.php index 314b98e7a977ffe5c5e2f7acd2bb88b548e63f15..a5b0c4e07760b17b7aea8c133d2a04a9893f18fc 100644 --- a/plugins/CoreConsole/Commands/GenerateSettings.php +++ b/plugins/CoreConsole/Commands/GenerateSettings.php @@ -20,38 +20,72 @@ class GenerateSettings extends GeneratePluginBase protected function configure() { $this->setName('generate:settings') - ->setDescription('Adds a plugin setting class to an existing plugin') - ->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have settings yet'); + ->setDescription('Adds a SystemSetting, UserSetting or MeasurableSetting class to an existing plugin') + ->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have settings yet') + ->addOption('settingstype', null, InputOption::VALUE_REQUIRED, 'The type of settings you want to create. Should be one of these values: ' . implode(', ', $this->getSettingTypes())); } protected function execute(InputInterface $input, OutputInterface $output) { - $pluginName = $this->getPluginName($input, $output); + $settingsType = $this->getSettingsType($input, $output); + $settingsFilename = $settingsType . '.php'; + + $pluginName = $this->getPluginName($input, $output, $settingsType, $settingsFilename); $this->checkAndUpdateRequiredPiwikVersion($pluginName, $output); $exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExampleSettingsPlugin'; $replace = array('ExampleSettingsPlugin' => $pluginName); - $whitelistFiles = array('/Settings.php'); + $whitelistFiles = array('/' . $settingsFilename); $this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles); $this->writeSuccessMessage($output, array( - sprintf('Settings.php for %s generated.', $pluginName), - 'You can now start defining your plugin settings', + sprintf('%s for %s generated.', $settingsFilename, $pluginName), + 'You can now start defining your ' . $settingsType, 'Enjoy!' )); } + private function getSettingTypes() + { + return array('system', 'user', 'measurable'); + } + + private function getSettingsType(InputInterface $input, OutputInterface $output) + { + $availableTypes = $this->getSettingTypes(); + + $validate = function ($type) use ($availableTypes) { + if (empty($type) || !in_array($type, $availableTypes)) { + throw new \InvalidArgumentException('Please enter a valid settings type (' . implode(', ', $availableTypes) . '). '); + } + + return $type; + }; + + $settingsType = $input->getOption('settingstype'); + + if (empty($settingsType)) { + $dialog = $this->getHelperSet()->get('dialog'); + $settingsType = $dialog->askAndValidate($output, 'Please choose the type of settings you want to create (' . implode(', ', $availableTypes) . '): ', $validate, false, null, $availableTypes); + } else { + $validate($settingsType); + } + + return ucfirst($settingsType) . 'Settings'; + } + /** * @param InputInterface $input * @param OutputInterface $output + * @param string $settingsType * @return array * @throws \RuntimeException */ - protected function getPluginName(InputInterface $input, OutputInterface $output) + protected function getPluginName(InputInterface $input, OutputInterface $output, $settingsType, $settingsFile) { - $pluginNames = $this->getPluginNamesHavingNotSpecificFile('Settings.php'); - $invalidName = 'You have to enter the name of an existing plugin which does not already have settings'; + $pluginNames = $this->getPluginNamesHavingNotSpecificFile($settingsFile); + $invalidName = 'You have to enter the name of an existing plugin which does not already have ' . $settingsType; return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName); } diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php index 9e6afdb107c47085a693d53509a89743bd3e859a..e7b844db39fe2158dcc5d1a22c8ecbe5282bc13c 100644 --- a/plugins/CoreHome/CoreHome.php +++ b/plugins/CoreHome/CoreHome.php @@ -147,6 +147,7 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/ucfirst.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/directives/directive.module.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/common/directives/attributes.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/directives/autocomplete-matched.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/directives/ignore-click.js"; @@ -200,6 +201,14 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/angularjs/quick-access/quick-access.directive.js"; $jsFiles[] = "plugins/CoreHome/angularjs/selector/selector.directive.js"; + + + // we have to load these CorePluginsAdmin files here. If we loaded them in CorePluginsAdmin, + // there would be JS errors as CorePluginsAdmin is loaded first. Meaning it is loaded before + // any angular JS file is loaded etc. + $jsFiles[] = "plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.controller.js"; + $jsFiles[] = "plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.js"; + $jsFiles[] = "plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.js"; } public function getClientSideTranslationKeys(&$translationKeys) diff --git a/plugins/CoreHome/angularjs/common/directives/attributes.js b/plugins/CoreHome/angularjs/common/directives/attributes.js new file mode 100644 index 0000000000000000000000000000000000000000..c8285d9e8ee92d14a38299678791323219543145 --- /dev/null +++ b/plugins/CoreHome/angularjs/common/directives/attributes.js @@ -0,0 +1,37 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * If the given text or resolved expression matches any text within the element, the matching text will be wrapped + * with a class. + * + * Example: + * <div piwik-autocomplete-matched="'text'">My text</div> ==> <div>My <span class="autocompleteMatched">text</span></div> + * + * <div piwik-autocomplete-matched="searchTerm">{{ name }}</div> + * <input type="text" ng-model="searchTerm"> + */ +(function () { + angular.module('piwikApp.directive').directive('piwikAttributes', piwikAttributes); + + piwikAttributes.$inject = ['$sanitize']; + + function piwikAttributes(piwik, $sanitize) { + + return { + link: function (scope, element, attrs) { + attrs.piwikAttributes = JSON.parse(attrs.piwikAttributes); + + if (angular.isObject(attrs.piwikAttributes)) { + angular.forEach(attrs.piwikAttributes, function (value, key) { + element.attr(key, value); + }); + } + } + }; + } +})(); diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js index 7b999aab08f746bbc90652790191b56dcdd6fd87..83a714ceb71d0565a2c92367cc458a277b226757 100644 --- a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js @@ -7,9 +7,9 @@ (function () { angular.module('piwikApp').factory('reportingMenuModel', reportingMenuModelService); - reportingMenuModelService.$inject = ['$filter', '$q', 'piwikApi', 'reportingPagesModel', '$location']; + reportingMenuModelService.$inject = ['$filter', '$q', 'reportingPagesModel', '$location']; - function reportingMenuModelService ($filter, $q, piwikApi, reportingPagesModel, $location) { + function reportingMenuModelService ($filter, $q, reportingPagesModel, $location) { // those sites are going to be displayed var model = { diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js index 4018fcee8c54f0073d2ad73be0babdf0c16fed6e..9683228b4f5098d2d849a0536779140b92583876 100644 --- a/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js @@ -7,9 +7,9 @@ (function () { angular.module('piwikApp').factory('reportingPageModel', reportingPageModelService); - reportingPageModelService.$inject = ['$filter', 'piwikApi', 'reportingPagesModel', 'reportMetadataModel']; + reportingPageModelService.$inject = ['$filter', 'reportingPagesModel', 'reportMetadataModel']; - function reportingPageModelService ($filter, piwikApi, reportingPagesModel, reportMetadataModel) { + function reportingPageModelService ($filter, reportingPagesModel, reportMetadataModel) { var init = false; // those sites are going to be displayed diff --git a/plugins/CorePluginsAdmin/API.php b/plugins/CorePluginsAdmin/API.php new file mode 100644 index 0000000000000000000000000000000000000000..5ebd6dddbb029c5f6aa92b823170cb6653701e23 --- /dev/null +++ b/plugins/CorePluginsAdmin/API.php @@ -0,0 +1,109 @@ +<?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\Plugins\CorePluginsAdmin; +use Piwik\Piwik; +use Piwik\Plugin\SettingsProvider; +use Exception; + +/** + * API for plugin CorePluginsAdmin + * + * @method static \Piwik\Plugins\CorePluginsAdmin\API getInstance() + */ +class API extends \Piwik\Plugin\API +{ + /** + * @var SettingsMetadata + */ + private $settingsMetadata; + + /** + * @var SettingsProvider + */ + private $settingsProvider; + + public function __construct(SettingsProvider $settingsProvider, SettingsMetadata $settingsMetadata) + { + $this->settingsProvider = $settingsProvider; + $this->settingsMetadata = $settingsMetadata; + } + + /** + * @ignore + * @param array $settingValues Format: array('PluginName' => array(array('name' => 'SettingName1', 'value' => 'SettingValue1), ..)) + * @throws Exception + */ + public function setSystemSettings($settingValues) + { + Piwik::checkUserHasSuperUserAccess(); + + $pluginsSettings = $this->settingsProvider->getAllSystemSettings(); + + $this->settingsMetadata->setPluginSettings($pluginsSettings, $settingValues); + + try { + foreach ($pluginsSettings as $pluginSetting) { + $pluginSetting->save(); + } + } catch (Exception $e) { + throw new Exception(Piwik::translate('CoreAdminHome_PluginSettingsSaveFailed')); + } + } + + /** + * @ignore + * @param array $settingValues Format: array('PluginName' => array(array('name' => 'SettingName1', 'value' => 'SettingValue1), ..)) + * @throws Exception + */ + public function setUserSettings($settingValues) + { + Piwik::checkUserIsNotAnonymous(); + + $pluginsSettings = $this->settingsProvider->getAllUserSettings(); + + $this->settingsMetadata->setPluginSettings($pluginsSettings, $settingValues); + + try { + foreach ($pluginsSettings as $pluginSetting) { + $pluginSetting->save(); + } + } catch (Exception $e) { + throw new Exception(Piwik::translate('CoreAdminHome_PluginSettingsSaveFailed')); + } + } + + /** + * @ignore + * @return array + * @throws \Piwik\NoAccessException + */ + public function getSystemSettings() + { + Piwik::checkUserHasSuperUserAccess(); + + $systemSettings = $this->settingsProvider->getAllSystemSettings(); + + return $this->settingsMetadata->formatSettings($systemSettings); + } + + /** + * @ignore + * @return array + * @throws \Piwik\NoAccessException + */ + public function getUserSettings() + { + Piwik::checkUserIsNotAnonymous(); + + $userSettings = $this->settingsProvider->getAllUserSettings(); + + return $this->settingsMetadata->formatSettings($userSettings); + } + +} diff --git a/plugins/CorePluginsAdmin/Controller.php b/plugins/CorePluginsAdmin/Controller.php index f4e171c158bf2b01136807f81dbb6d67dde32113..4af63c245d1a5c3f9b654e0cdd5a36d4797b7769 100644 --- a/plugins/CorePluginsAdmin/Controller.php +++ b/plugins/CorePluginsAdmin/Controller.php @@ -18,7 +18,6 @@ use Piwik\Nonce; use Piwik\Notification; use Piwik\Piwik; use Piwik\Plugin; -use Piwik\Settings\Manager as SettingsManager; use Piwik\Translation\Translator; use Piwik\Url; use Piwik\Version; @@ -40,9 +39,15 @@ class Controller extends Plugin\ControllerAdmin */ private $translator; - public function __construct(Translator $translator) + /** + * @var Plugin\SettingsProvider + */ + private $settingsProvider; + + public function __construct(Translator $translator, Plugin\SettingsProvider $settingsProvider) { $this->translator = $translator; + $this->settingsProvider = $settingsProvider; parent::__construct(); } @@ -246,7 +251,7 @@ class Controller extends Plugin\ControllerAdmin $view->otherUsersCount = count($users) - 1; $view->themeEnabled = \Piwik\Plugin\Manager::getInstance()->getThemeEnabled()->getPluginName(); - $view->pluginNamesHavingSettings = $this->getPluginNamesHavingSettingsForCurrentUser(); + $view->pluginNamesHavingSettings = array_keys($this->settingsProvider->getAllSystemSettings()); $view->isMarketplaceEnabled = CorePluginsAdmin::isMarketplaceEnabled(); $view->isPluginsAdminEnabled = CorePluginsAdmin::isPluginsAdminEnabled(); @@ -427,9 +432,9 @@ class Controller extends Plugin\ControllerAdmin } $message = $this->translator->translate('CorePluginsAdmin_SuccessfullyActicated', array($pluginName)); - if (SettingsManager::hasSystemPluginSettingsForCurrentUser($pluginName)) { + if ($this->settingsProvider->getSystemSettings($pluginName)) { $target = sprintf('<a href="index.php%s#%s">', - Url::getCurrentQueryStringWithParametersModified(array('module' => 'CoreAdminHome', 'action' => 'adminPluginSettings')), + Url::getCurrentQueryStringWithParametersModified(array('module' => 'CoreAdminHome', 'action' => 'generalSettings')), $pluginName); $message .= ' ' . $this->translator->translate('CorePluginsAdmin_ChangeSettingsPossible', array($target, '</a>')); } @@ -502,11 +507,6 @@ class Controller extends Plugin\ControllerAdmin } } - private function getPluginNamesHavingSettingsForCurrentUser() - { - return SettingsManager::getPluginNamesHavingSystemSettings(); - } - private function tryToRepairPiwik() { // in case any opcaches etc were not cleared after an update for instance. Might prevent from getting the diff --git a/plugins/CorePluginsAdmin/CorePluginsAdmin.php b/plugins/CorePluginsAdmin/CorePluginsAdmin.php index 6e03b3b46aa8a6f610762e310467af854325ff24..dc550eead3fc7db571dbead03e2513de8bfee528 100644 --- a/plugins/CorePluginsAdmin/CorePluginsAdmin.php +++ b/plugins/CorePluginsAdmin/CorePluginsAdmin.php @@ -30,6 +30,7 @@ class CorePluginsAdmin extends \Piwik\Plugin $stylesheets[] = "plugins/CorePluginsAdmin/stylesheets/marketplace.less"; $stylesheets[] = "plugins/CorePluginsAdmin/stylesheets/plugins_admin.less"; $stylesheets[] = "plugins/CorePluginsAdmin/stylesheets/plugin-details.less"; + $stylesheets[] = "plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.less"; } public static function isMarketplaceEnabled() @@ -55,6 +56,10 @@ class CorePluginsAdmin extends \Piwik\Plugin public function getClientSideTranslationKeys(&$translations) { $translations[] = 'CorePluginsAdmin_NoZipFileSelected'; + $translations[] = 'CorePluginsAdmin_NoPluginSettings'; + $translations[] = 'CoreAdminHome_PluginSettingsIntro'; + $translations[] = 'CoreAdminHome_PluginSettingsSaveSuccess'; + $translations[] = 'General_Save'; } } diff --git a/plugins/CorePluginsAdmin/Menu.php b/plugins/CorePluginsAdmin/Menu.php index fe3be3d8416f30f9727d7f61f01f7e5920444506..8095870ac8c4e44e5f6a51d5a28c874f120fe03f 100644 --- a/plugins/CorePluginsAdmin/Menu.php +++ b/plugins/CorePluginsAdmin/Menu.php @@ -41,8 +41,8 @@ class Menu extends \Piwik\Plugin\Menu if ($hasSuperUserAcess) { $menu->addManageItem(Piwik::translate('General_Plugins') . $pluginsUpdateMessage, - $this->urlForAction('plugins', array('activated' => '')), - $order = 4); + $this->urlForAction('plugins', array('activated' => '')), + $order = 4); } if ($this->isAllowedToSeeMarketPlace()) { @@ -56,8 +56,6 @@ class Menu extends \Piwik\Plugin\Menu { $isAnonymous = Piwik::isUserIsAnonymous(); $isMarketplaceEnabled = CorePluginsAdmin::isMarketplaceEnabled(); - return $isMarketplaceEnabled && !$isAnonymous; } - } diff --git a/plugins/CorePluginsAdmin/SettingsMetadata.php b/plugins/CorePluginsAdmin/SettingsMetadata.php new file mode 100644 index 0000000000000000000000000000000000000000..fa62d12b1124bd69a7ab80f68e9efdda949865a0 --- /dev/null +++ b/plugins/CorePluginsAdmin/SettingsMetadata.php @@ -0,0 +1,127 @@ +<?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\Plugins\CorePluginsAdmin; + +use Piwik\Common; +use Piwik\Piwik; +use Piwik\Settings\Setting; +use Piwik\Settings\Settings; +use Exception; + +class SettingsMetadata +{ + + /** + * @param Settings[] $settingsInstances + * @param array $settingValues array('pluginName' => array('settingName' => 'settingValue')) + * @throws Exception; + */ + public function setPluginSettings($settingsInstances, $settingValues) + { + try { + foreach ($settingsInstances as $pluginName => $pluginSetting) { + foreach ($pluginSetting->getSettingsWritableByCurrentUser() as $setting) { + + $value = $this->findSettingValueFromRequest($settingValues, $pluginName, $setting->getName()); + + if (isset($value)) { + $setting->setValue($value); + } + } + } + + } catch (Exception $e) { + $message = $e->getMessage(); + + if (!empty($setting)) { + $title = Piwik::translate(strip_tags($setting->configureField()->title)); + throw new Exception($title . ': ' . $message); + } + } + } + + private function findSettingValueFromRequest($settingValues, $pluginName, $settingName) + { + if (!array_key_exists($pluginName, $settingValues)) { + return; + } + + foreach ($settingValues[$pluginName] as $setting) { + if ($setting['name'] === $settingName) { + $value = null; + if (array_key_exists('value', $setting)) { + $value = $setting['value']; + } + + if (is_string($value)) { + return Common::unsanitizeInputValue($value); + } + + return $value; + } + } + } + + + /** + * @param Settings[] $allSettings A list of Settings instead by pluginname + * @return array + */ + public function formatSettings($allSettings) + { + $metadata = array(); + foreach ($allSettings as $pluginName => $settings) { + $writableSettings = $settings->getSettingsWritableByCurrentUser(); + + if (empty($writableSettings)) { + continue; + } + + $plugin = array( + 'pluginName' => $pluginName, + 'settings' => array() + ); + + foreach ($writableSettings as $writableSetting) { + $plugin['settings'][] = $this->formatMetadata($writableSetting); + } + + $metadata[] = $plugin; + } + + return $metadata; + } + + private function formatMetadata(Setting $setting) + { + $config = $setting->configureField(); + + $availableValues = $config->availableValues; + + if (is_array($availableValues)) { + $availableValues = (object) $availableValues; + } + + return array( + 'name' => $setting->getName(), + 'title' => $config->title, + 'value' => $setting->getValue(), + 'defaultValue' => $setting->getDefaultValue(), + 'type' => $setting->getType(), + 'uiControl' => $config->uiControl, + 'uiControlAttributes' => $config->uiControlAttributes, + 'availableValues' => $availableValues, + 'description' => $config->description, + 'inlineHelp' => $config->inlineHelp, + 'introduction' => $config->introduction, + 'condition' => $config->condition, + ); + } + +} \ No newline at end of file diff --git a/plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.html b/plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.html new file mode 100644 index 0000000000000000000000000000000000000000..3a3cf49605006fb3889aec7089430e6f4b3c1ace --- /dev/null +++ b/plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.html @@ -0,0 +1,89 @@ +<div class="form-group" ng-show="formField.showField"> + <p ng-if="formField.introduction" class="settingIntroduction">{{ formField.introduction }}</p> + + <label ng-if="formField.uiControl != 'checkbox'" ng-bind-html="formField.title"></label> + + <div class="form-help" ng-show="formField.inlineHelp"> + <span ng-bind-html="formField.inlineHelp"></span> + + <span ng-show="formField.defaultValue && formField.uiControl != 'checkbox' && formField.uiControl != 'radio'"> + <br /> + {{ 'General_Default'|translate }}: + <span>{{formField.defaultValue|limitTo:50}}</span> + </span> + </div> + + <select ng-if="formField.uiControl == 'select'" + name="{{ formField.name }}" + ng-model="formField.value" + ng-options="t.key as t.value group by t.group for t in formField.availableValues" + piwik-attributes="{{formField.uiControlAttributes}}"> + </select> + + <select ng-if="formField.uiControl == 'multiselect'" + multiple + name="{{ formField.name }}" + ng-model="formField.value" + ng-options="t.key as t.value for t in formField.availableValues" + piwik-attributes="{{formField.uiControlAttributes}}"> + </select> + + <textarea ng-if="formField.uiControl == 'textarea' && formField.type !== 'array'" + name="{{ formField.name }}" + piwik-attributes="{{formField.uiControlAttributes}}" + ng-model="formField.value" + ></textarea> + + <textarea ng-if="formField.uiControl == 'textarea' && formField.type === 'array'" + name="{{ formField.name }}" + ng-list=" " ng-trim="false" + piwik-attributes="{{formField.uiControlAttributes}}" + ng-model="formField.value" + ></textarea> + + <label ng-if="formField.uiControl == 'radio'" + ng-repeat="(key,value) in formField.availableValues" + class="radio"> + <input ng-model="formField.value" + ng-value="key" + type="radio" + name="{{ formField.name }}" + piwik-attributes="{{formField.uiControlAttributes}}" + > + {{ value }} + <span ng-show="formField.description" class='form-description'>{{ formField.description }}</span> + </label> + + <label ng-if="formField.uiControl == 'checkbox'" class="checkbox"> + <input ng-model="formField.value" + piwik-attributes="{{formField.uiControlAttributes}}" + ng-value="1" + type="checkbox" + name="{{ formField.name }}"> + + <span ng-bind-html="formField.title"></span> + + <span ng-show="formField.description" class='form-description'>{{ formField.description }}</span> + </label> + + <input ng-if="(formField.uiControl == 'text' || formField.uiControl == 'password') && formField.type !== 'array'" + class="control_{{ formField.uiControl }}" + type="{{ formField.uiControl }}" + name="{{ formField.name }}" + ng-model="formField.value" + piwik-attributes="{{formField.uiControlAttributes}}" + > + + <input ng-if="(formField.uiControl == 'text' || formField.uiControl == 'password') && formField.type === 'array'" + class="control_{{ formField.uiControl }}" + type="{{ formField.uiControl }}" + name="{{ formField.name }}" + ng-list + ng-model="formField.value" + piwik-attributes="{{formField.uiControlAttributes}}" + > + + <span ng-show="formField.uiControl != 'checkbox' && formField.uiControl != 'radio'" + class='form-description'>{{ formField.description }}</span> + +</div> \ No newline at end of file diff --git a/plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.js b/plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.js new file mode 100644 index 0000000000000000000000000000000000000000..b46067bf9d2c4905c342ae65d39f3d78c0c5e1b9 --- /dev/null +++ b/plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.js @@ -0,0 +1,128 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Usage: + * <div piwik-form-field="{...}"> + */ +(function () { + angular.module('piwikApp').directive('piwikFormField', piwikFormField); + + piwikFormField.$inject = ['piwik']; + + function piwikFormField(piwik){ + + return { + restrict: 'A', + scope: { + piwikFormField: '=', + allSettings: '=' + }, + templateUrl: 'plugins/CorePluginsAdmin/angularjs/form-field/form-field.directive.html?cb=' + piwik.cacheBuster, + compile: function (element, attrs) { + + function evaluateConditionalExpression(scope, field) + { + if (!field.condition) { + return; + } + + var values = {}; + angular.forEach(scope.allSettings, function (setting) { + if (setting.value === '0') { + values[setting.name] = 0; + } else { + values[setting.name] = setting.value; + } + }); + + field.showField = scope.$eval(field.condition, values); + } + + function hasUiControl(field, uiControlType) + { + return field.uiControl === uiControlType; + } + + function isSelectControl(field) + { + return hasUiControl(field, 'select') || hasUiControl(field, 'multiselect'); + } + + function hasGroupedValues(availableValues) + { + if (!angular.isObject(availableValues) + || angular.isArray(availableValues)) { + return false; + } + + var key; + for (key in availableValues) { + if (Object.prototype.hasOwnProperty.call(availableValues, key)) { + if (angular.isObject(availableValues[key])) { + return true; + } else { + return false; + } + } + } + + return false; + } + + return function (scope, element, attrs) { + var field = scope.piwikFormField; + + if (angular.isArray(field.defaultValue)) { + field.defaultValue = field.defaultValue.join(','); + } + + if (isSelectControl(field) && field.availableValues) { + var availableValues = field.availableValues; + + if (!hasGroupedValues(availableValues)) { + availableValues = {'': availableValues}; + } + + var flatValues = []; + angular.forEach(availableValues, function (values, group) { + angular.forEach(values, function (value, key) { + + if (field.type === 'integer' && angular.isString(key)) { + key = parseInt(key, 10); + } + + flatValues.push({group: group, key: key, value: value}); + }); + }); + + field.availableValues = flatValues; + } + + field.showField = true; + + if (field.condition && scope.allSettings) { + evaluateConditionalExpression(scope, field); + + for (var key in scope.allSettings) { + if(scope.allSettings.hasOwnProperty(key)) { + scope.$watchCollection('allSettings[' + key + '].value', function (val, oldVal) { + if (val !== oldVal) { + evaluateConditionalExpression(scope, field); + } + }); + } + } + + } + + scope.formField = field; + }; + } + }; + } +})(); \ No newline at end of file diff --git a/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.controller.js b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.controller.js new file mode 100644 index 0000000000000000000000000000000000000000..bbe3c02eb056fbfb2ebe92b27c28b36591d68eee --- /dev/null +++ b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.controller.js @@ -0,0 +1,72 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').controller('PluginSettingsController', PluginSettingsController); + + PluginSettingsController.$inject = ['$scope', 'piwikApi']; + + function PluginSettingsController($scope, piwikApi) { + // remember to keep controller very simple. Create a service/factory (model) if needed + + var self = this; + + this.isLoading = true; + + var apiMethod = 'CorePluginsAdmin.getUserSettings'; + + if ($scope.mode === 'admin') { + apiMethod = 'CorePluginsAdmin.getSystemSettings'; + } + + piwikApi.fetch({method: apiMethod}).then(function (settings) { + self.isLoading = false; + self.settingsPerPlugin = settings; + }, function () { + self.isLoading = false; + }); + + this.save = function () { + var apiMethod = 'CorePluginsAdmin.setUserSettings'; + if ($scope.mode === 'admin') { + apiMethod = 'CorePluginsAdmin.setSystemSettings'; + } + + this.isLoading = true; + + var values = {}; + angular.forEach(this.settingsPerPlugin, function (settings) { + if (!values[settings.pluginName]) { + values[settings.pluginName] = []; + } + + angular.forEach(settings.settings, function (setting) { + var value = setting.value; + if (value === false) { + value = '0'; + } else if (value === true) { + value = '1'; + } + values[settings.pluginName].push({ + name: setting.name, + value: value + }); + }); + }); + + piwikApi.post({method: apiMethod}, {settingValues: values}).then(function (success) { + self.isLoading = false; + + var UI = require('piwik/UI'); + var notification = new UI.Notification(); + notification.show(_pk_translate('CoreAdminHome_PluginSettingsSaveSuccess'), {context: 'success'}); + + }, function () { + self.isLoading = false; + }); + }; + } +})(); \ No newline at end of file diff --git a/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.html b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.html new file mode 100644 index 0000000000000000000000000000000000000000..3748c3d458d236ac2ee1ccea9a08caa79051856c --- /dev/null +++ b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.html @@ -0,0 +1,31 @@ +<div class="pluginSettings"> + + <p> + {{ 'CoreAdminHome_PluginSettingsIntro'|translate }} + + <span ng-repeat="settings in pluginSettings.settingsPerPlugin"> + <a href="#{{ settings.pluginName }}">{{ settings.pluginName }}</a><span ng-hide="$last">, </span> + </span> + </p> + + <p ng-if="!pluginSettings.isLoading && pluginSettings.settingsPerPlugin.length === 0"> + {{ 'CorePluginsAdmin_NoPluginSettings'|translate }} + </p> + + <div piwik-activity-indicator loading="pluginSettings.isLoading"></div> + + <div ng-repeat="settings in pluginSettings.settingsPerPlugin" + id="pluginSettings"> + + <h2 id="{{ settings.pluginName }}" class="secondary">{{ settings.pluginName }}</h2> + + <div ng-repeat="setting in settings.settings"> + <div piwik-form-field="setting" all-settings="settings.settings"></div> + </div> + </div> + + <input type="button" ng-click="pluginSettings.save()" + value="{{ 'General_Save'|translate }}" + class="pluginsSettingsSubmit submit"/> + +</div> \ No newline at end of file diff --git a/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.js b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.js new file mode 100644 index 0000000000000000000000000000000000000000..927868325fdf5e0bdb3da3fcc779b9761e80291a --- /dev/null +++ b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.js @@ -0,0 +1,44 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Usage: + * <div piwik-plugin-settings> + */ +(function () { + angular.module('piwikApp').directive('piwikPluginSettings', piwikPluginSettings); + + piwikPluginSettings.$inject = ['piwik']; + + function piwikPluginSettings(piwik){ + var defaults = { + mode: '' + }; + + return { + restrict: 'A', + scope: { + mode: '@' + }, + templateUrl: 'plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.html?cb=' + piwik.cacheBuster, + controller: 'PluginSettingsController', + controllerAs: 'pluginSettings', + compile: function (element, attrs) { + + for (var index in defaults) { + if (defaults.hasOwnProperty(index) && attrs[index] === undefined) { + attrs[index] = defaults[index]; + } + } + + return function (scope, element, attrs) { + + }; + } + }; + } +})(); \ No newline at end of file diff --git a/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.less b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.less new file mode 100644 index 0000000000000000000000000000000000000000..cd747097ed7f318112920d05507dd893e15dd0b1 --- /dev/null +++ b/plugins/CorePluginsAdmin/angularjs/plugin-settings/plugin-settings.directive.less @@ -0,0 +1,6 @@ +.pluginSettings { + textarea { + width: 376px; + height: 250px; + } +} \ No newline at end of file diff --git a/plugins/CorePluginsAdmin/lang/en.json b/plugins/CorePluginsAdmin/lang/en.json index d3b5a1d6856d0f92503653914900a7be3634b123..10aa1f8f0021fee9e59da67bc50149b5be2b6ae9 100644 --- a/plugins/CorePluginsAdmin/lang/en.json +++ b/plugins/CorePluginsAdmin/lang/en.json @@ -51,6 +51,7 @@ "MissingRequirementsPleaseInstallNotice": "Please install %1$s %2$s as it is required by %3$s.", "NewVersion": "new version", "NoPluginsFound": "No plugins found", + "NoPluginSettings": "No plugin settings that can be configured", "NotAllowedToBrowseMarketplacePlugins": "You can browse the list of plugins that can be installed to customize or extend your Piwik platform. Please contact your administrator if you need any of these installed.", "NotAllowedToBrowseMarketplaceThemes": "You can browse the list of themes that can be installed to customize the appearance of the Piwik platform. Please contact your administrator to get any of these installed for you.", "NoThemesFound": "No themes found", diff --git a/plugins/CorePluginsAdmin/templates/macros.twig b/plugins/CorePluginsAdmin/templates/macros.twig index f0b66123e5fb6be6289cd75d495905764206774d..c64500c518976cd9fa6504b44869e96cca751ff5 100644 --- a/plugins/CorePluginsAdmin/templates/macros.twig +++ b/plugins/CorePluginsAdmin/templates/macros.twig @@ -166,7 +166,7 @@ {% if name in pluginNamesHavingSettings %} <br /><br /> - <a href="{{ linkTo({'module':'CoreAdminHome', 'action': 'adminPluginSettings'}) }}#{{ name|e('html_attr') }}" class="settingsLink">{{ 'General_Settings'|translate }}</a> + <a href="{{ linkTo({'module':'CoreAdminHome', 'action': 'generalSettings'}) }}#{{ name|e('html_attr') }}" class="settingsLink">{{ 'General_Settings'|translate }}</a> {% endif %} </td> <td class="desc"> diff --git a/plugins/CustomAlerts b/plugins/CustomAlerts index dd33d73ee4117d3c3e7f342e135e8fcd1da8dba3..1282ff93f053af06d84661af2b6e4ce5e8ffbe05 160000 --- a/plugins/CustomAlerts +++ b/plugins/CustomAlerts @@ -1 +1 @@ -Subproject commit dd33d73ee4117d3c3e7f342e135e8fcd1da8dba3 +Subproject commit 1282ff93f053af06d84661af2b6e4ce5e8ffbe05 diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions index d18b214313b8fde350f7092659af3e92de5a11a0..072bd2b3d901c0dc45b43683dd3385686d61900a 160000 --- a/plugins/CustomDimensions +++ b/plugins/CustomDimensions @@ -1 +1 @@ -Subproject commit d18b214313b8fde350f7092659af3e92de5a11a0 +Subproject commit 072bd2b3d901c0dc45b43683dd3385686d61900a diff --git a/plugins/DBStats/Reports/GetMetricDataSummary.php b/plugins/DBStats/Reports/GetMetricDataSummary.php index 94735c4e033ea5a260463cc6e0f88eb56bd4659c..34b773531d82ea8b39f97e4d5d9db59041c67dfa 100644 --- a/plugins/DBStats/Reports/GetMetricDataSummary.php +++ b/plugins/DBStats/Reports/GetMetricDataSummary.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * Shows a datatable that displays the amount of space each numeric archive table @@ -35,7 +35,7 @@ class GetMetricDataSummary extends Base public function getRelatedReports() { return array( - Reports::factory('DBStats', 'getMetricDataSummaryByYear'), + ReportsProvider::factory('DBStats', 'getMetricDataSummaryByYear'), ); } diff --git a/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php b/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php index 81b89d5d99f006e38e4b845ea3b311cde9a56d2e..55bc6f90e2e70d1f63bdbca40a7e27e41ef63da6 100644 --- a/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php +++ b/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * Shows a datatable that displays the amount of space each numeric archive table @@ -36,7 +36,7 @@ class GetMetricDataSummaryByYear extends Base public function getRelatedReports() { return array( - Reports::factory('DBStats', 'getMetricDataSummary'), + ReportsProvider::factory('DBStats', 'getMetricDataSummary'), ); } diff --git a/plugins/DBStats/Reports/GetReportDataSummary.php b/plugins/DBStats/Reports/GetReportDataSummary.php index 58c1b065c5f90ef22d3cc8cd8713fce90c0cfb50..781b3988b99240f71b77266552641fba93608d21 100644 --- a/plugins/DBStats/Reports/GetReportDataSummary.php +++ b/plugins/DBStats/Reports/GetReportDataSummary.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * Shows a datatable that displays the amount of space each blob archive table @@ -35,7 +35,7 @@ class GetReportDataSummary extends Base public function getRelatedReports() { return array( - Reports::factory('DBStats', 'getReportDataSummaryByYear'), + ReportsProvider::factory('DBStats', 'getReportDataSummaryByYear'), ); } } diff --git a/plugins/DBStats/Reports/GetReportDataSummaryByYear.php b/plugins/DBStats/Reports/GetReportDataSummaryByYear.php index 7ff78a638bc90747cd32bd66379c739302147547..228d4281b016fe12de598bbb41f4d6a9903fd719 100644 --- a/plugins/DBStats/Reports/GetReportDataSummaryByYear.php +++ b/plugins/DBStats/Reports/GetReportDataSummaryByYear.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; /** * Shows a datatable that displays the amount of space each blob archive table @@ -36,7 +36,7 @@ class GetReportDataSummaryByYear extends Base public function getRelatedReports() { return array( - Reports::factory('DBStats', 'getReportDataSummary'), + ReportsProvider::factory('DBStats', 'getReportDataSummary'), ); } diff --git a/plugins/DevicesDetection/Reports/GetBrowserVersions.php b/plugins/DevicesDetection/Reports/GetBrowserVersions.php index 66c7f91f552486832ed27b4c7f5cc19977b9d07b..0c71c602f2c925507b8d8cf017779deaec5be190 100644 --- a/plugins/DevicesDetection/Reports/GetBrowserVersions.php +++ b/plugins/DevicesDetection/Reports/GetBrowserVersions.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\BrowserVersion; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetBrowserVersions extends Base { @@ -36,7 +36,7 @@ class GetBrowserVersions extends Base public function getRelatedReports() { return array( - Reports::factory('DevicesDetection', 'getBrowsers'), + ReportsProvider::factory('DevicesDetection', 'getBrowsers'), ); } } diff --git a/plugins/DevicesDetection/Reports/GetBrowsers.php b/plugins/DevicesDetection/Reports/GetBrowsers.php index 5c39a275eeea696f8028a8509324778583d23b21..b1a2f936d0a7df15cf00aade749b3718081ad5f9 100644 --- a/plugins/DevicesDetection/Reports/GetBrowsers.php +++ b/plugins/DevicesDetection/Reports/GetBrowsers.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\BrowserName; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetBrowsers extends Base { @@ -37,7 +37,7 @@ class GetBrowsers extends Base public function getRelatedReports() { return array( - Reports::factory('DevicesDetection', 'getBrowserVersions'), + ReportsProvider::factory('DevicesDetection', 'getBrowserVersions'), ); } } diff --git a/plugins/DevicesDetection/Reports/GetOsFamilies.php b/plugins/DevicesDetection/Reports/GetOsFamilies.php index a283a83f7b4473f43378e4516cf97f81a094a9e6..ef0d056b9a7727392b1aeaef1f0a9becbd28ea1b 100644 --- a/plugins/DevicesDetection/Reports/GetOsFamilies.php +++ b/plugins/DevicesDetection/Reports/GetOsFamilies.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\Os; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetOsFamilies extends Base { @@ -37,7 +37,7 @@ class GetOsFamilies extends Base public function getRelatedReports() { return array( - Reports::factory('DevicesDetection', 'getOsVersions'), + ReportsProvider::factory('DevicesDetection', 'getOsVersions'), ); } diff --git a/plugins/DevicesDetection/Reports/GetOsVersions.php b/plugins/DevicesDetection/Reports/GetOsVersions.php index b330054c6f89407adbda6aba78a5a2eba18f1cbf..c100b2e39faf5c0bc17c6e8718463740101e163c 100644 --- a/plugins/DevicesDetection/Reports/GetOsVersions.php +++ b/plugins/DevicesDetection/Reports/GetOsVersions.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\OsVersion; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetOsVersions extends Base { @@ -37,7 +37,7 @@ class GetOsVersions extends Base public function getRelatedReports() { return array( - Reports::factory('DevicesDetection', 'getOsFamilies'), + ReportsProvider::factory('DevicesDetection', 'getOsFamilies'), ); } } diff --git a/plugins/Diagnostics/ConfigReader.php b/plugins/Diagnostics/ConfigReader.php index 7d0c90938d78dcc2860d388180dbcff8cab766c2..d1f57be422f673be9529d4880aafa2188520bbba 100644 --- a/plugins/Diagnostics/ConfigReader.php +++ b/plugins/Diagnostics/ConfigReader.php @@ -136,12 +136,12 @@ class ConfigReader * for already existing configured config values that overwrite a plugin system setting. * * @param array $configValues - * @param \Piwik\Plugin\Settings[] $pluginSettings + * @param \Piwik\Settings\Plugin\SystemSettings[] $systemSettings * @return array */ - public function addConfigValuesFromPluginSettings($configValues, $pluginSettings) + public function addConfigValuesFromSystemSettings($configValues, $systemSettings) { - foreach ($pluginSettings as $pluginSetting) { + foreach ($systemSettings as $pluginSetting) { $pluginName = $pluginSetting->getPluginName(); if (empty($pluginName)) { @@ -150,36 +150,34 @@ class ConfigReader $configs[$pluginName] = array(); - foreach ($pluginSetting->getSettings() as $setting) { - if ($setting instanceof PiwikSettings\SystemSetting && $setting->isReadableByCurrentUser()) { - $name = $setting->getName(); + foreach ($pluginSetting->getSettingsWritableByCurrentUser() as $setting) { + $name = $setting->getName(); + $config = $setting->configureField(); - $description = ''; - if (!empty($setting->description)) { - $description .= $setting->description . ' '; - } + $description = ''; + if (!empty($config->description)) { + $description .= $config->description . ' '; + } - if (!empty($setting->inlineHelp)) { - $description .= $setting->inlineHelp; - } + if (!empty($config->inlineHelp)) { + $description .= $config->inlineHelp; + } + + if (isset($configValues[$pluginName][$name])) { + $configValues[$pluginName][$name]['defaultValue'] = $setting->getDefaultValue(); + $configValues[$pluginName][$name]['description'] = trim($description); - if (isset($configValues[$pluginName][$name])) { - $configValues[$pluginName][$name]['defaultValue'] = $setting->defaultValue; - $configValues[$pluginName][$name]['description'] = trim($description); - - if ($setting->uiControlType === PluginSettings::CONTROL_PASSWORD) { - $value = $configValues[$pluginName][$name]['value']; - $configValues[$pluginName][$name]['value'] = $this->getMaskedPassword(); - } - } else { - $defaultValue = $setting->getValue(); - $configValues[$pluginName][$name] = array( - 'value' => null, - 'description' => trim($description), - 'isCustomValue' => false, - 'defaultValue' => $defaultValue - ); + if ($config->uiControl === PiwikSettings\FieldConfig::UI_CONTROL_PASSWORD) { + $configValues[$pluginName][$name]['value'] = $this->getMaskedPassword(); } + } else { + $defaultValue = $setting->getValue(); + $configValues[$pluginName][$name] = array( + 'value' => null, + 'description' => trim($description), + 'isCustomValue' => false, + 'defaultValue' => $defaultValue + ); } } diff --git a/plugins/Diagnostics/Controller.php b/plugins/Diagnostics/Controller.php index 7d2341a1958eb4b0f3d5455ed13856b2b22822aa..a350ff47a3c4f9c902f087c10db2584f9f04e379 100644 --- a/plugins/Diagnostics/Controller.php +++ b/plugins/Diagnostics/Controller.php @@ -10,6 +10,7 @@ namespace Piwik\Plugins\Diagnostics; use Piwik\Config; use Piwik\Piwik; +use Piwik\Plugin\SettingsProvider; use Piwik\View; use Piwik\Settings; @@ -30,10 +31,11 @@ class Controller extends \Piwik\Plugin\ControllerAdmin { Piwik::checkUserHasSuperUserAccess(); - $allSettings = Settings\Manager::getAllPluginSettings(); + $settings = new SettingsProvider(\Piwik\Plugin\Manager::getInstance()); + $allSettings = $settings->getAllSystemSettings(); $configValues = $this->configReader->getConfigValuesFromFiles(); - $configValues = $this->configReader->addConfigValuesFromPluginSettings($configValues, $allSettings); + $configValues = $this->configReader->addConfigValuesFromSystemSettings($configValues, $allSettings); $configValues = $this->sortConfigValues($configValues); return $this->renderTemplate('configfile', array( diff --git a/plugins/Diagnostics/Test/Integration/ConfigReaderTest.php b/plugins/Diagnostics/Test/Integration/ConfigReaderTest.php index bb05cb61e7bc2e4b980f51dca7d22d0b64d6c27c..6634c4a38a36341f940bd29bc11ffb7b33499735 100644 --- a/plugins/Diagnostics/Test/Integration/ConfigReaderTest.php +++ b/plugins/Diagnostics/Test/Integration/ConfigReaderTest.php @@ -10,9 +10,12 @@ namespace Piwik\Plugins\Diagnostics\Test\Integration\Commands; use Piwik\Application\Kernel\GlobalSettingsProvider; use Piwik\Ini\IniReader; +use Piwik\Piwik; use Piwik\Plugins\Diagnostics\ConfigReader; -use Piwik\Plugins\ExampleSettingsPlugin\Settings; +use Piwik\Plugins\ExampleSettingsPlugin\SystemSettings; +use Piwik\Settings\FieldConfig; use Piwik\Tests\Fixtures\OneVisitorTwoVisits; +use Piwik\Tests\Framework\Mock\FakeAccess; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; /** @@ -29,8 +32,12 @@ class ConfigReaderTest extends IntegrationTestCase public function setUp() { + parent::setUp(); + $settings = new GlobalSettingsProvider($this->configPath('global.ini.php'), $this->configPath('config.ini.php'), $this->configPath('common.config.ini.php')); $this->configReader = new ConfigReader($settings, new IniReader()); + + FakeAccess::clearAccess($superUser = true); } public function test_getConfigValuesFromFiles() @@ -160,9 +167,9 @@ with multiple lines', public function test_addConfigValuesFromPluginSettings() { - $settings = new Settings(); + $settings = new SystemSettings(); - $configValues = $this->configReader->addConfigValuesFromPluginSettings(array(), array($settings)); + $configValues = $this->configReader->addConfigValuesFromSystemSettings(array(), array($settings)); $expected = array ( 'ExampleSettingsPlugin' => @@ -208,7 +215,7 @@ Another line', public function test_addConfigValuesFromPluginSettings_shouldAddDescriptionAndDefaultValueForExistingConfigValues() { - $settings = new Settings(); + $settings = new SystemSettings(); $existing = array( 'ExampleSettingsPlugin' => @@ -223,7 +230,7 @@ Another line', ) ); - $configValues = $this->configReader->addConfigValuesFromPluginSettings($existing, array($settings)); + $configValues = $this->configReader->addConfigValuesFromSystemSettings($existing, array($settings)); $this->assertSame('Choose the metric that should be displayed in the browser tab', $configValues['ExampleSettingsPlugin']['metric']['description']); $this->assertSame('nb_visits', $configValues['ExampleSettingsPlugin']['metric']['defaultValue']); @@ -231,8 +238,8 @@ Another line', public function test_addConfigValuesFromPluginSettings_shouldMaskValueIfTypeIsPassword() { - $settings = new Settings(); - $settings->metric->uiControlType = Settings::CONTROL_PASSWORD; + $settings = new SystemSettings(); + $settings->metric->configureField()->uiControl = FieldConfig::UI_CONTROL_PASSWORD; $existing = array( 'ExampleSettingsPlugin' => @@ -247,11 +254,18 @@ Another line', ) ); - $configValues = $this->configReader->addConfigValuesFromPluginSettings($existing, array($settings)); + $configValues = $this->configReader->addConfigValuesFromSystemSettings($existing, array($settings)); $this->assertSame('******', $configValues['ExampleSettingsPlugin']['metric']['value']); } + public function provideContainerConfig() + { + return array( + 'Piwik\Access' => new FakeAccess(), + ); + } + private function configPath($file) { return PIWIK_INCLUDE_PATH . '/tests/resources/Config/' . $file; diff --git a/plugins/Events/Events.php b/plugins/Events/Events.php index 15c49e87f1f8c6eea6edfedf5f7a7d02fafc6cc7..8ae0f5cb2ece21ed5606643bfed342d45531b81a 100644 --- a/plugins/Events/Events.php +++ b/plugins/Events/Events.php @@ -13,7 +13,7 @@ use Piwik\DataTable; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugin\ViewDataTable; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable\AllColumns; class Events extends \Piwik\Plugin @@ -180,7 +180,7 @@ class Events extends \Piwik\Plugin $this->addRelatedReports($view, $secondaryDimension); $this->addTooltipEventValue($view); - $subtableReport = Reports::factory('Events', $view->config->subtable_controller_action); + $subtableReport = ReportsProvider::factory('Events', $view->config->subtable_controller_action); $view->config->pivot_by_dimension = $subtableReport->getDimension()->getId(); $view->config->pivot_by_column = 'nb_events'; } diff --git a/plugins/ExampleSettingsPlugin/MeasurableSettings.php b/plugins/ExampleSettingsPlugin/MeasurableSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..be1879750b9b277027f1a2cf72f07b2e1146f56a --- /dev/null +++ b/plugins/ExampleSettingsPlugin/MeasurableSettings.php @@ -0,0 +1,65 @@ +<?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\Plugins\ExampleSettingsPlugin; + +use Piwik\Plugins\MobileAppMeasurable\Type as MobileAppType; +use Piwik\Settings\Setting; +use Piwik\Settings\FieldConfig; + +/** + * Defines Settings for ExampleSettingsPlugin. + * + * Usage like this: + * // require Piwik\Plugin\SettingsProvider via Dependency Injection eg in constructor of your class + * $settings = $settingsProvider->getMeasurableSettings('ExampleSettingsPlugin', $idSite); + * $settings->appId->getValue(); + * $settings->contactEmails->getValue(); + */ +class MeasurableSettings extends \Piwik\Settings\Measurable\MeasurableSettings +{ + /** @var Setting|null */ + public $appId; + + /** @var Setting */ + public $contactEmails; + + protected function init() + { + if ($this->hasMeasurableType(MobileAppType::ID)) { + // this setting will be only shown for mobile apps + $this->appId = $this->makeAppIdSetting(); + } + + $this->contactEmails = $this->makeContactEmailsSetting(); + } + + private function makeAppIdSetting() + { + $defaultValue = ''; + $type = FieldConfig::TYPE_STRING; + + return $this->makeSetting('mobile_app_id', $defaultValue, $type, function (FieldConfig $field) { + $field->title = 'App ID'; + $field->inlineHelp = 'Enter the id of the mobile app eg "org.domain.example"'; + $field->uiControl = FieldConfig::UI_CONTROL_TEXT; + }); + } + + private function makeContactEmailsSetting() + { + $defaultValue = array(); + $type = FieldConfig::TYPE_ARRAY; + + return $this->makeSetting('contact_email', $defaultValue, $type, function (FieldConfig $field) { + $field->title = 'Contact email addresses'; + $field->uiControl = FieldConfig::UI_CONTROL_TEXTAREA; + }); + } + +} diff --git a/plugins/ExampleSettingsPlugin/Settings.php b/plugins/ExampleSettingsPlugin/Settings.php deleted file mode 100644 index 1b110d2871fabd01f1207cfd40e7e0c114a8f3bc..0000000000000000000000000000000000000000 --- a/plugins/ExampleSettingsPlugin/Settings.php +++ /dev/null @@ -1,160 +0,0 @@ -<?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\Plugins\ExampleSettingsPlugin; - -use Piwik\Settings\SystemSetting; -use Piwik\Settings\UserSetting; - -/** - * Defines Settings for ExampleSettingsPlugin. - * - * Usage like this: - * $settings = new Settings('ExampleSettingsPlugin'); - * $settings->autoRefresh->getValue(); - * $settings->metric->getValue(); - */ -class Settings extends \Piwik\Plugin\Settings -{ - /** @var UserSetting */ - public $autoRefresh; - - /** @var UserSetting */ - public $refreshInterval; - - /** @var UserSetting */ - public $color; - - /** @var SystemSetting */ - public $metric; - - /** @var SystemSetting */ - public $browsers; - - /** @var SystemSetting */ - public $description; - - /** @var SystemSetting */ - public $password; - - protected function init() - { - $this->setIntroduction('Here you can specify the settings for this plugin.'); - - // User setting --> checkbox converted to bool - $this->createAutoRefreshSetting(); - - // User setting --> textbox converted to int defining a validator and filter - $this->createRefreshIntervalSetting(); - - // User setting --> radio - $this->createColorSetting(); - - // System setting --> allows selection of a single value - $this->createMetricSetting(); - - // System setting --> allows selection of multiple values - $this->createBrowsersSetting(); - - // System setting --> textarea - $this->createDescriptionSetting(); - - // System setting --> textarea - $this->createPasswordSetting(); - } - - private function createAutoRefreshSetting() - { - $this->autoRefresh = new UserSetting('autoRefresh', 'Auto refresh'); - $this->autoRefresh->type = static::TYPE_BOOL; - $this->autoRefresh->uiControlType = static::CONTROL_CHECKBOX; - $this->autoRefresh->description = 'If enabled, the value will be automatically refreshed depending on the specified interval'; - $this->autoRefresh->defaultValue = false; - - $this->addSetting($this->autoRefresh); - } - - private function createRefreshIntervalSetting() - { - $this->refreshInterval = new UserSetting('refreshInterval', 'Refresh Interval'); - $this->refreshInterval->type = static::TYPE_INT; - $this->refreshInterval->uiControlType = static::CONTROL_TEXT; - $this->refreshInterval->uiControlAttributes = array('size' => 3); - $this->refreshInterval->description = 'Defines how often the value should be updated'; - $this->refreshInterval->inlineHelp = 'Enter a number which is >= 15'; - $this->refreshInterval->defaultValue = '30'; - $this->refreshInterval->validate = function ($value, $setting) { - if ($value < 15) { - throw new \Exception('Value is invalid'); - } - }; - - $this->addSetting($this->refreshInterval); - } - - private function createColorSetting() - { - $this->color = new UserSetting('color', 'Color'); - $this->color->uiControlType = static::CONTROL_RADIO; - $this->color->description = 'Pick your favourite color'; - $this->color->availableValues = array('red' => 'Red', 'blue' => 'Blue', 'green' => 'Green'); - - $this->addSetting($this->color); - } - - private function createMetricSetting() - { - $this->metric = new SystemSetting('metric', 'Metric to display'); - $this->metric->type = static::TYPE_STRING; - $this->metric->uiControlType = static::CONTROL_SINGLE_SELECT; - $this->metric->availableValues = array('nb_visits' => 'Visits', 'nb_actions' => 'Actions', 'visitors' => 'Visitors'); - $this->metric->introduction = 'Only Super Users can change the following settings:'; - $this->metric->description = 'Choose the metric that should be displayed in the browser tab'; - $this->metric->defaultValue = 'nb_visits'; - $this->metric->readableByCurrentUser = true; - - $this->addSetting($this->metric); - } - - private function createBrowsersSetting() - { - $this->browsers = new SystemSetting('browsers', 'Supported Browsers'); - $this->browsers->type = static::TYPE_ARRAY; - $this->browsers->uiControlType = static::CONTROL_MULTI_SELECT; - $this->browsers->availableValues = array('firefox' => 'Firefox', 'chromium' => 'Chromium', 'safari' => 'safari'); - $this->browsers->description = 'The value will be only displayed in the following browsers'; - $this->browsers->defaultValue = array('firefox', 'chromium', 'safari'); - $this->browsers->readableByCurrentUser = true; - - $this->addSetting($this->browsers); - } - - private function createDescriptionSetting() - { - $this->description = new SystemSetting('description', 'Description for value'); - $this->description->readableByCurrentUser = true; - $this->description->uiControlType = static::CONTROL_TEXTAREA; - $this->description->description = 'This description will be displayed next to the value'; - $this->description->defaultValue = "This is the value: \nAnother line"; - - $this->addSetting($this->description); - } - - private function createPasswordSetting() - { - $this->password = new SystemSetting('password', 'API password'); - $this->password->readableByCurrentUser = true; - $this->password->uiControlType = static::CONTROL_PASSWORD; - $this->password->description = 'Password for the 3rd API where we fetch the value'; - $this->password->transform = function ($value) { - return sha1($value . 'salt'); - }; - - $this->addSetting($this->password); - } -} diff --git a/plugins/ExampleSettingsPlugin/SystemSettings.php b/plugins/ExampleSettingsPlugin/SystemSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..1d2082e94973ca012cb76286688043ae102439a1 --- /dev/null +++ b/plugins/ExampleSettingsPlugin/SystemSettings.php @@ -0,0 +1,96 @@ +<?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\Plugins\ExampleSettingsPlugin; + +use Piwik\Settings\Setting; +use Piwik\Settings\FieldConfig; + +/** + * Defines Settings for ExampleSettingsPlugin. + * + * Usage like this: + * $settings = new SystemSettings(); + * $settings->metric->getValue(); + * $settings->description->getValue(); + */ +class SystemSettings extends \Piwik\Settings\Plugin\SystemSettings +{ + /** @var Setting */ + public $metric; + + /** @var Setting */ + public $browsers; + + /** @var Setting */ + public $description; + + /** @var Setting */ + public $password; + + protected function init() + { + // System setting --> allows selection of a single value + $this->metric = $this->createMetricSetting(); + + // System setting --> allows selection of multiple values + $this->browsers = $this->createBrowsersSetting(); + + // System setting --> textarea + $this->description = $this->createDescriptionSetting(); + + // System setting --> textarea + $this->password = $this->createPasswordSetting(); + } + + private function createMetricSetting() + { + return $this->makeSetting('metric', $default = 'nb_visits', FieldConfig::TYPE_STRING, function (FieldConfig $field) { + $field->title = 'Metric to display'; + $field->uiControl = FieldConfig::UI_CONTROL_SINGLE_SELECT; + $field->availableValues = array('nb_visits' => 'Visits', 'nb_actions' => 'Actions', 'visitors' => 'Visitors'); + $field->introduction = 'Only Super Users can change the following settings:'; + $field->description = 'Choose the metric that should be displayed in the browser tab'; + }); + } + + private function createBrowsersSetting() + { + $default = array('firefox', 'chromium', 'safari'); + + return $this->makeSetting('browsers', $default, FieldConfig::TYPE_ARRAY, function (FieldConfig $field) { + $field->title = 'Supported Browsers'; + $field->uiControl = FieldConfig::UI_CONTROL_MULTI_SELECT; + $field->availableValues = array('firefox' => 'Firefox', 'chromium' => 'Chromium', 'safari' => 'safari'); + $field->description = 'The value will be only displayed in the following browsers'; + }); + } + + private function createDescriptionSetting() + { + $default = "This is the value: \nAnother line"; + + return $this->makeSetting('description', $default, FieldConfig::TYPE_STRING, function (FieldConfig $field) { + $field->title = 'Description for value'; + $field->uiControl = FieldConfig::UI_CONTROL_TEXTAREA; + $field->description = 'This description will be displayed next to the value'; + }); + } + + private function createPasswordSetting() + { + return $this->makeSetting('password', $default = null, FieldConfig::TYPE_STRING, function (FieldConfig $field) { + $field->title = 'API password'; + $field->uiControl = FieldConfig::UI_CONTROL_PASSWORD; + $field->description = 'Password for the 3rd API where we fetch the value'; + $field->transform = function ($value) { + return sha1($value . 'salt'); + }; + }); + } +} diff --git a/plugins/ExampleSettingsPlugin/UserSettings.php b/plugins/ExampleSettingsPlugin/UserSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..cffa88d16d27ceca1de7159baa0902e120341185 --- /dev/null +++ b/plugins/ExampleSettingsPlugin/UserSettings.php @@ -0,0 +1,80 @@ +<?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\Plugins\ExampleSettingsPlugin; + +use Piwik\Settings\Setting; +use Piwik\Settings\FieldConfig; + +/** + * Defines Settings for ExampleSettingsPlugin. + * + * Usage like this: + * $settings = new UserSettings(); + * $settings->autoRefresh->getValue(); + * $settings->color->getValue(); + */ +class UserSettings extends \Piwik\Settings\Plugin\UserSettings +{ + /** @var Setting */ + public $autoRefresh; + + /** @var Setting */ + public $refreshInterval; + + /** @var Setting */ + public $color; + + protected function init() + { + // User setting --> checkbox converted to bool + $this->autoRefresh = $this->createAutoRefreshSetting(); + + // User setting --> textbox converted to int defining a validator and filter + $this->refreshInterval = $this->createRefreshIntervalSetting(); + + // User setting --> radio + $this->color = $this->createColorSetting(); + } + + private function createAutoRefreshSetting() + { + return $this->makeSetting('autoRefresh', $default = false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) { + $field->title = 'Auto refresh'; + $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX; + $field->description = 'If enabled, the value will be automatically refreshed depending on the specified interval'; + }); + } + + private function createRefreshIntervalSetting() + { + return $this->makeSetting('refreshInterval', $default = '30', FieldConfig::TYPE_INT, function (FieldConfig $field) { + $field->title = 'Refresh Interval'; + $field->uiControl = FieldConfig::UI_CONTROL_TEXT; + $field->uiControlAttributes = array('size' => 3); + $field->description = 'Defines how often the value should be updated'; + $field->inlineHelp = 'Enter a number which is >= 15'; + $field->validate = function ($value, $setting) { + if ($value < 15) { + throw new \Exception('Value is invalid'); + } + }; + }); + } + + private function createColorSetting() + { + return $this->makeSetting('color', $default = 'red', FieldConfig::TYPE_STRING, function (FieldConfig $field) { + $field->title = 'Color'; + $field->uiControl = FieldConfig::UI_CONTROL_RADIO; + $field->description = 'Pick your favourite color'; + $field->availableValues = array('red' => 'Red', 'blue' => 'Blue', 'green' => 'Green'); + }); + } + +} diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php index bb7da8cbaeedd1d7a93f98a9cef6f3b8fc2dd32c..e1db0d187ccd5c34140b91e8a25a88ed9ed9cdf8 100644 --- a/plugins/Goals/API.php +++ b/plugins/Goals/API.php @@ -22,7 +22,7 @@ use Piwik\Plugin\Report; use Piwik\Plugins\API\DataTable\MergeDataTables; use Piwik\Plugins\CoreHome\Columns\Metrics\ConversionRate; use Piwik\Plugins\Goals\Columns\Metrics\AverageOrderRevenue; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Segment\SegmentExpression; use Piwik\Site; use Piwik\Tracker\Cache; @@ -415,7 +415,7 @@ class API extends \Piwik\Plugin\API $requestedColumns = array_unique(array_merge($requestedColumns, $metricsToAdd)); } - $report = Reports::factory('Goals', 'getMetrics'); + $report = ReportsProvider::factory('Goals', 'getMetrics'); $columnsToGet = $report->getMetricsRequiredForReport($allMetrics, $requestedColumns); $inDbMetricNames = array_map(function ($name) use ($idGoal) { diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php index 03420aa8d7381ad356851c6bd2c947a7f1364cad..1f9d229428f739a9bb24276c966f3cabd4f006ee 100644 --- a/plugins/Goals/Goals.php +++ b/plugins/Goals/Goals.php @@ -12,7 +12,7 @@ use Piwik\ArchiveProcessor; use Piwik\Common; use Piwik\Db; use Piwik\Piwik; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Tracker\GoalManager; use Piwik\Category\Subcategory; @@ -180,7 +180,7 @@ class Goals extends \Piwik\Plugin { $reportsWithGoals = array(); - $reports = new Reports(); + $reports = new ReportsProvider(); foreach ($reports->getAllReports() as $report) { if ($report->hasGoalMetrics()) { diff --git a/plugins/Goals/Pages.php b/plugins/Goals/Pages.php index 50e3f63e374d1c602f60eb220e05809e867a7241..be55bff1445555a473767d149ae7e1db902cb58e 100644 --- a/plugins/Goals/Pages.php +++ b/plugins/Goals/Pages.php @@ -13,7 +13,7 @@ use Piwik\Common; use Piwik\Piwik; use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Widget\WidgetContainerConfig; use Piwik\Widget\WidgetConfig; use Piwik\Report\ReportWidgetFactory; @@ -335,7 +335,7 @@ class Pages private function createWidgetForReport($module, $action) { - $report = Reports::factory($module, $action); + $report = ReportsProvider::factory($module, $action); $factory = new ReportWidgetFactory($report); return $factory->createWidget(); } diff --git a/plugins/LogViewer b/plugins/LogViewer index 1703d7536e39240643204a1f334d8b8da6cd6fc5..15d48dd1788f71bcf0a7578fe5664af6c4503625 160000 --- a/plugins/LogViewer +++ b/plugins/LogViewer @@ -1 +1 @@ -Subproject commit 1703d7536e39240643204a1f334d8b8da6cd6fc5 +Subproject commit 15d48dd1788f71bcf0a7578fe5664af6c4503625 diff --git a/plugins/MobileAppMeasurable/Type.php b/plugins/MobileAppMeasurable/Type.php index 6a6fd64c585af4e07184eb5603d0e6a20374bb6e..34ff4335b5e2f1911f2790ec03db857a669b7869 100644 --- a/plugins/MobileAppMeasurable/Type.php +++ b/plugins/MobileAppMeasurable/Type.php @@ -16,6 +16,5 @@ class Type extends \Piwik\Measurable\Type protected $description = 'MobileAppMeasurable_MobileAppDescription'; protected $howToSetupUrl = 'http://developer.piwik.org/guides/tracking-api-clients#mobile-sdks'; - } diff --git a/plugins/MobileAppMeasurable/config/test.php b/plugins/MobileAppMeasurable/config/test.php deleted file mode 100644 index 08a33595571d8d50389162c8f9d7ea7dc8a011db..0000000000000000000000000000000000000000 --- a/plugins/MobileAppMeasurable/config/test.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php - -return array( - - 'Piwik\Plugins\MobileAppMeasurable\Type' => DI\object('Piwik\Plugins\MobileAppMeasurable\tests\Framework\Mock\Type'), - -); \ No newline at end of file diff --git a/plugins/MobileAppMeasurable/tests/Framework/Mock/Type.php b/plugins/MobileAppMeasurable/tests/Framework/Mock/Type.php deleted file mode 100644 index c573f5b101eaa0088f5d017d95ff4f0cdc1f742d..0000000000000000000000000000000000000000 --- a/plugins/MobileAppMeasurable/tests/Framework/Mock/Type.php +++ /dev/null @@ -1,29 +0,0 @@ -<?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\Plugins\MobileAppMeasurable\tests\Framework\Mock; - -use Piwik\Measurable\MeasurableSetting; -use Piwik\Measurable\MeasurableSettings; -use Piwik\Tracker; - -class Type extends \Piwik\Plugins\MobileAppMeasurable\Type -{ - - public function configureMeasurableSettings(MeasurableSettings $settings) - { - $appId = new MeasurableSetting('app_id', 'App-ID'); - $appId->validate = function ($value) { - if (strlen($value) > 100) { - throw new \Exception('Only 100 characters are allowed'); - } - }; - - $settings->addSetting($appId); - } -} diff --git a/plugins/Morpheus/Menu.php b/plugins/Morpheus/Menu.php index 5fc5f5c6edca13ae30d20c7e2523d362720adcdd..a45b35c0b6c7aa722d23dc162533945e5ba54b99 100644 --- a/plugins/Morpheus/Menu.php +++ b/plugins/Morpheus/Menu.php @@ -28,9 +28,5 @@ class Menu extends \Piwik\Plugin\Menu if (Development::isEnabled() && Piwik::isUserHasSomeAdminAccess()) { $menu->addDevelopmentItem('UI Demo', $this->urlForAction('demo')); } - - if (Development::isEnabled() && Piwik::isUserHasSomeAdminAccess()) { - $menu->addPlatformItem('UI Demo', $this->urlForAction('demo'), $order = 15); - } } } diff --git a/plugins/Morpheus/templates/settingsMacros.twig b/plugins/Morpheus/templates/settingsMacros.twig index 19a88bfa28554f1d24122de4a899faf904e11255..c09aa608eb0b153da48fbb863caf08c08a390121 100644 --- a/plugins/Morpheus/templates/settingsMacros.twig +++ b/plugins/Morpheus/templates/settingsMacros.twig @@ -22,14 +22,14 @@ {% set settingValue = setting.getValue %} - {% if setting.uiControlType != 'checkbox' %} + {% if setting.uiControl != 'checkbox' %} <label>{{ setting.title }}</label> {% endif %} {% if setting.inlineHelp %} <div class="form-help"> {{ setting.inlineHelp }} - {% if setting.defaultValue and setting.uiControlType != 'checkbox' and setting.uiControlType != 'radio' %} + {% if setting.defaultValue and setting.uiControl != 'checkbox' and setting.uiControl != 'radio' %} <br/> {{ 'General_Default'|translate }}: {% if setting.defaultValue is iterable %} @@ -41,13 +41,13 @@ </div> {% endif %} - {% if setting.uiControlType == 'select' or setting.uiControlType == 'multiselect' %} + {% if setting.uiControl == 'select' or setting.uiControl == 'multiselect' %} <select {% for attr, val in setting.uiControlAttributes %} {{ attr|e('html_attr') }}="{{ val|e('html_attr') }}" {% endfor %} name="{{ setting.getKey|e('html_attr') }}" - {% if setting.uiControlType == 'multiselect' %}multiple{% endif %}> + {% if setting.uiControl == 'multiselect' %}multiple{% endif %}> {% for key, value in setting.availableValues %} <option value='{{ key }}' @@ -61,7 +61,7 @@ {% endfor %} </select> - {% elseif setting.uiControlType == 'textarea' %} + {% elseif setting.uiControl == 'textarea' %} <textarea style="width: 376px; height: 250px;" {% for attr, val in setting.uiControlAttributes %} {{ attr|e('html_attr') }}="{{ val|e('html_attr') }}" @@ -70,7 +70,7 @@ > {{- settingValue -}} </textarea> - {% elseif setting.uiControlType == 'radio' %} + {% elseif setting.uiControl == 'radio' %} {% for key, value in setting.availableValues %} <label class="radio"> @@ -95,7 +95,7 @@ </label> {% endfor %} - {% elseif setting.uiControlType == 'checkbox' %} + {% elseif setting.uiControl == 'checkbox' %} <label class="checkbox"> <input id="name-value-{{ index }}" @@ -122,14 +122,14 @@ {% for attr, val in setting.uiControlAttributes %} {{ attr|e('html_attr') }}="{{ val|e('html_attr') }}" {% endfor %} - class="control_{{ setting.uiControlType|e('html_attr') }}" - type="{{ setting.uiControlType|e('html_attr') }}" + class="control_{{ setting.uiControl|e('html_attr') }}" + type="{{ setting.uiControl|e('html_attr') }}" name="{{ setting.getKey|e('html_attr') }}" value="{{ settingValue|e('html_attr') }}"> {% endif %} - {% if setting.uiControlType != 'checkbox' and setting.uiControlType != 'radio' %} + {% if setting.uiControl != 'checkbox' and setting.uiControl != 'radio' %} <span class='form-description'>{{ setting.description }}</span> {% endif %} diff --git a/plugins/PiwikPro/Widgets.php b/plugins/PiwikPro/Widgets.php deleted file mode 100644 index f8e007aa074f3a84fe0bc690adf1549c547b23ba..0000000000000000000000000000000000000000 --- a/plugins/PiwikPro/Widgets.php +++ /dev/null @@ -1,82 +0,0 @@ -<?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\Plugins\PiwikPro; - -use Piwik\Piwik; -use Piwik\PiwikPro\Advertising; -use Piwik\Plugins\ExampleRssWidget\RssRenderer; -use Piwik\View; - -class Widgets extends \Piwik\Plugin\Widgets -{ - protected $category = 'About Piwik'; - - /** - * @var Advertising - */ - private $advertising; - - /** - * @var Promo - */ - private $promo; - - public function __construct(Advertising $advertising, Promo $promo) - { - $this->advertising = $advertising; - $this->promo = $promo; - } - - protected function init() - { - if ($this->advertising->arePiwikProAdsEnabled()) { - $this->addWidget('PiwikPro_WidgetBlogTitle', 'rssPiwikPro'); - $this->addWidget('PiwikPro_WidgetPiwikProAd', 'promoPiwikPro'); - } - } - - public function rssPiwikPro() - { - try { - $rss = new RssRenderer('https://piwik.pro/feed/'); - $rss->showDescription(true); - - return $rss->get(); - - } catch (\Exception $e) { - - return $this->error($e); - } - } - - public function promoPiwikPro() - { - $view = new View('@PiwikPro/promoPiwikProWidget'); - - $promo = $this->promo->getContent(); - - $view->ctaLinkUrl = $this->advertising->getPromoUrlForOnPremises('PromoWidget', $promo['campaignContent']); - $view->ctaText = $promo['text']; - $view->ctaLinkTitle = $this->promo->getLinkTitle(); - - return $view->render(); - } - - /** - * @param \Exception $e - * @return string - */ - private function error($e) - { - return '<div class="pk-emptyDataTable">' - . Piwik::translate('General_ErrorRequest', array('', '')) - . ' - ' . $e->getMessage() . '</div>'; - } - -} diff --git a/plugins/QueuedTracking b/plugins/QueuedTracking index a7137646fa4d738c6378686df6cd222fd291217f..be67d637924b3b84b989e8c89cc85619bec63250 160000 --- a/plugins/QueuedTracking +++ b/plugins/QueuedTracking @@ -1 +1 @@ -Subproject commit a7137646fa4d738c6378686df6cd222fd291217f +Subproject commit be67d637924b3b84b989e8c89cc85619bec63250 diff --git a/plugins/Resolution/Reports/GetConfiguration.php b/plugins/Resolution/Reports/GetConfiguration.php index 600f07edd9336babfa9c0095af2f83cfb61cf849..8e42b28a245858fb7b43c7313bf36f5f1e169da7 100644 --- a/plugins/Resolution/Reports/GetConfiguration.php +++ b/plugins/Resolution/Reports/GetConfiguration.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\Resolution\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Resolution\Columns\Configuration; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetConfiguration extends Base { @@ -38,7 +38,7 @@ class GetConfiguration extends Base public function getRelatedReports() { return array( - Reports::factory('Resolution', 'getResolution'), + ReportsProvider::factory('Resolution', 'getResolution'), ); } } diff --git a/plugins/Resolution/Reports/GetResolution.php b/plugins/Resolution/Reports/GetResolution.php index 3b27236a86b0e5f09a8c979dbd27857f402112a0..2e18ec95aa113a39d8655987db16d57f3d0e6b24 100644 --- a/plugins/Resolution/Reports/GetResolution.php +++ b/plugins/Resolution/Reports/GetResolution.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\Resolution\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Resolution\Columns\Resolution; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetResolution extends Base { @@ -36,7 +36,7 @@ class GetResolution extends Base public function getRelatedReports() { return array( - Reports::factory('Resolution', 'getConfiguration'), + ReportsProvider::factory('Resolution', 'getConfiguration'), ); } } diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php index d6b969f9ad50b5e27052528d929c65aaddfa8cfc..70711c2f0bb8d8c99789fcf73d0d4accabb7b28d 100644 --- a/plugins/SitesManager/API.php +++ b/plugins/SitesManager/API.php @@ -18,7 +18,11 @@ use Piwik\Metrics\Formatter; use Piwik\Network\IPUtils; use Piwik\Option; use Piwik\Piwik; -use Piwik\Measurable\MeasurableSettings; +use Piwik\Plugin\SettingsProvider; +use Piwik\Plugins\CorePluginsAdmin\SettingsMetadata; +use Piwik\Plugins\WebsiteMeasurable\Settings\Urls; +use Piwik\Settings\Measurable\MeasurableProperty; +use Piwik\Settings\Measurable\MeasurableSettings; use Piwik\ProxyHttp; use Piwik\Scheduler\Scheduler; use Piwik\SettingsPiwik; @@ -60,6 +64,22 @@ class API extends \Piwik\Plugin\API const OPTION_SITE_SPECIFIC_USER_AGENT_EXCLUDE_ENABLE = 'SitesManager_EnableSiteSpecificUserAgentExclude'; const OPTION_KEEP_URL_FRAGMENTS_GLOBAL = 'SitesManager_KeepURLFragmentsGlobal'; + /** + * @var SettingsProvider + */ + private $settingsProvider; + + /** + * @var SettingsMetadata + */ + private $settingsMetadata; + + public function __construct(SettingsProvider $provider, SettingsMetadata $settingsMetadata) + { + $this->settingsProvider = $provider; + $this->settingsMetadata = $settingsMetadata; + } + /** * Returns the javascript tag for the given idSite. * This tag must be included on every page to be tracked by Piwik @@ -505,7 +525,7 @@ class API extends \Piwik\Plugin\API * @param null|string $excludedUserAgents * @param int $keepURLFragments If 1, URL fragments will be kept when tracking. If 2, they * will be removed. If 0, the default global behavior will be used. - * @param array|null $settings JSON serialized settings eg {settingName: settingValue, ...} + * @param array|null $settingValues JSON serialized settings eg {settingName: settingValue, ...} * @see getKeepURLFragmentsGlobal. * @param string $type The website type, defaults to "website" if not set. * @param bool|null $excludeUnknownUrls Track only URL matching one of website URLs @@ -513,7 +533,7 @@ class API extends \Piwik\Plugin\API * @return int the website ID created */ public function addSite($siteName, - $urls, + $urls = null, $ecommerce = null, $siteSearch = null, $searchKeywordParameters = null, @@ -527,20 +547,47 @@ class API extends \Piwik\Plugin\API $excludedUserAgents = null, $keepURLFragments = null, $type = null, - $settings = null, + $settingValues = null, $excludeUnknownUrls = null) { Piwik::checkUserHasSuperUserAccess(); $this->checkName($siteName); - $urls = $this->cleanParameterUrls($urls); - $this->checkUrls($urls); - $this->checkAtLeastOneUrl($urls); - $siteSearch = $this->checkSiteSearch($siteSearch); - list($searchKeywordParameters, $searchCategoryParameters) = $this->checkSiteSearchParameters($searchKeywordParameters, $searchCategoryParameters); - $keepURLFragments = (int)$keepURLFragments; - self::checkKeepURLFragmentsValue($keepURLFragments); + if (empty($settingValues)) { + $settingValues = array(); + } + + if (isset($urls)) { + $settingValues = $this->setSettingValue('urls', $urls, $settingValues); + } + if (isset($ecommerce)) { + $settingValues = $this->setSettingValue('ecommerce', $ecommerce, $settingValues); + } + if (isset($siteSearch)) { + $settingValues = $this->setSettingValue('sitesearch', $siteSearch, $settingValues); + } + if (isset($searchKeywordParameters)) { + $settingValues = $this->setSettingValue('sitesearch_keyword_parameters', explode(',', $searchKeywordParameters), $settingValues); + } + if (isset($searchCategoryParameters)) { + $settingValues = $this->setSettingValue('sitesearch_category_parameters', explode(',', $searchCategoryParameters), $settingValues); + } + if (isset($keepURLFragments)) { + $settingValues = $this->setSettingValue('keep_url_fragment', $keepURLFragments, $settingValues); + } + if (isset($excludeUnknownUrls)) { + $settingValues = $this->setSettingValue('exclude_unknown_urls', $excludeUnknownUrls, $settingValues); + } + if (isset($excludedIps)) { + $settingValues = $this->setSettingValue('excluded_ips', explode(',', $excludedIps), $settingValues); + } + if (isset($excludedQueryParameters)) { + $settingValues = $this->setSettingValue('excluded_parameters', explode(',', $excludedQueryParameters), $settingValues); + } + if (isset($excludedUserAgents)) { + $settingValues = $this->setSettingValue('excluded_user_agents', explode(',', $excludedUserAgents), $settingValues); + } $timezone = trim($timezone); if (empty($timezone)) { @@ -553,23 +600,10 @@ class API extends \Piwik\Plugin\API } $this->checkValidCurrency($currency); - $url = $urls[0]; - $urls = array_slice($urls, 1); - - $bind = array('name' => $siteName, - 'main_url' => $url); - - $bind['exclude_unknown_urls'] = (int)$excludeUnknownUrls; - $bind['excluded_ips'] = $this->checkAndReturnExcludedIps($excludedIps); - $bind['excluded_parameters'] = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters); - $bind['excluded_user_agents'] = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents); - $bind['keep_url_fragment'] = $keepURLFragments; + $bind = array('name' => $siteName); $bind['timezone'] = $timezone; $bind['currency'] = $currency; - $bind['ecommerce'] = (int)$ecommerce; - $bind['sitesearch'] = $siteSearch; - $bind['sitesearch_keyword_parameters'] = $searchKeywordParameters; - $bind['sitesearch_category_parameters'] = $searchCategoryParameters; + $bind['main_url'] = ''; if (is_null($startDate)) { $bind['ts_created'] = Date::now()->getDatetime(); @@ -585,21 +619,31 @@ class API extends \Piwik\Plugin\API $bind['group'] = ""; } - if (!empty($settings)) { - $this->validateMeasurableSettings(0, $bind['type'], $settings); + $allSettings = $this->setAndValidateMeasurableSettings(0, $bind['type'], $settingValues); + + foreach ($allSettings as $settings) { + foreach ($settings->getSettingsWritableByCurrentUser() as $setting) { + $name = $setting->getName(); + if ($setting instanceof MeasurableProperty && $name !== 'urls') { + $default = $setting->getDefaultValue(); + if (is_bool($default)) { + $default = (int) $default; + } elseif (is_array($default)) { + $default = implode(',', $default); + } + + $bind[$name] = $default; + } + } } $idSite = $this->getModel()->createSite($bind); - $this->insertSiteUrls($idSite, $urls); + $this->saveMeasurableSettings($idSite, $bind['type'], $settingValues); // we reload the access list which doesn't yet take in consideration this new website Access::getInstance()->reloadAccess(); - if (!empty($settings)) { - $this->updateMeasurableSettings($idSite, $settings); - } - $this->postUpdateWebsite($idSite); /** @@ -612,34 +656,57 @@ class API extends \Piwik\Plugin\API return (int) $idSite; } - private function validateMeasurableSettings($idSite, $idType, $settings) + private function setSettingValue($fieldName, $value, $settingValues) { - $measurableSettings = new MeasurableSettings($idSite, $idType); + $pluginName = 'WebsiteMeasurable'; + if (empty($settingValues[$pluginName])) { + $settingValues[$pluginName] = array(); + } - foreach ($measurableSettings->getSettingsForCurrentUser() as $measurableSetting) { - $name = $measurableSetting->getName(); - if (!empty($settings[$name])) { - $measurableSetting->setValue($settings[$name]); + $found = false; + foreach ($settingValues[$pluginName] as $key => $setting) { + if ($setting['name'] === $fieldName) { + $setting['value'] = $value; + $found = true; + break; } } + + if (!$found) { + $settingValues[$pluginName][] = array('name' => $fieldName, 'value' => $value); + } + + return $settingValues; } - private function updateMeasurableSettings($idSite, $settings) + public function getSiteSettings($idSite) { - $idType = Site::getTypeFor($idSite); + Piwik::checkUserHasAdminAccess($idSite); - $measurableSettings = new MeasurableSettings($idSite, $idType); + $measurableSettings = $this->settingsProvider->getAllMeasurableSettings($idSite, $idMeasurableType = false); - foreach ($measurableSettings->getSettingsForCurrentUser() as $measurableSetting) { - $name = $measurableSetting->getName(); - if (!empty($settings[$name])) { - $measurableSetting->setValue($settings[$name]); - } - // we do not clear existing settings if the value is missing. - // There can be so many settings added by random plugins one would always clear some settings. - } + return $this->settingsMetadata->formatSettings($measurableSettings); + } - $measurableSettings->save(); + private function setAndValidateMeasurableSettings($idSite, $idType, $settingValues) + { + $measurableSettings = $this->settingsProvider->getAllMeasurableSettings($idSite, $idType); + + $this->settingsMetadata->setPluginSettings($measurableSettings, $settingValues); + + return $measurableSettings; + } + + /** + * @param MeasurableSettings[] $measurableSettings + */ + private function saveMeasurableSettings($idSite, $idType, $settingValues) + { + $measurableSettings = $this->setAndValidateMeasurableSettings($idSite, $idType, $settingValues); + + foreach ($measurableSettings as $measurableSetting) { + $measurableSetting->save(); + } } private function postUpdateWebsite($idSite) @@ -685,21 +752,6 @@ class API extends \Piwik\Plugin\API Piwik::postEvent('SitesManager.deleteSite.end', array($idSite)); } - /** - * Checks that the array has at least one element - * - * @param array $urls - * @throws Exception - */ - private function checkAtLeastOneUrl($urls) - { - if (!is_array($urls) - || count($urls) == 0 - ) { - throw new Exception(Piwik::translate("SitesManager_ExceptionNoUrl")); - } - } - private function checkValidTimezone($timezone) { $timezones = $this->getTimezonesList(); @@ -775,15 +827,26 @@ class API extends \Piwik\Plugin\API { Piwik::checkUserHasAdminAccess($idSite); - $urls = $this->cleanParameterUrls($urls); - $this->checkUrls($urls); + if (empty($urls)) { + return 0; + } + + if (!is_array($urls)) { + $urls = array($urls); + } $urlsInit = $this->getSiteUrlsFromId($idSite); - $toInsert = array_diff($urls, $urlsInit); - $this->insertSiteUrls($idSite, $toInsert); + $toInsert = array_merge($urlsInit, $urls); + + $urlsProperty = new Urls($idSite); + $urlsProperty->setValue($toInsert); + $urlsProperty->save(); + + $inserted = array_diff($urlsProperty->getValue(), $urlsInit); + $this->postUpdateWebsite($idSite); - return count($toInsert); + return count($inserted); } /** @@ -798,14 +861,18 @@ class API extends \Piwik\Plugin\API { Piwik::checkUserHasAdminAccess($idSite); - $urls = $this->cleanParameterUrls($urls); - $this->checkUrls($urls); + $mainUrl = Site::getMainUrlFor($idSite); + array_unshift($urls, $mainUrl); + + $urlsProperty = new Urls($idSite); + $urlsProperty->setValue($urls); + $urlsProperty->save(); + + $inserted = array_diff($urlsProperty->getValue(), $urls); - $this->getModel()->deleteSiteAliasUrls($idSite); - $this->insertSiteUrls($idSite, $urls); $this->postUpdateWebsite($idSite); - return count($urls); + return count($inserted); } /** @@ -1093,7 +1160,7 @@ class API extends \Piwik\Plugin\API * @param int|null $keepURLFragments If 1, URL fragments will be kept when tracking. If 2, they * will be removed. If 0, the default global behavior will be used. * @param string $type The Website type, default value is "website" - * @param array|null $settings JSON serialized settings eg {settingName: settingValue, ...} + * @param array|null $settingValues JSON serialized settings eg {settingName: settingValue, ...} * @param bool|null $excludeUnknownUrls Track only URL matching one of website URLs * @throws Exception * @see getKeepURLFragmentsGlobal. If null, the existing value will @@ -1117,7 +1184,7 @@ class API extends \Piwik\Plugin\API $excludedUserAgents = null, $keepURLFragments = null, $type = null, - $settings = null, + $settingValues = null, $excludeUnknownUrls = null) { Piwik::checkUserHasAdminAccess($idSite); @@ -1136,71 +1203,74 @@ class API extends \Piwik\Plugin\API $bind['name'] = $siteName; } - if (!is_null($urls)) { - $urls = $this->cleanParameterUrls($urls); - $this->checkUrls($urls); - $this->checkAtLeastOneUrl($urls); - $url = $urls[0]; - $bind['main_url'] = $url; + if (empty($settingValues)) { + $settingValues = array(); } - if (!is_null($currency)) { + if (isset($urls)) { + $settingValues = $this->setSettingValue('urls', $urls, $settingValues); + } + if (isset($ecommerce)) { + $settingValues = $this->setSettingValue('ecommerce', $ecommerce, $settingValues); + } + if (isset($siteSearch)) { + $settingValues = $this->setSettingValue('sitesearch', $siteSearch, $settingValues); + } + if (isset($searchKeywordParameters)) { + $settingValues = $this->setSettingValue('sitesearch_keyword_parameters', explode(',', $searchKeywordParameters), $settingValues); + } + if (isset($searchCategoryParameters)) { + $settingValues = $this->setSettingValue('sitesearch_category_parameters', explode(',', $searchCategoryParameters), $settingValues); + } + if (isset($keepURLFragments)) { + $settingValues = $this->setSettingValue('keep_url_fragment', $keepURLFragments, $settingValues); + } + if (isset($excludeUnknownUrls)) { + $settingValues = $this->setSettingValue('exclude_unknown_urls', $excludeUnknownUrls, $settingValues); + } + if (isset($excludedIps)) { + $settingValues = $this->setSettingValue('excluded_ips', explode(',', $excludedIps), $settingValues); + } + if (isset($excludedQueryParameters)) { + $settingValues = $this->setSettingValue('excluded_parameters', explode(',', $excludedQueryParameters), $settingValues); + } + if (isset($excludedUserAgents)) { + $settingValues = $this->setSettingValue('excluded_user_agents', explode(',', $excludedUserAgents), $settingValues); + } + + if (isset($currency)) { $currency = trim($currency); $this->checkValidCurrency($currency); $bind['currency'] = $currency; } - if (!is_null($timezone)) { + if (isset($timezone)) { $timezone = trim($timezone); $this->checkValidTimezone($timezone); $bind['timezone'] = $timezone; } - if (!is_null($group) + if (isset($group) && Piwik::hasUserSuperUserAccess() ) { $bind['group'] = trim($group); } - if (!is_null($ecommerce)) { - $bind['ecommerce'] = (int)(bool)$ecommerce; - } - if (!is_null($startDate)) { + if (isset($startDate)) { $bind['ts_created'] = Date::factory($startDate)->getDatetime(); } - $bind['exclude_unknown_urls'] = (int)$excludeUnknownUrls; - $bind['excluded_ips'] = $this->checkAndReturnExcludedIps($excludedIps); - $bind['excluded_parameters'] = $this->checkAndReturnCommaSeparatedStringList($excludedQueryParameters); - $bind['excluded_user_agents'] = $this->checkAndReturnCommaSeparatedStringList($excludedUserAgents); - - if (!is_null($keepURLFragments)) { - $keepURLFragments = (int)$keepURLFragments; - self::checkKeepURLFragmentsValue($keepURLFragments); - - $bind['keep_url_fragment'] = $keepURLFragments; - } - $bind['sitesearch'] = $this->checkSiteSearch($siteSearch); - list($searchKeywordParameters, $searchCategoryParameters) = $this->checkSiteSearchParameters($searchKeywordParameters, $searchCategoryParameters); - $bind['sitesearch_keyword_parameters'] = $searchKeywordParameters; - $bind['sitesearch_category_parameters'] = $searchCategoryParameters; - - if (!is_null($type)) { + if (isset($type)) { $bind['type'] = $this->checkAndReturnType($type); } - if (!empty($settings)) { - $this->validateMeasurableSettings($idSite, Site::getTypeFor($idSite), $settings); + if (!empty($settingValues)) { + $this->setAndValidateMeasurableSettings($idSite, $idType = null, $settingValues); } - $this->getModel()->updateSite($bind, $idSite); - - if (!empty($settings)) { - $this->updateMeasurableSettings($idSite, $settings); + if (!empty($bind)) { + $this->getModel()->updateSite($bind, $idSite); } - // we now update the main + alias URLs - $this->getModel()->deleteSiteAliasUrls($idSite); - - if (count($urls) > 1) { - $this->addSiteAliasUrls($idSite, array_slice($urls, 1)); + if (!empty($settingValues)) { + $this->saveMeasurableSettings($idSite, $idType = null, $settingValues); } $this->postUpdateWebsite($idSite); @@ -1358,23 +1428,6 @@ class API extends \Piwik\Plugin\API return $this->getModel()->getUniqueSiteTimezones(); } - /** - * Insert the list of alias URLs for the website. - * The URLs must not exist already for this website! - */ - private function insertSiteUrls($idSite, $urls) - { - if (count($urls) != 0) { - foreach ($urls as $url) { - try { - $this->getModel()->insertSiteUrl($idSite, $url); - } catch(Exception $e) { - // See bug #4149 - } - } - } - } - /** * Remove the final slash in the URLs if found * @@ -1429,77 +1482,6 @@ class API extends \Piwik\Plugin\API } } - private function checkSiteSearch($siteSearch) - { - if ($siteSearch === null) { - return "1"; - } - return $siteSearch == 1 ? "1" : "0"; - } - - private function checkSiteSearchParameters($searchKeywordParameters, $searchCategoryParameters) - { - $searchKeywordParameters = trim($searchKeywordParameters); - $searchCategoryParameters = trim($searchCategoryParameters); - if (empty($searchKeywordParameters)) { - $searchKeywordParameters = ''; - } - - if (empty($searchCategoryParameters)) { - $searchCategoryParameters = ''; - } - - return array($searchKeywordParameters, $searchCategoryParameters); - } - - /** - * Check that the array of URLs are valid URLs - * - * @param array $urls - * @throws Exception if any of the urls is not valid - */ - private function checkUrls($urls) - { - foreach ($urls as $url) { - if (!$this->isValidUrl($url)) { - throw new Exception(sprintf(Piwik::translate("SitesManager_ExceptionInvalidUrl"), $url)); - } - } - } - - /** - * Clean the parameter URLs: - * - if the parameter is a string make it an array - * - remove the trailing slashes if found - * - * @param string|array urls - * @return array the array of cleaned URLs - */ - private function cleanParameterUrls($urls) - { - if (!is_array($urls)) { - $urls = array($urls); - } - - $urls = array_filter($urls); - $urls = array_map('urldecode', $urls); - - foreach ($urls as &$url) { - $url = $this->removeTrailingSlash($url); - $scheme = parse_url($url, PHP_URL_SCHEME); - if (empty($scheme) - && strpos($url, '://') === false - ) { - $url = 'http://' . $url; - } - $url = trim($url); - $url = Common::sanitizeInputValue($url); - } - - $urls = array_unique($urls); - return $urls; - } - public function renameGroup($oldGroupName, $newGroupName) { Piwik::checkUserHasSuperUserAccess(); @@ -1567,19 +1549,4 @@ class API extends \Piwik\Plugin\API return SettingsPiwik::getWebsitesCountToDisplay(); } - /** - * Utility function that throws if a value is not valid for the 'keep_url_fragment' - * column of the piwik_site table. - * - * @param int $keepURLFragments - * @throws Exception - */ - private static function checkKeepURLFragmentsValue($keepURLFragments) - { - // make sure value is between 0 & 2 - if (!in_array($keepURLFragments, array(0, 1, 2))) { - throw new Exception("Error in SitesManager.updateSite: keepURLFragments must be between 0 & 2" . - " (actual value: $keepURLFragments)."); - } - } } diff --git a/plugins/SitesManager/Controller.php b/plugins/SitesManager/Controller.php index d64fb45fa9be2289c1be55e906fdb1fddffa2770..5eb1ecf3ed3f660fc67396c191d9711d96d78921 100644 --- a/plugins/SitesManager/Controller.php +++ b/plugins/SitesManager/Controller.php @@ -13,7 +13,7 @@ use Piwik\API\ResponseBuilder; use Piwik\Common; use Piwik\Exception\UnexpectedWebsiteFoundException; use Piwik\Piwik; -use Piwik\Measurable\MeasurableSettings; +use Piwik\Settings\Measurable\MeasurableSettings; use Piwik\SettingsPiwik; use Piwik\Site; use Piwik\Tracker\TrackerCodeGenerator; @@ -50,8 +50,8 @@ class Controller extends \Piwik\Plugin\ControllerAdmin $view = new View('@SitesManager/measurable_type_settings'); - $propSettings = new MeasurableSettings($idSite, $idType); - $view->settings = $propSettings->getSettingsForCurrentUser(); +// $propSettings = new MeasurableSettings($idSite, $idType); + $view->settings = array(); return $view->render(); } diff --git a/plugins/SitesManager/SitesManager.php b/plugins/SitesManager/SitesManager.php index 5ebc5898f6df3152c17a07af64d944005cad9bc3..ee77874aa2a858ed610d43a40e24713c514bcc9f 100644 --- a/plugins/SitesManager/SitesManager.php +++ b/plugins/SitesManager/SitesManager.php @@ -14,6 +14,7 @@ use Piwik\Container\StaticContainer; use Piwik\Db; use Piwik\Plugins\PrivacyManager\PrivacyManager; use Piwik\Measurable\Settings\Storage; +use Piwik\Settings\Storage\Backend\MeasurableSettingsTable; use Piwik\Tracker\Cache; use Piwik\Tracker\Model as TrackerModel; @@ -73,8 +74,7 @@ class SitesManager extends \Piwik\Plugin $archiveInvalidator = StaticContainer::get('Piwik\Archive\ArchiveInvalidator'); $archiveInvalidator->forgetRememberedArchivedReportsToInvalidateForSite($idSite); - $measurableStorage = new Storage(Db::get(), $idSite); - $measurableStorage->deleteAllValues(); + MeasurableSettingsTable::removeAllSettingsForSite($idSite); } /** diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js index 0fac17cc22c0a331533e8dfa6ba9929cea6f0f1d..a88b34b969888fe8d9415277ec532739dadb63f0 100644 --- a/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js +++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager-site.controller.js @@ -7,9 +7,9 @@ (function () { angular.module('piwikApp').controller('SitesManagerSiteController', SitesManagerSiteController); - SitesManagerSiteController.$inject = ['$scope', '$filter', 'sitesManagerApiHelper', 'sitesManagerTypeModel']; + SitesManagerSiteController.$inject = ['$scope', '$filter', 'sitesManagerApiHelper', 'sitesManagerTypeModel', 'piwikApi']; - function SitesManagerSiteController($scope, $filter, sitesManagerApiHelper, sitesManagerTypeModel) { + function SitesManagerSiteController($scope, $filter, sitesManagerApiHelper, sitesManagerTypeModel, piwikApi) { var translate = $filter('translate'); @@ -18,11 +18,19 @@ initModel(); initActions(); + $scope.site.isLoading = true; sitesManagerTypeModel.fetchTypeById($scope.site.type).then(function (type) { + $scope.site.isLoading = false; + if (type) { $scope.currentType = type; $scope.howToSetupUrl = type.howToSetupUrl; $scope.isInternalSetupUrl = '?' === ('' + type.howToSetupUrl).substr(0, 1); + $scope.typeSettings = type.settings; + + if (isSiteNew()) { + $scope.measurableSettings = angular.copy(type.settings); + } } else { $scope.currentType = {name: $scope.site.type}; } @@ -39,27 +47,30 @@ var initModel = function() { - if(siteIsNew()) + if (isSiteNew()) { initNewSite(); - else - initExistingSite(); + } else { + $scope.site.excluded_ips = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_ips); + $scope.site.excluded_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_parameters); + $scope.site.excluded_user_agents = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_user_agents); + $scope.site.sitesearch_keyword_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.sitesearch_keyword_parameters); + $scope.site.sitesearch_category_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.sitesearch_category_parameters); + } - $scope.site.editDialog = {}; $scope.site.removeDialog = {}; }; var editSite = function () { + $scope.site.editMode = true; - if ($scope.siteIsBeingEdited) { - - $scope.site.editDialog.show = true; - $scope.site.editDialog.title = translate('SitesManager_OnlyOneSiteAtTime', '"' + $scope.lookupCurrentEditSite().name + '"'); - - } else { - - $scope.site.editMode = true; - $scope.informSiteIsBeingEdited(); - } + $scope.measurableSettings = []; + $scope.site.isLoading = true; + piwikApi.fetch({method: 'SitesManager.getSiteSettings', idSite: $scope.site.idsite}).then(function (settings) { + $scope.measurableSettings = settings; + $scope.site.isLoading = false; + }, function () { + $scope.site.isLoading = false; + }); }; var saveSite = function() { @@ -67,106 +78,96 @@ var sendSiteSearchKeywordParams = $scope.site.sitesearch == '1' && !$scope.site.useDefaultSiteSearchParams; var sendSearchCategoryParameters = sendSiteSearchKeywordParams && $scope.customVariablesActivated; - var ajaxHandler = new ajaxHelper(); - ajaxHandler.addParams({ - module: 'API', - format: 'json' - }, 'GET'); - - if(siteIsNew()) { - - ajaxHandler.addParams({ - method: 'SitesManager.addSite' - }, 'GET'); + var values = { + siteName: $scope.site.name, + timezone: $scope.site.timezone, + currency: $scope.site.currency, + type: $scope.site.type, + settingValues: {} + }; - } else { + var isNewSite = isSiteNew(); - ajaxHandler.addParams({ - idSite: $scope.site.idsite, - method: 'SitesManager.updateSite' - }, 'GET'); + var apiMethod = 'SitesManager.addSite'; + if (!isNewSite) { + apiMethod = 'SitesManager.updateSite'; + values.idSite = $scope.site.idsite; } - var settings = $('.typeSettings fieldset').serializeArray(); + angular.forEach($scope.measurableSettings, function (settings) { + if (!values['settingValues'][settings.pluginName]) { + values['settingValues'][settings.pluginName] = []; + } - var flatSettings = ''; - if (settings.length) { - flatSettings = {}; - angular.forEach(settings, function (setting) { - flatSettings[setting.name] = setting.value; + angular.forEach(settings.settings, function (setting) { + var value = setting.value; + if (value === false) { + value = '0'; + } else if (value === true) { + value = '1'; + } + if (angular.isArray(value) && setting.uiControl == 'textarea') { + var newValue = []; + angular.forEach(value, function (val) { + // as they are line separated we cannot trim them in the view + if (val) { + newValue.push(val); + } + }); + value = newValue; + } + + values['settingValues'][settings.pluginName].push({ + name: setting.name, + value: value + }); }); - } + }); - ajaxHandler.addParams({ - siteName: $scope.site.name, - timezone: $scope.site.timezone, - currency: $scope.site.currency, - ecommerce: $scope.site.ecommerce, - excludedIps: $scope.site.excluded_ips.join(','), - excludedQueryParameters: $scope.site.excluded_parameters.join(','), - excludedUserAgents: $scope.site.excluded_user_agents.join(','), - keepURLFragments: $scope.site.keep_url_fragment, - siteSearch: $scope.site.sitesearch, - type: $scope.site.type, - searchKeywordParameters: sendSiteSearchKeywordParams ? $scope.site.sitesearch_keyword_parameters.join(',') : null, - searchCategoryParameters: sendSearchCategoryParameters ? $scope.site.sitesearch_category_parameters.join(',') : null, - urls: $scope.site.alias_urls, - excludeUnknownUrls: $scope.site.exclude_unknown_urls, - settings: flatSettings - }, 'POST'); + piwikApi.post({method: apiMethod}, values).then(function (response) { + $scope.site.editMode = false; - ajaxHandler.redirectOnSuccess($scope.redirectParams); - ajaxHandler.setLoadingElement(); - ajaxHandler.send(true); + var UI = require('piwik/UI'); + var notification = new UI.Notification(); + + var message = 'Website updated'; + if (isNewSite) { + message = 'Website created'; + } + + notification.show(message, {context: 'success', id: 'websitecreated'}); + notification.scrollToNotification(); + + if (!$scope.site.idsite && response && response.value) { + $scope.site.idsite = response.value; + } + + angular.forEach(values.settingValues, function (settings, pluginName) { + angular.forEach(settings, function (setting) { + if (setting.name === 'urls') { + $scope.site.alias_urls = setting.value; + } else { + $scope.site[setting.name] = setting.value; + } + }); + }); + }); }; - var siteIsNew = function() { + var isSiteNew = function() { return angular.isUndefined($scope.site.idsite); }; var initNewSite = function() { - - $scope.informSiteIsBeingEdited(); - $scope.site.editMode = true; $scope.site.name = "Name"; - $scope.site.alias_urls = [ - "http://siteUrl.com/", - "http://siteUrl2.com/" - ]; - $scope.site.exclude_unknown_urls = 0; - $scope.site.keep_url_fragment = 0; - $scope.site.excluded_ips = []; - $scope.site.excluded_parameters = []; - $scope.site.excluded_user_agents = []; - $scope.site.sitesearch_keyword_parameters = []; - $scope.site.sitesearch_category_parameters = []; - $scope.site.sitesearch = $scope.globalSettings.searchKeywordParametersGlobal.length ? 1 : 0; $scope.site.timezone = $scope.globalSettings.defaultTimezone; $scope.site.currency = $scope.globalSettings.defaultCurrency; - $scope.site.ecommerce = 0; - - updateSiteWithSiteSearchConfig(); - }; - var initExistingSite = function() { - - $scope.site.keep_url_fragment = parseInt($scope.site.keep_url_fragment, 10); - $scope.site.ecommerce = parseInt($scope.site.ecommerce, 10); - $scope.site.sitesearch = parseInt($scope.site.sitesearch, 10); - $scope.site.excluded_ips = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_ips); - $scope.site.excluded_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_parameters); - $scope.site.excluded_user_agents = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.excluded_user_agents); - $scope.site.sitesearch_keyword_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.sitesearch_keyword_parameters); - $scope.site.sitesearch_category_parameters = sitesManagerApiHelper.commaDelimitedFieldToArray($scope.site.sitesearch_category_parameters); - - updateSiteWithSiteSearchConfig(); - }; - - var updateSiteWithSiteSearchConfig = function() { - - $scope.site.useDefaultSiteSearchParams = - $scope.globalSettings.searchKeywordParametersGlobal.length && !$scope.site.sitesearch_keyword_parameters.length; + if ($scope.typeSettings) { + // we do not want to manipulate initial type settings + $scope.measurableSettings = angular.copy($scope.typeSettings); + } }; var openDeleteDialog = function() { diff --git a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js index 66c27a7703e6c1b67bbf8be14d2b8277d8e3e353..1236243d2a531162e7d9e02fdb49b4d0d4330932 100644 --- a/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js +++ b/plugins/SitesManager/angularjs/sites-manager/sites-manager.controller.js @@ -20,7 +20,6 @@ $scope.adminSites = adminSites; $scope.hasSuperUserAccess = piwik.hasSuperUserAccess; $scope.redirectParams = {showaddsite: false}; - $scope.siteIsBeingEdited = false; $scope.cacheBuster = piwik.cacheBuster; $scope.totalNumberOfSites = '?'; @@ -40,8 +39,6 @@ $scope.addSite = addSite; $scope.addNewEntity = addNewEntity; $scope.saveGlobalSettings = saveGlobalSettings; - - $scope.informSiteIsBeingEdited = informSiteIsBeingEdited; $scope.lookupCurrentEditSite = lookupCurrentEditSite; $scope.closeAddMeasurableDialog = function () { @@ -62,15 +59,8 @@ }); }; - var informSiteIsBeingEdited = function() { - - $scope.siteIsBeingEdited = true; - }; - var initSelectLists = function() { - initSiteSearchSelectOptions(); - initEcommerceSelectOptions(); initCurrencyList(); initTimezones(); }; @@ -115,14 +105,6 @@ addNewEntity(); }; - var initEcommerceSelectOptions = function() { - - $scope.eCommerceptions = [ - {key: 0, value: translate('SitesManager_NotAnEcommerceSite')}, - {key: 1, value: translate('SitesManager_EnableEcommerce')} - ]; - }; - var initUtcTime = function() { var currentDate = new Date(); @@ -186,14 +168,6 @@ }); }; - var initSiteSearchSelectOptions = function() { - - $scope.siteSearchOptions = [ - {key: 1, value: translate('SitesManager_EnableSiteSearch')}, - {key: 0, value: translate('SitesManager_DisableSiteSearch')} - ]; - }; - var initKeepURLFragmentsList = function() { $scope.keepURLFragmentsOptions = [ {key: 0, value: ($scope.globalSettings.keepURLFragmentsGlobal ? translate('General_Yes') : translate('General_No')) + ' (' + translate('General_Default') + ')'}, @@ -248,9 +222,17 @@ ajaxHandler.send(true); }; - var cancelEditSite = function ($event) { - $event.stopPropagation(); - piwik.helper.redirect($scope.redirectParams); + var cancelEditSite = function (site) { + site.editMode = false; + + var idSite = site.idsite; + if (idSite) { + var siteElement = $('.site[idsite=' + idSite + ']'); + if (siteElement[0]) { + // todo move this into a directive + siteElement[0].scrollIntoView(); + } + } }; var lookupCurrentEditSite = function () { diff --git a/plugins/SitesManager/templates/dialogs/dialogs.html b/plugins/SitesManager/templates/dialogs/dialogs.html index 2f3d5d8072e7380301807f1476958ffd962336f2..e50578ebbc027285cac2d70fe0a5cb1157b97bbe 100644 --- a/plugins/SitesManager/templates/dialogs/dialogs.html +++ b/plugins/SitesManager/templates/dialogs/dialogs.html @@ -1,2 +1 @@ -<div ng-include="'plugins/SitesManager/templates/dialogs/edit-dialog.html'"></div> <div ng-include="'plugins/SitesManager/templates/dialogs/remove-dialog.html'"></div> diff --git a/plugins/SitesManager/templates/dialogs/edit-dialog.html b/plugins/SitesManager/templates/dialogs/edit-dialog.html deleted file mode 100644 index 1bb6067f4762ea22ab64febaa402c4340e16aa09..0000000000000000000000000000000000000000 --- a/plugins/SitesManager/templates/dialogs/edit-dialog.html +++ /dev/null @@ -1,5 +0,0 @@ -<div class="ui-confirm" piwik-dialog="site.editDialog.show"> - <h2>{{ site.editDialog.title }}</h2> - - <input role="no" type="button" value="{{ 'General_Ok'|translate }}"/> -</div> diff --git a/plugins/SitesManager/templates/sites-list/site-fields.html b/plugins/SitesManager/templates/sites-list/site-fields.html index 2f0eaa7b760aec23ade5558db55f9a8a45981225..29b74a48b53e59829e5963b5e05a81377754f0da 100644 --- a/plugins/SitesManager/templates/sites-list/site-fields.html +++ b/plugins/SitesManager/templates/sites-list/site-fields.html @@ -1,4 +1,4 @@ -<div class="site" ng-class="{'editingSite': site.editMode==true}"> +<div class="site" idsite="{{site.idSite}}" ng-class="{'editingSite': site.editMode==true}"> <div class="row" ng-if="!site.editMode"> @@ -71,57 +71,12 @@ <input type="text" ng-model="site.name"/> </div> - <div class="form-group typeSettings" - ng-include="'?module=SitesManager&action=getMeasurableTypeSettings&idSite=' + site.idsite + '&idType=' + site.type" - > - </div> - - <div class="form-group"> - <label>{{ 'SitesManager_Urls'|translate }}</label> - <div class="form-help"> - {{ 'SitesManager_AliasUrlHelp' | translate }} - </div> - <div sites-manager-multiline-field field="site.alias_urls" cols="25" rows="3"></div> + <div piwik-activity-indicator loading="site.isLoading"></div> - <div class="form-help"> - {{ 'SitesManager_OnlyMatchedUrlsAllowedHelp' | translate }} - {{ 'SitesManager_OnlyMatchedUrlsAllowedHelpExamples' | translate }} + <div ng-repeat="settingsPerPlugin in measurableSettings"> + <div ng-repeat="setting in settingsPerPlugin.settings"> + <div piwik-form-field="setting" all-settings="settingsPerPlugin.settings"></div> </div> - <label class="checkbox"> - <input type="checkbox" ng-model="site.exclude_unknown_urls" ng-true-value="1" ng-false-value="0"> {{ 'SitesManager_OnlyMatchedUrlsAllowed' | translate:'':'' }} - </label> - </div> - - <div class="form-group"> - <label>{{ 'SitesManager_KeepURLFragmentsLong'|translate }}</label> - <select ng-options="option.key as option.value for option in keepURLFragmentsOptions" - ng-model="site.keep_url_fragment"></select> - </div> - - <div class="form-group"> - <label>{{ 'SitesManager_ExcludedIps'|translate }}</label> - <div ng-include="'plugins/SitesManager/templates/help/excluded-ip-help.html'"></div> - <div sites-manager-multiline-field field="site.excluded_ips" cols="20" rows="4"></div> - </div> - - <div class="form-group"> - <label>{{ 'SitesManager_ExcludedParameters'|translate }}</label> - <div ng-include="'plugins/SitesManager/templates/help/excluded-query-parameters-help.html'"></div> - <div sites-manager-multiline-field field="site.excluded_parameters" cols="20" rows="4"></div> - </div> - - <div class="form-group" ng-if="globalSettings.siteSpecificUserAgentExcludeEnabled"> - <label>{{ 'SitesManager_ExcludedUserAgents'|translate }}</label> - <div ng-include="'plugins/SitesManager/templates/help/excluded-user-agents-help.html'"></div> - <div sites-manager-multiline-field field="site.excluded_user_agents" cols="20" rows="4"></div> - </div> - - <div ng-include="'plugins/SitesManager/templates/sites-list/site-search-field.html'"></div> - - <div class="form-group"> - <label>{{ 'SitesManager_Timezone'|translate }}</label> - <div ng-include="'plugins/SitesManager/templates/help/timezone-help.html'"></div> - <select ng-model="site.timezone" ng-options="t.code as t.label group by t.group for t in timezones"></select> </div> <div class="form-group"> @@ -133,18 +88,14 @@ </div> <div class="form-group"> - <label>{{ 'Goals_Ecommerce'|translate }}</label> - <div class="form-help"> - {{ 'SitesManager_EcommerceHelp' | translate }} - <br/> - <span ng-bind-html="'SitesManager_PiwikOffersEcommerceAnalytics'|translate:'<a href=\'http://piwik.org/docs/ecommerce-analytics/\' target=\'_blank\'>':'</a>'"></span> - </div> - <select ng-options="option.key as option.value for option in eCommerceptions" ng-model="site.ecommerce"></select> + <label>{{ 'SitesManager_Timezone'|translate }}</label> + <div ng-include="'plugins/SitesManager/templates/help/timezone-help.html'"></div> + <select ng-model="site.timezone" ng-options="t.code as t.label group by t.group for t in timezones"></select> </div> <div class="editingSiteFooter"> - <input type="submit" class="btn" value="{{ 'General_Save' | translate }}" ng-click="saveSite()"/> - <button class="btn btn-link" ng-click="cancelEditSite($event)">{{ 'General_Cancel' | translate:'':'' }}</button> + <input ng-show="!site.isLoading" type="submit" class="btn" value="{{ 'General_Save' | translate }}" ng-click="saveSite()"/> + <button class="btn btn-link" ng-click="cancelEditSite(site)">{{ 'General_Cancel' | translate:'':'' }}</button> </div> </div> diff --git a/plugins/SitesManager/tests/Integration/ApiTest.php b/plugins/SitesManager/tests/Integration/ApiTest.php index 3b26d215cb2d72883ea9c75155f2de697be124a5..ba897a400015b242fa94766c5e75dc5fc24abec9 100644 --- a/plugins/SitesManager/tests/Integration/ApiTest.php +++ b/plugins/SitesManager/tests/Integration/ApiTest.php @@ -8,10 +8,13 @@ namespace Piwik\Plugins\SitesManager\tests\Integration; +use Piwik\Container\StaticContainer; +use Piwik\Settings\Measurable\MeasurableSetting; +use Piwik\Settings\Measurable\MeasurableSettings; use Piwik\Piwik; use Piwik\Plugin; use Piwik\Plugins\MobileAppMeasurable; -use Piwik\Plugins\MobileAppMeasurable\tests\Framework\Mock\Type; +use Piwik\Plugins\MobileAppMeasurable\Type; use Piwik\Plugins\SitesManager\API; use Piwik\Plugins\SitesManager\Model; use Piwik\Plugins\UsersManager\API as APIUsersManager; @@ -189,13 +192,13 @@ class ApiTest extends IntegrationTestCase /** * @expectedException \Exception - * @expectedExceptionMessage Only 100 characters are allowed + * @expectedExceptionMessage SitesManager_OnlyMatchedUrlsAllowed */ public function test_addSite_ShouldFailAndNotCreatedASite_IfASettingIsInvalid() { try { $type = MobileAppMeasurable\Type::ID; - $settings = array('app_id' => str_pad('test', 789, 't')); + $settings = array('WebsiteMeasurable' => array(array('name' => 'exclude_unknown_urls', 'value' => 'fooBar'))); $this->addSiteWithType($type, $settings); } catch (Exception $e) { @@ -210,15 +213,24 @@ class ApiTest extends IntegrationTestCase public function test_addSite_ShouldSavePassedMeasurableSettings_IfSettingsAreValid() { $type = MobileAppMeasurable\Type::ID; - $settings = array('app_id' => 'org.piwik.mobile2'); + $settings = array('WebsiteMeasurable' => array(array('name' => 'urls', 'value' => array('http://www.piwik.org')))); $idSite = $this->addSiteWithType($type, $settings); $this->assertSame(1, $idSite); - $measurable = new Measurable($idSite); - $appId = $measurable->getSettingValue('app_id'); + $settings = $this->getWebsiteMeasurable($idSite); + $urls = $settings->urls->getValue(); + + $this->assertSame(array('http://www.piwik.org'), $urls); + } - $this->assertSame('org.piwik.mobile2', $appId); + /** + * @return \Piwik\Plugins\WebsiteMeasurable\MeasurableSettings + */ + private function getWebsiteMeasurable($idSite) + { + $settings = StaticContainer::get('Piwik\Plugin\SettingsProvider'); + return $settings->getMeasurableSettings('WebsiteMeasurable', $idSite, null); } /** @@ -642,6 +654,7 @@ class ApiTest extends IntegrationTestCase FakeAccess::setIdSitesAdmin(array()); $sites = API::getInstance()->getSitesWithViewAccess(); + // we dont test the ts_created unset($sites[0]['ts_created']); unset($sites[1]['ts_created']); @@ -753,6 +766,7 @@ class ApiTest extends IntegrationTestCase // Updating the group to something $group = 'something'; API::getInstance()->updateSite($idsite, "test toto@{}", $newMainUrl, $ecommerce = 0, $ss = true, $ss_kwd = null, $ss_cat = '', $ips = null, $parametersExclude = null, $timezone = null, $currency = null, $group); + $websites = API::getInstance()->getSitesFromGroup($group); $this->assertEquals(1, count($websites)); $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($websites[0]['ts_created']))); @@ -844,7 +858,7 @@ class ApiTest extends IntegrationTestCase /** * @expectedException \Exception - * @expectedExceptionMessage Only 100 characters are allowed + * @expectedExceptionMessage SitesManager_OnlyMatchedUrlsAllowed */ public function test_updateSite_ShouldFailAndNotUpdateSite_IfASettingIsInvalid() { @@ -852,7 +866,8 @@ class ApiTest extends IntegrationTestCase $idSite = $this->addSiteWithType($type, array()); try { - $this->updateSiteSettings($idSite, 'newSiteName', array('app_id' => str_pad('t', 589, 't'))); + $settings = array('WebsiteMeasurable' => array(array('name' => 'exclude_unknown_urls', 'value' => 'fooBar'))); + $this->updateSiteSettings($idSite, 'newSiteName', $settings); } catch (Exception $e) { // verify nothing was updated (not even the name) @@ -870,12 +885,16 @@ class ApiTest extends IntegrationTestCase $this->assertSame(1, $idSite); - $this->updateSiteSettings($idSite, 'newSiteName', $settings = array('app_id' => 'org.piwik.mobile2')); + $settings = array('WebsiteMeasurable' => array(array('name' => 'urls', 'value' => array('http://www.piwik.org')))); + + $this->updateSiteSettings($idSite, 'newSiteName', $settings); + + $settings = $this->getWebsiteMeasurable($idSite); // verify it was updated $measurable = new Measurable($idSite); $this->assertSame('newSiteName', $measurable->getName()); - $this->assertSame('org.piwik.mobile2', $measurable->getSettingValue('app_id')); + $this->assertSame(array('http://www.piwik.org'), $settings->urls->getValue()); } public function test_updateSite_CorreclySavesExcludedUnknownUrlSettings() @@ -1210,7 +1229,6 @@ class ApiTest extends IntegrationTestCase { return array( 'Piwik\Access' => new FakeAccess(), - 'Piwik\Plugins\MobileAppMeasurable\Type' => new Type() ); } diff --git a/plugins/SitesManager/tests/System/ApiTest.php b/plugins/SitesManager/tests/System/ApiTest.php index d4cc198888f514def3697c2e20429ead546bf439..393a8fc6a44dba2f2d639f5c49951fa26d210bd0 100644 --- a/plugins/SitesManager/tests/System/ApiTest.php +++ b/plugins/SitesManager/tests/System/ApiTest.php @@ -59,6 +59,11 @@ class ApiTest extends SystemTestCase 'otherRequestParameters' => array('pattern' => 'SiteTest1') ) ); + $apiToTest[] = array(array('SitesManager.getSiteSettings'), + array( + 'idSite' => 1 + ) + ); return $apiToTest; } diff --git a/plugins/SitesManager/tests/System/expected/test_SitesManager__SitesManager.getSiteSettings.xml b/plugins/SitesManager/tests/System/expected/test_SitesManager__SitesManager.getSiteSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..6be613478e710638645bbcdad2469b6881ecfc1e --- /dev/null +++ b/plugins/SitesManager/tests/System/expected/test_SitesManager__SitesManager.getSiteSettings.xml @@ -0,0 +1,233 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>WebsiteMeasurable</pluginName> + <settings> + <row> + <name>urls</name> + <title>URLs</title> + <value> + <row>http://piwik.net</row> + </value> + <defaultValue> + <row>http://siteUrl.com/</row> + <row>http://siteUrl2.com/</row> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>25</cols> + <rows>3</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>It is recommended, but not required, to specify the various URLs, one per line, that your visitors use to access this website. Alias URLs for a website will not appear in the Referrers > Websites report. Note that it is not necessary to specify the URLs with and without 'www' as Piwik automatically considers both.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>exclude_unknown_urls</name> + <title>Only track visits and actions when the action URL starts with one of the above URLs.</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>When enabled, Piwik will only track internal actions when the Page URL is one of the known URLs for your website. This prevents people from spamming your analytics with URLs for other websites.<br />The domain and the path has to be an exact match and each valid subdomain has to be specified separately. For example when the known URLs are 'http://example.com/path' and 'http://good.example.com', tracking requests for 'http://example.com/otherpath' or 'http://bad.example.com' are ignored.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>keep_url_fragment</name> + <title>Keep Page URL fragments when tracking Page URLs</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>string</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <row>No (Default)</row> + <row>Yes</row> + <row>No</row> + </availableValues> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>excluded_ips</name> + <title>Excluded IPs</title> + <value> + <row/> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>20</cols> + <rows>4</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter the list of IPs, one per line, that you wish to exclude from being tracked by Piwik. You can use wildcards, eg. 1.2.3.* or 1.2.*.*<br /><br />Your current IP address is <i>127.0.0.1</i></inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>excluded_parameters</name> + <title>Excluded Parameters</title> + <value> + <row/> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>20</cols> + <rows>4</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter the list of URL Query Parameters, one per line, to exclude from the Page URLs reports.<br /><br />Piwik will automatically exclude the common session parameters (phpsessid, sessionid, ...).</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>excluded_user_agents</name> + <title>Excluded User Agents</title> + <value> + <row/> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>20</cols> + <rows>4</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter the list of user agents to exclude from being tracked by Piwik.<br /><br />If the visitor's user agent string contains any of the strings you specify, the visitor will be excluded from Piwik.<br />You can use this to exclude some bots from being tracked.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>sitesearch</name> + <title>Site Search</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>integer</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <row key="1">Site Search tracking enabled</row> + <row key="0">Do not track Site Search</row> + </availableValues> + <description /> + <inlineHelp>You can use Piwik to track and report what visitors are searching in your website's internal search engine.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>use_default_site_search_params</name> + <title>Use <a href='#globalSettings'>default</a> Site Search parameters</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>Query parameter (Default): q,query,s,search,searchword,k,keyword & Category parameter: </description> + <inlineHelp /> + <introduction /> + <condition>1 && sitesearch</condition> + </row> + <row> + <name>sitesearch_keyword_parameters</name> + <title>Query parameter</title> + <value> + <row/> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter a comma separated list of all query parameter names containing the site search keyword.</inlineHelp> + <introduction /> + <condition>sitesearch && !use_default_site_search_params</condition> + </row> + <row> + <name>sitesearch_category_parameters</name> + <title>Category parameter</title> + <value> + <row/> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>(optional)<br /><br />You may enter a comma-separated list of query parameters specifying the search category.</inlineHelp> + <introduction /> + <condition>1 && sitesearch && !use_default_site_search_params</condition> + </row> + <row> + <name>ecommerce</name> + <title>Ecommerce</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <row>Not an Ecommerce site</row> + <row>Ecommerce enabled</row> + </availableValues> + <description /> + <inlineHelp>When enabled, the "Goals" report will have a new "Ecommerce" section.<br />Piwik allows for advanced Ecommerce Analytics tracking & reporting. Learn more about <a href='http://piwik.org/docs/ecommerce-analytics/' target='_blank'> Ecommerce Analytics</a>.</inlineHelp> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>contact_email</name> + <title>Contact email addresses</title> + <value> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/plugins/UserLanguage/Reports/GetLanguage.php b/plugins/UserLanguage/Reports/GetLanguage.php index 8db3629134d3b522f73acb1d45f116b97fef7ff4..ef570b229f6c809ba3017a2bb0192e79443e908a 100644 --- a/plugins/UserLanguage/Reports/GetLanguage.php +++ b/plugins/UserLanguage/Reports/GetLanguage.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\UserLanguage\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\UserLanguage\Columns\Language; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetLanguage extends Base { @@ -37,7 +37,7 @@ class GetLanguage extends Base public function getRelatedReports() { return array( - Reports::factory('UserLanguage', 'getLanguageCode'), + ReportsProvider::factory('UserLanguage', 'getLanguageCode'), ); } diff --git a/plugins/UserLanguage/Reports/GetLanguageCode.php b/plugins/UserLanguage/Reports/GetLanguageCode.php index 9d9a46f2013db0f6f59f8b73829727db9b2f59ed..278bf7a75110878fb8163975cccdb1e69ef720b4 100644 --- a/plugins/UserLanguage/Reports/GetLanguageCode.php +++ b/plugins/UserLanguage/Reports/GetLanguageCode.php @@ -10,7 +10,7 @@ namespace Piwik\Plugins\UserLanguage\Reports; use Piwik\Piwik; use Piwik\Plugins\UserLanguage\Columns\Language; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetLanguageCode extends GetLanguage { @@ -26,7 +26,7 @@ class GetLanguageCode extends GetLanguage public function getRelatedReports() { return array( - Reports::factory('UserLanguage', 'getLanguage'), + ReportsProvider::factory('UserLanguage', 'getLanguage'), ); } diff --git a/plugins/UsersManager/templates/userSettings.twig b/plugins/UsersManager/templates/userSettings.twig index 5752807eafaad7a6710b5af35b23d896308e99e3..48d5f47ed95b107a03d4e8fd582fcf67e64bf131 100644 --- a/plugins/UsersManager/templates/userSettings.twig +++ b/plugins/UsersManager/templates/userSettings.twig @@ -117,18 +117,24 @@ </form> -<h2 id="excludeCookie">{{ 'UsersManager_ExcludeVisitsViaCookie'|translate }}</h2> -<p> - {% if ignoreCookieSet %} - {{ 'UsersManager_YourVisitsAreIgnoredOnDomain'|translate("<strong>", piwikHost, "</strong>")|raw }} - {% else %} - {{ 'UsersManager_YourVisitsAreNotIgnored'|translate("<strong>","</strong>")|raw }} - {% endif %} -</p> -<span style="margin-left:20px;"> + <hr /> + + <h2 piwik-enriched-headline>{{ 'CoreAdminHome_PersonalPluginSettings'|translate }}</h2> + + <div piwik-plugin-settings mode="user"></div> + + <hr /> + <h2 id="excludeCookie">{{ 'UsersManager_ExcludeVisitsViaCookie'|translate }}</h2> + <p> + {% if ignoreCookieSet %} + {{ 'UsersManager_YourVisitsAreIgnoredOnDomain'|translate("<strong>", piwikHost, "</strong>")|raw }} + {% else %} + {{ 'UsersManager_YourVisitsAreNotIgnored'|translate("<strong>","</strong>")|raw }} + {% endif %} + </p> + <span style="margin-left:20px;"> <a href='{{ linkTo({'ignoreSalt':ignoreSalt, 'action':'setIgnoreCookie'}) }}#excludeCookie'>› {% if ignoreCookieSet %}{{ 'UsersManager_ClickHereToDeleteTheCookie'|translate }} {% else %}{{'UsersManager_ClickHereToSetTheCookieOnDomain'|translate(piwikHost) }}{% endif %} <br/> </a></span> - {% endblock %} diff --git a/plugins/VisitTime/Reports/GetByDayOfWeek.php b/plugins/VisitTime/Reports/GetByDayOfWeek.php index a93c6f21ee4284312fffc155525e95c87026f798..2cc5bdc6ad5d655d618c843d5d0dff150f619a59 100644 --- a/plugins/VisitTime/Reports/GetByDayOfWeek.php +++ b/plugins/VisitTime/Reports/GetByDayOfWeek.php @@ -14,7 +14,7 @@ use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; use Piwik\Plugins\VisitTime\Columns\DayOfTheWeek; use Piwik\Period; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Site; class GetByDayOfWeek extends Base @@ -78,7 +78,7 @@ class GetByDayOfWeek extends Base public function getRelatedReports() { return array( - Reports::factory('VisitTime', 'getVisitInformationPerLocalTime') + ReportsProvider::factory('VisitTime', 'getVisitInformationPerLocalTime') ); } } diff --git a/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php b/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php index 937287561988896fa53b1fdf2947d24e0102a12b..5f79fdc6fec78fb6fea9055a91f12a21d4668795 100644 --- a/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php +++ b/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php @@ -13,7 +13,7 @@ use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; use Piwik\Plugins\VisitTime\Columns\LocalTime; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; class GetVisitInformationPerLocalTime extends Base { @@ -49,7 +49,7 @@ class GetVisitInformationPerLocalTime extends Base public function getRelatedReports() { return array( - Reports::factory('VisitTime', 'getByDayOfWeek') + ReportsProvider::factory('VisitTime', 'getByDayOfWeek') ); } } diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php index c46bd93b7b604af99a45845779f9b1b4521b3e17..db0a52ce8639d11274c667961641f8226ca79bf0 100644 --- a/plugins/VisitsSummary/API.php +++ b/plugins/VisitsSummary/API.php @@ -12,7 +12,7 @@ use Piwik\Archive; use Piwik\Metrics\Formatter; use Piwik\Piwik; use Piwik\Plugin\Report; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\SettingsPiwik; /** @@ -30,7 +30,7 @@ class API extends \Piwik\Plugin\API $requestedColumns = Piwik::getArrayFromApiParameter($columns); - $report = Reports::factory("VisitsSummary", "get"); + $report = ReportsProvider::factory("VisitsSummary", "get"); $columns = $report->getMetricsRequiredForReport($this->getCoreColumns($period), $requestedColumns); $dataTable = $archive->getDataTableFromNumeric($columns); diff --git a/plugins/VisitsSummary/Widgets/Index.php b/plugins/VisitsSummary/Widgets/Index.php index 1b39fad7c60295b85c9767c3324dd810c6b3a542..0de38cfd420497de9ad7a02a05bcd2778ce188e8 100644 --- a/plugins/VisitsSummary/Widgets/Index.php +++ b/plugins/VisitsSummary/Widgets/Index.php @@ -11,7 +11,7 @@ namespace Piwik\Plugins\VisitsSummary\Widgets; use Piwik\Plugin\Report; use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Widget\WidgetsList; @@ -24,12 +24,12 @@ class Index extends \Piwik\Widget\WidgetContainerConfig public function isEnabled() { - return Reports::factory('VisitsSummary', 'get')->isEnabled(); + return ReportsProvider::factory('VisitsSummary', 'get')->isEnabled(); } public function getWidgetConfigs() { - $report = Reports::factory('VisitsSummary', 'get'); + $report = ReportsProvider::factory('VisitsSummary', 'get'); $factory = new ReportWidgetFactory($report); $widgets = array(); diff --git a/plugins/WebsiteMeasurable/MeasurableSettings.php b/plugins/WebsiteMeasurable/MeasurableSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..625007238f25464f90a68a68535c6d7c0a00b6ed --- /dev/null +++ b/plugins/WebsiteMeasurable/MeasurableSettings.php @@ -0,0 +1,314 @@ +<?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\Plugins\WebsiteMeasurable; +use Piwik\IP; +use Piwik\Network\IPUtils; +use Piwik\Piwik; +use Piwik\Plugin; +use Piwik\Plugins\WebsiteMeasurable\Settings\Urls; +use Piwik\Settings\Setting; +use Piwik\Settings\FieldConfig; +use Piwik\Plugins\SitesManager; +use Exception; + +/** + * Defines Settings for ExampleSettingsPlugin. + * + * Usage like this: + * $settings = new MeasurableSettings($idSite); + * $settings->autoRefresh->getValue(); + * $settings->metric->getValue(); + */ +class MeasurableSettings extends \Piwik\Settings\Measurable\MeasurableSettings +{ + /** @var Setting */ + public $urls; + + /** @var Setting */ + public $onlyTrackWhitelstedUrls; + + /** @var Setting */ + public $keepPageUrlFragments; + + /** @var Setting */ + public $excludeKnownUrls; + + /** @var Setting */ + public $excludedUserAgents; + + /** @var Setting */ + public $excludedIps; + + /** @var Setting */ + public $siteSearch; + + /** @var Setting */ + public $useDefaultSiteSearchParams; + + /** @var Setting */ + public $siteSearchKeywords; + + /** @var Setting */ + public $siteSearchCategory; + + /** @var Setting */ + public $excludedParameters; + + /** @var Setting */ + public $ecommerce; + + /** + * @var SitesManager\API + */ + private $sitesManagerApi; + + /** + * @var Plugin\Manager + */ + private $pluginManager; + + public function __construct(SitesManager\API $api, Plugin\Manager $pluginManager, $idSite, $idMeasurableType) + { + $this->sitesManagerApi = $api; + $this->pluginManager = $pluginManager; + + parent::__construct($idSite, $idMeasurableType); + } + + protected function init() + { + $this->urls = new Urls($this->idSite); + $this->addSetting($this->urls); + + $this->excludeKnownUrls = $this->makeExcludeUnknownUrls(); + $this->keepPageUrlFragments = $this->makeKeepUrlFragments($this->sitesManagerApi); + $this->excludedIps = $this->makeExcludeIps(); + $this->excludedParameters = $this->makeExcludedParameters(); + $this->excludedUserAgents = $this->makeExcludedUserAgents(); + + /** + * SiteSearch + */ + $this->siteSearch = $this->makeSiteSearch(); + $this->useDefaultSiteSearchParams = $this->makeUseDefaultSiteSearchParams($this->sitesManagerApi); + $this->siteSearchKeywords = $this->makeSiteSearchKeywords(); + + $siteSearchKeywords = $this->siteSearchKeywords->getValue(); + $this->useDefaultSiteSearchParams->setDefaultValue(empty($siteSearchKeywords)); + + $this->siteSearchCategory = $this->makeSiteSearchCategory($this->pluginManager); + /** + * SiteSearch End + */ + + $this->ecommerce = $this->makeEcommerce(); + } + + private function makeExcludeUnknownUrls() + { + return $this->makeProperty('exclude_unknown_urls', $default = false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) { + $field->title = Piwik::translate('SitesManager_OnlyMatchedUrlsAllowed'); + $field->inlineHelp = Piwik::translate('SitesManager_OnlyMatchedUrlsAllowedHelp') + . '<br />' + . Piwik::translate('SitesManager_OnlyMatchedUrlsAllowedHelpExamples'); + $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX; + }); + } + + private function makeKeepUrlFragments(SitesManager\API $sitesManagerApi) + { + return $this->makeProperty('keep_url_fragment', $default = '0', FieldConfig::TYPE_STRING, function (FieldConfig $field) use ($sitesManagerApi) { + $field->title = Piwik::translate('SitesManager_KeepURLFragmentsLong'); + $field->uiControl = FieldConfig::UI_CONTROL_SINGLE_SELECT; + + if ($sitesManagerApi->getKeepURLFragmentsGlobal()) { + $default = Piwik::translate('General_Yes'); + } else { + $default = Piwik::translate('General_No'); + } + + $field->availableValues = array( + '0' => $default . ' (' . Piwik::translate('General_Default') . ')', + '1' => Piwik::translate('General_Yes'), + '2' => Piwik::translate('General_No') + ); + }); + } + + private function makeExcludeIps() + { + return $this->makeProperty('excluded_ips', $default = array(), FieldConfig::TYPE_ARRAY, function (FieldConfig $field) { + $ip = IP::getIpFromHeader(); + + $field->title = Piwik::translate('SitesManager_ExcludedIps'); + $field->inlineHelp = Piwik::translate('SitesManager_HelpExcludedIps', array('1.2.3.*', '1.2.*.*')) + . '<br /><br />' + . Piwik::translate('SitesManager_YourCurrentIpAddressIs', array('<i>' . $ip . '</i>')); + $field->uiControl = FieldConfig::UI_CONTROL_TEXTAREA; + $field->uiControlAttributes = array('cols' => '20', 'rows' => '4'); + + $field->validate = function ($value) { + if (!empty($value)) { + $ips = array_map('trim', $value); + $ips = array_filter($ips, 'strlen'); + + foreach ($ips as $ip) { + if (IPUtils::getIPRangeBounds($ip) === null) { + throw new Exception(Piwik::translate('SitesManager_ExceptionInvalidIPFormat', array($ip, "1.2.3.4, 1.2.3.*, or 1.2.3.4/5"))); + } + } + } + }; + $field->transform = function ($value) { + if (empty($value)) { + return array(); + } + + $ips = array_map('trim', $value); + $ips = array_filter($ips, 'strlen'); + return $ips; + }; + }); + } + + private function makeExcludedParameters() + { + $self = $this; + return $this->makeProperty('excluded_parameters', $default = array(), FieldConfig::TYPE_ARRAY, function (FieldConfig $field) use ($self) { + $field->title = Piwik::translate('SitesManager_ExcludedParameters'); + $field->inlineHelp = Piwik::translate('SitesManager_ListOfQueryParametersToExclude') + . '<br /><br />' + . Piwik::translate('SitesManager_PiwikWillAutomaticallyExcludeCommonSessionParameters', array('phpsessid, sessionid, ...')); + $field->uiControl = FieldConfig::UI_CONTROL_TEXTAREA; + $field->uiControlAttributes = array('cols' => '20', 'rows' => '4'); + $field->transform = function ($value) use ($self) { + return $self->checkAndReturnCommaSeparatedStringList($value); + }; + }); + } + + private function makeExcludedUserAgents() + { + $self = $this; + return $this->makeProperty('excluded_user_agents', $default = array(), FieldConfig::TYPE_ARRAY, function (FieldConfig $field) use ($self) { + $field->title = Piwik::translate('SitesManager_ExcludedUserAgents'); + $field->inlineHelp = Piwik::translate('SitesManager_GlobalExcludedUserAgentHelp1') + . '<br /><br />' + . Piwik::translate('SitesManager_GlobalListExcludedUserAgents_Desc') + . '<br />' + . Piwik::translate('SitesManager_GlobalExcludedUserAgentHelp2'); + $field->uiControl = FieldConfig::UI_CONTROL_TEXTAREA; + $field->uiControlAttributes = array('cols' => '20', 'rows' => '4'); + $field->transform = function ($value) use ($self) { + return $self->checkAndReturnCommaSeparatedStringList($value); + }; + }); + } + + private function makeSiteSearch() + { + return $this->makeProperty('sitesearch', $default = 1, FieldConfig::TYPE_INT, function (FieldConfig $field) { + $field->title = Piwik::translate('Actions_SubmenuSitesearch'); + $field->inlineHelp = Piwik::translate('SitesManager_SiteSearchUse'); + $field->uiControl = FieldConfig::UI_CONTROL_SINGLE_SELECT; + $field->availableValues = array( + 1 => Piwik::translate('SitesManager_EnableSiteSearch'), + 0 => Piwik::translate('SitesManager_DisableSiteSearch') + ); + }); + } + + private function makeUseDefaultSiteSearchParams(SitesManager\API $sitesManagerApi) + { + return $this->makeSetting('use_default_site_search_params', $default = true, FieldConfig::TYPE_BOOL, function (FieldConfig $field) use ($sitesManagerApi) { + + if (Piwik::hasUserSuperUserAccess()) { + $title = Piwik::translate('SitesManager_SearchUseDefault', array("<a href='#globalSettings'>","</a>")); + } else { + $title = Piwik::translate('SitesManager_SearchUseDefault', array('', '')); + } + + $field->title = $title; + $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX; + + $searchKeywordsGlobal = $sitesManagerApi->getSearchKeywordParametersGlobal(); + + $hasParams = (int) !empty($searchKeywordsGlobal); + $field->condition = $hasParams . ' && sitesearch'; + + $searchKeywordsGlobal = $sitesManagerApi->getSearchKeywordParametersGlobal(); + $searchCategoryGlobal = $sitesManagerApi->getSearchCategoryParametersGlobal(); + + $field->description = Piwik::translate('SitesManager_SearchKeywordLabel'); + $field->description .= ' (' . Piwik::translate('General_Default') . ')'; + $field->description .= ': '; + $field->description .= $searchKeywordsGlobal; + $field->description .= ' & '; + $field->description .= Piwik::translate('SitesManager_SearchCategoryLabel'); + $field->description .= ': '; + $field->description .= $searchCategoryGlobal; + $field->transform = function () { + return null;// never actually save a value for this + }; + }); + } + + private function makeSiteSearchKeywords() + { + return $this->makeProperty('sitesearch_keyword_parameters', $default = array(), FieldConfig::TYPE_ARRAY, function (FieldConfig $field) { + $field->title = Piwik::translate('SitesManager_SearchKeywordLabel'); + $field->uiControl = FieldConfig::UI_CONTROL_TEXT; + $field->inlineHelp = Piwik::translate('SitesManager_SearchKeywordParametersDesc'); + $field->condition = Piwik::translate('sitesearch && !use_default_site_search_params'); + }); + } + + private function makeSiteSearchCategory(Plugin\Manager $pluginManager) + { + return $this->makeProperty('sitesearch_category_parameters', $default = array(), FieldConfig::TYPE_ARRAY, function (FieldConfig $field) use ($pluginManager) { + $field->title = Piwik::translate('SitesManager_SearchCategoryLabel'); + $field->uiControl = FieldConfig::UI_CONTROL_TEXT; + $field->inlineHelp = Piwik::translate('Goals_Optional') + . '<br /><br />' + . Piwik::translate('SitesManager_SearchCategoryParametersDesc'); + + $hasCustomVars = (int) $pluginManager->isPluginActivated('CustomVariables'); + $field->condition = $hasCustomVars . ' && sitesearch && !use_default_site_search_params'; + }); + } + + private function makeEcommerce() + { + return $this->makeProperty('ecommerce', $default = 0, FieldConfig::TYPE_INT, function (FieldConfig $field) { + $field->title = Piwik::translate('Goals_Ecommerce'); + $field->inlineHelp = Piwik::translate('SitesManager_EcommerceHelp') + . '<br />' + . Piwik::translate('SitesManager_PiwikOffersEcommerceAnalytics', + array("<a href='http://piwik.org/docs/ecommerce-analytics/' target='_blank'>", '</a>')); + $field->uiControl = FieldConfig::UI_CONTROL_SINGLE_SELECT; + $field->availableValues = array( + 0 => Piwik::translate('SitesManager_NotAnEcommerceSite'), + 1 => Piwik::translate('SitesManager_EnableEcommerce') + ); + }); + } + + public function checkAndReturnCommaSeparatedStringList($parameters) + { + if (empty($parameters)) { + return array(); + } + + $parameters = array_map('trim', $parameters); + $parameters = array_filter($parameters, 'strlen'); + $parameters = array_unique($parameters); + return $parameters; + } + +} diff --git a/plugins/WebsiteMeasurable/Settings/Urls.php b/plugins/WebsiteMeasurable/Settings/Urls.php new file mode 100644 index 0000000000000000000000000000000000000000..3aa023c1e04559b37c6d8c0a85d035bd8c992e2f --- /dev/null +++ b/plugins/WebsiteMeasurable/Settings/Urls.php @@ -0,0 +1,141 @@ +<?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\Plugins\WebsiteMeasurable\Settings; +use Piwik\Common; +use Piwik\Piwik; +use Piwik\Plugin; +use Piwik\Settings\FieldConfig; +use Piwik\Plugins\SitesManager; +use Exception; +use Piwik\UrlHelper; + +class Urls extends \Piwik\Settings\Measurable\MeasurableProperty +{ + + public function __construct($idSite) + { + $name = 'urls'; + $pluginName = 'WebsiteMeasurable'; + $defaultValue = array('http://siteUrl.com/', 'http://siteUrl2.com/'); + $type = FieldConfig::TYPE_ARRAY; + + parent::__construct($name, $defaultValue, $type, $pluginName, $idSite); + } + + public function configureField() + { + if ($this->config) { + return $this->config; + } + + $config = new FieldConfig(); + $config->title = Piwik::translate('SitesManager_Urls'); + $config->inlineHelp = Piwik::translate('SitesManager_AliasUrlHelp'); + $config->uiControl = FieldConfig::UI_CONTROL_TEXTAREA; + $config->uiControlAttributes = array('cols' => '25', 'rows' => '3'); + + $self = $this; + $config->validate = function ($urls) use ($self) { + $self->checkUrls($urls); + $self->checkAtLeastOneUrl($urls); + }; + + $config->transform = function ($urls) use ($self) { + return $this->cleanParameterUrls($urls); + }; + + $this->config = $config; + return $this->config; + } + + /** + * Checks that the array has at least one element + * + * @param array $urls + * @throws Exception + */ + public function checkAtLeastOneUrl($urls) + { + $urls = $this->cleanParameterUrls($urls); + + if (!is_array($urls) + || count($urls) == 0 + ) { + throw new Exception(Piwik::translate('SitesManager_ExceptionNoUrl')); + } + } + + /** + * Check that the array of URLs are valid URLs + * + * @param array $urls + * @throws Exception if any of the urls is not valid + */ + public function checkUrls($urls) + { + $urls = $this->cleanParameterUrls($urls); + + foreach ($urls as $url) { + if (!UrlHelper::isLookLikeUrl($url)) { + throw new Exception(sprintf(Piwik::translate('SitesManager_ExceptionInvalidUrl'), $url)); + } + } + } + + /** + * Clean the parameter URLs: + * - if the parameter is a string make it an array + * - remove the trailing slashes if found + * + * @param string|array urls + * @return array the array of cleaned URLs + */ + public function cleanParameterUrls($urls) + { + if (!is_array($urls)) { + $urls = array($urls); + } + + $urls = array_filter($urls); + $urls = array_map('urldecode', $urls); + + foreach ($urls as &$url) { + $url = $this->removeTrailingSlash($url); + $scheme = parse_url($url, PHP_URL_SCHEME); + if (empty($scheme) + && strpos($url, '://') === false + ) { + $url = 'http://' . $url; + } + $url = trim($url); + $url = Common::sanitizeInputValue($url); + } + + $urls = array_unique($urls); + return $urls; + } + + /** + * Remove the final slash in the URLs if found + * + * @param string $url + * @return string the URL without the trailing slash + */ + private function removeTrailingSlash($url) + { + // if there is a final slash, we take the URL without this slash (expected URL format) + if (strlen($url) > 5 + && $url[strlen($url) - 1] == '/' + ) { + $url = substr($url, 0, strlen($url) - 1); + } + + return $url; + } +} diff --git a/plugins/WebsiteMeasurable/Type.php b/plugins/WebsiteMeasurable/Type.php index 714b9dd580c5b11bc0258de595a2629dd3b3cec6..0552f47103f476bdebde3ca2534df32b39c646bc 100644 --- a/plugins/WebsiteMeasurable/Type.php +++ b/plugins/WebsiteMeasurable/Type.php @@ -15,5 +15,6 @@ class Type extends \Piwik\Measurable\Type protected $namePlural = 'SitesManager_Sites'; // translated into more languages protected $description = 'WebsiteMeasurable_WebsiteDescription'; protected $howToSetupUrl = '?module=CoreAdminHome&action=trackingCodeGenerator'; + } diff --git a/tests/PHPUnit/Framework/Fixture.php b/tests/PHPUnit/Framework/Fixture.php index 9ef26bbb6795c41cd6a57a494de61f9f0c9aead9..736ffad5fe86741724516bab3e0dd7761a425dbc 100644 --- a/tests/PHPUnit/Framework/Fixture.php +++ b/tests/PHPUnit/Framework/Fixture.php @@ -342,6 +342,7 @@ class Fixture extends \PHPUnit_Framework_Assert self::unloadAllPlugins(); + if ($this->dropDatabaseInTearDown) { $this->dropDatabase(); } @@ -368,6 +369,7 @@ class Fixture extends \PHPUnit_Framework_Assert Singleton::clearAll(); PluginsArchiver::$archivers = array(); + Plugin\API::unsetAllInstances(); $_GET = $_REQUEST = array(); Translate::reset(); diff --git a/tests/PHPUnit/Framework/Mock/Settings/FakeBackend.php b/tests/PHPUnit/Framework/Mock/Settings/FakeBackend.php new file mode 100644 index 0000000000000000000000000000000000000000..f57a90d15941bf795fd036c7bf87234e4afa7896 --- /dev/null +++ b/tests/PHPUnit/Framework/Mock/Settings/FakeBackend.php @@ -0,0 +1,43 @@ +<?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\Tests\Framework\Mock\Settings; + +use Piwik\Settings\Storage\Backend\BackendInterface; + +class FakeBackend implements BackendInterface +{ + private $storageId; + + private $data = array('field1' => 'value1', 'field2' => 'value2'); + + public function __construct($storageId) + { + $this->storageId = $storageId; + } + + public function load() + { + return $this->data; + } + + public function getStorageId() + { + return $this->storageId; + } + + public function delete() + { + $this->data = array(); + } + + public function save($values) + { + $this->data = $values; + } +} diff --git a/tests/PHPUnit/Framework/Mock/Settings/FakeMeasurableSettings.php b/tests/PHPUnit/Framework/Mock/Settings/FakeMeasurableSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..4fb569b9d85ff837ea6cd650a6d6b792e85c06b9 --- /dev/null +++ b/tests/PHPUnit/Framework/Mock/Settings/FakeMeasurableSettings.php @@ -0,0 +1,36 @@ +<?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\Tests\Framework\Mock\Settings; + +use Piwik\Settings\Setting; + +class FakeMeasurableSettings extends \Piwik\Plugins\ExampleSettingsPlugin\MeasurableSettings { + protected $pluginName = 'ExampleSettingsPlugin'; + + public function init() + { + + } + + public function makeSetting($name, $defaultValue, $type, $fieldConfigCallback) + { + return parent::makeSetting($name, $defaultValue, $type, $fieldConfigCallback); + } + + public function makeProperty($name, $defaultValue, $type, $configureCallback) + { + return parent::makeProperty($name, $defaultValue, $type, $configureCallback); + } + + public function addSetting(Setting $setting) + { + parent::addSetting($setting); + } +} + diff --git a/tests/PHPUnit/Framework/Mock/Settings/FakeSystemSettings.php b/tests/PHPUnit/Framework/Mock/Settings/FakeSystemSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..b7c77def9ebac8aa1f475737c0a200ff8100b8f6 --- /dev/null +++ b/tests/PHPUnit/Framework/Mock/Settings/FakeSystemSettings.php @@ -0,0 +1,31 @@ +<?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\Tests\Framework\Mock\Settings; + +use Piwik\Settings\Setting; + +class FakeSystemSettings extends \Piwik\Plugins\ExampleSettingsPlugin\SystemSettings { + protected $pluginName = 'ExampleSettingsPlugin'; + + public function init() + { + + } + + public function makeSetting($name, $defaultValue, $type, $configureCallback) + { + return parent::makeSetting($name, $defaultValue, $type, $configureCallback); + } + + public function addSetting(Setting $setting) + { + parent::addSetting($setting); + } +} + diff --git a/tests/PHPUnit/Framework/Mock/Settings/FakeUserSettings.php b/tests/PHPUnit/Framework/Mock/Settings/FakeUserSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..9d4bb5fdb1f433741e1fe419a0bd6cd7ec891e5e --- /dev/null +++ b/tests/PHPUnit/Framework/Mock/Settings/FakeUserSettings.php @@ -0,0 +1,31 @@ +<?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\Tests\Framework\Mock\Settings; + +use Piwik\Settings\Setting; + +class FakeUserSettings extends \Piwik\Plugins\ExampleSettingsPlugin\UserSettings { + protected $pluginName = 'ExampleSettingsPlugin'; + + public function init() + { + + } + + public function makeSetting($name, $defaultValue, $type, $configureCallback) + { + return parent::makeSetting($name, $defaultValue, $type, $configureCallback); + } + + public function addSetting(Setting $setting) + { + parent::addSetting($setting); + } +} + diff --git a/tests/PHPUnit/Integration/Measurable/MeasurableSettingTest.php b/tests/PHPUnit/Integration/Measurable/MeasurableSettingTest.php index d0e45286e7dc73413e175306d5d106fc7271aab3..5c8ae14aad36b50fd1829af8e242974a8678e192 100644 --- a/tests/PHPUnit/Integration/Measurable/MeasurableSettingTest.php +++ b/tests/PHPUnit/Integration/Measurable/MeasurableSettingTest.php @@ -8,8 +8,10 @@ namespace Piwik\Tests\Integration\Measurable; -use Piwik\Measurable\MeasurableSetting; -use Piwik\Settings\Storage; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Measurable\MeasurableSetting; +use Piwik\Settings\Storage\Storage; +use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\Mock\FakeAccess; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; @@ -21,14 +23,13 @@ class MeasurableSettingTest extends IntegrationTestCase public function setUp() { parent::setUp(); + Fixture::createWebsite('2014-01-01 00:00:01'); FakeAccess::$superUser = true; } private function createSetting() { - $setting = new MeasurableSetting('name', 'test'); - $storage = new Storage('test'); - $setting->setStorage($storage); + $setting = new MeasurableSetting('name', $default = '', FieldConfig::TYPE_STRING, 'Plugin', $idSite = 1); return $setting; } @@ -62,16 +63,6 @@ class MeasurableSettingTest extends IntegrationTestCase $this->createSetting()->setValue('test'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed - */ - public function testGetSettingValue_shouldThrowException_IfNoPermissionToRead() - { - FakeAccess::clearAccess(); - $this->createSetting()->getValue(); - } - public function provideContainerConfig() { return array( diff --git a/tests/PHPUnit/Integration/Measurable/MeasurableSettingsTest.php b/tests/PHPUnit/Integration/Measurable/MeasurableSettingsTest.php index 60e1951d93443b68ee86c53c4d500de302e0b62c..c4f8a19ce99da76b7c14272ff572f99a518f234c 100644 --- a/tests/PHPUnit/Integration/Measurable/MeasurableSettingsTest.php +++ b/tests/PHPUnit/Integration/Measurable/MeasurableSettingsTest.php @@ -8,12 +8,11 @@ namespace Piwik\Tests\Integration\Measurable; +use Piwik\Access; use Piwik\Db; use Piwik\Plugin; -use Piwik\Plugins\MobileAppMeasurable\tests\Framework\Mock\Type; -use Piwik\Plugins\MobileAppMeasurable\Type as MobileAppType; -use Piwik\Measurable\MeasurableSetting; -use Piwik\Measurable\MeasurableSettings; +use Piwik\Plugins\WebsiteMeasurable\Type as WebsiteType; +use Piwik\Plugins\WebsiteMeasurable\MeasurableSettings; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\Mock\FakeAccess; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; @@ -36,10 +35,8 @@ class MeasurableSettingsTest extends IntegrationTestCase FakeAccess::$superUser = true; - Plugin\Manager::getInstance()->activatePlugin('MobileAppMeasurable'); - if (!Fixture::siteCreated($this->idSite)) { - $type = MobileAppType::ID; + $type = WebsiteType::ID; Fixture::createWebsite('2015-01-01 00:00:00', $ecommerce = 0, $siteName = false, $siteUrl = false, $siteSearch = 1, $searchKeywordParameters = null, @@ -49,50 +46,37 @@ class MeasurableSettingsTest extends IntegrationTestCase $this->settings = $this->createSettings(); } - public function test_init_shouldAddSettingsFromType() - { - $this->assertNotEmpty($this->settings->getSetting('app_id')); - } - public function test_save_shouldActuallyStoreValues() { - $this->settings->getSetting('test2')->setValue('value2'); - $this->settings->getSetting('test3')->setValue('value3'); - - $this->assertStoredSettingsValue(null, 'test2'); - $this->assertStoredSettingsValue(null, 'test3'); - + $this->settings->siteSearchKeywords->setValue(array('value2')); + $this->settings->siteSearchCategory->setValue(array('value3')); $this->settings->save(); - $this->assertStoredSettingsValue('value2', 'test2'); - $this->assertStoredSettingsValue('value3', 'test3'); + $this->assertStoredSettingsValue(array('value2'), 'sitesearch_keyword_parameters'); + $this->assertStoredSettingsValue(array('value3'), 'sitesearch_category_parameters'); } /** * @expectedException \Exception - * @expectedExceptionMessage checkUserHasAdminAccess + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed */ public function test_save_shouldCheckAdminPermissionsForThatSite() { FakeAccess::clearAccess(); + $this->settings = $this->createSettings(); + $this->settings->siteSearchKeywords->setValue(array('value4')); $this->settings->save(); } private function createSettings() { - $settings = new MeasurableSettings($this->idSite, MobileAppType::ID); - $settings->addSetting($this->createSetting('test2')); - $settings->addSetting($this->createSetting('test3')); + $provider = new Plugin\SettingsProvider(Plugin\Manager::getInstance()); + $settings = $provider->getMeasurableSettings('WebsiteMeasurable', $this->idSite, WebsiteType::ID); return $settings; } - private function createSetting($name) - { - return new MeasurableSetting($name, $name . ' Name'); - } - private function assertStoredSettingsValue($expectedValue, $settingName) { $settings = $this->createSettings(); @@ -105,7 +89,6 @@ class MeasurableSettingsTest extends IntegrationTestCase { return array( 'Piwik\Access' => new FakeAccess(), - 'Piwik\Plugins\MobileAppMeasurable\Type' => new Type() ); } } diff --git a/tests/PHPUnit/Integration/Measurable/MeasurableTest.php b/tests/PHPUnit/Integration/Measurable/MeasurableTest.php deleted file mode 100644 index e74ebb7b4038034d4600fb9ffe9ba565856285c3..0000000000000000000000000000000000000000 --- a/tests/PHPUnit/Integration/Measurable/MeasurableTest.php +++ /dev/null @@ -1,93 +0,0 @@ -<?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\Tests\Integration\Measurable; - -use Piwik\Db; -use Piwik\Plugins\MobileAppMeasurable\tests\Framework\Mock\Type; -use Piwik\Plugins\MobileAppMeasurable\Type as MobileAppType; -use Piwik\Plugin; -use Piwik\Measurable\Measurable; -use Piwik\Measurable\MeasurableSettings; -use Piwik\Tests\Framework\Fixture; -use Piwik\Tests\Framework\Mock\FakeAccess; -use Piwik\Tests\Framework\TestCase\IntegrationTestCase; - -/** - * @group Core - */ -class MeasurableTest extends IntegrationTestCase -{ - private $idSite = 1; - - /** - * @var Measurable - */ - private $measurable; - - private $settingName = 'app_id'; - - public function setUp() - { - parent::setUp(); - - Plugin\Manager::getInstance()->activatePlugin('MobileAppMeasurable'); - - if (!Fixture::siteCreated($this->idSite)) { - $type = MobileAppType::ID; - Fixture::createWebsite('2015-01-01 00:00:00', - $ecommerce = 0, $siteName = false, $siteUrl = false, - $siteSearch = 1, $searchKeywordParameters = null, - $searchCategoryParameters = null, $timezone = null, $type); - } - - $this->measurable = new Measurable($this->idSite); - } - - public function testGetSettingValue_shouldReturnValue_IfSettingExistsAndIsReadable() - { - $setting = new MeasurableSettings($this->idSite, Measurable::getTypeFor($this->idSite)); - $setting->getSetting($this->settingName)->setValue('mytest'); - - $value = $this->measurable->getSettingValue($this->settingName); - $this->assertNull($value); - - $setting->save(); // actually save value - - $value = $this->measurable->getSettingValue($this->settingName); - $this->assertSame('mytest', $value); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage does not exist - */ - public function testGetSettingValue_shouldThrowException_IfSettingDoesNotExist() - {; - $this->measurable->getSettingValue('NoTeXisTenT'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed - */ - public function testGetSettingValue_shouldThrowException_IfNoPermissionToRead() - { - FakeAccess::clearAccess(); - $this->measurable->getSettingValue('app_id'); - } - - public function provideContainerConfig() - { - return array( - 'Piwik\Access' => new FakeAccess(), - 'Piwik\Plugins\MobileAppMeasurable\Type' => new Type() - ); - } - -} diff --git a/tests/PHPUnit/Integration/Measurable/Settings/StorageTest.php b/tests/PHPUnit/Integration/Measurable/Settings/StorageTest.php deleted file mode 100644 index 9264a51ba349fd06a6e18c968492fc00ecae827b..0000000000000000000000000000000000000000 --- a/tests/PHPUnit/Integration/Measurable/Settings/StorageTest.php +++ /dev/null @@ -1,188 +0,0 @@ -<?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\Tests\Integration\Measurable\Settings; - -use Piwik\Db; -use Piwik\Measurable\MeasurableSetting; -use Piwik\Measurable\Settings\Storage; -use Piwik\Settings\Setting; -use Piwik\Tests\Framework\Fixture; -use Piwik\Tests\Framework\TestCase\IntegrationTestCase; - -/** - * @group Core - */ -class StorageTest extends IntegrationTestCase -{ - private $idSite = 1; - - /** - * @var Storage - */ - private $storage; - - /** - * @var MeasurableSetting - */ - private $setting; - - public function setUp() - { - parent::setUp(); - - if (!Fixture::siteCreated($this->idSite)) { - Fixture::createWebsite('2015-01-01 00:00:00'); - } - - $this->storage = $this->createStorage(); - $this->setting = $this->createSetting('test'); - } - - private function createStorage($idSite = null) - { - if (!isset($idSite)) { - $idSite = $this->idSite; - } - - return new Storage(Db::get(), $idSite); - } - - private function createSetting($name) - { - return new MeasurableSetting($name, $name . ' Name'); - } - - public function test_getValue_shouldReturnNullByDefault() - { - $value = $this->storage->getValue($this->setting); - $this->assertNull($value); - } - - public function test_getValue_shouldReturnADefaultValueIfOneIsSet() - { - $this->setting->defaultValue = 194.34; - $value = $this->storage->getValue($this->setting); - $this->assertSame(194.34, $value); - } - - public function test_setValue_getValue_shouldSetAndGetActualValue() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $value = $this->storage->getValue($this->setting); - $this->assertEquals('myRandomVal', $value); - } - - public function test_setValue_shouldNotSaveItInDatabase() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - - // make sure not actually stored - $this->assertSettingValue(null, $this->setting); - } - - public function test_save_shouldPersistValueInDatabase() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $this->storage->save(); - - // make sure actually stored - $this->assertSettingValue('myRandomVal', $this->setting); - } - - public function test_save_shouldPersistValueForEachSiteInDatabase() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $this->storage->save(); - - // make sure actually stored - $this->assertSettingValue('myRandomVal', $this->setting); - - $storage = $this->createStorage($idSite = 2); - $valueForDifferentSite = $storage->getValue($this->setting); - $this->assertNull($valueForDifferentSite); - } - - public function test_save_shouldPersistMultipleValues_ContainingInt() - { - $this->saveMultipleValues(); - - $this->assertSettingValue('myRandomVal', $this->setting); - $this->assertSettingValue(5, $this->createSetting('test2')); - $this->assertSettingValue(array(1, 2, '4'), $this->createSetting('test3')); - } - - public function test_deleteAll_ShouldRemoveTheEntireEntry() - { - $this->saveMultipleValues(); - - $this->assertSettingNotEmpty($this->setting); - $this->assertSettingNotEmpty($this->createSetting('test2')); - $this->assertSettingNotEmpty($this->createSetting('test3')); - - $this->storage->deleteAllValues(); - - $this->assertSettingEmpty($this->setting); - $this->assertSettingEmpty($this->createSetting('test2')); - $this->assertSettingEmpty($this->createSetting('test3')); - } - - public function test_deleteValue_ShouldOnlyDeleteOneValue() - { - $this->saveMultipleValues(); - - $this->assertSettingNotEmpty($this->setting); - $this->assertSettingNotEmpty($this->createSetting('test2')); - $this->assertSettingNotEmpty($this->createSetting('test3')); - - $this->storage->deleteValue($this->createSetting('test2')); - $this->storage->save(); - - $this->assertSettingEmpty($this->createSetting('test2')); - - $this->assertSettingNotEmpty($this->setting); - $this->assertSettingNotEmpty($this->createSetting('test3')); - } - - public function test_deleteValue_saveValue_ShouldNotResultInADeletedValue() - { - $this->saveMultipleValues(); - - $this->storage->deleteValue($this->createSetting('test2')); - $this->storage->setValue($this->createSetting('test2'), 'PiwikTest'); - $this->storage->save(); - - $this->assertSettingValue('PiwikTest', $this->createSetting('test2')); - } - - private function assertSettingValue($expectedValue, $setting) - { - $value = $this->createStorage()->getValue($setting); - $this->assertSame($expectedValue, $value); - } - - private function assertSettingNotEmpty(Setting $setting) - { - $value = $this->createStorage()->getValue($setting); - $this->assertNotNull($value); - } - - private function assertSettingEmpty(Setting $setting) - { - $value = $this->createStorage()->getValue($setting); - $this->assertNull($value); - } - - private function saveMultipleValues() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $this->storage->setValue($this->createSetting('test2'), 5); - $this->storage->setValue($this->createSetting('test3'), array(1, 2, '4')); - $this->storage->save(); - } -} diff --git a/tests/PHPUnit/Integration/Plugin/ManagerTest.php b/tests/PHPUnit/Integration/Plugin/ManagerTest.php index e05e3a021e24bc8559fdcea67fe94bf73cc801d9..5822e22c058db90c46098799e5fba4f50ab0d305 100644 --- a/tests/PHPUnit/Integration/Plugin/ManagerTest.php +++ b/tests/PHPUnit/Integration/Plugin/ManagerTest.php @@ -97,7 +97,7 @@ class ManagerTest extends IntegrationTestCase list($controller, $module, $action) = explode('.', $hook); try { - $resolver = new ControllerResolver(StaticContainer::getContainer(), new Plugin\Widgets($this->manager)); + $resolver = new ControllerResolver(StaticContainer::getContainer(), new Plugin\WidgetsProvider($this->manager)); $params = array(); $controller = $resolver->getController($module, $action, $params); } catch (\Exception $e) { diff --git a/tests/PHPUnit/Integration/Plugin/SettingsProviderTest.php b/tests/PHPUnit/Integration/Plugin/SettingsProviderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ceb804228bf5b44b11043880a4523ff7bfa00deb --- /dev/null +++ b/tests/PHPUnit/Integration/Plugin/SettingsProviderTest.php @@ -0,0 +1,165 @@ +<?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\Tests\Integration\Plugin; + +use Piwik\Container\StaticContainer; +use Piwik\Db; +use Piwik\Plugin; +use Piwik\Plugin\SettingsProvider; +use Piwik\Settings\Measurable\MeasurableSettings; +use Piwik\Settings\Plugin\SystemSettings; +use Piwik\Settings\Plugin\UserSettings; +use Piwik\Settings\Storage; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; + +/** + * @group SettingsProvider + * @group SettingsProviderTest + */ +class SettingsProviderTest extends IntegrationTestCase +{ + /** + * @var SettingsProvider + */ + private $settings; + + /** + * @var Plugin\Manager + */ + private $pluginManager; + + private $examplePlugin = 'ExampleSettingsPlugin'; + + public function setUp() + { + parent::setUp(); + + $_GET['idSite'] = 1; + if (!Fixture::siteCreated(1)) { + Fixture::createWebsite('2015-01-01 00:00:00'); + } + + $this->pluginManager = StaticContainer::get('Piwik\Plugin\Manager'); + $this->settings = new SettingsProvider($this->pluginManager); + } + + public function tearDown() + { + parent::tearDown(); + unset($_GET['idSite']); + } + + public function test_getSystemSettings_shouldFindASystemSettingOfPlugin() + { + $settings = $this->settings->getSystemSettings($this->examplePlugin); + + $this->assertTrue($settings instanceof SystemSettings); + $this->assertSame($this->examplePlugin, $settings->getPluginName()); + } + + public function test_getSystemSettings_shouldReturnNull_IfPluginHasNoSystemSettings() + { + $settings = $this->settings->getSystemSettings('Intl'); + + $this->assertNull($settings); + } + + public function test_getSystemSettings_shouldReturnNull_IfPluginHasSettingButIsNotLoaded() + { + $this->pluginManager->unloadPlugin($this->examplePlugin); + $settings = $this->settings->getSystemSettings($this->examplePlugin); + $this->pluginManager->loadPlugin($this->examplePlugin); + + $this->assertNull($settings); + } + + public function test_getAllSystemSettings_shouldFindAllSystemSettings() + { + $settings = $this->settings->getAllSystemSettings(); + + $this->assertArrayHasKey($this->examplePlugin, $settings); + $this->assertArrayHasKey('AnonymousPiwikUsageMeasurement', $settings); + $this->assertArrayHasKey('QueuedTracking', $settings); + + foreach ($settings as $setting) { + $this->assertTrue($setting instanceof SystemSettings); + } + } + + public function test_getUserSettings_shouldFindASystemSettingOfPlugin() + { + $settings = $this->settings->getUserSettings($this->examplePlugin); + + $this->assertTrue($settings instanceof UserSettings); + $this->assertSame($this->examplePlugin, $settings->getPluginName()); + } + + public function test_getUserSettings_shouldReturnNull_IfPluginHasNoSystemSettings() + { + $settings = $this->settings->getUserSettings('Intl'); + + $this->assertNull($settings); + } + + public function test_getUserSettings_shouldReturnNull_IfPluginHasSettingButIsNotLoaded() + { + $this->pluginManager->unloadPlugin($this->examplePlugin); + $settings = $this->settings->getUserSettings($this->examplePlugin); + $this->pluginManager->loadPlugin($this->examplePlugin); + + $this->assertNull($settings); + } + + public function test_getAllUserSettings_shouldFindAllSystemSettings() + { + $settings = $this->settings->getAllUserSettings(); + + $this->assertArrayHasKey($this->examplePlugin, $settings); + + foreach ($settings as $setting) { + $this->assertTrue($setting instanceof UserSettings); + } + } + + public function test_getMeasurableSettings_shouldFindASystemSettingOfPlugin() + { + $settings = $this->settings->getMeasurableSettings($this->examplePlugin, $idSite = 1, $idType = null); + + $this->assertTrue($settings instanceof MeasurableSettings); + $this->assertSame($this->examplePlugin, $settings->getPluginName()); + } + + public function test_getMeasurableSettings_shouldReturnNull_IfPluginHasNoSystemSettings() + { + $settings = $this->settings->getMeasurableSettings('Intl', $idSite = 1, $idType = null); + + $this->assertNull($settings); + } + + public function test_getMeasurableSettings_shouldReturnNull_IfPluginHasSettingButIsNotLoaded() + { + $this->pluginManager->unloadPlugin($this->examplePlugin); + $settings = $this->settings->getMeasurableSettings($this->examplePlugin, $idSite = 1, $idType = null); + $this->pluginManager->loadPlugin($this->examplePlugin); + + $this->assertNull($settings); + } + + public function test_getAllMeasurableSettings_shouldReturnOnlyMeasurableSettings() + { + $settings = $this->settings->getAllMeasurableSettings($idSite = 1, $idType = null); + $this->assertArrayHasKey($this->examplePlugin, $settings); + + foreach ($settings as $setting) { + $this->assertTrue($setting instanceof MeasurableSettings); + } + } + +} diff --git a/tests/PHPUnit/Integration/Plugin/SettingsTest.php b/tests/PHPUnit/Integration/Plugin/SettingsTest.php deleted file mode 100644 index 679b84ccbae610394710dd4014616864b0203b57..0000000000000000000000000000000000000000 --- a/tests/PHPUnit/Integration/Plugin/SettingsTest.php +++ /dev/null @@ -1,372 +0,0 @@ -<?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\Tests\Integration\Plugin; - -use Piwik\Db; -use Piwik\Plugin\Settings as PluginSettings; -use Piwik\Settings\Storage; -use Piwik\SettingsServer; -use Piwik\Tests\Integration\Settings\CorePluginTestSettings; -use Piwik\Tests\Integration\Settings\IntegrationTestCase; -use Piwik\Tracker\Cache; -use Piwik\Tracker\SettingsStorage; - -/** - * @group PluginSettings - */ -class SettingsTest extends IntegrationTestCase -{ - - public function test_constructor_shouldNotEstablishADatabaseConnection() - { - Db::destroyDatabaseObject(); - - $this->assertNotDbConnectionCreated(); - - $this->createSettingsInstance(); - - $this->assertNotDbConnectionCreated(); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage A setting with name "myname" does already exist for plugin "ExampleSettingsPlugin" - */ - public function test_addSetting_shouldThrowException_InCaseTwoSettingsHaveTheSameName() - { - $this->addUserSetting('myname', 'mytitle'); - - $setting = $this->buildUserSetting('myname', 'mytitle2'); - $this->settings->addSetting($setting); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage The setting name "myname-" in plugin "ExampleSettingsPlugin" is not valid. Only underscores, alpha and numerical characters are allowed - */ - public function test_addSetting_shouldThrowException_IfTheSettingNameIsNotValid() - { - $setting = $this->buildUserSetting('myname-', 'mytitle'); - $this->settings->addSetting($setting); - } - - public function test_addSetting_shouldAssignDefaultType_IfFieldIsGivenButNoType() - { - $setting = $this->buildUserSetting('myname', 'mytitle'); - $setting->uiControlType = CorePluginTestSettings::CONTROL_MULTI_SELECT; - - $this->settings->addSetting($setting); - - $this->assertEquals(CorePluginTestSettings::TYPE_ARRAY, $setting->type); - } - - public function test_addSetting_shouldAssignDefaultField_IfTypeIsGivenButNoField() - { - $setting = $this->buildUserSetting('myname', 'mytitle'); - $setting->type = CorePluginTestSettings::TYPE_ARRAY; - - $this->settings->addSetting($setting); - - $this->assertEquals(CorePluginTestSettings::CONTROL_MULTI_SELECT, $setting->uiControlType); - } - - public function test_addSetting_shouldAddAValidator_IfFieldOptionsAreGiven() - { - $setting = $this->buildUserSetting('myname', 'mytitle'); - $setting->availableValues = array('allowedval' => 'DisplayName', 'allowedval2' => 'Name 2'); - - $this->settings->addSetting($setting); - - $this->assertInstanceOf('\Closure', $setting->validate); - } - - public function test_addSetting_shouldAddTheSettings_IfValid() - { - $setting = $this->addUserSetting('myname', 'mytitle'); - - $this->assertEquals(array('myname' => $setting), $this->settings->getSettings()); - } - - public function test_addSetting_shouldPassTheStorage_ToTheSetting() - { - $this->setSuperUser(); - - $setting = $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); - $this->settings->addSetting($setting); - - $storage = $setting->getStorage(); - $this->assertTrue($storage instanceof Storage); - - $setting->setValue(5); - $this->assertSettingHasValue($setting, 5); - - $this->assertEquals($this->settings->getSetting('myname')->getValue(), 5); - } - - public function test_addSetting_shouldPassTrackerStorage_IfInTrackerMode() - { - $this->setSuperUser(); - - SettingsServer::setIsTrackerApiRequest(); - - $settings = $this->createSettingsInstance(); - $setting = $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); - $settings->addSetting($setting); - - SettingsServer::setIsNotTrackerApiRequest(); - - $storage = $setting->getStorage(); - $this->assertTrue($storage instanceof SettingsStorage); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingsValueNotAllowed - */ - public function test_setSettingValue_shouldApplyValidationAndFail_IfOptionsAreSet() - { - $this->setUser(); - $setting = $this->buildUserSetting('mysystem', 'mytitle'); - $setting->availableValues = array('allowed' => 'text', 'allowed2' => 'text2'); - $this->settings->addSetting($setting); - $setting->setValue('notallowed'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingsValueNotAllowed - */ - public function test_setSettingValue_shouldApplyValidationAndFail_IfOptionsAreSetAndValueIsAnArray() - { - $this->setUser(); - $setting = $this->buildUserSetting('mysystem', 'mytitle'); - $setting->availableValues = array('allowed' => 'text', 'allowed2' => 'text2'); - $setting->uiControlType = PluginSettings::CONTROL_MULTI_SELECT; - - $this->settings->addSetting($setting); - - $setting->setValue(array('allowed', 'notallowed')); - } - - public function test_setSettingValue_shouldApplyValidationAndSucceed_IfOptionsAreSet() - { - $this->setUser(); - $setting = $this->buildUserSetting('mysystem', 'mytitle'); - $setting->availableValues = array('allowed' => 'text', 'allowed2' => 'text2'); - $setting->uiControlType = PluginSettings::CONTROL_MULTI_SELECT; - - $this->settings->addSetting($setting); - - $setting->setValue(array('allowed', 'allowed2')); - $this->assertSettingHasValue($setting, array('allowed', 'allowed2')); - - $setting->type = PluginSettings::TYPE_STRING; - $setting->setValue('allowed'); - $this->assertSettingHasValue($setting, 'allowed'); - } - - public function test_getSettingsForCurrentUser_shouldOnlyReturnSettingsHavingEnoughAdminPermissions() - { - $this->setUser(); - - $this->addSystemSetting('mysystemsetting1', 'mytitle1'); - $this->addSystemSetting('mysystemsetting2', 'mytitle2'); - $this->addSystemSetting('mysystemsetting3', 'mytitle3'); - $this->addSystemSetting('mysystemsetting4', 'mytitle4'); - $userSetting = $this->addUserSetting('myusersetting1', 'mytitle5'); - - $this->assertEquals(array('myusersetting1' => $userSetting), $this->settings->getSettingsForCurrentUser()); - - // but all of them should be available via getSettings() - $this->assertCount(5, $this->settings->getSettings()); - } - - public function test_getSettingsForCurrentUser_shouldReturnAllSettingsIfEnoughPermissionsAndSortThemBySettingOrder() - { - $this->setSuperUser(); - - $this->addSystemSetting('mysystemsetting1', 'mytitle1'); - $this->addSystemSetting('mysystemsetting2', 'mytitle2'); - $this->addUserSetting('myusersetting2', 'mytitle6'); - $this->addSystemSetting('mysystemsetting3', 'mytitle3'); - $this->addSystemSetting('mysystemsetting4', 'mytitle4'); - $this->addUserSetting('myusersetting1', 'mytitle5'); - - $expected = array('myusersetting2', 'myusersetting1', 'mysystemsetting1', 'mysystemsetting2', 'mysystemsetting3', 'mysystemsetting4'); - $this->assertEquals($expected, array_keys($this->settings->getSettingsForCurrentUser())); - } - - public function test_save_shouldSaveAllValues() - { - $this->setSuperUser(); - - $this->addSystemSetting('mysystemsetting2', 'mytitle2'); - $this->addSystemSetting('mysystemsetting1', 'mytitle1')->setValue('111'); - $this->addSystemSetting('mysystemsetting4', 'mytitle4')->setValue('4444'); - $this->addUserSetting('myusersetting1', 'mytitle5')->setValue('55555'); - $this->addSystemSetting('mysystemsetting3', 'mytitle3'); - - $this->settings->save(); - - // verify actually saved - $verifySettings = $this->createSettingsInstance(); - - $setting1 = $this->buildSystemSetting('mysystemsetting1', 'mytitle1'); - $setting2 = $this->buildSystemSetting('mysystemsetting2', 'mytitle2'); - $setting3 = $this->buildSystemSetting('mysystemsetting3', 'mytitle3'); - $setting4 = $this->buildSystemSetting('mysystemsetting4', 'mytitle4'); - $setting5 = $this->buildUserSetting('myusersetting1', 'mytitle5'); - - $verifySettings->addSetting($setting1); - $verifySettings->addSetting($setting2); - $verifySettings->addSetting($setting3); - $verifySettings->addSetting($setting4); - $verifySettings->addSetting($setting5); - - $this->assertEquals('111', $setting1->getValue()); - $this->assertEquals(null, $setting2->getValue()); - $this->assertEquals(null, $setting3->getValue()); - $this->assertEquals('4444', $setting4->getValue()); - $this->assertEquals('55555', $setting5->getValue()); - } - - - public function test_save_shouldClearTrackerCacheEntries() - { - $this->setSuperUser(); - - Cache::setCacheGeneral(array('testSetting' => 1)); - - $this->assertArrayHasKey('testSetting', Cache::getCacheGeneral()); - - $this->addSystemSetting('mysystemsetting2', 'mytitle2'); - $this->settings->save(); - - $this->assertArrayNotHasKey('testSetting', Cache::getCacheGeneral()); - } - - public function test_removeAllPluginSettings_shouldRemoveAllSettings() - { - $this->setSuperUser(); - - $this->addSystemSetting('mysystemsetting3', 'mytitle3'); - $this->addSystemSetting('mysystemsetting4', 'mytitle4'); - $this->addSystemSetting('mysystemsetting1', 'mytitle1')->setValue('111'); - $this->addSystemSetting('mysystemsetting2', 'mytitle2')->setValue('4444'); - $this->addUserSetting('myusersetting1', 'mytitle5')->setValue('55555'); - $this->settings->save(); - - $this->settings->removeAllPluginSettings(); - - $verifySettings = $this->createSettingsInstance(); - - $setting1 = $this->buildSystemSetting('mysystemsetting1', 'mytitle1'); - $setting2 = $this->buildSystemSetting('mysystemsetting2', 'mytitle2'); - $setting3 = $this->buildSystemSetting('mysystemsetting3', 'mytitle3'); - $setting4 = $this->buildSystemSetting('mysystemsetting4', 'mytitle4'); - $setting5 = $this->buildUserSetting('myusersetting1', 'mytitle5'); - - $verifySettings->addSetting($setting1); - $verifySettings->addSetting($setting2); - $verifySettings->addSetting($setting3); - $verifySettings->addSetting($setting4); - $verifySettings->addSetting($setting5); - - $this->assertEquals(null, $setting1->getValue()); - $this->assertEquals(null, $setting2->getValue()); - $this->assertEquals(null, $setting3->getValue()); - $this->assertEquals(null, $setting4->getValue()); - $this->assertEquals(null, $setting5->getValue()); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage checkUserHasSuperUserAccess Fake exception - */ - public function test_removeAllPluginSettings_shouldThrowException_InCaseUserIsNotSuperUser() - { - $this->setUser(); - - $this->settings->removeAllPluginSettings(); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage checkUserHasSuperUserAccess Fake exception - */ - public function test_removeAllPluginSettings_shouldThrowException_InCaseAnonymousUser() - { - $this->setAnonymousUser(); - - $this->settings->removeAllPluginSettings(); - } - - public function test_userSetting_shouldGenerateDifferentKey_ThenSystemSetting() - { - $this->setSuperUser(); - - $user = $this->buildUserSetting('myname', 'mytitle'); - $system = $this->buildSystemSetting('myname', 'mytitle'); - - $this->assertNotEquals($user->getKey(), $system->getKey()); - $this->assertEquals('myname', $system->getKey()); - $this->assertEquals('myname#superUserLogin#', $user->getKey()); - } - - public function test_userSetting_shouldSaveValuesPerUser() - { - $this->setSuperUser(); - $user1Login = 'user1'; - $user2Login = '_user2_'; - $user3Login = null; // current loggged in user - - $user = $this->buildUserSetting('myuser', 'mytitle', $user1Login); - - $this->settings->addSetting($user); - - $user->setValue('111'); - $user->setUserLogin($user2Login); - $user->setValue('222'); - $user->setUserLogin($user3Login); - $user->setValue('333'); - - $user->setUserLogin($user1Login); - $this->assertSettingHasValue($user, '111'); - $user->setUserLogin($user2Login); - $this->assertSettingHasValue($user, '222'); - $user->setUserLogin($user3Login); - $this->assertSettingHasValue($user, '333'); - - $user->setUserLogin($user2Login); - $user->removeValue(); - - $user->setUserLogin($user1Login); - $this->assertSettingHasValue($user, '111'); - $user->setUserLogin($user2Login); - $this->assertSettingHasValue($user, null); - $user->setUserLogin($user3Login); - $this->assertSettingHasValue($user, '333'); - - $this->settings->removeAllPluginSettings(); - - $user->setUserLogin($user1Login); - $this->assertSettingHasValue($user, null); - $user->setUserLogin($user2Login); - $this->assertSettingHasValue($user, null); - $user->setUserLogin($user3Login); - $this->assertSettingHasValue($user, null); - } - - public function test_construct_shouldDetectTheNameOfThePluginAutomatically_IfPluginNameNotGiven() - { - $setting = new \Piwik\Plugins\ExampleSettingsPlugin\Settings(); - - $this->assertEquals('ExampleSettingsPlugin', $setting->getPluginName()); - } -} diff --git a/tests/PHPUnit/Integration/Plugin/WidgetsTest.php b/tests/PHPUnit/Integration/Plugin/WidgetsProviderTest.php similarity index 87% rename from tests/PHPUnit/Integration/Plugin/WidgetsTest.php rename to tests/PHPUnit/Integration/Plugin/WidgetsProviderTest.php index 185faba06425f03ae8035a2c1e4453fd4a57e9ed..9370c8f62815674345db96b25a8ea78b68fcc56a 100644 --- a/tests/PHPUnit/Integration/Plugin/WidgetsTest.php +++ b/tests/PHPUnit/Integration/Plugin/WidgetsProviderTest.php @@ -10,7 +10,7 @@ namespace Piwik\Tests\Integration\Plugin; use Piwik\Container\StaticContainer; use Piwik\Db; -use Piwik\Plugin\Widgets; +use Piwik\Plugin\WidgetsProvider; use Piwik\Settings\Storage; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; @@ -18,13 +18,13 @@ use Piwik\Widget\WidgetConfig; use Piwik\Widget\WidgetContainerConfig; /** - * @group Widgets - * @group WidgetsTest + * @group WidgetsProvider + * @group WidgetsProviderTest */ -class WidgetsTest extends IntegrationTestCase +class WidgetsProviderTest extends IntegrationTestCase { /** - * @var Widgets + * @var WidgetsProvider */ private $widgets; @@ -37,7 +37,7 @@ class WidgetsTest extends IntegrationTestCase Fixture::createWebsite('2015-01-01 00:00:00'); } - $this->widgets = new Widgets(StaticContainer::get('Piwik\Plugin\Manager')); + $this->widgets = new WidgetsProvider(StaticContainer::get('Piwik\Plugin\Manager')); } public function tearDown() diff --git a/tests/PHPUnit/Integration/Report/ReportsTest.php b/tests/PHPUnit/Integration/Report/ReportsTest.php index 9681d73e646574bbe57f7ceca8e541ce669a23fd..874bd4fb94f1b9e9b488f29f8844aa161d804837 100644 --- a/tests/PHPUnit/Integration/Report/ReportsTest.php +++ b/tests/PHPUnit/Integration/Report/ReportsTest.php @@ -16,7 +16,7 @@ use Piwik\Piwik; use Piwik\Metrics; use Piwik\Plugins\ExampleTracker\Columns\ExampleDimension; use Piwik\Plugins\Referrers\Columns\Keyword; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Translate; use Piwik\Plugin\Manager as PluginManager; @@ -34,7 +34,7 @@ class ReportTest extends IntegrationTestCase { $this->unloadAllPlugins(); - $reports = new Reports(); + $reports = new ReportsProvider(); $report = $reports->getAllReports(); $this->assertEquals(array(), $report); @@ -45,7 +45,7 @@ class ReportTest extends IntegrationTestCase $this->loadExampleReportPlugin(); $this->loadMorePlugins(); - $reports = new Reports(); + $reports = new ReportsProvider(); $reports = $reports->getAllReports(); $this->assertGreaterThan(20, count($reports)); diff --git a/tests/PHPUnit/Integration/ReportTest.php b/tests/PHPUnit/Integration/ReportTest.php index 036516bd917e78bbd465e773e8dd9c79f7aa6748..fc89a4ea59113b88d3137e117689a7938295bb1b 100644 --- a/tests/PHPUnit/Integration/ReportTest.php +++ b/tests/PHPUnit/Integration/ReportTest.php @@ -16,7 +16,7 @@ use Piwik\Piwik; use Piwik\Metrics; use Piwik\Plugins\ExampleTracker\Columns\ExampleDimension; use Piwik\Plugins\Referrers\Columns\Keyword; -use Piwik\Plugin\Reports; +use Piwik\Plugin\ReportsProvider; use Piwik\Report\ReportWidgetFactory; use Piwik\Translate; use Piwik\Plugin\Manager as PluginManager; @@ -315,14 +315,14 @@ class ReportTest extends IntegrationTestCase $module = 'ExampleReport'; $action = 'getExampleReport'; - $report = Reports::factory($module, $action); + $report = ReportsProvider::factory($module, $action); $this->assertInstanceOf('Piwik\Plugins\ExampleReport\Reports\GetExampleReport', $report); $this->assertEquals($module, $report->getModule()); $this->assertEquals($action, $report->getAction()); // action ucfirst should work as well - $report = Reports::factory($module, ucfirst($action)); + $report = ReportsProvider::factory($module, ucfirst($action)); $this->assertInstanceOf('Piwik\Plugins\ExampleReport\Reports\GetExampleReport', $report); $this->assertEquals($module, $report->getModule()); @@ -345,7 +345,7 @@ class ReportTest extends IntegrationTestCase { PluginManager::getInstance()->loadPlugins(array('Referrers')); - $report = Reports::factory('Referrers', 'getSearchEngines'); + $report = ReportsProvider::factory('Referrers', 'getSearchEngines'); $subtableDimension = $report->getSubtableDimension(); $this->assertNotNull($subtableDimension); diff --git a/tests/PHPUnit/Integration/Settings/BaseSettingsTestCase.php b/tests/PHPUnit/Integration/Settings/BaseSettingsTestCase.php new file mode 100644 index 0000000000000000000000000000000000000000..0a94ba7953aa5333529680d8890b6e2dfa8c7094 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/BaseSettingsTestCase.php @@ -0,0 +1,111 @@ +<?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\Tests\Integration\Settings; + +use Piwik\Db; +use Piwik\Piwik; +use Piwik\Settings\FieldConfig; + +/** + * @group PluginSettings + * @group SystemSettings + */ +class BaseSettingsTestCase extends IntegrationTestCase +{ + protected $updateEventName; + + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + Db::destroyDatabaseObject(); + + $this->assertNotDbConnectionCreated(); + + $this->createSettingsInstance(); + + $this->assertNotDbConnectionCreated(); + } + + public function test_makeSetting_ShouldAlsoAddTheSetting() + { + $this->assertNull($this->settings->getSetting('myName')); + + $this->makeSetting('myName'); + + $this->assertNotNull($this->settings->getSetting('myName')); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage A setting with name "myName" does already exist for plugin "ExampleSettingsPlugin" + */ + public function test_makeSetting_ShouldFailWhenAdingSameSettingTwice() + { + $this->makeSetting('myName'); + $this->makeSetting('myName'); + } + + public function test_getSetting_CanRetrieveAspecificSetting() + { + $this->makeSetting('myName'); + + $this->assertSame('myName', $this->settings->getSetting('myName')->getName()); + } + + public function test_getSetting_IsCaseSensitive() + { + $this->makeSetting('myName'); + + $this->assertNull($this->settings->getSetting('myname')); + } + + public function test_getSetting_ReturnsNullWhenNoSuchSettingFound() + { + $this->assertNull($this->settings->getSetting('myName')); + } + + public function test_getSettingsWritableByCurrentUser_returnsOnlySettingsThatAreWritable() + { + $this->assertSame(array(), $this->settings->getSettingsWritableByCurrentUser()); + + $setting1 = $this->makeSetting('myName1'); + $setting1->setIsWritableByCurrentUser(true); + + $setting2 = $this->makeSetting('myName2'); + $setting2->setIsWritableByCurrentUser(false); + + $setting3 = $this->makeSetting('myName3'); + $setting3->setIsWritableByCurrentUser(true); + + $expected = array( + 'myName1' => $setting1, + 'myName3' => $setting3 + ); + $this->assertSame($expected, $this->settings->getSettingsWritableByCurrentUser()); + } + + public function test_save_triggersAnEvent() + { + $settings = null; + + Piwik::addAction($this->updateEventName, function ($instance) use (&$settings) { + $settings = $instance; + }); + + $this->settings->save(); + + $this->assertSame($settings, $this->settings); + } + + protected function makeSetting($name) + { + $type = FieldConfig::TYPE_STRING; + return $this->settings->makeSetting($name, $default = '', $type, function () {}); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/CorePluginTestSettings.php b/tests/PHPUnit/Integration/Settings/CorePluginTestSettings.php deleted file mode 100644 index 7792f1f3534619355dbf776a96368814047583a7..0000000000000000000000000000000000000000 --- a/tests/PHPUnit/Integration/Settings/CorePluginTestSettings.php +++ /dev/null @@ -1,25 +0,0 @@ -<?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\Tests\Integration\Settings; - -use Piwik\Settings\Setting; - -class CorePluginTestSettings extends \Piwik\Plugins\ExampleSettingsPlugin\Settings { - - public function init() - { - - } - - public function addSetting(Setting $setting) - { - parent::addSetting($setting); - } -} - diff --git a/tests/PHPUnit/Integration/Settings/IntegrationTestCase.php b/tests/PHPUnit/Integration/Settings/IntegrationTestCase.php index 37c8a205a627fdbd4c8b7c06a255e5333f17a5b4..8a323924a60979af102d93b1c24bb290cd031f27 100644 --- a/tests/PHPUnit/Integration/Settings/IntegrationTestCase.php +++ b/tests/PHPUnit/Integration/Settings/IntegrationTestCase.php @@ -9,9 +9,13 @@ namespace Piwik\Tests\Integration\Settings; use Piwik\Db; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Plugin\SystemSetting; +use Piwik\Settings\Plugin\UserSetting; use Piwik\Settings\Setting; use Piwik\Settings\Storage; use Piwik\Tests\Framework\Mock\FakeAccess; +use Piwik\Tests\Framework\Mock\Settings\FakeSystemSettings; /** * @group PluginSettings @@ -21,7 +25,7 @@ use Piwik\Tests\Framework\Mock\FakeAccess; class IntegrationTestCase extends \Piwik\Tests\Framework\TestCase\IntegrationTestCase { /** - * @var CorePluginTestSettings + * @var FakeSystemSettings */ protected $settings; @@ -32,28 +36,9 @@ class IntegrationTestCase extends \Piwik\Tests\Framework\TestCase\IntegrationTes $this->settings = $this->createSettingsInstance(); } - public function tearDown() - { - $this->setSuperUser(); - if ($this->settings) { - $this->settings->removeAllPluginSettings(); - } - - parent::tearDown(); - } - - public function test_constructor_shouldNotEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - new Storage('PluginName'); - - $this->assertNotDbConnectionCreated(); - } - protected function assertSettingHasValue(Setting $setting, $expectedValue, $expectedType = null) { - $value = $setting->getValue($setting); + $value = $setting->getValue(); $this->assertEquals($expectedValue, $value); if (!is_null($expectedType)) { @@ -61,22 +46,6 @@ class IntegrationTestCase extends \Piwik\Tests\Framework\TestCase\IntegrationTes } } - protected function buildUserSetting($name, $title, $userLogin = null) - { - $userSetting = new \Piwik\Settings\UserSetting($name, $title, $userLogin); - $userSetting->setStorage(new Storage('ExampleSettingsPlugin')); - - return $userSetting; - } - - protected function buildSystemSetting($name, $title) - { - $systemSetting = new \Piwik\Settings\SystemSetting($name, $title); - $systemSetting->setStorage(new Storage('ExampleSettingsPlugin')); - - return $systemSetting; - } - protected function setSuperUser() { FakeAccess::$superUser = true; @@ -95,32 +64,7 @@ class IntegrationTestCase extends \Piwik\Tests\Framework\TestCase\IntegrationTes protected function createSettingsInstance() { - return new CorePluginTestSettings('ExampleSettingsPlugin'); - } - - protected function addSystemSetting($name, $title) - { - $setting = $this->buildSystemSetting($name, $title); - $this->settings->addSetting($setting); - return $setting; - } - - protected function addUserSetting($name, $title) - { - $setting = $this->buildUserSetting($name, $title); - $this->settings->addSetting($setting); - return $setting; - } - - - protected function assertSettingIsNotSavedInTheDb($settingName, $expectedValue) - { - // by creating a new instance... - $setting = $this->buildSystemSetting($settingName, 'mytitle'); - $verifySettings = $this->createSettingsInstance(); - $verifySettings->addSetting($setting); - - $this->assertEquals($expectedValue, $setting->getValue()); + return new FakeSystemSettings(); } public function provideContainerConfig() diff --git a/tests/PHPUnit/Integration/Settings/Measurable/MeasurablePropertyTest.php b/tests/PHPUnit/Integration/Settings/Measurable/MeasurablePropertyTest.php new file mode 100644 index 0000000000000000000000000000000000000000..38a8c43b70f57faee582c880fb74b17dd11f903c --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Measurable/MeasurablePropertyTest.php @@ -0,0 +1,62 @@ +<?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\Tests\Integration\Settings\Plugin; + +use Piwik\Config; +use Piwik\Db; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Measurable\MeasurableProperty; +use Piwik\Settings\Measurable\MeasurableSetting; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\Mock\Settings\FakeMeasurableSettings; +use Piwik\Tests\Integration\Settings\IntegrationTestCase; + +/** + * @group MeasurableSettings + * @group Settings + * @group MeasurableProperty + */ +class MeasurablePropertyTest extends IntegrationTestCase +{ + + public function setUp() + { + parent::setUp(); + Db::destroyDatabaseObject(); + } + + protected function createSettingsInstance() + { + if (!Fixture::siteCreated(1)) { + Fixture::createWebsite('2014-01-01 01:01:01'); + } + + return new FakeMeasurableSettings($idSite = 1); + } + + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + new MeasurableProperty('ecommerce', $default = 5, FieldConfig::TYPE_INT, 'MyPlugin', $idSite = 1); + + $this->assertNotDbConnectionCreated(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Name "name" is not allowed to be used + */ + public function test_constructor_shouldThrowAnExceptionWhenNotWhitelistedNameIsUsed() + { + new MeasurableProperty('name', $default = 5, FieldConfig::TYPE_INT, 'MyPlugin', $idSite = 1); + } + + +} diff --git a/tests/PHPUnit/Integration/Settings/Measurable/MeasurableSettingTest.php b/tests/PHPUnit/Integration/Settings/Measurable/MeasurableSettingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..29f6be7c67bba9e1e4c7795511dc6d19728e2d40 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Measurable/MeasurableSettingTest.php @@ -0,0 +1,98 @@ +<?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\Tests\Integration\Settings\Plugin; + +use Piwik\Config; +use Piwik\Db; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Measurable\MeasurableSetting; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\Mock\Settings\FakeMeasurableSettings; +use Piwik\Tests\Integration\Settings\IntegrationTestCase; + +/** + * @group MeasurableSettings + * @group Settings + * @group MeasurableSetting + */ +class MeasurableSettingTest extends IntegrationTestCase +{ + + public function setUp() + { + parent::setUp(); + foreach (array(2,3) as $idSite) { + if (!Fixture::siteCreated($idSite)) { + Fixture::createWebsite('2014-01-01 01:01:01'); + } + } + + Db::destroyDatabaseObject(); + } + + protected function createSettingsInstance() + { + if (!Fixture::siteCreated(1)) { + Fixture::createWebsite('2014-01-01 01:01:01'); + } + + return new FakeMeasurableSettings($idSite = 1); + } + + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + new MeasurableSetting('name', $default = 5, FieldConfig::TYPE_INT, 'MyPlugin', $idSite = 1); + + $this->assertNotDbConnectionCreated(); + } + + public function test_save() + { + $site1 = $this->buildSetting('field1', null, $site = '1'); + $site1->setValue('value1'); + $site1->save(); + + $site2 = $this->buildSetting('field1', null, $site = '2'); + $this->assertSame('value1', $site1->getValue()); + $this->assertSame('', $site2->getValue()); + $site2->setValue('value2'); + $site2->save(); + + $site3 = $this->buildSetting('field1', null, $site = '3'); + $this->assertSame('value1', $site1->getValue()); + $this->assertSame('value2', $site2->getValue()); + $this->assertSame('', $site3->getValue()); + + $site1Field2 = $this->buildSetting('field2', null, $site = '1'); + $this->assertSame('', $site1Field2->getValue()); + $site1Field2->setValue('value1Field2'); + $site1Field2->save(); + + $this->assertSame('value1', $site1->getValue()); + $this->assertSame('value1Field2', $site1Field2->getValue()); + } + + private function buildSetting($name, $type = null, $idSite = null) + { + if (!isset($type)) { + $type = FieldConfig::TYPE_STRING; + } + + if (!isset($idSite)) { + $idSite = 1; + } + + $userSetting = new MeasurableSetting($name, $default = '', $type, 'MyPluginName', $idSite); + + return $userSetting; + } + +} diff --git a/tests/PHPUnit/Integration/Settings/Measurable/MeasurableSettingsTest.php b/tests/PHPUnit/Integration/Settings/Measurable/MeasurableSettingsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..689bab5d92e09cbfc8c34b1374e1e9e68da1961f --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Measurable/MeasurableSettingsTest.php @@ -0,0 +1,58 @@ +<?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\Tests\Integration\Settings\Plugin; + +use Piwik\Db; +use Piwik\Plugins\WebsiteMeasurable\Type; +use Piwik\Settings\Measurable\MeasurableSetting; +use Piwik\Settings\Measurable\MeasurableSettings; +use Piwik\Settings\Plugin\UserSetting; +use Piwik\Settings\Plugin\UserSettings; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\Mock\Settings\FakeMeasurableSettings; +use Piwik\Tests\Integration\Settings\BaseSettingsTestCase; + +/** + * @group PluginSettings + * @group UserSettings + */ +class MeasurableSettingsTest extends BaseSettingsTestCase +{ + protected $updateEventName = 'MeasurableSettings.updated'; + + protected function createSettingsInstance() + { + if (!Fixture::siteCreated(1)) { + Fixture::createWebsite('2014-01-01 00:00:01'); + } + Db::destroyDatabaseObject(); + return new FakeMeasurableSettings($idSite = 1, $type = Type::ID); + } + + public function test_weAreWorkingWithMeasurableSettings() + { + $this->assertTrue($this->settings instanceof MeasurableSettings); + } + + public function test_constructor_getPluginName_canDetectPluginNameAutomatically() + { + $this->assertSame('ExampleSettingsPlugin', $this->settings->getPluginName()); + + $settings = new \Piwik\Plugins\ExampleSettingsPlugin\MeasurableSettings($idSite = 1); + $this->assertSame('ExampleSettingsPlugin', $settings->getPluginName()); + } + + public function test_makeSetting_ShouldCreateAMeasurableSetting() + { + $setting = $this->makeSetting('myName'); + + $this->assertTrue($setting instanceof MeasurableSetting); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/SystemSettingTest.php b/tests/PHPUnit/Integration/Settings/Plugin/SystemSettingTest.php similarity index 51% rename from tests/PHPUnit/Integration/Settings/SystemSettingTest.php rename to tests/PHPUnit/Integration/Settings/Plugin/SystemSettingTest.php index e740f61f704ff1a623afe480f3de46b858f8cbbe..9b9e93db5f750e395eeea8db1b36b137bec989e3 100644 --- a/tests/PHPUnit/Integration/Settings/SystemSettingTest.php +++ b/tests/PHPUnit/Integration/Settings/Plugin/SystemSettingTest.php @@ -6,12 +6,13 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ -namespace Piwik\Tests\Integration\Settings; +namespace Piwik\Tests\Integration\Settings\Plugin; use Piwik\Config; use Piwik\Db; -use Piwik\Plugin\Settings; -use Piwik\Settings\SystemSetting; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Plugin\SystemSetting; +use Piwik\Tests\Integration\Settings\IntegrationTestCase; /** * @group PluginSettings @@ -31,7 +32,7 @@ class SystemSettingTest extends IntegrationTestCase { $this->assertNotDbConnectionCreated(); - new SystemSetting('name', 'title'); + new SystemSetting('name', $default = 5, FieldConfig::TYPE_INT, 'MyPlugin'); $this->assertNotDbConnectionCreated(); } @@ -43,7 +44,7 @@ class SystemSettingTest extends IntegrationTestCase public function test_setSettingValue_shouldThrowException_IfAUserIsTryingToSetASettingWhichNeedsSuperUserPermission() { $this->setUser(); - $setting = $this->addSystemSetting('mysystem', 'mytitle'); + $setting = $this->buildSetting('mysystem'); $setting->setValue(2); } @@ -55,7 +56,7 @@ class SystemSettingTest extends IntegrationTestCase public function test_setSettingValue_shouldThrowException_IfAnonymousIsTryingToSetASettingWhichNeedsSuperUserPermission() { $this->setAnonymousUser(); - $setting = $this->addSystemSetting('mysystem', 'mytitle'); + $setting = $this->buildSetting('mysystem'); $setting->setValue(2); } @@ -64,59 +65,23 @@ class SystemSettingTest extends IntegrationTestCase { $this->setSuperUser(); - $setting = $this->addSystemSetting('mysystem', 'mytitle'); + $setting = $this->buildSetting('mysystem'); $setting->setValue(2); $this->assertSettingHasValue($setting, 2); } - public function test_setSettingValue_shouldNotPersistValueInDatabase_OnSuccess() - { - $this->setSuperUser(); - - $setting = $this->buildSystemSetting('mysystem', 'mytitle'); - $this->settings->addSetting($setting); - $setting->setValue(2); - - // make sure stored on the instance - $this->assertSettingHasValue($setting, 2); - $this->assertSettingIsNotSavedInTheDb('mysystem', null); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed - */ - public function test_getSettingValue_shouldThrowException_IfUserHasNotEnoughPermissionToReadValue() - { - $this->setUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->getValue(); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed - */ - public function test_getSettingValue_shouldThrowException_IfAnonymousTriedToReadValue() - { - $this->setAnonymousUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->getValue(); - } - public function test_getSettingValue_shouldBeReadableBySuperUser() { $this->setSuperUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); + $setting = $this->buildSetting('myusersetting'); $this->assertEquals('', $setting->getValue()); } public function test_getSettingValue_shouldReturnValue_IfReadbleByCurrentUserIsAllowed() { $this->setUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->readableByCurrentUser = true; + $setting = $this->buildSetting('myusersetting'); $this->assertEquals('', $setting->getValue()); } @@ -124,8 +89,7 @@ class SystemSettingTest extends IntegrationTestCase public function test_getSettingValue_fromConfig_IfOneIsConfiguredInsteadOfTheValueFromDatabase() { $this->setSuperUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->setPluginName('MyPluginName'); + $setting = $this->buildSetting('myusersetting'); $setting->setValue('test'); $this->assertEquals('test', $setting->getValue()); @@ -137,26 +101,21 @@ class SystemSettingTest extends IntegrationTestCase public function test_getSettingValue_fromConfig_ShouldConvertToTheSpecifiedType() { $this->setSuperUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->setPluginName('MyPluginName'); + $setting = $this->buildSetting('myusersetting', FieldConfig::TYPE_BOOL); Config::getInstance()->MyPluginName = array('myusersetting' => '1'); - $this->assertSame('1', $setting->getValue()); - - $setting->type = Settings::TYPE_BOOL; $this->assertTrue($setting->getValue()); } public function test_getSettingValue_fromConfig_isCaseSensitive() { $this->setSuperUser(); - $setting = $this->addSystemSetting('myUsersetting', 'mytitle'); - $setting->setPluginName('MyPluginName'); + $setting = $this->buildSetting('myUsersetting'); Config::getInstance()->MyPluginName = array('myusersetting' => '1'); - $this->assertNull($setting->getValue()); + $this->assertSame('', $setting->getValue()); Config::getInstance()->MyPluginName = array('myUsersetting' => '1'); @@ -166,8 +125,7 @@ class SystemSettingTest extends IntegrationTestCase public function test_getSettingsValue_fromConfig_ShouldSetObjectToNotWritableAsSoonAsAValueIsConfigured() { $this->setSuperUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->setPluginName('MyPluginName'); + $setting = $this->buildSetting('myusersetting'); $this->assertTrue($setting->isWritableByCurrentUser()); @@ -178,8 +136,7 @@ class SystemSettingTest extends IntegrationTestCase public function test_setIsWritableByCurrentUser() { $this->setSuperUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->setPluginName('MyPluginName'); + $setting = $this->buildSetting('myusersetting'); $this->assertTrue($setting->isWritableByCurrentUser()); @@ -197,47 +154,50 @@ class SystemSettingTest extends IntegrationTestCase public function test_setSettingsValue_shouldNotBePossible_AsSoonAsAConfigValueIsConfigured() { $this->setSuperUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->setPluginName('MyPluginName'); + $setting = $this->buildSetting('myusersetting'); Config::getInstance()->MyPluginName = array('myusersetting' => '0'); $setting->setValue('test'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_removeSettingValue_shouldThrowException_IfUserHasNotEnoughAdminPermissions() + public function test_save_shouldSaveDifferentValuesForDifferentPluginsAndFields() { - $this->setUser(); - $setting = $this->addSystemSetting('mysystemsetting', 'mytitle'); - $setting->removeValue(); - } + $plugin1 = $this->buildSetting('field1', null, $login = 'plugin1'); + $plugin1->setValue('value1'); + $plugin1->save(); - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_removeSettingValue_shouldThrowException_IfAnonymousTriesToRemoveValue() - { - $this->setAnonymousUser(); - $setting = $this->addSystemSetting('mysystemsetting', 'mytitle'); - $setting->removeValue(); + $plugin2 = $this->buildSetting('field1', null, $login = 'plugin2'); + $this->assertSame('value1', $plugin1->getValue()); + $this->assertSame('', $plugin2->getValue()); + $plugin2->setValue('value2'); + $plugin2->save(); + + $plugin3 = $this->buildSetting('field1', null, $login = 'plugin3'); + $this->assertSame('value1', $plugin1->getValue()); + $this->assertSame('value2', $plugin2->getValue()); + $this->assertSame('', $plugin3->getValue()); + + $plugin1Field2 = $this->buildSetting('field2', null, $login = 'plugin1'); + $this->assertSame('', $plugin1Field2->getValue()); + $plugin1Field2->setValue('value1Field2'); + $plugin1Field2->save(); + + $this->assertSame('value1', $plugin1->getValue()); + $this->assertSame('value1Field2', $plugin1Field2->getValue()); } - public function test_removeSettingValue_shouldRemoveValue_ShouldNotSaveValueInDb() + private function buildSetting($name, $type = null, $plugin = null) { - $this->setSuperUser(); + if (!isset($type)) { + $type = FieldConfig::TYPE_STRING; + } + if (!isset($plugin)) { + $plugin = 'MyPluginName'; + } - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->setValue('12345657'); - $this->settings->save(); + $systemSetting = new SystemSetting($name, $default = '', $type, $plugin); - $setting->removeValue(); - $this->assertSettingHasValue($setting, null); - - // should still have same value - $this->assertSettingIsNotSavedInTheDb('myusersetting', '12345657'); + return $systemSetting; } + } diff --git a/tests/PHPUnit/Integration/Settings/Plugin/SystemSettingsTest.php b/tests/PHPUnit/Integration/Settings/Plugin/SystemSettingsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..52339b6a815446f55f2e96ea01a3b9c6cde0f1ab --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Plugin/SystemSettingsTest.php @@ -0,0 +1,43 @@ +<?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\Tests\Integration\Settings\Plugin; + +use Piwik\Db; +use Piwik\Settings\Plugin\SystemSetting; +use Piwik\Settings\Plugin\SystemSettings; +use Piwik\Tests\Integration\Settings\BaseSettingsTestCase; + +/** + * @group PluginSettings + * @group SystemSettings + */ +class SystemSettingsTest extends BaseSettingsTestCase +{ + protected $updateEventName = 'SystemSettings.updated'; + + public function test_weAreWorkingWithSystemSettings() + { + $this->assertTrue($this->settings instanceof SystemSettings); + } + + public function test_constructor_getPluginName_canDetectPluginNameAutomatically() + { + $settings = new \Piwik\Plugins\ExampleSettingsPlugin\SystemSettings(); + $this->assertSame('ExampleSettingsPlugin', $settings->getPluginName()); + $this->assertSame('ExampleSettingsPlugin', $this->settings->getPluginName()); + } + + public function test_makeSetting_ShouldCreateASystemSetting() + { + $setting = $this->makeSetting('myName'); + + $this->assertTrue($setting instanceof SystemSetting); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/Plugin/UserSettingTest.php b/tests/PHPUnit/Integration/Settings/Plugin/UserSettingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..2a4935db692a74d6b727003470cda222a383fd06 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Plugin/UserSettingTest.php @@ -0,0 +1,227 @@ +<?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\Tests\Integration\Settings\Plugin; + +use Piwik\Db; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Plugin\UserSetting; +use Piwik\Settings\Storage\Storage; +use Piwik\Tests\Framework\Mock\FakeAccess; +use Piwik\Tests\Framework\Mock\Settings\FakeBackend; +use Piwik\Tests\Framework\Mock\Settings\FakeUserSettings; +use Piwik\Tests\Integration\Settings\IntegrationTestCase; + +/** + * @group PluginSettings + * @group Settings + * @group UserSetting + */ +class UserSettingTest extends IntegrationTestCase +{ + protected function createSettingsInstance() + { + return new FakeUserSettings(); + } + + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + new UserSetting('name', $default = 5, FieldConfig::TYPE_INT, 'MyPlugin', 'login'); + + $this->assertNotDbConnectionCreated(); + } + + public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeGetAValue() + { + $this->setSuperUser(); + Db::destroyDatabaseObject(); + + $setting = $this->buildSetting('testSetting'); + + $this->assertNotDbConnectionCreated(); + + $setting->getValue(); + + $this->assertDbConnectionCreated(); + } + + public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeSetAValue() + { + $this->setSuperUser(); + Db::destroyDatabaseObject(); + + $setting = $this->buildSetting('testSetting'); + $settings = $this->createSettingsInstance(); + $settings->addSetting($setting); + + $this->assertNotDbConnectionCreated(); + + $setting->setValue('5'); + + $this->assertDbConnectionCreated(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed + */ + public function test_setSettingValue_shouldThrowException_IfAnonymousIsTryingToSetASettingWhichNeedsUserPermission() + { + $this->setAnonymousUser(); + $setting = $this->buildSetting('mysystem'); + + $setting->setValue(2); + } + + public function test_setSettingValue_shouldSucceed_IfUserIsTryingToSetASettingWhichNeedsUserPermission() + { + $this->setUser(); + $setting = $this->buildSetting('mysystem'); + $setting->setValue(2); + + $this->assertSettingHasValue($setting, 2); + } + + public function test_setSettingValue_shouldCastValue_IfTypeIsSetButNoFilter() + { + $this->setUser(); + + // cast to INT + $setting = $this->buildSetting('mysystem', FieldConfig::TYPE_INT); + $setting->setValue('31'); + $this->assertSettingHasValue($setting, 31, 'integer'); + + // ARRAY + $setting = $this->buildSetting('mysystem2', FieldConfig::TYPE_ARRAY); + $setting->setValue('31xm42'); + $this->assertSettingHasValue($setting, array('31xm42'), 'array'); + + // BOOL + $setting = $this->buildSetting('mysystem3', FieldConfig::TYPE_BOOL); + $setting->setValue('1'); + $this->assertSettingHasValue($setting, true, 'boolean'); + + // FLOAT + $setting = $this->buildSetting('mysystem4', FieldConfig::TYPE_FLOAT); + $setting->setValue('1.21'); + $this->assertSettingHasValue($setting, 1.21, 'float'); + + // STRING + $setting = $this->buildSetting('mysystem5', FieldConfig::TYPE_STRING); + $setting->setValue('31xm42'); + $this->assertSettingHasValue($setting, '31xm42'); + } + + public function test_setSettingValue_shouldApplyFilterAndNotCast_IfAFilterIsSet() + { + $this->setUser(); + + $self = $this; + + $setting = $this->buildSetting('mysystem', FieldConfig::TYPE_INT); + $setting->setConfigureCallback(function (FieldConfig $field) use ($self, $setting) { + $field->transform = function ($value, $userSetting) use ($self, $setting) { + $self->assertEquals('31', $value); + $self->assertEquals($setting, $userSetting); + + return '43939kmf3m3'; + }; + }); + + $setting->setValue('31'); + + // should not be casted to int + $this->assertSettingHasValue($setting, 43939, 'integer'); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Validation Fail + */ + public function test_setSettingValue_shouldValidateAValue_IfAFilterIsSet() + { + $this->setUser(); + $self = $this; + + $setting = $this->buildSetting('mysystem', FieldConfig::TYPE_INT); + $setting->setConfigureCallback(function (FieldConfig $field) use ($self, $setting) { + $field->validate = function ($value, $userSetting) use ($self, $setting) { + $self->assertEquals('31xm42', $value); + $self->assertEquals($setting, $userSetting); + + throw new \Exception('Validation Fail'); + }; + }); + + $setting->setValue('31xm42'); + } + + public function test_getSettingValue_shouldReturnUncastedDefaultValue_IfNoValueIsSet() + { + $this->setUser(); + + $setting = $this->buildSetting('mydefaultsystem', FieldConfig::TYPE_INT, $default = 'mytestvalue'); + $this->settings->addSetting($setting); + + // should not be casted to int + $this->assertSettingHasValue($setting, 'mytestvalue', 'string'); + } + + public function test_getSettingValue_shouldReturnValue_IfValueExistsAndUserHasPermission() + { + $this->setUser(); + $setting = $this->buildSetting('myusersetting', FieldConfig::TYPE_ARRAY); + $setting->setValue(array(2,3,4)); + + $this->assertSettingHasValue($setting, array(2,3,4)); + } + + public function test_save_shouldSaveDifferentValuesForDifferentUsersAndFields() + { + $login1 = $this->buildSetting('field1', null, '', $login = 'user1'); + $login1->setValue('value1'); + $login1->save(); + + $login2 = $this->buildSetting('field1', null, '', $login = 'user2'); + $this->assertSame('value1', $login1->getValue()); + $this->assertSame('', $login2->getValue()); + $login2->setValue('value2'); + $login2->save(); + + $login3 = $this->buildSetting('field1', null, '', $login = 'user3'); + $this->assertSame('value1', $login1->getValue()); + $this->assertSame('value2', $login2->getValue()); + $this->assertSame('', $login3->getValue()); + + $login1Field2 = $this->buildSetting('field2', null, '', $login = 'user1'); + $this->assertSame('', $login1Field2->getValue()); + $login1Field2->setValue('value1Field2'); + $login1Field2->save(); + + $this->assertSame('value1', $login1->getValue()); + $this->assertSame('value1Field2', $login1Field2->getValue()); + } + + private function buildSetting($name, $type = null, $default = '', $login = null) + { + if (!isset($type)) { + $type = FieldConfig::TYPE_STRING; + } + + if (!isset($login)) { + $login = FakeAccess::$identity; + } + + $userSetting = new UserSetting($name, $default, $type, 'MyPluginName', $login); + + return $userSetting; + } + +} diff --git a/tests/PHPUnit/Integration/Settings/Plugin/UserSettingsTest.php b/tests/PHPUnit/Integration/Settings/Plugin/UserSettingsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..66c9a30152fc98d4edc6b348f6ed227b3fda4879 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Plugin/UserSettingsTest.php @@ -0,0 +1,49 @@ +<?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\Tests\Integration\Settings\Plugin; + +use Piwik\Db; +use Piwik\Settings\Plugin\UserSetting; +use Piwik\Settings\Plugin\UserSettings; +use Piwik\Tests\Framework\Mock\Settings\FakeUserSettings; +use Piwik\Tests\Integration\Settings\BaseSettingsTestCase; + +/** + * @group PluginSettings + * @group UserSettings + */ +class UserSettingsTest extends BaseSettingsTestCase +{ + protected $updateEventName = 'UserSettings.updated'; + + protected function createSettingsInstance() + { + return new FakeUserSettings(); + } + + public function test_weAreWorkingWithUserSettings() + { + $this->assertTrue($this->settings instanceof UserSettings); + } + + public function test_constructor_getPluginName_canDetectPluginNameAutomatically() + { + $settings = new \Piwik\Plugins\ExampleSettingsPlugin\UserSettings(); + $this->assertSame('ExampleSettingsPlugin', $settings->getPluginName()); + $this->assertSame('ExampleSettingsPlugin', $this->settings->getPluginName()); + } + + public function test_makeSetting_ShouldCreateAUserSetting() + { + $setting = $this->makeSetting('myName'); + + $this->assertTrue($setting instanceof UserSetting); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/SettingTest.php b/tests/PHPUnit/Integration/Settings/SettingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..70aa00db49262d10d7ec53d092e389b3e05010bd --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/SettingTest.php @@ -0,0 +1,249 @@ +<?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\Tests\Integration\Settings\Plugin; + +use Piwik\Db; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Setting; +use Piwik\Settings\Storage\Storage; +use Piwik\Settings\Storage\Backend; +use Exception; +use Piwik\Tests\Framework\Mock\Settings\FakeBackend; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; + + +/** + * @group Settings + * @group Setting + */ +class SettingTest extends IntegrationTestCase +{ + + /** + * @expectedException \Exception + * @expectedExceptionMessage setting name "myname-" in plugin "MyPluginName" is invalid + */ + public function test_constructor_shouldThrowException_IfTheSettingNameIsNotValid() + { + $this->makeSetting('myname-'); + } + + public function test_configureField_shouldAssignDefaultField_IfTypeIsGivenButNoField() + { + $setting = $this->makeSetting('myname', FieldConfig::TYPE_ARRAY); + $field = $setting->configureField(); + $this->assertEquals(FieldConfig::UI_CONTROL_MULTI_SELECT, $field->uiControl); + + $setting = $this->makeSetting('myname2', FieldConfig::TYPE_BOOL); + $field = $setting->configureField(); + $this->assertEquals(FieldConfig::UI_CONTROL_CHECKBOX, $field->uiControl); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Type must be an array when using a multi select + */ + public function test_configureField_ShouldCheckThatTypeMakesActuallySenseForConfiguredUiControl() + { + $setting = $this->makeSetting('myname', FieldConfig::TYPE_STRING, $default = '', function (FieldConfig $field) { + $field->uiControl = FieldConfig::UI_CONTROL_MULTI_SELECT; + }); + $setting->configureField(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Type does not exist + */ + public function test_configureField_ChecksTheGivenTypeIsKnown() + { + $setting = $this->makeSetting('myname', 'unknOwnTyPe'); + $setting->configureField(); + } + + public function test_setValue_shouldValidateAutomatically_IfFieldOptionsAreGiven() + { + $setting = $this->makeSetting('myname', null, $default = '', function (FieldConfig $field) { + $field->availableValues = array('allowedval' => 'DisplayName', 'allowedval2' => 'Name 2'); + }); + + // valid value + $setting->setValue('allowedval'); + $this->assertSame('allowedval', $setting->getValue()); + + try { + $setting->setValue('invAliDValue'); + } catch (Exception $e) { + $this->assertContains('CoreAdminHome_PluginSettingsValueNotAllowed', $e->getMessage()); + return; + } + + $this->fail('An expected exception has not been thrown'); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingsValueNotAllowed + */ + public function test_setValue_shouldApplyValidationAndFail_IfOptionsAreSetAndValueIsAnArray() + { + $setting = $this->makeSetting('myname', FieldConfig::TYPE_ARRAY, $default = '', function (FieldConfig $field) { + $field->availableValues = array('allowedval' => 'DisplayName', 'allowedval2' => 'Name 2'); + $field->uiControl = FieldConfig::UI_CONTROL_MULTI_SELECT; + }); + + $setting->setValue(array('allowed', 'notallowed')); + } + + public function test_setSettingValue_shouldApplyValidationAndSucceed_IfOptionsAreSet() + { + $setting = $this->makeSetting('myname', FieldConfig::TYPE_ARRAY, $default = '', function (FieldConfig $field) { + $field->availableValues = array('allowedval' => 'DisplayName', 'allowedval2' => 'Name 2'); + $field->uiControl = FieldConfig::UI_CONTROL_MULTI_SELECT; + }); + $setting->setValue(array('allowedval', 'allowedval2')); + $this->assertSame($setting->getValue(), array('allowedval', 'allowedval2')); + + $setting = $this->makeSetting('myname2', null, $default = '', function (FieldConfig $field) { + $field->availableValues = array('allowedval' => 'DisplayName', 'allowedval2' => 'Name 2'); + }); + + $setting->setValue('allowedval'); + $this->assertSame($setting->getValue(), 'allowedval'); + } + + public function test_setValue_shouldValidateAutomatically_IfTypeBoolIsUsed() + { + $setting = $this->makeSetting('myname', FieldConfig::TYPE_BOOL); + + // valid values + $setting->setValue('1'); + $this->assertSame(true, $setting->getValue()); + $setting->setValue(false); + $this->assertSame(false, $setting->getValue()); + $setting->setValue(1); + $this->assertSame(true, $setting->getValue()); + + try { + $setting->setValue('invAliDValue'); + } catch (Exception $e) { + $this->assertContains('CoreAdminHome_PluginSettingsValueNotAllowed', $e->getMessage()); + return; + } + + $this->fail('An expected exception has not been thrown'); + } + + /** + * @dataProvider getNumericTypes + */ + public function test_setValue_shouldValidateAutomatically_IfTypeIsNumeric($type) + { + $setting = $this->makeSetting('myname', $type); + + // valid values + $setting->setValue('1'); + $setting->setValue('1.5'); + $setting->setValue(0); + $setting->setValue(0.5); + $setting->setValue(-22.5); + + try { + $setting->setValue('1invalid'); + } catch (Exception $e) { + $this->assertContains('CoreAdminHome_PluginSettingsValueNotAllowed', $e->getMessage()); + return; + } + + $this->fail('An expected exception has not been thrown'); + } + + public function getNumericTypes() + { + return array(array(FieldConfig::TYPE_INT), array(FieldConfig::TYPE_FLOAT)); + } + + public function test_isWritableByCurrentUser_shouldNotBeWritableByDefault() + { + $setting = new Setting($name = 'test', $default = 0, $type = FieldConfig::TYPE_INT, function () {}); + $this->assertFalse($setting->isWritableByCurrentUser()); + } + + public function test_setIsWritableByCurrentUser() + { + $setting = $this->makeSetting('myName'); + $this->assertTrue($setting->isWritableByCurrentUser()); + + $setting->setIsWritableByCurrentUser(0); + $this->assertFalse($setting->isWritableByCurrentUser()); + + $setting->setIsWritableByCurrentUser(1); + $this->assertTrue($setting->isWritableByCurrentUser()); + + $setting->setIsWritableByCurrentUser(false); + $this->assertFalse($setting->isWritableByCurrentUser()); + } + + public function test_setDefaultValue_getDefaultValue() + { + $setting = $this->makeSetting('myname'); + $setting->setDefaultValue(5); + $this->assertSame(5, $setting->getDefaultValue()); + } + + public function test_getType() + { + $setting = $this->makeSetting('myname', FieldConfig::TYPE_ARRAY); + $this->assertSame(FieldConfig::TYPE_ARRAY, $setting->getType()); + } + + public function test_getName() + { + $setting = $this->makeSetting('myName'); + $this->assertSame('myName', $setting->getName()); + } + + protected function makeSetting($name, $type = null, $default = '', $configure = null) + { + if (!isset($type)) { + $type = FieldConfig::TYPE_STRING; + } + + $setting = new Setting($name, $default, $type, 'MyPluginName'); + $setting->setStorage(new Storage(new Backend\Null('myId'))); + $setting->setIsWritableByCurrentUser(true); + + if (isset($configure)) { + $setting->setConfigureCallback($configure); + } + + return $setting; + } + + public function test_save_shouldPersistValue() + { + $value = array(2,3,4); + + $backend = new FakeBackend('test'); + $backend->save(array()); + $storage = new Storage($backend); + + $setting = $this->makeSetting('mysetting', FieldConfig::TYPE_ARRAY); + $setting->setStorage($storage); + $setting->setValue($value); + + // assert not saved in backend + $this->assertSame(array(), $backend->load()); + + $setting->save(); + + // assert saved in backend + $this->assertSame(array('mysetting' => $value), $backend->load()); + } +} diff --git a/tests/PHPUnit/Integration/Settings/Storage/Backend/CacheTest.php b/tests/PHPUnit/Integration/Settings/Storage/Backend/CacheTest.php new file mode 100644 index 0000000000000000000000000000000000000000..c43b90fd1d95e297c19228d67d6e42e18d3b22cb --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Storage/Backend/CacheTest.php @@ -0,0 +1,116 @@ +<?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\Tests\Integration\Settings\Storage\Backend; + +use Piwik\Settings\Storage\Backend\Cache; +use Piwik\Tests\Framework\Mock\Settings\FakeBackend; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; + +/** + * @group Settings + * @group Backend + * @group Storage + */ +class CacheTest extends IntegrationTestCase +{ + + /** + * @var FakeBackend + */ + private $backend; + + /** + * @var Cache + */ + private $cacheBackend; + + public function setUp() + { + parent::setUp(); + + $this->backend = new FakeBackend('MySuperStorageKey'); + $this->cacheBackend = new Cache($this->backend); + } + + public function test_getStorageId_shouldReturnStorageOfActualPlugin() + { + $this->assertSame('MySuperStorageKey', $this->cacheBackend->getStorageId()); + } + + public function test_load_ShouldActuallyLoadDataFromBackend() + { + $this->assertSame($this->backend->load(), $this->cacheBackend->load()); + $this->assertNotEmpty($this->cacheBackend->load()); + } + + public function test_load_ShouldCacheData() + { + $this->assertNotValueCached(); + + $this->cacheBackend->load(); + + $this->assertValueCached(); + $this->assertValueIsActuallyInCache(); + } + + public function test_delete_ShouldClearCacheAndData() + { + $this->cacheBackend->load(); + $this->assertValueCached(); + + $this->cacheBackend->delete(); + + $this->assertNotValueCached(); + $this->assertSame(array(), $this->cacheBackend->load()); + $this->assertSame(array(), $this->backend->load()); + } + + public function test_save_ShouldClearCacheAndUpdateData() + { + $this->cacheBackend->load(); + $this->assertValueCached(); + + $value = array('new' => 'value'); + $this->cacheBackend->save($value); + + $this->assertNotValueCached(); + + $this->assertSame($value, $this->cacheBackend->load()); + $this->assertSame($value, $this->backend->load()); + + $this->assertValueCached(); + $this->assertValueIsActuallyInCache(); + } + + private function assertValueIsActuallyInCache() + { + $this->assertSame($this->backend->load(), $this->getCache()->fetch($this->getCacheKey())); + } + + private function assertValueCached() + { + $this->assertTrue($this->getCache()->contains($this->getCacheKey())); + } + + private function assertNotValueCached() + { + $this->assertFalse($this->getCache()->contains($this->getCacheKey())); + } + + private function getCacheKey() + { + return $this->cacheBackend->getStorageId(); + } + + private function getCache() + { + return Cache::buildCache(); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/Storage/Backend/MeasurableSettingsTableTest.php b/tests/PHPUnit/Integration/Settings/Storage/Backend/MeasurableSettingsTableTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8b0e7a5bec4cab1679b2ba1ac933eb3ee80e74e0 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Storage/Backend/MeasurableSettingsTableTest.php @@ -0,0 +1,253 @@ +<?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\Tests\Integration\Settings\Storage\Backend; + +use Piwik\Config; +use Piwik\Db; +use Piwik\Settings\Storage\Backend\MeasurableSettingsTable; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; + +/** + * @group Settings + * @group Backend + * @group Storage + */ +class MeasurableSettingsTableTest extends IntegrationTestCase +{ + + /** + * @var MeasurableSettingsTable + */ + private $backendSite1; + + /** + * @var MeasurableSettingsTable + */ + private $backendSite2; + + /** + * @var MeasurableSettingsTable + */ + private $backendSite1Plugin2; + + /** + * @var MeasurableSettingsTable[] + */ + private $allBackends = array(); + + public function setUp() + { + parent::setUp(); + + $this->backendSite1 = $this->createSettings(1, 'MyPluginName'); + $this->backendSite2 = $this->createSettings(2, 'MyPluginName'); + $this->backendSite1Plugin2 = $this->createSettings(1, 'MyPluginName2'); + $this->allBackends = array($this->backendSite1, $this->backendSite2, $this->backendSite1Plugin2); + } + + private function createSettings($idSite, $plugin) + { + return new MeasurableSettingsTable($idSite, $plugin); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No plugin name given + */ + public function test_construct_shouldThrowAnException_IfPluginNameIsEmpty() + { + $this->createSettings(1, ''); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No idSite given + */ + public function test_construct_shouldThrowAnException_IfIdSiteIsEmpty() + { + $this->createSettings(0, 'MyPlugin'); + } + + public function test_load_shouldNotHaveAnySettingsByDefault() + { + $this->assertSame(array(), $this->backendSite1->load()); + $this->assertSame(array(), $this->backendSite2->load()); + $this->assertSame(array(), $this->backendSite1Plugin2->load()); + } + + public function test_getStorageId_shouldIncludePluginNameAndLogin() + { + $this->assertSame('MeasurableSettings_1_MyPluginName', $this->backendSite1->getStorageId()); + $this->assertSame('MeasurableSettings_2_MyPluginName', $this->backendSite2->getStorageId()); + $this->assertSame('MeasurableSettings_1_MyPluginName2', $this->backendSite1Plugin2->getStorageId()); + } + + public function test_save_ShouldOnlySaveForSpecificPluginAndIdSite() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + + $this->backendSite1->save($value1); + + $this->assertSame($value1, $this->backendSite1->load()); + $this->assertSame(array(), $this->backendSite2->load()); + $this->assertSame(array(), $this->backendSite1Plugin2->load()); + + $value2 = $this->getExampleValues(); + $this->backendSite2->save($value2); + + $this->assertSame($value1, $this->backendSite1->load()); + $this->assertSame($value2, $this->backendSite2->load()); + $this->assertSame(array(), $this->backendSite1Plugin2->load()); + + $value3 = $this->getExampleValues(); + $this->backendSite1Plugin2->save($value3); + + $this->assertSame($value1, $this->backendSite1->load()); + $this->assertSame($value2, $this->backendSite2->load()); + $this->assertSame($value3, $this->backendSite1Plugin2->load()); + } + + public function test_delete_shouldDeleteAllValuesButOnlyForSpecificPluginAndIdSite() + { + $values = array(); + foreach ($this->allBackends as $index => $backend) { + $values[$index] = $this->getExampleValues(); + $backend->save($values[$index]); + $this->assertSame($values[$index], $backend->load()); + } + + foreach ($this->allBackends as $index => $backend) { + $backend->delete(); + $values[$index] = array(); + + // we make sure the values for all others are still set and only the current one was deleted + foreach ($this->allBackends as $j => $backend2) { + $this->assertSame($values[$j], $backend2->load()); + } + } + } + + public function test_save_DuplicateValuesShouldBeOverwritten() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + + $this->backendSite1->save($value1); + + $this->assertSame($value1, $this->backendSite1->load()); + + $value2 = array('mytest' => 'test2', 'Mysetting2' => 'val', 'Mysetting1' => 'valueNew'); + $this->backendSite1->save($value2); + + $this->assertEquals($value2, $this->backendSite1->load()); + } + + public function test_save_NoLongerExistingValues_shouldBeRemoved() + { + $value = $this->saveValueForAllBackends(); + + // overwrite only user1 + $value2 = array('mytest' => 'test2', 'Mysetting1' => 'valueNew'); + $this->backendSite1Plugin2->save($value2); + $this->assertEquals($value2, $this->backendSite1Plugin2->load()); + + // make sure other backends remain unchanged + foreach ($this->allBackends as $backend) { + if ($backend !== $this->backendSite1Plugin2) { + $this->assertSame($value, $backend->load()); + } + } + } + + public function test_save_load_ShouldBeAbleToSaveAndLoadArrayValues() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => array('val', 'val7', 'val5')); + + $this->backendSite1Plugin2->save($value1); + $this->assertEquals($value1, $this->backendSite1Plugin2->load()); + } + + public function test_save_load_ShouldBeAbleToSaveAndLoadArrayValues_OnlyOneKey() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => array('val')); + + $this->backendSite1Plugin2->save($value1); + + + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + // it doesn't return an array for Mysetting2 but it is supposed to be casted to array by storage in this case + $this->assertEquals($value1, $this->backendSite1Plugin2->load()); + } + + public function test_save_ShouldBeAbleToSaveBoolValues() + { + $value1 = array('Mysetting1' => true, 'Mysetting2' => array('val', 'val7', false, true, 'val5')); + + $this->backendSite1Plugin2->save($value1); + + $value1 = array('Mysetting1' => '1', 'Mysetting2' => array('val', 'val7', '0', '1', 'val5')); + $this->assertEquals($value1, $this->backendSite1Plugin2->load()); + } + + public function test_save_ShouldIgnoreNullValues() + { + $value1 = array('Mysetting1' => true, 'MySetting3' => null, 'Mysetting2' => array('val', null, true, 'val5')); + + $this->backendSite1Plugin2->save($value1); + + $value1 = array('Mysetting1' => '1', 'Mysetting2' => array('val', '1', 'val5')); + $this->assertEquals($value1, $this->backendSite1Plugin2->load()); + } + + public function test_removeAllUserSettingsForUser_shouldOnlyRemoveSettingsForThatUser() + { + $value = $this->saveValueForAllBackends(); + + MeasurableSettingsTable::removeAllSettingsForSite('2'); + + foreach ($this->allBackends as $backend) { + if ($backend === $this->backendSite2) { + $this->assertSame(array(), $backend->load()); + } else { + $this->assertSame($value, $backend->load()); + } + } + } + + public function test_removeAllSettingsForPlugin_shouldOnlyRemoveSettingsForThatPlugin() + { + $value = $this->saveValueForAllBackends(); + + MeasurableSettingsTable::removeAllSettingsForPlugin('MyPluginName'); + + foreach ($this->allBackends as $backend) { + if ($backend === $this->backendSite1Plugin2) { + $this->assertSame($value, $backend->load()); + } else { + $this->assertSame(array(), $backend->load()); + } + } + } + + private function saveValueForAllBackends() + { + $value = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + + foreach ($this->allBackends as $backend) { + $backend->save($value); + $this->assertSame($value, $backend->load()); + } + + return $value; + } + + private function getExampleValues() + { + return array('Mysetting3' => 'value3', 'Mysetting4' . rand(4,99) => 'val' . rand(0, 10)); + } +} diff --git a/tests/PHPUnit/Integration/Settings/Storage/Backend/NullTest.php b/tests/PHPUnit/Integration/Settings/Storage/Backend/NullTest.php new file mode 100644 index 0000000000000000000000000000000000000000..fcbafa3b82c2fa32e3c32f007414c5a82bfc197c --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Storage/Backend/NullTest.php @@ -0,0 +1,48 @@ +<?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\Tests\Integration\Settings\Storage\Backend; + +use Piwik\Config; +use Piwik\Db; +use Piwik\Settings\Storage\Backend\Null; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; + +/** + * @group Settings + * @group Backend + * @group Storage + */ +class NullTest extends IntegrationTestCase +{ + + /** + * @var Null + */ + private $backend; + + public function setUp() + { + parent::setUp(); + + $this->backend = new Null('storageId1FooBar'); + } + + public function test_getStorageId_shouldReturnStorageId() + { + $this->assertSame('storageId1FooBar', $this->backend->getStorageId()); + } + + public function test_save_load_shouldNotSaveAnything() + { + $this->assertSame(array(), $this->backend->load()); + $this->backend->save(array('foo' => 'bar')); + $this->assertSame(array(), $this->backend->load()); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/Storage/Backend/PluginSettingsTableTest.php b/tests/PHPUnit/Integration/Settings/Storage/Backend/PluginSettingsTableTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9a15bee767b9599a297ba4cb0328318e6e8404d0 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Storage/Backend/PluginSettingsTableTest.php @@ -0,0 +1,288 @@ +<?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\Tests\Integration\Settings\Storage\Backend; + +use Piwik\Config; +use Piwik\Db; +use Piwik\Settings\Storage\Backend\PluginSettingsTable; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; + +/** + * @group Settings + * @group Backend + * @group Storage + */ +class PluginSettingsTableTest extends IntegrationTestCase +{ + + /** + * @var PluginSettingsTable + */ + private $backendPlugin1; + + /** + * @var PluginSettingsTable + */ + private $backendPlugin2; + + /** + * @var PluginSettingsTable + */ + private $backendUser1; + + /** + * @var PluginSettingsTable + */ + private $backendUser2; + + /** + * @var PluginSettingsTable[] + */ + private $allBackends = array(); + + public function setUp() + { + parent::setUp(); + + $this->backendPlugin1 = $this->createSettings('MyPluginName', ''); + $this->backendPlugin2 = $this->createSettings('MyPluginName2', ''); + $this->backendUser1 = $this->createSettings('MyPluginName', 'user1'); + $this->backendUser2 = $this->createSettings('MyPluginName', 'user2'); + $this->allBackends = array($this->backendPlugin1, $this->backendPlugin2, $this->backendUser1, $this->backendUser2); + } + + private function createSettings($plugin, $login) + { + return new PluginSettingsTable($plugin, $login); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No plugin name given + */ + public function test_construct_shouldThrowAnException_IfPluginNameIsEmpty() + { + $this->createSettings('', ''); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid user login name + */ + public function test_construct_shouldThrowAnException_IfUserLoginFalse() + { + $this->createSettings('MyPlugin', false); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid user login name + */ + public function test_construct_shouldThrowAnException_IfUserLoginNull() + { + $this->createSettings('MyPlugin', null); + } + + public function test_load_shouldNotHaveAnySettingsByDefault() + { + $this->assertSame(array(), $this->backendPlugin1->load()); + $this->assertSame(array(), $this->backendPlugin2->load()); + $this->assertSame(array(), $this->backendUser1->load()); + $this->assertSame(array(), $this->backendUser2->load()); + } + + public function test_getStorageId_shouldIncludePluginNameAndLogin() + { + $this->assertSame('PluginSettings_MyPluginName_User_', $this->backendPlugin1->getStorageId()); + $this->assertSame('PluginSettings_MyPluginName2_User_', $this->backendPlugin2->getStorageId()); + $this->assertSame('PluginSettings_MyPluginName_User_user1', $this->backendUser1->getStorageId()); + $this->assertSame('PluginSettings_MyPluginName_User_user2', $this->backendUser2->getStorageId()); + } + + public function test_save_ShouldOnlySaveForSpecificPlugin_NoUserGiven() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + + $this->backendPlugin1->save($value1); + + $this->assertSame($value1, $this->backendPlugin1->load()); + $this->assertSame(array(), $this->backendPlugin2->load()); + $this->assertSame(array(), $this->backendUser1->load()); + $this->assertSame(array(), $this->backendUser2->load()); + + $value2 = array('mytest' => 'test2'); + $this->backendPlugin2->save($value2); + + $this->assertSame($value1, $this->backendPlugin1->load()); + $this->assertSame($value2, $this->backendPlugin2->load()); + $this->assertSame(array(), $this->backendUser1->load()); + $this->assertSame(array(), $this->backendUser2->load()); + } + + public function test_save_ShouldOnlySaveForSpecificPluginAndUser() + { + $values = array_fill(0, count($this->allBackends), array()); + + foreach ($this->allBackends as $index => $backend) { + $values[$index] = $this->getExampleValues(); + $backend->save($values[$index]); + + foreach ($this->allBackends as $j => $backend2) { + $this->assertSame($values[$j], $backend2->load()); + } + } + } + + public function test_delete_shouldDeleteAllValuesButOnlyForSpecificPluginAndLogin() + { + $values = array(); + foreach ($this->allBackends as $index => $backend) { + $values[$index] = $this->getExampleValues(); + $backend->save($values[$index]); + $this->assertSame($values[$index], $backend->load()); + } + + foreach ($this->allBackends as $index => $backend) { + $backend->delete(); + $values[$index] = array(); + + // we make sure the values for all others are still set and only the current one was deleted + foreach ($this->allBackends as $j => $backend2) { + $this->assertSame($values[$j], $backend2->load()); + } + } + } + + public function test_save_DuplicateValuesShouldBeOverwritten() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + + $this->backendPlugin1->save($value1); + + $this->assertSame($value1, $this->backendPlugin1->load()); + + $value2 = array('mytest' => 'test2', 'Mysetting2' => 'val', 'Mysetting1' => 'valueNew'); + $this->backendPlugin1->save($value2); + + $this->assertEquals($value2, $this->backendPlugin1->load()); + } + + public function test_save_NoLongerExistingValues_shouldBeRemoved() + { + $value = $this->saveValueForAllBackends(); + + // overwrite only user1 + $value2 = array('mytest' => 'test2', 'Mysetting1' => 'valueNew'); + $this->backendUser1->save($value2); + $this->assertEquals($value2, $this->backendUser1->load()); + + // make sure other backends remain unchanged + foreach ($this->allBackends as $backend) { + if ($backend !== $this->backendUser1) { + $this->assertSame($value, $backend->load()); + } + } + } + + public function test_save_load_ShouldBeAbleToSaveAndLoadArrayValues() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => array('val', 'val7', 'val5')); + + $this->backendUser1->save($value1); + $this->assertEquals($value1, $this->backendUser1->load()); + } + + public function test_save_load_ShouldBeAbleToSaveAndLoadArrayValues_OnlyOneKey() + { + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => array('val')); + + $this->backendUser1->save($value1); + + + $value1 = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + // it doesn't return an array for Mysetting2 but it is supposed to be casted to array by storage in this case + $this->assertEquals($value1, $this->backendUser1->load()); + } + + public function test_save_ShouldBeAbleToSaveBoolValues() + { + $value1 = array('Mysetting1' => true, 'Mysetting2' => array('val', 'val7', false, true, 'val5')); + + $this->backendUser1->save($value1); + + $value1 = array('Mysetting1' => '1', 'Mysetting2' => array('val', 'val7', '0', '1', 'val5')); + $this->assertEquals($value1, $this->backendUser1->load()); + } + + public function test_save_ShouldIgnoreNullValues() + { + $value1 = array('Mysetting1' => true, 'MySetting3' => null, 'Mysetting2' => array('val', null, true, 'val5')); + + $this->backendUser1->save($value1); + + $value1 = array('Mysetting1' => '1', 'Mysetting2' => array('val', '1', 'val5')); + $this->assertEquals($value1, $this->backendUser1->load()); + } + + public function test_removeAllUserSettingsForUser_shouldOnlyRemoveSettingsForThatUser() + { + $value = $this->saveValueForAllBackends(); + + PluginSettingsTable::removeAllUserSettingsForUser('user1'); + + foreach ($this->allBackends as $backend) { + if ($backend === $this->backendUser1) { + $this->assertSame(array(), $backend->load()); + } else { + $this->assertSame($value, $backend->load()); + } + } + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No userLogin specified + */ + public function test_removeAllUserSettingsForUser_shouldThrowAnExceptionIfLoginIsEmpty() + { + PluginSettingsTable::removeAllUserSettingsForUser(''); + } + + public function test_removeAllSettingsForPlugin_shouldOnlyRemoveSettingsForThatPlugin() + { + $value = $this->saveValueForAllBackends(); + + PluginSettingsTable::removeAllSettingsForPlugin('MyPluginName'); + + foreach ($this->allBackends as $backend) { + if ($backend === $this->backendPlugin2) { + $this->assertSame($value, $backend->load()); + } else { + $this->assertSame(array(), $backend->load()); + } + } + } + + private function saveValueForAllBackends() + { + $value = array('Mysetting1' => 'value1', 'Mysetting2' => 'val'); + + foreach ($this->allBackends as $backend) { + $backend->save($value); + $this->assertSame($value, $backend->load()); + } + + return $value; + } + + private function getExampleValues() + { + return array('Mysetting3' => 'value3', 'Mysetting4' . rand(4,99) => 'val' . rand(0, 10)); + } +} diff --git a/tests/PHPUnit/Integration/Settings/Storage/Backend/SitesTableTest.php b/tests/PHPUnit/Integration/Settings/Storage/Backend/SitesTableTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1b3000a443d2ea9c143352bbfc5545524452ea46 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Storage/Backend/SitesTableTest.php @@ -0,0 +1,194 @@ +<?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\Tests\Integration\Settings\Storage\Backend; + +use Piwik\Config; +use Piwik\Db; +use Piwik\Settings\Storage\Backend\SitesTable; +use Piwik\Tests\Framework\Fixture; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; + +/** + * @group Settings + * @group Backend + * @group Storage + */ +class SitesTableTest extends IntegrationTestCase +{ + + /** + * @var SitesTable + */ + private $backendSite1; + + /** + * @var SitesTable + */ + private $backendSite2; + + public function setUp() + { + parent::setUp(); + + $idSite1 = Fixture::createWebsite('2014-01-01 00:01:02'); + $idSite2 = Fixture::createWebsite('2014-01-01 00:01:02'); + + $this->backendSite1 = $this->createSettings($idSite1); + $this->backendSite2 = $this->createSettings($idSite2); + } + + private function createSettings($idSite) + { + return new SitesTable($idSite); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage No idSite given + */ + public function test_construct_shouldThrowAnException_IfPluginNameIsEmpty() + { + $this->createSettings(0); + } + + public function test_load_shouldHaveValuesByDefaultForExistingSites() + { + $this->assertFieldsLoaded(array('idsite' => '1'), $this->backendSite1); + $this->assertFieldsLoaded(array('idsite' => '2'), $this->backendSite2); + } + + /** + * @expectedException \Piwik\Exception\UnexpectedWebsiteFoundException + */ + public function test_load_shouldThrowException_IfSiteDoesNotExist() + { + $this->createSettings($idSite = 999)->load(); + } + + public function test_getStorageId_shouldIncludePluginNameAndLogin() + { + $this->assertSame('SitesTable_1', $this->backendSite1->getStorageId()); + $this->assertSame('SitesTable_2', $this->backendSite2->getStorageId()); + } + + public function test_save_ShouldOnlySaveForSpecificIdSite() + { + $value1 = array('ecommerce' => '1', 'sitesearch' => '0'); + $this->backendSite1->save($value1); + + $value2 = array('ecommerce' => '0', 'sitesearch' => '1'); + $this->backendSite2->save($value2); + + $this->assertFieldsLoaded($value1, $this->backendSite1); + $this->assertFieldsLoaded($value2, $this->backendSite2); + } + + public function test_delete_shouldNotDeleteAnything() + { + $value = $this->saveValueForAllBackends(); + + $this->backendSite1->delete(); + $this->backendSite2->delete(); + + $this->assertFieldsLoaded($value, $this->backendSite1); + $this->assertFieldsLoaded($value, $this->backendSite2); + } + + public function test_save_DuplicateValuesShouldBeOverwritten() + { + $value = array('ecommerce' => '0', 'sitesearch' => '1'); + + $this->backendSite1->save($value); + $this->assertFieldsLoaded($value, $this->backendSite1); + + $value = array('ecommerce' => '1', 'sitesearch' => '0'); + $this->backendSite1->save($value); + $this->assertFieldsLoaded($value, $this->backendSite1); + } + + public function test_save_ShouldNotRemoveAnyExistingUrls_WhenNoUrlsGiven() + { + $value = array('ecommerce' => '0', 'sitesearch' => '1'); + + $this->backendSite1->save($value); + + $value = array('urls' => array('http://piwik.net')); + $this->assertFieldsLoaded($value, $this->backendSite1); + } + + public function test_save_ShouldBeAbleToHandleBooleanValues() + { + $value = array('ecommerce' => true, 'sitesearch' => false); + $this->backendSite1->save($value); + + $value = array('ecommerce' => '1', 'sitesearch' => '0'); + $this->assertFieldsLoaded($value, $this->backendSite1); + } + + public function test_save_NotSetValues_ShouldRemain() + { + $value = array('ecommerce' => '0', 'sitesearch' => '1'); + $this->backendSite1->save($value); + $this->assertFieldsLoaded($value, $this->backendSite1); + + // make sure name is still set + $this->assertFieldsLoaded(array('name' => 'Piwik test'), $this->backendSite1); + } + + public function test_save_load_ShouldBeAbleToSaveAndLoadArrayValues() + { + $value1 = array( + 'sitesearch_keyword_parameters' => array('val', 'val7', 'val5'), + 'excluded_parameters' => array('val4', 'val17', 'val45'), + ); + + $this->backendSite1->save($value1); + $this->assertFieldsLoaded($value1, $this->backendSite1); + } + + public function test_save_SaveMainUrlAndUrlsCorrectly_ManyUrls() + { + $urls = array('piwik.org', 'demo.piwik.org', 'test.piwik.org'); + $value = array('urls' => $urls); + $this->backendSite1->save($value); + + $value = array('main_url' => 'piwik.org', 'urls' => $urls); + $this->assertFieldsLoaded($value, $this->backendSite1); + } + + public function test_save_SaveMainUrlAndUrlsCorrectly_OnlyOneUrlGiven() + { + $urls = array('piwik.org'); + $value = array('urls' => $urls); + $this->backendSite1->save($value); + + $value = array('main_url' => 'piwik.org', 'urls' => $urls); + $this->assertFieldsLoaded($value, $this->backendSite1); + } + + private function assertFieldsLoaded($expectedValues, SitesTable $backend) + { + $loaded = $backend->load(); + foreach ($expectedValues as $key => $value) { + $this->assertEquals($loaded[$key], $value); + } + } + + private function saveValueForAllBackends() + { + $value = array('ecommerce' => '1', 'sitesearch' => '0'); + + foreach (array($this->backendSite1, $this->backendSite2) as $backend) { + $backend->save($value); + $this->assertFieldsLoaded($value, $backend); + } + + return $value; + } +} diff --git a/tests/PHPUnit/Integration/Settings/Storage/FactoryTest.php b/tests/PHPUnit/Integration/Settings/Storage/FactoryTest.php index 9c2de666670fc1d3330a3f77c387433e41937efb..2f2590cdcab6bf10260c14de3c36b39516bfc4a9 100644 --- a/tests/PHPUnit/Integration/Settings/Storage/FactoryTest.php +++ b/tests/PHPUnit/Integration/Settings/Storage/FactoryTest.php @@ -8,11 +8,16 @@ namespace Piwik\Tests\Integration\Settings\Storage; -use Piwik\Settings\Storage; +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Storage\Backend\Cache; +use Piwik\Settings\Storage\Backend\Null; +use Piwik\Settings\Storage\Backend\SitesTable; +use Piwik\Settings\Storage\Backend\MeasurableSettingsTable; +use Piwik\Settings\Storage\Backend\PluginSettingsTable; +use Piwik\Settings\Storage\Storage; use Piwik\Settings\Storage\Factory; use Piwik\SettingsServer; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; -use Piwik\Tracker\SettingsStorage; /** * @group Tracker @@ -23,41 +28,120 @@ use Piwik\Tracker\SettingsStorage; */ class FactoryTest extends IntegrationTestCase { + /** + * @var Factory + */ + private $factory; - public function test_make_shouldCreateDefaultInstance() + public function setUp() { - $storage = Factory::make('PluginName'); + parent::setUp(); + $this->factory = new Factory(); + } + + public function test_getPluginStorage_shouldReturnStorageWithPluginBackend() + { + $storage = $this->factory->getPluginStorage('PluginName', $login = 'user5'); + $this->assertTrue($storage instanceof Storage); + + $backend = $storage->getBackend(); + $this->assertTrue($backend instanceof PluginSettingsTable); + $this->assertSame('PluginSettings_PluginName_User_user5', $backend->getStorageId()); + } + + public function test_getPluginStorage_shouldDecorateWithCacheBackendInTrackerMode() + { + SettingsServer::setIsTrackerApiRequest(); + $storage = $this->factory->getPluginStorage('pluginName', 'userlogin'); + SettingsServer::setIsNotTrackerApiRequest(); + + $this->assertTrue($storage->getBackend() instanceof Cache); + } + + public function test_getMeasurableSettingsStorage_shouldReturnStorageWithMeasurableSettingsBackend() + { + $storage = $this->factory->getMeasurableSettingsStorage($idSite = 4, 'PluginNameFoo'); $this->assertTrue($storage instanceof Storage); + + $backend = $storage->getBackend(); + $this->assertTrue($backend instanceof MeasurableSettingsTable); + $this->assertSame('MeasurableSettings_4_PluginNameFoo', $backend->getStorageId()); } - public function test_make_shouldCreateTrackerInstance_IfInTrackerMode() + public function test_getMeasurableSettingsStorage_shouldDecorateWithCacheBackendInTrackerMode() { - $storage = $this->makeTrackerInstance(); + SettingsServer::setIsTrackerApiRequest(); + $storage = $this->factory->getMeasurableSettingsStorage($idSite = 4, 'PluginNameFoo'); + SettingsServer::setIsNotTrackerApiRequest(); - $this->assertTrue($storage instanceof SettingsStorage); + $this->assertTrue($storage->getBackend() instanceof Cache); } - public function test_make_shouldPassThePluginNameToTheStorage() + public function test_getMeasurableSettingsStorage_shouldReturnNonPersistentStorageWhenEmptySiteIsGiven() { - $storage = Factory::make('PluginName'); - $this->assertEquals('Plugin_PluginName_Settings', $storage->getOptionKey()); + $storage = $this->factory->getMeasurableSettingsStorage($idSite = 0, 'PluginNameFoo'); + $this->assertTrue($storage instanceof Storage); + + $backend = $storage->getBackend(); + $this->assertTrue($backend instanceof Null); + $this->assertSame('measurableSettings0#PluginNameFoo#nonpersistent', $backend->getStorageId()); } - public function test_make_shouldPassThePluginNameToTheSettingsStorage() + public function test_getSitesTable_shouldReturnStorageWithSitesTableBackend() { - $storage = $this->makeTrackerInstance(); + $storage = $this->factory->getSitesTable($idSite = 3); + $this->assertTrue($storage instanceof Storage); - $this->assertEquals('Plugin_PluginName_Settings', $storage->getOptionKey()); + $backend = $storage->getBackend(); + $this->assertTrue($backend instanceof SitesTable); + $this->assertSame('SitesTable_3', $backend->getStorageId()); } - private function makeTrackerInstance() + public function test_getSitesTable_shouldDecorateWithCacheBackendInTrackerMode() { SettingsServer::setIsTrackerApiRequest(); + $storage = $this->factory->getSitesTable($idSite = 3); + SettingsServer::setIsNotTrackerApiRequest(); + + $this->assertTrue($storage->getBackend() instanceof Cache); + } + + public function test_getSitesTable_shouldReturnNonPersistentStorageWhenEmptySiteIsGiven() + { + $storage = $this->factory->getSitesTable($idSite = 0); + $this->assertTrue($storage instanceof Storage); + + $backend = $storage->getBackend(); + $this->assertTrue($backend instanceof Null); + $this->assertSame('sitesTable#0#nonpersistent', $backend->getStorageId()); + } - $storage = Factory::make('PluginName'); + public function test_getNonPersistentStorage_shouldReturnStorageWithNullBackend() + { + $storage = $this->factory->getNonPersistentStorage('myKey'); + $this->assertTrue($storage instanceof Storage); + $backend = $storage->getBackend(); + $this->assertTrue($backend instanceof Null); + $this->assertSame('myKey', $backend->getStorageId()); + } + + public function test_getNonPersistentStorage_shouldNotDecorateWithCacheBackendInTrackerMode() + { + SettingsServer::setIsTrackerApiRequest(); + $storage = $this->factory->getNonPersistentStorage('anykey'); SettingsServer::setIsNotTrackerApiRequest(); - return $storage; + $this->assertTrue($storage->getBackend() instanceof Null); } + + public function test_getNonPersistentStorage_shouldNotUseCache() + { + $storage = $this->factory->getNonPersistentStorage('myKey'); + $storage->setValue('mytest', 'myval'); + + $storage = $this->factory->getNonPersistentStorage('myKey'); + $this->assertSame('', $storage->getValue('mytest', $default = '', FieldConfig::TYPE_STRING)); + } + } diff --git a/tests/PHPUnit/Integration/Settings/Storage/StorageTest.php b/tests/PHPUnit/Integration/Settings/Storage/StorageTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7e014c900277cd5362ff6ec38d53be58c529a7f9 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Storage/StorageTest.php @@ -0,0 +1,153 @@ +<?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\Tests\Integration\Settings\Storage; + +use Piwik\Settings\FieldConfig; +use Piwik\Settings\Storage\Backend\BackendInterface; +use Piwik\Settings\Storage\Storage; +use Piwik\Tests\Framework\Mock\Settings\FakeBackend; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; +use Piwik\Tracker\Cache as TrackerCache; + +/** + * @group PluginSettings + * @group Storage + */ +class StorageTest extends IntegrationTestCase +{ + /** + * @var Storage + */ + protected $storage; + + /** + * @var BackendInterface + */ + protected $backend; + + /** + * @var string + */ + protected $settingName = 'myname'; + + public function setUp() + { + parent::setUp(); + + $this->backend = new FakeBackend('MyTestId'); + $this->backend->save(array($this->settingName => 'value1')); + $this->storage = $this->buildStorage(); + } + + public function test_getBackend() + { + $this->assertSame($this->backend, $this->storage->getBackend()); + } + + public function test_getValue_shouldReturnDefaultValue_IfNoValueIsSet() + { + $value = $this->storage->getValue('UnkNownFielD', $default = '123', FieldConfig::TYPE_STRING); + $this->assertSame($default, $value); + } + + public function test_getValue_shouldReturnDefaultValue_AndNotCastDefaultValue() + { + $value = $this->storage->getValue('UnkNownFielD', $default = '123', FieldConfig::TYPE_INT); + $this->assertSame($default, $value); + } + + public function test_getValue_shouldReturnASavedValueFromBackend() + { + $value = $this->getValueFromStorage($this->settingName); + $this->assertSame('value1', $value); + } + + public function test_setValue_getValue_shouldSetAndGetActualValue() + { + $this->storage->setValue($this->settingName, 'myRandomVal'); + $value = $this->getValueFromStorage($this->settingName); + $this->assertEquals('myRandomVal', $value); + } + + public function test_setValue_getValue_shouldCastValueWhenGettingTheValue() + { + $this->storage->setValue($this->settingName, '1'); + $value = $this->getValueFromStorage($this->settingName, FieldConfig::TYPE_BOOL); + $this->assertTrue($value); + } + + public function test_setValue_shouldNotSaveItInDatabase() + { + $loaded = $this->backend->load(); + $this->storage->setValue($this->settingName, 'myRandomVal'); + + $this->assertSame($loaded, $this->loadValuesFromBackend()); + } + + public function test_save_shouldPersistValueInDatabase() + { + $this->storage->setValue($this->settingName, 'myRandomVal'); + $this->storage->save(); + + $this->assertEquals(array($this->settingName => 'myRandomVal'), + $this->loadValuesFromBackend()); + } + + public function test_save_shouldPersistMultipleValues_ContainingInt() + { + $this->storage->setValue($this->settingName, 'myRandomVal'); + $this->storage->setValue('mySecondName', 5); + $this->storage->save(); + + $this->assertEquals(array($this->settingName => 'myRandomVal', 'mySecondName' => 5), + $this->loadValuesFromBackend()); + } + + public function test_save_shouldNotClearTrackerCacheEntries_IfThereWasNoChange() + { + TrackerCache::setCacheGeneral(array('testSetting' => 1)); + + $this->assertArrayHasKey('testSetting', TrackerCache::getCacheGeneral()); + + $this->storage->save(); + + $this->assertArrayHasKey('testSetting', TrackerCache::getCacheGeneral()); + } + + public function test_save_shouldClearTrackerCacheEntries_IfThereWasActuallyAChange() + { + TrackerCache::setCacheGeneral(array('testSetting' => 1)); + + $this->assertArrayHasKey('testSetting', TrackerCache::getCacheGeneral()); + + $this->storage->setValue('myTest', 5); // it will save only when there was actually a change + $this->storage->save(); + + $this->assertArrayNotHasKey('testSetting', TrackerCache::getCacheGeneral()); + } + + private function getValueFromStorage($settingName, $type = null) + { + if (!isset($type)) { + $type = FieldConfig::TYPE_STRING; + } + return $this->storage->getValue($settingName, $default = '', $type); + } + + protected function buildStorage() + { + return new Storage($this->backend); + } + + protected function loadValuesFromBackend() + { + return $this->backend->load(); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/StorageTest.php b/tests/PHPUnit/Integration/Settings/StorageTest.php deleted file mode 100644 index 20a5652e676fd96bca37e103e722160b0d9404c8..0000000000000000000000000000000000000000 --- a/tests/PHPUnit/Integration/Settings/StorageTest.php +++ /dev/null @@ -1,162 +0,0 @@ -<?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\Tests\Integration\Settings; - -use Piwik\Option; -use Piwik\Settings\Storage; -use Piwik\Settings\Setting; - -/** - * @group PluginSettings - * @group Storage - */ -class StorageTest extends IntegrationTestCase -{ - /** - * @var Storage - */ - protected $storage; - - /** - * @var Setting - */ - protected $setting; - - public function setUp() - { - parent::setUp(); - - $this->setSuperUser(); - $this->storage = $this->buildStorage(); - $this->setting = $this->buildUserSetting('myname', 'My Name'); - } - - public function test_constructor_shouldNotEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - $this->buildStorage(); - - $this->assertNotDbConnectionCreated(); - } - - public function test_getValue_shouldEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - $this->storage->getValue($this->setting); - - $this->assertDbConnectionCreated(); - } - - public function test_setValue_shouldEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - $this->storage->setValue($this->setting, 5); - - $this->assertDbConnectionCreated(); - } - - public function test_deleteValue_shouldEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - $this->storage->deleteValue($this->setting, 5); - - $this->assertDbConnectionCreated(); - } - - public function test_deleteAll_shouldEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - $this->storage->deleteAllValues(); - - $this->assertDbConnectionCreated(); - } - - public function test_save_shouldEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - $this->storage->save(); - - $this->assertDbConnectionCreated(); - } - - public function test_getValue_shouldReturnNullByDefault() - { - $value = $this->storage->getValue($this->setting); - $this->assertNull($value); - } - - public function test_getValue_shouldReturnADefaultValueIfOneIsSet() - { - $this->setting->defaultValue = 194.34; - $value = $this->storage->getValue($this->setting); - $this->assertSame(194.34, $value); - } - - public function test_setValue_getValue_shouldSetAndGetActualValue() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $value = $this->storage->getValue($this->setting); - $this->assertEquals('myRandomVal', $value); - } - - public function test_setValue_shouldNotSaveItInDatabase() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - - $this->assertFalse($this->getValueFromOptionTable()); - } - - public function test_save_shouldPersistValueInDatabase() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $this->storage->save(); - - $this->assertEquals('a:1:{s:22:"myname#superUserLogin#";s:11:"myRandomVal";}', $this->getValueFromOptionTable()); - } - - public function test_save_shouldPersistMultipleValues_ContainingInt() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $this->storage->setValue($this->buildUserSetting('mySecondName', 'My Name'), 5); - $this->storage->save(); - - $this->assertEquals('a:2:{s:22:"myname#superUserLogin#";s:11:"myRandomVal";s:28:"mySecondName#superUserLogin#";i:5;}', $this->getValueFromOptionTable()); - } - - public function test_deleteAll_ShouldRemoveTheEntireEntry() - { - $this->storage->setValue($this->setting, 'myRandomVal'); - $this->storage->save(); - $this->storage->deleteAllValues(); - - $this->assertFalse($this->getValueFromOptionTable()); - } - - public function test_getOptionKey_shouldContainThePluginName() - { - $this->assertEquals('Plugin_PluginName_Settings', $this->storage->getOptionKey()); - } - - protected function buildStorage() - { - return new Storage('PluginName'); - } - - protected function getValueFromOptionTable() - { - return Option::get($this->storage->getOptionKey()); - } - -} diff --git a/tests/PHPUnit/Integration/Settings/UserSettingTest.php b/tests/PHPUnit/Integration/Settings/UserSettingTest.php deleted file mode 100644 index fa49d96ab3ed610c84e367c634aba20af751db8b..0000000000000000000000000000000000000000 --- a/tests/PHPUnit/Integration/Settings/UserSettingTest.php +++ /dev/null @@ -1,249 +0,0 @@ -<?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\Tests\Integration\Settings; - -use Piwik\Db; -use Piwik\Settings\UserSetting; -use Piwik\Plugin\Settings as PluginSettings; - -/** - * @group PluginSettings - * @group Settings - * @group UserSetting - */ -class UserSettingTest extends IntegrationTestCase -{ - public function test_constructor_shouldNotEstablishADatabaseConnection() - { - $this->assertNotDbConnectionCreated(); - - new UserSetting('name', 'title'); - - $this->assertNotDbConnectionCreated(); - } - - public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeGetAValue() - { - $this->setSuperUser(); - Db::destroyDatabaseObject(); - - $setting = $this->buildUserSetting('testSetting', 'Test Setting'); - - $this->assertNotDbConnectionCreated(); - - $setting->getValue($setting); - - $this->assertDbConnectionCreated(); - } - - public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeSetAValue() - { - $this->setSuperUser(); - Db::destroyDatabaseObject(); - - $setting = $this->buildUserSetting('testSetting', 'Test Setting'); - $settings = $this->createSettingsInstance(); - $settings->addSetting($setting); - - $this->assertNotDbConnectionCreated(); - - $setting->setValue('5'); - - $this->assertDbConnectionCreated(); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_setSettingValue_shouldThrowException_IfAnonymousIsTryingToSetASettingWhichNeedsUserPermission() - { - $this->setAnonymousUser(); - $setting = $this->addUserSetting('mysystem', 'mytitle'); - - $setting->setValue(2); - } - - public function test_setSettingValue_shouldSucceed_IfUserIsTryingToSetASettingWhichNeedsUserPermission() - { - $this->setUser(); - $setting = $this->addUserSetting('mysystem', 'mytitle'); - $setting->setValue(2); - - $this->assertSettingHasValue($setting, 2); - } - - public function test_setSettingValue_shouldCastValue_IfTypeIsSetButNoFilter() - { - $this->setUser(); - - // cast to INT - $setting = $this->addUserSetting('mysystem', 'mytitle'); - $setting->type = PluginSettings::TYPE_INT; - $setting->setValue('31xm42'); - $this->assertSettingHasValue($setting, 31, 'integer'); - - // ARRAY - $setting->type = PluginSettings::TYPE_ARRAY; - $setting->setValue('31xm42'); - $this->assertSettingHasValue($setting, array('31xm42'), 'array'); - - // BOOL - $setting->type = PluginSettings::TYPE_BOOL; - $setting->setValue('1'); - $this->assertSettingHasValue($setting, true, 'boolean'); - - // FLOAT - $setting->type = PluginSettings::TYPE_FLOAT; - $setting->setValue('1.21'); - $this->assertSettingHasValue($setting, 1.21, 'float'); - - // STRING - $setting->type = PluginSettings::TYPE_STRING; - $setting->setValue('31xm42'); - $this->assertSettingHasValue($setting, '31xm42'); - } - - public function test_setSettingValue_shouldApplyFilterAndNotCast_IfAFilterIsSet() - { - $this->setUser(); - - $setting = $this->buildUserSetting('mysystem', 'mytitle'); - $setting->type = PluginSettings::TYPE_INT; - - $self = $this; - $setting->transform = function ($value, $userSetting) use ($self, $setting) { - $self->assertEquals('31xm42', $value); - $self->assertEquals($setting, $userSetting); - - return '43939kmf3m3'; - }; - - $setting->setValue('31xm42'); - - // should not be casted to int - $this->assertSettingHasValue($setting, '43939kmf3m3', 'string'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Validation Fail - */ - public function test_setSettingValue_shouldValidateAValue_IfAFilterIsSet() - { - $this->setUser(); - - $setting = $this->buildUserSetting('mysystem', 'mytitle'); - $setting->type = PluginSettings::TYPE_INT; - - $self = $this; - $setting->validate = function ($value, $userSetting) use ($self, $setting) { - $self->assertEquals('31xm42', $value); - $self->assertEquals($setting, $userSetting); - - throw new \Exception('Validation Fail'); - }; - - $setting->setValue('31xm42'); - } - - public function test_getSettingValue_shouldReturnUncastedDefaultValue_IfNoValueIsSet() - { - $this->setUser(); - - $setting = $this->addUserSetting('mydefaultsystem', 'mytitle'); - $setting->type = PluginSettings::TYPE_INT; - $setting->defaultValue ='mytestvalue'; - - // should not be casted to int - $this->assertSettingHasValue($setting, 'mytestvalue', 'string'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed - */ - public function test_getSettingValue_shouldThrowException_IfGivenSettingDoesNotExist() - { - $this->setAnonymousUser(); - $setting = $this->buildUserSetting('myusersetting', 'mytitle'); - $setting->getValue(); - } - - public function test_getSettingValue_shouldReturnValue_IfValueExistsAndUserHasPermission() - { - $this->setUser(); - $setting = $this->addUserSetting('myusersetting', 'mytitle'); - $setting->type = PluginSettings::TYPE_ARRAY; - $setting->setValue(array(2,3,4)); - - $this->assertSettingHasValue($setting, array(2,3,4)); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_removeSettingValue_shouldThrowException_IfUserHasNotEnoughUserPermissions() - { - $this->setAnonymousUser(); - $setting = $this->addUserSetting('myusersetting', 'mytitle'); - $setting->removeValue(); - } - - public function test_removeSettingValue_shouldRemoveValue_IfValueExistsAndHasEnoughPermissions() - { - $this->setUser(); - $setting = $this->addUserSetting('myusersetting', 'mytitle'); - $setting->setValue('12345657'); - $this->assertSettingHasValue($setting, '12345657'); - - $setting->removeValue(); - $this->assertSettingHasValue($setting, null); - } - - public function test_userSetting_shouldGenerateDifferentKey_ForDifferentUsers() - { - $this->setSuperUser(); - - $user1 = $this->buildUserSetting('myname', 'mytitle', 'user1'); - $user2 = $this->buildUserSetting('myname', 'mytitle', '_user2_'); - $user3 = $this->buildUserSetting('myname', 'mytitle'); - - $this->assertEquals('myname#user1#', $user1->getKey()); - $this->assertEquals('myname#_user2_#', $user2->getKey()); - $this->assertEquals('myname#superUserLogin#', $user3->getKey()); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage You do not have the permission to read the settings of a different user - */ - public function test_userSetting_shouldThrowException_IfSomeoneTriesToReadSettingsFromAnotherUserAndIsNotSuperuser() - { - $this->setUser(); - - $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); - } - - public function test_userSetting_shouldBeAbleToSetLoginAndChangeValues_IfUserHasSuperUserAccess() - { - $this->setSuperUser(); - - $setting = $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); - $this->settings->addSetting($setting); - - $setting->setValue(5); - $this->assertSettingHasValue($setting, 5); - - $setting->removeValue(); - $this->assertSettingHasValue($setting, null); - } - -} diff --git a/tests/PHPUnit/Integration/Tracker/SettingsStorageTest.php b/tests/PHPUnit/Integration/Tracker/SettingsStorageTest.php deleted file mode 100644 index dd17e673143bbeae7ce34cb272248933e0b74223..0000000000000000000000000000000000000000 --- a/tests/PHPUnit/Integration/Tracker/SettingsStorageTest.php +++ /dev/null @@ -1,118 +0,0 @@ -<?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\Tests\Integration\Tracker; - -use Piwik\Cache as PiwikCache; -use Piwik\Settings\Storage; -use Piwik\Tests\Integration\Settings\StorageTest; -use Piwik\Tracker\Cache; -use Piwik\Tracker\SettingsStorage; - -/** - * @group PluginSettings - * @group Storage - * @group SettingStorage - */ -class SettingsStorageTest extends StorageTest -{ - - public function test_storageShouldLoadSettingsFromCacheIfPossible() - { - $this->setSettingValueInCache('my0815RandomName'); - - $this->assertEquals('my0815RandomName', $this->storage->getValue($this->setting)); - } - - public function test_storageShouldLoadSettingsFromCache_AndNotCreateADatabaseInstance() - { - $this->setSettingValueInCache('my0815RandomName'); - - $this->storage->getValue($this->setting); - - $this->assertNotDbConnectionCreated(); - } - - public function test_clearCache_shouldActuallyClearTheCacheEntry() - { - $this->setSettingValueInCache('my0815RandomName'); - - $this->assertTrue($this->hasCache()); - - SettingsStorage::clearCache(); - - $this->assertFalse($this->hasCache()); - } - - private function hasCache() - { - return $this->getCache()->contains($this->storage->getOptionKey()); - } - - public function test_storageShouldNotCastAnyCachedValue() - { - $this->setSettingValueInCache(5); - - $this->assertEquals(5, $this->storage->getValue($this->setting)); - } - - public function test_storageShouldFallbackToDatebaseInCaseNoCacheExists() - { - $this->storage->setValue($this->setting, 5); - $this->storage->save(); - - $this->assertFalse($this->hasCache()); - $this->assertNotFalse($this->getValueFromOptionTable()); // make sure saved in db - - $storage = $this->buildStorage(); - $this->assertEquals(5, $storage->getValue($this->setting)); - $this->assertTrue($this->hasCache()); - } - - public function test_storageCreateACacheEntryIfNoCacheExistsYet() - { - $cache = Cache::getCacheGeneral(); - $this->assertArrayNotHasKey('settingsStorage', $cache); // make sure there is no cache entry yet - - $this->setSettingValueAndMakeSureCacheGetsCreated('myVal'); - - $cache = $this->getCache()->fetch($this->storage->getOptionKey()); - - $this->assertEquals(array( - $this->setting->getKey() => 'myVal' - ), $cache); - } - - protected function buildStorage() - { - return new SettingsStorage('PluginName'); - } - - private function getCache() - { - return PiwikCache::getEagerCache(); - } - - private function setSettingValueInCache($value) - { - $cache = $this->getCache(); - $cache->save($this->storage->getOptionKey(), array( - $this->setting->getKey() => $value - )); - } - - private function setSettingValueAndMakeSureCacheGetsCreated($value) - { - $this->storage->setValue($this->setting, $value); - $this->storage->save(); - - $storage = $this->buildStorage(); - $storage->getValue($this->setting); // force creation of cache by loading settings - } - -} diff --git a/tests/PHPUnit/Integration/Tracker/VisitTest.php b/tests/PHPUnit/Integration/Tracker/VisitTest.php index f4bc1fd5edc52fe197a8493a6cab14d4579734df..92baae429eeb964867d26822e5a12542044f6e10 100644 --- a/tests/PHPUnit/Integration/Tracker/VisitTest.php +++ b/tests/PHPUnit/Integration/Tracker/VisitTest.php @@ -34,7 +34,10 @@ class VisitTest extends IntegrationTestCase FakeAccess::$superUser = true; Manager::getInstance()->loadTrackerPlugins(); - Manager::getInstance()->loadPlugin('SitesManager'); + $pluginNames = array_keys(Manager::getInstance()->getLoadedPlugins()); + $pluginNames[] = 'SitesManager'; + $pluginNames[] = 'WebsiteMeasurable'; + Manager::getInstance()->loadPlugins($pluginNames); Visit::$dimensions = null; } diff --git a/tests/PHPUnit/System/BackwardsCompatibility1XTest.php b/tests/PHPUnit/System/BackwardsCompatibility1XTest.php index 12a60f3821f70fe907996417c7f6f8453bf5e14c..79525cd28caf043402f5f8f0dabe0252bcb322f9 100644 --- a/tests/PHPUnit/System/BackwardsCompatibility1XTest.php +++ b/tests/PHPUnit/System/BackwardsCompatibility1XTest.php @@ -13,7 +13,6 @@ use Piwik\Plugins\VisitFrequency\API as VisitFrequencyApi; use Piwik\Tests\Framework\TestCase\SystemTestCase; use Piwik\Tests\Fixtures\SqlDump; use Piwik\Tests\Framework\Fixture; -use Piwik\Tests\Framework\TestingEnvironmentVariables; /** * Tests that Piwik 2.0 works w/ data from Piwik 1.12. diff --git a/tests/PHPUnit/System/ImportLogsTest.php b/tests/PHPUnit/System/ImportLogsTest.php index 725b2fba1630cd1dd9ac1a0604d7e62e119b0a2b..56ffe1c0b726a3a4a52543b389504826a89d2e2d 100755 --- a/tests/PHPUnit/System/ImportLogsTest.php +++ b/tests/PHPUnit/System/ImportLogsTest.php @@ -8,7 +8,6 @@ namespace Piwik\Tests\System; use Piwik\Access; -use Piwik\Common; use Piwik\Plugins\SitesManager\API; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\TestCase\SystemTestCase; diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bf91acc3d7635c9bc9c3c7adba7a5d83488b1d0 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getSystemSettings.xml @@ -0,0 +1,329 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>metric</name> + <title>Metric to display</title> + <value>nb_visits</value> + <defaultValue>nb_visits</defaultValue> + <type>string</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <nb_visits>Visits</nb_visits> + <nb_actions>Actions</nb_actions> + <visitors>Visitors</visitors> + </availableValues> + <description>Choose the metric that should be displayed in the browser tab</description> + <inlineHelp /> + <introduction>Only Super Users can change the following settings:</introduction> + <condition /> + </row> + <row> + <name>browsers</name> + <title>Supported Browsers</title> + <value> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </value> + <defaultValue> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </defaultValue> + <type>array</type> + <uiControl>multiselect</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <firefox>Firefox</firefox> + <chromium>Chromium</chromium> + <safari>safari</safari> + </availableValues> + <description>The value will be only displayed in the following browsers</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>description</name> + <title>Description for value</title> + <value>This is the value: +Another line</value> + <defaultValue>This is the value: +Another line</defaultValue> + <type>string</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>This description will be displayed next to the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>password</name> + <title>API password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>Password for the 3rd API where we fetch the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>canUserOptOut</name> + <title>Let users disable anonymous tracking</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, logged in users can opt out in their plugin settings. Anonymous users cannot opt out.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>trackToPiwik</name> + <title>Send usage data to Piwik.org</title> + <value>0</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymized usage data will be sent to demo-anonymous.piwik.org and the tracked data can be viewed there (the data is public). The collected data is used to improve Piwik. Thank you for making Piwik better!</description> + <inlineHelp /> + <introduction>Send anonmyized usage data to the creator of Piwik</introduction> + <condition /> + </row> + <row> + <name>ownPiwikSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If specified, anonymized usage data will be sent to the specified site in this Piwik.</description> + <inlineHelp /> + <introduction>Send anonymize usage data to this Piwik</introduction> + <condition /> + </row> + <row> + <name>anonymizeSelfPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>customSiteUrl</name> + <title>Piwik Url</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. http://example.com/piwik</placeHolder> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction>Send anonymize usage data to a custom Piwik</introduction> + <condition /> + </row> + <row> + <name>customSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. "2"</placeHolder> + </uiControlAttributes> + <availableValues /> + <description>If a URL and Site Id is specified, usage data will be sent to the custom Piwik instance.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>anonymizeCustomPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>QueuedTracking</pluginName> + <settings> + <row> + <name>redisHost</name> + <title>Redis host</title> + <value>127.0.0.1</value> + <defaultValue>127.0.0.1</defaultValue> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>300</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Remote host of the Redis server. Max 300 characters are allowed.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPort</name> + <title>Redis port</title> + <value>6379</value> + <defaultValue>6379</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Port the Redis server is running on. Value should be between 1 and 65535.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisDatabase</name> + <title>Redis database</title> + <value>15</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>In case you are using Redis for caching make sure to use a different database.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPassword</name> + <title>Redis password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + <size>100</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Password set on the Redis server, if any. Redis can be instructed to require a password before allowing clients to execute commands.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>queueEnabled</name> + <title>Queue enabled</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, all tracking requests will be written into a queue instead of the directly into the database. Requires a Redis server and phpredis PHP extension.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numQueueWorkers</name> + <title>Number of queue workers</title> + <value>4</value> + <defaultValue>1</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Number of allowed maximum queue workers. Accepts a number between 1 and 16. Best practice is to set the number of CPUs you want to make available for queue processing. Be aware you need to make sure to start the workers manually. We recommend to not use 9-15 workers, rather use 8 or 16 as the queue might not be distributed evenly into different queues. DO NOT USE more than 1 worker if you make use the UserId feature when tracking see https://github.com/piwik/piwik/issues/7691</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numRequestsToProcess</name> + <title>Number of requests that are processed in one batch</title> + <value>25</value> + <defaultValue>25</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Defines how many requests will be picked out of the queue and processed at once. Enter a number which is >= 1.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>processDuringTrackingRequest</name> + <title>Process during tracking request</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, we will process all requests within a queue during a normal tracking request once there are enough requests in the queue. This will not slow down the tracking request. If disabled, you have to setup a cronjob that executes the "./console queuedtracking:process" console command eg every minute to process the queue.</inlineHelp> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getUserSettings.xml b/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getUserSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d18c736bb3ba72c05df84815c4b3ac9c8164526 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_ImportLogs__CorePluginsAdmin.getUserSettings.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>autoRefresh</name> + <title>Auto refresh</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, the value will be automatically refreshed depending on the specified interval</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>refreshInterval</name> + <title>Refresh Interval</title> + <value>30</value> + <defaultValue>30</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description>Defines how often the value should be updated</description> + <inlineHelp>Enter a number which is >= 15</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>color</name> + <title>Color</title> + <value>red</value> + <defaultValue>red</defaultValue> + <type>string</type> + <uiControl>radio</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <red>Red</red> + <blue>Blue</blue> + <green>Green</green> + </availableValues> + <description>Pick your favourite color</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>userTrackingEnabled</name> + <title>Piwik usage tracking enabled</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymous usage data will be tracked. For example which pages are viewed and which reports are used most often. For more information contact your system administrator.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bf91acc3d7635c9bc9c3c7adba7a5d83488b1d0 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getSystemSettings.xml @@ -0,0 +1,329 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>metric</name> + <title>Metric to display</title> + <value>nb_visits</value> + <defaultValue>nb_visits</defaultValue> + <type>string</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <nb_visits>Visits</nb_visits> + <nb_actions>Actions</nb_actions> + <visitors>Visitors</visitors> + </availableValues> + <description>Choose the metric that should be displayed in the browser tab</description> + <inlineHelp /> + <introduction>Only Super Users can change the following settings:</introduction> + <condition /> + </row> + <row> + <name>browsers</name> + <title>Supported Browsers</title> + <value> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </value> + <defaultValue> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </defaultValue> + <type>array</type> + <uiControl>multiselect</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <firefox>Firefox</firefox> + <chromium>Chromium</chromium> + <safari>safari</safari> + </availableValues> + <description>The value will be only displayed in the following browsers</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>description</name> + <title>Description for value</title> + <value>This is the value: +Another line</value> + <defaultValue>This is the value: +Another line</defaultValue> + <type>string</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>This description will be displayed next to the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>password</name> + <title>API password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>Password for the 3rd API where we fetch the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>canUserOptOut</name> + <title>Let users disable anonymous tracking</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, logged in users can opt out in their plugin settings. Anonymous users cannot opt out.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>trackToPiwik</name> + <title>Send usage data to Piwik.org</title> + <value>0</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymized usage data will be sent to demo-anonymous.piwik.org and the tracked data can be viewed there (the data is public). The collected data is used to improve Piwik. Thank you for making Piwik better!</description> + <inlineHelp /> + <introduction>Send anonmyized usage data to the creator of Piwik</introduction> + <condition /> + </row> + <row> + <name>ownPiwikSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If specified, anonymized usage data will be sent to the specified site in this Piwik.</description> + <inlineHelp /> + <introduction>Send anonymize usage data to this Piwik</introduction> + <condition /> + </row> + <row> + <name>anonymizeSelfPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>customSiteUrl</name> + <title>Piwik Url</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. http://example.com/piwik</placeHolder> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction>Send anonymize usage data to a custom Piwik</introduction> + <condition /> + </row> + <row> + <name>customSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. "2"</placeHolder> + </uiControlAttributes> + <availableValues /> + <description>If a URL and Site Id is specified, usage data will be sent to the custom Piwik instance.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>anonymizeCustomPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>QueuedTracking</pluginName> + <settings> + <row> + <name>redisHost</name> + <title>Redis host</title> + <value>127.0.0.1</value> + <defaultValue>127.0.0.1</defaultValue> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>300</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Remote host of the Redis server. Max 300 characters are allowed.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPort</name> + <title>Redis port</title> + <value>6379</value> + <defaultValue>6379</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Port the Redis server is running on. Value should be between 1 and 65535.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisDatabase</name> + <title>Redis database</title> + <value>15</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>In case you are using Redis for caching make sure to use a different database.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPassword</name> + <title>Redis password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + <size>100</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Password set on the Redis server, if any. Redis can be instructed to require a password before allowing clients to execute commands.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>queueEnabled</name> + <title>Queue enabled</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, all tracking requests will be written into a queue instead of the directly into the database. Requires a Redis server and phpredis PHP extension.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numQueueWorkers</name> + <title>Number of queue workers</title> + <value>4</value> + <defaultValue>1</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Number of allowed maximum queue workers. Accepts a number between 1 and 16. Best practice is to set the number of CPUs you want to make available for queue processing. Be aware you need to make sure to start the workers manually. We recommend to not use 9-15 workers, rather use 8 or 16 as the queue might not be distributed evenly into different queues. DO NOT USE more than 1 worker if you make use the UserId feature when tracking see https://github.com/piwik/piwik/issues/7691</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numRequestsToProcess</name> + <title>Number of requests that are processed in one batch</title> + <value>25</value> + <defaultValue>25</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Defines how many requests will be picked out of the queue and processed at once. Enter a number which is >= 1.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>processDuringTrackingRequest</name> + <title>Process during tracking request</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, we will process all requests within a queue during a normal tracking request once there are enough requests in the queue. This will not slow down the tracking request. If disabled, you have to setup a cronjob that executes the "./console queuedtracking:process" console command eg every minute to process the queue.</inlineHelp> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getUserSettings.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getUserSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d18c736bb3ba72c05df84815c4b3ac9c8164526 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__CorePluginsAdmin.getUserSettings.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>autoRefresh</name> + <title>Auto refresh</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, the value will be automatically refreshed depending on the specified interval</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>refreshInterval</name> + <title>Refresh Interval</title> + <value>30</value> + <defaultValue>30</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description>Defines how often the value should be updated</description> + <inlineHelp>Enter a number which is >= 15</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>color</name> + <title>Color</title> + <value>red</value> + <defaultValue>red</defaultValue> + <type>string</type> + <uiControl>radio</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <red>Red</red> + <blue>Blue</blue> + <green>Green</green> + </availableValues> + <description>Pick your favourite color</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>userTrackingEnabled</name> + <title>Piwik usage tracking enabled</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymous usage data will be tracked. For example which pages are viewed and which reports are used most often. For more information contact your system administrator.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getAvailableMeasurableTypes.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getAvailableMeasurableTypes.xml index b4433cb0f29c75dce8880d3566e5395628dbdf6e..eb12eef5d274fe75b2598a8127be566045c948e3 100644 --- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getAvailableMeasurableTypes.xml +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getAvailableMeasurableTypes.xml @@ -5,5 +5,233 @@ <name>Website</name> <description>A website consists of web pages typically served from a single web domain.</description> <howToSetupUrl>?module=CoreAdminHome&action=trackingCodeGenerator</howToSetupUrl> + <settings> + <row> + <pluginName>WebsiteMeasurable</pluginName> + <settings> + <row> + <name>urls</name> + <title>URLs</title> + <value> + <row>http://siteUrl.com/</row> + <row>http://siteUrl2.com/</row> + </value> + <defaultValue> + <row>http://siteUrl.com/</row> + <row>http://siteUrl2.com/</row> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>25</cols> + <rows>3</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>It is recommended, but not required, to specify the various URLs, one per line, that your visitors use to access this website. Alias URLs for a website will not appear in the Referrers > Websites report. Note that it is not necessary to specify the URLs with and without 'www' as Piwik automatically considers both.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>exclude_unknown_urls</name> + <title>Only track visits and actions when the action URL starts with one of the above URLs.</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>When enabled, Piwik will only track internal actions when the Page URL is one of the known URLs for your website. This prevents people from spamming your analytics with URLs for other websites.<br />The domain and the path has to be an exact match and each valid subdomain has to be specified separately. For example when the known URLs are 'http://example.com/path' and 'http://good.example.com', tracking requests for 'http://example.com/otherpath' or 'http://bad.example.com' are ignored.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>keep_url_fragment</name> + <title>Keep Page URL fragments when tracking Page URLs</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>string</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <row>No (Default)</row> + <row>Yes</row> + <row>No</row> + </availableValues> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>excluded_ips</name> + <title>Excluded IPs</title> + <value> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>20</cols> + <rows>4</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter the list of IPs, one per line, that you wish to exclude from being tracked by Piwik. You can use wildcards, eg. 1.2.3.* or 1.2.*.*<br /><br />Your current IP address is <i>127.0.0.1</i></inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>excluded_parameters</name> + <title>Excluded Parameters</title> + <value> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>20</cols> + <rows>4</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter the list of URL Query Parameters, one per line, to exclude from the Page URLs reports.<br /><br />Piwik will automatically exclude the common session parameters (phpsessid, sessionid, ...).</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>excluded_user_agents</name> + <title>Excluded User Agents</title> + <value> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + <cols>20</cols> + <rows>4</rows> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter the list of user agents to exclude from being tracked by Piwik.<br /><br />If the visitor's user agent string contains any of the strings you specify, the visitor will be excluded from Piwik.<br />You can use this to exclude some bots from being tracked.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>sitesearch</name> + <title>Site Search</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>integer</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <row key="1">Site Search tracking enabled</row> + <row key="0">Do not track Site Search</row> + </availableValues> + <description /> + <inlineHelp>You can use Piwik to track and report what visitors are searching in your website's internal search engine.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>use_default_site_search_params</name> + <title>Use <a href='#globalSettings'>default</a> Site Search parameters</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>Query parameter (Default): q,query,s,search,searchword,k,keyword & Category parameter: </description> + <inlineHelp /> + <introduction /> + <condition>1 && sitesearch</condition> + </row> + <row> + <name>sitesearch_keyword_parameters</name> + <title>Query parameter</title> + <value> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Enter a comma separated list of all query parameter names containing the site search keyword.</inlineHelp> + <introduction /> + <condition>sitesearch && !use_default_site_search_params</condition> + </row> + <row> + <name>sitesearch_category_parameters</name> + <title>Category parameter</title> + <value> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>(optional)<br /><br />You may enter a comma-separated list of query parameters specifying the search category.</inlineHelp> + <introduction /> + <condition>1 && sitesearch && !use_default_site_search_params</condition> + </row> + <row> + <name>ecommerce</name> + <title>Ecommerce</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <row>Not an Ecommerce site</row> + <row>Ecommerce enabled</row> + </availableValues> + <description /> + <inlineHelp>When enabled, the "Goals" report will have a new "Ecommerce" section.<br />Piwik allows for advanced Ecommerce Analytics tracking & reporting. Learn more about <a href='http://piwik.org/docs/ecommerce-analytics/' target='_blank'> Ecommerce Analytics</a>.</inlineHelp> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>contact_email</name> + <title>Contact email addresses</title> + <value> + </value> + <defaultValue> + </defaultValue> + <type>array</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + </settings> </row> </result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bf91acc3d7635c9bc9c3c7adba7a5d83488b1d0 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getSystemSettings.xml @@ -0,0 +1,329 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>metric</name> + <title>Metric to display</title> + <value>nb_visits</value> + <defaultValue>nb_visits</defaultValue> + <type>string</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <nb_visits>Visits</nb_visits> + <nb_actions>Actions</nb_actions> + <visitors>Visitors</visitors> + </availableValues> + <description>Choose the metric that should be displayed in the browser tab</description> + <inlineHelp /> + <introduction>Only Super Users can change the following settings:</introduction> + <condition /> + </row> + <row> + <name>browsers</name> + <title>Supported Browsers</title> + <value> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </value> + <defaultValue> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </defaultValue> + <type>array</type> + <uiControl>multiselect</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <firefox>Firefox</firefox> + <chromium>Chromium</chromium> + <safari>safari</safari> + </availableValues> + <description>The value will be only displayed in the following browsers</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>description</name> + <title>Description for value</title> + <value>This is the value: +Another line</value> + <defaultValue>This is the value: +Another line</defaultValue> + <type>string</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>This description will be displayed next to the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>password</name> + <title>API password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>Password for the 3rd API where we fetch the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>canUserOptOut</name> + <title>Let users disable anonymous tracking</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, logged in users can opt out in their plugin settings. Anonymous users cannot opt out.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>trackToPiwik</name> + <title>Send usage data to Piwik.org</title> + <value>0</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymized usage data will be sent to demo-anonymous.piwik.org and the tracked data can be viewed there (the data is public). The collected data is used to improve Piwik. Thank you for making Piwik better!</description> + <inlineHelp /> + <introduction>Send anonmyized usage data to the creator of Piwik</introduction> + <condition /> + </row> + <row> + <name>ownPiwikSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If specified, anonymized usage data will be sent to the specified site in this Piwik.</description> + <inlineHelp /> + <introduction>Send anonymize usage data to this Piwik</introduction> + <condition /> + </row> + <row> + <name>anonymizeSelfPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>customSiteUrl</name> + <title>Piwik Url</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. http://example.com/piwik</placeHolder> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction>Send anonymize usage data to a custom Piwik</introduction> + <condition /> + </row> + <row> + <name>customSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. "2"</placeHolder> + </uiControlAttributes> + <availableValues /> + <description>If a URL and Site Id is specified, usage data will be sent to the custom Piwik instance.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>anonymizeCustomPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>QueuedTracking</pluginName> + <settings> + <row> + <name>redisHost</name> + <title>Redis host</title> + <value>127.0.0.1</value> + <defaultValue>127.0.0.1</defaultValue> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>300</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Remote host of the Redis server. Max 300 characters are allowed.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPort</name> + <title>Redis port</title> + <value>6379</value> + <defaultValue>6379</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Port the Redis server is running on. Value should be between 1 and 65535.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisDatabase</name> + <title>Redis database</title> + <value>15</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>In case you are using Redis for caching make sure to use a different database.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPassword</name> + <title>Redis password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + <size>100</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Password set on the Redis server, if any. Redis can be instructed to require a password before allowing clients to execute commands.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>queueEnabled</name> + <title>Queue enabled</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, all tracking requests will be written into a queue instead of the directly into the database. Requires a Redis server and phpredis PHP extension.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numQueueWorkers</name> + <title>Number of queue workers</title> + <value>4</value> + <defaultValue>1</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Number of allowed maximum queue workers. Accepts a number between 1 and 16. Best practice is to set the number of CPUs you want to make available for queue processing. Be aware you need to make sure to start the workers manually. We recommend to not use 9-15 workers, rather use 8 or 16 as the queue might not be distributed evenly into different queues. DO NOT USE more than 1 worker if you make use the UserId feature when tracking see https://github.com/piwik/piwik/issues/7691</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numRequestsToProcess</name> + <title>Number of requests that are processed in one batch</title> + <value>25</value> + <defaultValue>25</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Defines how many requests will be picked out of the queue and processed at once. Enter a number which is >= 1.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>processDuringTrackingRequest</name> + <title>Process during tracking request</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, we will process all requests within a queue during a normal tracking request once there are enough requests in the queue. This will not slow down the tracking request. If disabled, you have to setup a cronjob that executes the "./console queuedtracking:process" console command eg every minute to process the queue.</inlineHelp> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getUserSettings.xml b/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getUserSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d18c736bb3ba72c05df84815c4b3ac9c8164526 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_noVisit_PeriodIsLast__CorePluginsAdmin.getUserSettings.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>autoRefresh</name> + <title>Auto refresh</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, the value will be automatically refreshed depending on the specified interval</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>refreshInterval</name> + <title>Refresh Interval</title> + <value>30</value> + <defaultValue>30</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description>Defines how often the value should be updated</description> + <inlineHelp>Enter a number which is >= 15</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>color</name> + <title>Color</title> + <value>red</value> + <defaultValue>red</defaultValue> + <type>string</type> + <uiControl>radio</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <red>Red</red> + <blue>Blue</blue> + <green>Green</green> + </availableValues> + <description>Pick your favourite color</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>userTrackingEnabled</name> + <title>Piwik usage tracking enabled</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymous usage data will be tracked. For example which pages are viewed and which reports are used most often. For more information contact your system administrator.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml b/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..5bf91acc3d7635c9bc9c3c7adba7a5d83488b1d0 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getSystemSettings.xml @@ -0,0 +1,329 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>metric</name> + <title>Metric to display</title> + <value>nb_visits</value> + <defaultValue>nb_visits</defaultValue> + <type>string</type> + <uiControl>select</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <nb_visits>Visits</nb_visits> + <nb_actions>Actions</nb_actions> + <visitors>Visitors</visitors> + </availableValues> + <description>Choose the metric that should be displayed in the browser tab</description> + <inlineHelp /> + <introduction>Only Super Users can change the following settings:</introduction> + <condition /> + </row> + <row> + <name>browsers</name> + <title>Supported Browsers</title> + <value> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </value> + <defaultValue> + <row>firefox</row> + <row>chromium</row> + <row>safari</row> + </defaultValue> + <type>array</type> + <uiControl>multiselect</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <firefox>Firefox</firefox> + <chromium>Chromium</chromium> + <safari>safari</safari> + </availableValues> + <description>The value will be only displayed in the following browsers</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>description</name> + <title>Description for value</title> + <value>This is the value: +Another line</value> + <defaultValue>This is the value: +Another line</defaultValue> + <type>string</type> + <uiControl>textarea</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>This description will be displayed next to the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>password</name> + <title>API password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>Password for the 3rd API where we fetch the value</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>canUserOptOut</name> + <title>Let users disable anonymous tracking</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, logged in users can opt out in their plugin settings. Anonymous users cannot opt out.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>trackToPiwik</name> + <title>Send usage data to Piwik.org</title> + <value>0</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymized usage data will be sent to demo-anonymous.piwik.org and the tracked data can be viewed there (the data is public). The collected data is used to improve Piwik. Thank you for making Piwik better!</description> + <inlineHelp /> + <introduction>Send anonmyized usage data to the creator of Piwik</introduction> + <condition /> + </row> + <row> + <name>ownPiwikSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If specified, anonymized usage data will be sent to the specified site in this Piwik.</description> + <inlineHelp /> + <introduction>Send anonymize usage data to this Piwik</introduction> + <condition /> + </row> + <row> + <name>anonymizeSelfPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>customSiteUrl</name> + <title>Piwik Url</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. http://example.com/piwik</placeHolder> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction>Send anonymize usage data to a custom Piwik</introduction> + <condition /> + </row> + <row> + <name>customSiteId</name> + <title>Site Id</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <placeHolder>eg. "2"</placeHolder> + </uiControlAttributes> + <availableValues /> + <description>If a URL and Site Id is specified, usage data will be sent to the custom Piwik instance.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>anonymizeCustomPiwik</name> + <title>Anonymize tracking requests</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>QueuedTracking</pluginName> + <settings> + <row> + <name>redisHost</name> + <title>Redis host</title> + <value>127.0.0.1</value> + <defaultValue>127.0.0.1</defaultValue> + <type>string</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>300</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Remote host of the Redis server. Max 300 characters are allowed.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPort</name> + <title>Redis port</title> + <value>6379</value> + <defaultValue>6379</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Port the Redis server is running on. Value should be between 1 and 65535.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisDatabase</name> + <title>Redis database</title> + <value>15</value> + <defaultValue>0</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>In case you are using Redis for caching make sure to use a different database.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>redisPassword</name> + <title>Redis password</title> + <value /> + <defaultValue /> + <type>string</type> + <uiControl>password</uiControl> + <uiControlAttributes> + <size>100</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Password set on the Redis server, if any. Redis can be instructed to require a password before allowing clients to execute commands.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>queueEnabled</name> + <title>Queue enabled</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, all tracking requests will be written into a queue instead of the directly into the database. Requires a Redis server and phpredis PHP extension.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numQueueWorkers</name> + <title>Number of queue workers</title> + <value>4</value> + <defaultValue>1</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>5</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Number of allowed maximum queue workers. Accepts a number between 1 and 16. Best practice is to set the number of CPUs you want to make available for queue processing. Be aware you need to make sure to start the workers manually. We recommend to not use 9-15 workers, rather use 8 or 16 as the queue might not be distributed evenly into different queues. DO NOT USE more than 1 worker if you make use the UserId feature when tracking see https://github.com/piwik/piwik/issues/7691</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>numRequestsToProcess</name> + <title>Number of requests that are processed in one batch</title> + <value>25</value> + <defaultValue>25</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>Defines how many requests will be picked out of the queue and processed at once. Enter a number which is >= 1.</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>processDuringTrackingRequest</name> + <title>Process during tracking request</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description /> + <inlineHelp>If enabled, we will process all requests within a queue during a normal tracking request once there are enough requests in the queue. This will not slow down the tracking request. If disabled, you have to setup a cronjob that executes the "./console queuedtracking:process" console command eg every minute to process the queue.</inlineHelp> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getUserSettings.xml b/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getUserSettings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d18c736bb3ba72c05df84815c4b3ac9c8164526 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_noVisit__CorePluginsAdmin.getUserSettings.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <pluginName>ExampleSettingsPlugin</pluginName> + <settings> + <row> + <name>autoRefresh</name> + <title>Auto refresh</title> + <value>0</value> + <defaultValue>0</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, the value will be automatically refreshed depending on the specified interval</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + <row> + <name>refreshInterval</name> + <title>Refresh Interval</title> + <value>30</value> + <defaultValue>30</defaultValue> + <type>integer</type> + <uiControl>text</uiControl> + <uiControlAttributes> + <size>3</size> + </uiControlAttributes> + <availableValues /> + <description>Defines how often the value should be updated</description> + <inlineHelp>Enter a number which is >= 15</inlineHelp> + <introduction /> + <condition /> + </row> + <row> + <name>color</name> + <title>Color</title> + <value>red</value> + <defaultValue>red</defaultValue> + <type>string</type> + <uiControl>radio</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues> + <red>Red</red> + <blue>Blue</blue> + <green>Green</green> + </availableValues> + <description>Pick your favourite color</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> + <row> + <pluginName>AnonymousPiwikUsageMeasurement</pluginName> + <settings> + <row> + <name>userTrackingEnabled</name> + <title>Piwik usage tracking enabled</title> + <value>1</value> + <defaultValue>1</defaultValue> + <type>boolean</type> + <uiControl>checkbox</uiControl> + <uiControlAttributes> + </uiControlAttributes> + <availableValues /> + <description>If enabled, anonymous usage data will be tracked. For example which pages are viewed and which reports are used most often. For more information contact your system administrator.</description> + <inlineHelp /> + <introduction /> + <condition /> + </row> + </settings> + </row> +</result> \ No newline at end of file diff --git a/tests/UI/expected-ui-screenshots b/tests/UI/expected-ui-screenshots index 6d644223c2094370677b11a0ee7ca2e474969d8e..6101bf6344dc3efbbd7d38fa814e3ff3ebc132b8 160000 --- a/tests/UI/expected-ui-screenshots +++ b/tests/UI/expected-ui-screenshots @@ -1 +1 @@ -Subproject commit 6d644223c2094370677b11a0ee7ca2e474969d8e +Subproject commit 6101bf6344dc3efbbd7d38fa814e3ff3ebc132b8 diff --git a/tests/UI/specs/UIIntegration_spec.js b/tests/UI/specs/UIIntegration_spec.js index 3c108061b31a5990f860aefba335fca6bebd03be..085081e9f0d5e595e247ca02894fe0fa0deae9f7 100644 --- a/tests/UI/specs/UIIntegration_spec.js +++ b/tests/UI/specs/UIIntegration_spec.js @@ -487,13 +487,13 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? it('should load the plugin settings admin page correctly', function (done) { expect.screenshot('admin_plugin_settings').to.be.captureSelector('.pageWrap', function (page) { - page.load("?" + generalParams + "&module=CoreAdminHome&action=adminPluginSettings"); + page.load("?" + generalParams + "&module=CoreAdminHome&action=generalSettings"); }, done); }); it('should load the plugin settings user page correctly', function (done) { expect.screenshot('user_plugin_settings').to.be.captureSelector('.pageWrap', function (page) { - page.load("?" + generalParams + "&module=CoreAdminHome&action=userPluginSettings"); + page.load("?" + generalParams + "&module=UsersManager&action=userSettings"); }, done); });