update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit d885a4baa9
5833 changed files with 418860 additions and 226988 deletions

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,52 +8,57 @@
*/
namespace Piwik\ViewDataTable;
use Piwik\API\Request as ApiRequest;
use Piwik\Common;
use Piwik\DataTable;
use Piwik\DataTable\Filter\PivotByDimension;
use Piwik\Metrics;
use Piwik\Plugin\Report;
use Piwik\Plugins\API\API;
/**
* Contains base display properties for {@link Piwik\Plugin\ViewDataTable}s. Manipulating these
* properties in a ViewDataTable instance will change how its report will be displayed.
*
*
* <a name="client-side-properties-desc"></a>
* **Client Side Properties**
*
*
* Client side properties are properties that should be passed on to the browser so
* client side JavaScript can use them. Only affects ViewDataTables that output HTML.
*
* <a name="overridable-properties-desc"></a>
* **Overridable Properties**
*
*
* Overridable properties are properties that can be set via the query string.
* If a request has a query parameter that matches an overridable property, the property
* will be set to the query parameter value.
*
*
* **Reusing base properties**
*
*
* Many of the properties in this class only have meaning for the {@link Piwik\Plugin\Visualization}
* class, but can be set for other visualizations that extend {@link Piwik\Plugin\ViewDataTable}
* class, but can be set for other visualizations that extend {@link Piwik\Plugin\ViewDataTable}
* directly.
*
*
* Visualizations that extend {@link Piwik\Plugin\ViewDataTable} directly and want to re-use these
* properties must make sure the properties are used in the exact same way they are used in
* {@link Piwik\Plugin\Visualization}.
*
*
* **Defining new display properties**
*
*
* If you are creating your own visualization and want to add new display properties for
* it, extend this class and add your properties as fields.
*
*
* Properties are marked as client side properties by calling the
* {@link addPropertiesThatShouldBeAvailableClientSide()} method.
*
*
* Properties are marked as overridable by calling the
* {@link addPropertiesThatCanBeOverwrittenByQueryParams()} method.
*
*
* ### Example
*
*
* **Defining new display properties**
*
*
* class MyCustomVizConfig extends Config
* {
* /**
@ -65,11 +70,11 @@ use Piwik\Plugins\API\API;
* * Another custom property. It is available client side.
* *\/
* public $another_custom_property = true;
*
*
* public function __construct()
* {
* parent::__construct();
*
*
* $this->addPropertiesThatShouldBeAvailableClientSide(array('another_custom_property'));
* $this->addPropertiesThatCanBeOverwrittenByQueryParams(array('my_custom_property'));
* }
@ -83,7 +88,10 @@ class Config
* The list of ViewDataTable properties that are 'Client Side Properties'.
*/
public $clientSideProperties = array(
'show_limit_control'
'show_limit_control',
'pivot_by_dimension',
'pivot_by_column',
'pivot_dimension_name'
);
/**
@ -93,6 +101,7 @@ class Config
'show_goals',
'show_exclude_low_population',
'show_flatten_table',
'show_pivot_by_subtable',
'show_table',
'show_table_all_columns',
'show_footer',
@ -113,7 +122,8 @@ class Config
'show_pagination_control',
'show_offset_information',
'hide_annotations_view',
'export_limit'
'export_limit',
'columns_to_display'
);
/**
@ -159,6 +169,11 @@ class Config
*/
public $show_goals = false;
/**
* Controls whether the 'insights' footer icon is shown.
*/
public $show_insights = true;
/**
* Array property mapping DataTable column names with their internationalized names.
*
@ -179,6 +194,28 @@ class Config
*/
public $show_flatten_table = true;
/**
* Whether to show the 'Pivot by subtable' option (visible in the popup that displays after clicking
* the 'cog' icon).
*/
public $show_pivot_by_subtable;
/**
* The ID of the dimension to pivot by when the 'pivot by subtable' option is clicked. Defaults
* to the subtable dimension of the report being displayed.
*/
public $pivot_by_dimension;
/**
* The column to display in pivot tables. Defaults to the first non-label column if not specified.
*/
public $pivot_by_column = '';
/**
* The human readable name of the pivot dimension.
*/
public $pivot_dimension_name = false;
/**
* Controls whether the footer icon that allows users to switch to the 'normal' DataTable view
* is shown.
@ -442,6 +479,7 @@ class Config
$this->report_id = $controllerName . '.' . $controllerAction;
$this->loadDocumentation();
$this->setShouldShowPivotBySubtable();
}
/** Load documentation from the API */
@ -449,7 +487,28 @@ class Config
{
$this->metrics_documentation = array();
$report = API::getInstance()->getMetadata(0, $this->controllerName, $this->controllerAction);
$idSite = Common::getRequestVar('idSite', 0, 'int');
if ($idSite < 1) {
return;
}
$apiParameters = array();
$idDimension = Common::getRequestVar('idDimension', 0, 'int');
$idGoal = Common::getRequestVar('idGoal', 0, 'int');
if ($idDimension > 0) {
$apiParameters['idDimension'] = $idDimension;
}
if ($idGoal > 0) {
$apiParameters['idGoal'] = $idGoal;
}
$report = API::getInstance()->getMetadata($idSite, $this->controllerName, $this->controllerAction, $apiParameters);
if (empty($report)) {
return;
}
$report = $report[0];
if (isset($report['metricsDocumentation'])) {
@ -464,7 +523,7 @@ class Config
/**
* Marks display properties as client side properties. [Read this](#client-side-properties-desc)
* to learn more.
*
*
* @param array $propertyNames List of property names, eg, `array('show_limit_control', 'show_goals')`.
*/
public function addPropertiesThatShouldBeAvailableClientSide(array $propertyNames)
@ -477,7 +536,7 @@ class Config
/**
* Marks display properties as overridable. [Read this](#overridable-properties-desc) to
* learn more.
*
*
* @param array $propertyNames List of property names, eg, `array('show_limit_control', 'show_goals')`.
*/
public function addPropertiesThatCanBeOverwrittenByQueryParams(array $propertyNames)
@ -490,7 +549,7 @@ class Config
/**
* Returns array of all property values in this config object. Property values are mapped
* by name.
*
*
* @return array eg, `array('show_limit_control' => 0, 'show_goals' => 1, ...)`
*/
public function getProperties()
@ -519,10 +578,21 @@ class Config
$this->columns_to_display = array_filter($columnsToDisplay);
}
public function removeColumnToDisplay($columnToRemove)
{
if (!empty($this->columns_to_display)) {
$key = array_search($columnToRemove, $this->columns_to_display);
if (false !== $key) {
unset($this->columns_to_display[$key]);
}
}
}
/**
* @ignore
*/
public function getFiltersToRun()
private function getFiltersToRun()
{
$priorityFilters = array();
$presentationFilters = array();
@ -546,12 +616,26 @@ class Config
return array($priorityFilters, $presentationFilters);
}
public function getPriorityFilters()
{
$filters = $this->getFiltersToRun();
return $filters[0];
}
public function getPresentationFilters()
{
$filters = $this->getFiltersToRun();
return $filters[1];
}
/**
* Adds a related report to the {@link $related_reports} property. If the report
* references the one that is currently being displayed, it will not be added to the related
* report list.
*
* @param string $relatedReport The plugin and method of the report, eg, `'UserSettings.getBrowser'`.
*
* @param string $relatedReport The plugin and method of the report, eg, `'DevicesDetection.getBrowsers'`.
* @param string $title The report's display name, eg, `'Browsers'`.
* @param array $queryParams Any extra query parameters to set in releated report's URL, eg,
* `array('idGoal' => 'ecommerceOrder')`.
@ -563,7 +647,7 @@ class Config
// don't add the related report if it references this report
if ($this->controllerName == $module
&& $this->controllerAction == $action) {
if(empty($queryParams)) {
if (empty($queryParams)) {
return;
}
}
@ -577,16 +661,16 @@ class Config
* Adds several related reports to the {@link $related_reports} property. If
* any of the reports references the report that is currently being displayed, it will not
* be added to the list. All other reports will still be added though.
*
*
* If you need to make sure the related report URL has some extra query parameters,
* use {@link addRelatedReport()}.
*
*
* @param array $relatedReports Array mapping report IDs with their internationalized display
* titles, eg,
* ```
* array(
* 'UserSettings.getBrowser' => 'Browsers',
* 'UserSettings.getConfiguration' => 'Configurations'
* 'DevicesDetection.getBrowsers' => 'Browsers',
* 'Resolution.getConfiguration' => 'Configurations'
* )
* ```
*/
@ -599,9 +683,9 @@ class Config
/**
* Associates internationalized text with a metric. Overwrites existing mappings.
*
*
* See {@link $translations}.
*
*
* @param string $columnName The name of a column in the report data, eg, `'nb_visits'` or
* `'goal_1_nb_conversions'`.
* @param string $translation The internationalized text, eg, `'Visits'` or `"Conversions for 'My Goal'"`.
@ -613,9 +697,9 @@ class Config
/**
* Associates multiple translations with metrics.
*
*
* See {@link $translations} and {@link addTranslation()}.
*
*
* @param array $translations An array of column name => text mappings, eg,
* ```
* array(
@ -630,4 +714,33 @@ class Config
$this->addTranslation($key, $translation);
}
}
private function setShouldShowPivotBySubtable()
{
$report = Report::factory($this->controllerName, $this->controllerAction);
if (empty($report)) {
$this->show_pivot_by_subtable = false;
$this->pivot_by_dimension = false;
} else {
$this->show_pivot_by_subtable = PivotByDimension::isPivotingReportBySubtableSupported($report);
$subtableDimension = $report->getSubtableDimension();
if (!empty($subtableDimension)) {
$this->pivot_by_dimension = $subtableDimension->getId();
$this->pivot_dimension_name = $subtableDimension->getName();
}
}
}
public function disablePivotBySubtableIfTableHasNoSubtables(DataTable $table)
{
foreach ($table->getRows() as $row) {
if ($row->getIdSubDataTable() !== null) {
return;
}
}
$this->show_pivot_by_subtable = false;
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,18 +8,18 @@
*/
namespace Piwik\ViewDataTable;
use Piwik\API\Proxy;
use Piwik\Common;
use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
/**
* Provides a means of creating {@link Piwik\Plugin\ViewDataTable} instances by ID.
*
* ### Examples
*
*
* **Creating a ViewDataTable for a report**
*
*
* // method in MyPlugin\Controller
* public function myReport()
* {
@ -28,9 +28,9 @@ use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
* $view->config->translations['myFancyMetric'] = "My Fancy Metric";
* return $view->render();
* }
*
*
* **Displaying a report in another way**
*
*
* // method in MyPlugin\Controller
* // use the same data that's used in myReport() above, but transform it in some way before
* // displaying.
@ -40,9 +40,9 @@ use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
* $view->config->filters[] = array('MyMagicFilter', array('an arg', 'another arg'));
* return $view->render();
* }
*
*
* **Force a report to be shown as a bar graph**
*
*
* // method in MyPlugin\Controller
* // force the myReport report to show as a bar graph if there is no viewDataTable query param,
* // even though it is configured to show as a table.
@ -52,7 +52,7 @@ use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
* $forceDefault = true);
* return $view->render();
* }
*
*
*
* @api
*/
@ -68,76 +68,140 @@ class Factory
/**
* Creates a {@link Piwik\Plugin\ViewDataTable} instance by ID. If the **viewDataTable** query parameter is set,
* this parameter's value is used as the ID.
*
*
* See {@link Piwik\Plugin\ViewDataTable} to read about the visualizations that are packaged with Piwik.
*
*
* @param string|null $defaultType A ViewDataTable ID representing the default ViewDataTable type to use. If
* the **viewDataTable** query parameter is not found, this value is used as
* the ID of the ViewDataTable to create.
*
*
* If a visualization type is configured for the report being displayed, it
* is used instead of the default type. (See {@hook ViewDataTable.getDefaultType}).
* If nothing is configured for the report and `null` is supplied for this
* argument, **table** is used.
* @param string|false $apiAction The API method for the report that will be displayed, eg,
* `'UserSettings.getBrowser'`.
* @param string|false $controllerAction The controller name and action dedicated to displaying the report. This
* @param bool|false|string $apiAction The API method for the report that will be displayed, eg,
* `'DevicesDetection.getBrowsers'`.
* @param bool|false|string $controllerAction The controller name and action dedicated to displaying the report. This
* action is used when reloading reports or changing the report visualization.
* Defaulted to `$apiAction` if `false` is supplied.
* @param bool $forceDefault If true, then the visualization type that was configured for the report will be
* ignored and `$defaultType` will be used as the default.
* @param bool $loadViewDataTableParametersForUser Whether the per-user parameters for this user, this ViewDataTable and this Api action
* should be loaded from the user preferences and override the default params values.
* @throws \Exception
* @return \Piwik\Plugin\ViewDataTable
*/
public static function build($defaultType = null, $apiAction = false, $controllerAction = false, $forceDefault = false)
public static function build($defaultType = null, $apiAction = false, $controllerAction = false, $forceDefault = false, $loadViewDataTableParametersForUser = null)
{
if (false === $controllerAction) {
$controllerAction = $apiAction;
}
$defaultViewType = self::getDefaultViewTypeForReport($apiAction);
$report = self::getReport($apiAction);
if (!$forceDefault && !empty($defaultViewType)) {
$defaultType = $defaultViewType;
$defaultViewType = self::getDefaultViewTypeForReport($report, $apiAction);
$params = array();
if(is_null($loadViewDataTableParametersForUser)) {
$loadViewDataTableParametersForUser = ('0' == Common::getRequestVar('widget', '0', 'string'));
}
if ($loadViewDataTableParametersForUser) {
$login = Piwik::getCurrentUserLogin();
$params = Manager::getViewDataTableParameters($login, $controllerAction);
}
$type = Common::getRequestVar('viewDataTable', false, 'string');
// Common::getRequestVar removes backslashes from the defaultValue in case magic quotes are enabled.
// therefore do not pass this as a default value to getRequestVar()
if ('' === $type) {
$type = $defaultType ? : HtmlTable::ID;
if (!self::isDefaultViewTypeForReportFixed($report)) {
$savedViewDataTable = false;
if (!empty($params['viewDataTable'])) {
$savedViewDataTable = $params['viewDataTable'];
}
// order of default viewDataTables' priority is: function specified default, saved default, configured default for report
// function specified default is preferred
// -> force default == true : defaultType ?: saved ?: defaultView
// -> force default == false : saved ?: defaultType ?: defaultView
if ($forceDefault) {
$defaultType = $defaultType ?: $savedViewDataTable ?: $defaultViewType;
} else {
$defaultType = $savedViewDataTable ?: $defaultType ?: $defaultViewType;
}
$type = Common::getRequestVar('viewDataTable', $defaultType, 'string');
// Common::getRequestVar removes backslashes from the defaultValue in case magic quotes are enabled.
// therefore do not pass this as a default value to getRequestVar()
if ('' === $type) {
$type = $defaultType ?: HtmlTable::ID;
}
} else {
$type = $defaultViewType;
}
$params['viewDataTable'] = $type;
$visualizations = Manager::getAvailableViewDataTables();
if (array_key_exists($type, $visualizations)) {
return new $visualizations[$type]($controllerAction, $apiAction);
}
if (class_exists($type)) {
return new $type($controllerAction, $apiAction);
return self::createViewDataTableInstance($visualizations[$type], $controllerAction, $apiAction, $params);
}
if (array_key_exists($defaultType, $visualizations)) {
return new $visualizations[$defaultType]($controllerAction, $apiAction);
return self::createViewDataTableInstance($visualizations[$defaultType], $controllerAction, $apiAction, $params);
}
if (array_key_exists(HtmlTable::ID, $visualizations)) {
return new $visualizations[HtmlTable::ID]($controllerAction, $apiAction);
return self::createViewDataTableInstance($visualizations[HtmlTable::ID], $controllerAction, $apiAction, $params);
}
throw new \Exception('No visualization found to render ViewDataTable');
}
/**
* Returns the default viewDataTable ID to use when determining which visualization to use.
* Return the report object for the given apiAction
* @param $apiAction
* @return null|Report
*/
private static function getDefaultViewTypeForReport($apiAction)
private static function getReport($apiAction)
{
list($module, $action) = explode('.', $apiAction);
$report = Report::factory($module, $action);
return $report;
}
/**
* Returns the default viewDataTable ID to use when determining which visualization to use.
*
* @param Report $report
* @param string $apiAction
*
* @return bool|string
*/
private static function getDefaultViewTypeForReport($report, $apiAction)
{
if (!empty($report) && $report->isEnabled()) {
return $report->getDefaultTypeViewDataTable();
}
$defaultViewTypes = self::getDefaultTypeViewDataTable();
return isset($defaultViewTypes[$apiAction]) ? $defaultViewTypes[$apiAction] : false;
}
/**
* Returns if the default viewDataTable ID to use is fixed.
*
* @param Report $report
* @return bool
*/
private static function isDefaultViewTypeForReportFixed($report)
{
if (!empty($report) && $report->isEnabled()) {
return $report->alwaysUseDefaultViewDataTable();
}
return false;
}
/**
* Returns a list of default viewDataTables ID to use when determining which visualization to use for multiple
* reports.
@ -147,28 +211,39 @@ class Factory
if (null === self::$defaultViewTypes) {
self::$defaultViewTypes = array();
/**
* Triggered when gathering the default view types for all available reports.
*
* If you define your own report, you may want to subscribe to this event to
* make sure the correct default Visualization is used (for example, a pie graph,
* bar graph, or something else).
*
* If there is no default type associated with a report, the **table** visualization
* used.
*
* **Example**
*
* public function getDefaultTypeViewDataTable(&$defaultViewTypes)
* {
* $defaultViewTypes['Referrers.getSocials'] = HtmlTable::ID;
* $defaultViewTypes['Referrers.getUrlsForSocial'] = Pie::ID;
* }
*
* @param array &$defaultViewTypes The array mapping report IDs with visualization IDs.
* @ignore
*/
Piwik::postEvent('ViewDataTable.getDefaultType', array(&self::$defaultViewTypes));
}
return self::$defaultViewTypes;
}
/**
* @param string $klass
* @param string $controllerAction
* @param string $apiAction
* @param array $params
*
* @internal param string $viewDataTableId
* @return \Piwik\Plugin\ViewDataTable
*/
private static function createViewDataTableInstance($klass, $controllerAction, $apiAction, $params)
{
if (empty($params)) {
$params = array();
}
if (!is_subclass_of($klass, 'Piwik\Plugin\Visualization')) {
// for now we ignore those params in case it is not a visualization. We do not want to apply
// any of those saved parameters to sparklines etc. Need to find a better solution here
$params = array();
}
if(!is_subclass_of($klass, 'Piwik\View\ViewInterface')) {
throw new \Exception("viewDataTable $klass must implement Piwik\View\ViewInterface interface.");
}
return new $klass($controllerAction, $apiAction, $params);
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,8 +8,11 @@
*/
namespace Piwik\ViewDataTable;
use Piwik\Cache;
use Piwik\Common;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
@ -17,6 +20,7 @@ use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Bar;
use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
use Piwik\Plugins\Goals\Visualizations\Goals;
use Piwik\Plugins\Insights\Visualizations\Insight;
use Piwik\Plugin\Manager as PluginManager;
/**
* ViewDataTable Manager.
@ -61,23 +65,35 @@ class Manager
*/
public static function getAvailableViewDataTables()
{
$cache = Cache::getTransientCache();
$cacheId = 'ViewDataTable.getAvailableViewDataTables';
$dataTables = $cache->fetch($cacheId);
if (!empty($dataTables)) {
return $dataTables;
}
$klassToExtend = '\\Piwik\\Plugin\\ViewDataTable';
/** @var string[] $visualizations */
$visualizations = array();
$visualizations = PluginManager::getInstance()->findMultipleComponents('Visualizations', $klassToExtend);
/**
* Triggered when gathering all available DataTable visualizations.
*
*
* Plugins that want to expose new DataTable visualizations should subscribe to
* this event and add visualization class names to the incoming array.
*
*
* **Example**
*
*
* public function addViewDataTable(&$visualizations)
* {
* $visualizations[] = 'Piwik\\Plugins\\MyPlugin\\MyVisualization';
* }
*
*
* @param array &$visualizations The array of all available visualizations.
* @ignore
* @deprecated since 2.5.0 Place visualization in a "Visualizations" directory instead.
*/
Piwik::postEvent('ViewDataTable.addViewDataTable', array(&$visualizations));
@ -88,7 +104,7 @@ class Manager
throw new \Exception("Invalid visualization class '$viz' found in Visualization.getAvailableVisualizations.");
}
if (!is_subclass_of($viz, '\\Piwik\\Plugin\\ViewDataTable')) {
if (!is_subclass_of($viz, $klassToExtend)) {
throw new \Exception("ViewDataTable class '$viz' does not extend Plugin/ViewDataTable");
}
@ -101,6 +117,8 @@ class Manager
$result[$vizId] = $viz;
}
$cache->save($cacheId, $result);
return $result;
}
@ -150,46 +168,7 @@ class Manager
{
$result = array();
// add normal view icons (eg, normal table, all columns, goals)
$normalViewIcons = array(
'class' => 'tableAllColumnsSwitch',
'buttons' => array(),
);
if ($view->config->show_table) {
$normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID);
}
if ($view->config->show_table_all_columns) {
$normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID);
}
if ($view->config->show_goals) {
$goalButton = static::getFooterIconFor(Goals::ID);
if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') {
$goalButton['icon'] = 'plugins/Zeitgeist/images/ecommerceOrder.gif';
}
$normalViewIcons['buttons'][] = $goalButton;
}
if ($view->config->show_ecommerce) {
$normalViewIcons['buttons'][] = array(
'id' => 'ecommerceOrder',
'title' => Piwik::translate('General_EcommerceOrders'),
'icon' => 'plugins/Zeitgeist/images/ecommerceOrder.gif',
'text' => Piwik::translate('General_EcommerceOrders')
);
$normalViewIcons['buttons'][] = array(
'id' => 'ecommerceAbandonedCart',
'title' => Piwik::translate('General_AbandonedCarts'),
'icon' => 'plugins/Zeitgeist/images/ecommerceAbandonedCart.gif',
'text' => Piwik::translate('General_AbandonedCarts')
);
}
$normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']);
$normalViewIcons = self::getNormalViewIcons($view);
if (!empty($normalViewIcons['buttons'])) {
$result[] = $normalViewIcons;
@ -201,25 +180,7 @@ class Manager
'buttons' => array(),
);
// add graph views
$graphViewIcons = array(
'class' => 'tableGraphViews tableGraphCollapsed',
'buttons' => array(),
);
if ($view->config->show_all_views_icons) {
if ($view->config->show_bar_chart) {
$graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID);
}
if ($view->config->show_pie_chart) {
$graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID);
}
if ($view->config->show_tag_cloud) {
$graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID);
}
}
$graphViewIcons = self::getGraphViewIcons($view);
$nonCoreVisualizations = static::getNonCoreViewDataTables();
@ -236,7 +197,9 @@ class Manager
$graphViewIcons['buttons'] = array_filter($graphViewIcons['buttons']);
if (!empty($insightsViewIcons['buttons'])) {
if (!empty($insightsViewIcons['buttons'])
&& $view->config->show_insights
) {
$result[] = $insightsViewIcons;
}
@ -270,4 +233,192 @@ class Manager
'icon' => $klass::FOOTER_ICON,
);
}
public static function clearAllViewDataTableParameters()
{
Option::deleteLike('viewDataTableParameters_%');
}
public static function clearUserViewDataTableParameters($userLogin)
{
Option::deleteLike('viewDataTableParameters_' . $userLogin . '_%');
}
public static function getViewDataTableParameters($login, $controllerAction)
{
$paramsKey = self::buildViewDataTableParametersOptionKey($login, $controllerAction);
$params = Option::get($paramsKey);
if (empty($params)) {
return array();
}
$params = json_decode($params);
$params = (array) $params;
// when setting an invalid parameter, we silently ignore the invalid parameter and proceed
$params = self::removeNonOverridableParameters($controllerAction, $params);
return $params;
}
/**
* Any parameter set here will be set into one of the following objects:
*
* - ViewDataTable.requestConfig[paramName]
* - ViewDataTable.config.custom_parameters[paramName]
* - ViewDataTable.config.custom_parameters[paramName]
*
* (see ViewDataTable::overrideViewPropertiesWithParams)
* @param $login
* @param $controllerAction
* @param $parametersToOverride
* @throws \Exception
*/
public static function saveViewDataTableParameters($login, $controllerAction, $parametersToOverride)
{
$params = self::getViewDataTableParameters($login, $controllerAction);
foreach ($parametersToOverride as $key => $value) {
if ($key === 'viewDataTable'
&& !empty($params[$key])
&& $params[$key] !== $value) {
if (!empty($params['columns'])) {
unset($params['columns']);
}
if (!empty($params['columns_to_display'])) {
unset($params['columns_to_display']);
}
}
$params[$key] = $value;
}
$paramsKey = self::buildViewDataTableParametersOptionKey($login, $controllerAction);
// when setting an invalid parameter, we fail and let user know
self::errorWhenSettingNonOverridableParameter($controllerAction, $params);
Option::set($paramsKey, json_encode($params));
}
private static function buildViewDataTableParametersOptionKey($login, $controllerAction)
{
return sprintf('viewDataTableParameters_%s_%s', $login, $controllerAction);
}
/**
* Display a meaningful error message when any invalid parameter is being set.
*
* @param $params
* @throws
*/
private static function errorWhenSettingNonOverridableParameter($controllerAction, $params)
{
$viewDataTable = self::makeTemporaryViewDataTableInstance($controllerAction, $params);
$viewDataTable->throwWhenSettingNonOverridableParameter($params);
}
private static function removeNonOverridableParameters($controllerAction, $params)
{
$viewDataTable = self::makeTemporaryViewDataTableInstance($controllerAction, $params);
$nonOverridableParams = $viewDataTable->getNonOverridableParams($params);
foreach($params as $key => $value) {
if(in_array($key, $nonOverridableParams)) {
unset($params[$key]);
}
}
return $params;
}
/**
* @param $controllerAction
* @param $params
* @return ViewDataTable
* @throws \Exception
*/
private static function makeTemporaryViewDataTableInstance($controllerAction, $params)
{
$report = new Report();
$viewDataTableType = isset($params['viewDataTable']) ? $params['viewDataTable'] : $report->getDefaultTypeViewDataTable();
$apiAction = $controllerAction;
$loadViewDataTableParametersForUser = false;
$viewDataTable = Factory::build($viewDataTableType, $apiAction, $controllerAction, $forceDefault = false, $loadViewDataTableParametersForUser);
return $viewDataTable;
}
private static function getNormalViewIcons(ViewDataTable $view)
{
// add normal view icons (eg, normal table, all columns, goals)
$normalViewIcons = array(
'class' => 'tableAllColumnsSwitch',
'buttons' => array(),
);
if ($view->config->show_table) {
$normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID);
}
if ($view->config->show_table_all_columns) {
$normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID);
}
if ($view->config->show_goals) {
$goalButton = static::getFooterIconFor(Goals::ID);
if (Common::getRequestVar('idGoal', false) == 'ecommerceOrder') {
$goalButton['icon'] = 'plugins/Morpheus/images/ecommerceOrder.gif';
}
$normalViewIcons['buttons'][] = $goalButton;
}
if ($view->config->show_ecommerce) {
$normalViewIcons['buttons'][] = array(
'id' => 'ecommerceOrder',
'title' => Piwik::translate('General_EcommerceOrders'),
'icon' => 'plugins/Morpheus/images/ecommerceOrder.gif',
'text' => Piwik::translate('General_EcommerceOrders')
);
$normalViewIcons['buttons'][] = array(
'id' => 'ecommerceAbandonedCart',
'title' => Piwik::translate('General_AbandonedCarts'),
'icon' => 'plugins/Morpheus/images/ecommerceAbandonedCart.gif',
'text' => Piwik::translate('General_AbandonedCarts')
);
}
$normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']);
return $normalViewIcons;
}
private static function getGraphViewIcons(ViewDataTable $view)
{
// add graph views
$graphViewIcons = array(
'class' => 'tableGraphViews tableGraphCollapsed',
'buttons' => array(),
);
if ($view->config->show_all_views_icons) {
if ($view->config->show_bar_chart) {
$graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID);
}
if ($view->config->show_pie_chart) {
$graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID);
}
if ($view->config->show_tag_cloud) {
$graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID);
}
}
return $graphViewIcons;
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -32,15 +32,11 @@ class Request
* It builds the API request string and uses Request to call the API.
* The requested DataTable object is stored in $this->dataTable.
*/
public function loadDataTableFromAPI($fixedRequestParams = array())
public function loadDataTableFromAPI()
{
// we build the request (URL) to call the API
$requestArray = $this->getRequestArray();
foreach ($fixedRequestParams as $key => $value) {
$requestArray[$key] = $value;
}
// we make the request to the API
$request = new ApiRequest($requestArray);
@ -73,6 +69,11 @@ class Request
'filter_excludelowpop_value',
'filter_column',
'filter_pattern',
'flat',
'expanded',
'pivotBy',
'pivotByColumn',
'pivotByColumnLimit'
);
foreach ($toSetEventually as $varToSet) {
@ -99,6 +100,14 @@ class Request
unset($requestArray['filter_limit']);
}
if ($this->requestConfig->disable_generic_filters) {
$requestArray['disable_generic_filters'] = '1';
}
if ($this->requestConfig->disable_queued_filters) {
$requestArray['disable_queued_filters'] = 1;
}
return $requestArray;
}
@ -114,8 +123,8 @@ class Request
if (isset($_GET[$nameVar])) {
return Common::sanitizeInputValue($_GET[$nameVar]);
}
$default = $this->getDefault($nameVar);
return $default;
return $this->getDefault($nameVar);
}
/**
@ -133,5 +142,4 @@ class Request
return false;
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,53 +8,53 @@
*/
namespace Piwik\ViewDataTable;
use Piwik\Common;
/**
* Contains base request properties for {@link Piwik\Plugin\ViewDataTable} instances. Manipulating
* these properties will change the way a {@link Piwik\Plugin\ViewDataTable} loads report data.
*
*
* <a name="client-side-parameters-desc"></a>
* **Client Side Parameters**
*
*
* Client side parameters are request properties that should be passed on to the browser so
* client side JavaScript can use them. These properties will also be passed to the server with
* every AJAX request made.
*
*
* Only affects ViewDataTables that output HTML.
*
*
* <a name="overridable-properties-desc"></a>
* **Overridable Properties**
*
* Overridable properties are properties that can be set via the query string.
* If a request has a query parameter that matches an overridable property, the property
* will be set to the query parameter value.
*
*
* **Reusing base properties**
*
*
* Many of the properties in this class only have meaning for the {@link Piwik\Plugin\Visualization}
* class, but can be set for other visualizations that extend {@link Piwik\Plugin\ViewDataTable}
* class, but can be set for other visualizations that extend {@link Piwik\Plugin\ViewDataTable}
* directly.
*
*
* Visualizations that extend {@link Piwik\Plugin\ViewDataTable} directly and want to re-use these
* properties must make sure the properties are used in the exact same way they are used in
* {@link Piwik\Plugin\Visualization}.
*
*
* **Defining new request properties**
*
*
* If you are creating your own visualization and want to add new request properties for
* it, extend this class and add your properties as fields.
*
*
* Properties are marked as client side parameters by calling the
* {@link addPropertiesThatShouldBeAvailableClientSide()} method.
*
*
* Properties are marked as overridable by calling the
* {@link addPropertiesThatCanBeOverwrittenByQueryParams()} method.
*
* ### Example
*
*
* **Defining new request properties**
*
*
* class MyCustomVizRequestConfig extends RequestConfig
* {
* /**
@ -66,16 +66,16 @@ use Piwik\Common;
* * Another custom property. It is available client side.
* *\/
* public $another_custom_property = true;
*
*
* public function __construct()
* {
* parent::__construct();
*
*
* $this->addPropertiesThatShouldBeAvailableClientSide(array('another_custom_property'));
* $this->addPropertiesThatCanBeOverwrittenByQueryParams(array('my_custom_property'));
* }
* }
*
*
* @api
*/
class RequestConfig
@ -88,7 +88,12 @@ class RequestConfig
'filter_excludelowpop_value',
'filter_pattern',
'filter_column',
'filter_offset'
'filter_offset',
'flat',
'expanded',
'pivotBy',
'pivotByColumn',
'pivotByColumnLimit'
);
/**
@ -104,7 +109,12 @@ class RequestConfig
'filter_excludelowpop',
'filter_excludelowpop_value',
'disable_generic_filters',
'disable_queued_filters'
'disable_queued_filters',
'flat',
'expanded',
'pivotBy',
'pivotByColumn',
'pivotByColumnLimit'
);
/**
@ -130,6 +140,21 @@ class RequestConfig
*/
public $filter_limit = false;
/**
* If set to true, the returned data will contain the flattened view of the table data set.
* The children of all first level rows will be aggregated under one row.
*
* Default value: false
*/
public $flat = false;
/**
* If set to true, the returned data will contain the first level results, as well as all sub-tables.
*
* Default value: false
*/
public $expanded = false;
/**
* The number of items from the start of the data set that should be ignored.
*
@ -213,6 +238,29 @@ class RequestConfig
*/
public $idSubtable = false;
/**
* Dimension ID to pivot by. See {@link Piwik\DataTable\Filter\PivotByDimension} for more info.
*
* @var string
*/
public $pivotBy = false;
/**
* The column to display in a pivot table, eg, `'nb_visits'`. See {@link Piwik\DataTable\Filter\PivotByDimension}
* for more info.
*
* @var string
*/
public $pivotByColumn = false;
/**
* The maximum number of columns to display in a pivot table. See {@link Piwik\DataTable\Filter\PivotByDimension}
* for more info.
*
* @var int
*/
public $pivotByColumnLimit = false;
public function getProperties()
{
return get_object_vars($this);
@ -221,7 +269,7 @@ class RequestConfig
/**
* Marks request properties as client side properties. [Read this](#client-side-properties-desc)
* to learn more.
*
*
* @param array $propertyNames List of property names, eg, `array('disable_queued_filters', 'filter_column')`.
*/
public function addPropertiesThatShouldBeAvailableClientSide(array $propertyNames)
@ -234,7 +282,7 @@ class RequestConfig
/**
* Marks display properties as overridable. [Read this](#overridable-properties-desc) to
* learn more.
*
*
* @param array $propertyNames List of property names, eg, `array('disable_queued_filters', 'filter_column')`.
*/
public function addPropertiesThatCanBeOverwrittenByQueryParams(array $propertyNames)
@ -244,7 +292,7 @@ class RequestConfig
}
}
public function setDefaultSort($columnsToDisplay, $hasNbUniqVisitors)
public function setDefaultSort($columnsToDisplay, $hasNbUniqVisitors, $actualColumns)
{
// default sort order to visits/visitors data
if ($hasNbUniqVisitors && in_array('nb_uniq_visitors', $columnsToDisplay)) {
@ -253,38 +301,19 @@ class RequestConfig
$this->filter_sort_column = 'nb_visits';
}
// if the default sort column does not exist, sort by the first non-label column
if (!in_array($this->filter_sort_column, $actualColumns)) {
foreach ($actualColumns as $column) {
if ($column != 'label') {
$this->filter_sort_column = $column;
break;
}
}
}
$this->filter_sort_order = 'desc';
}
/**
* Returns `true` if queued filters have been disabled, `false` if otherwise.
*
* @return bool
*/
public function areQueuedFiltersDisabled()
{
return isset($this->disable_queued_filters) && $this->disable_queued_filters;
}
/**
* Returns `true` if generic filters have been disabled, `false` if otherwise.
*
* @return bool
*/
public function areGenericFiltersDisabled()
{
// if disable_generic_filters query param is set to '1', generic filters are disabled
if (Common::getRequestVar('disable_generic_filters', '0', 'string') == 1) {
return true;
}
if (isset($this->disable_generic_filters) && true === $this->disable_generic_filters) {
return true;
}
return false;
}
public function getApiModuleToRequest()
{
list($module, $method) = explode('.', $this->apiMethodToRequestDataTable);