add piwik installation

This commit is contained in:
coderkun 2014-04-25 03:56:02 +02:00
commit 8c5d4f0c31
3197 changed files with 563902 additions and 0 deletions

View file

@ -0,0 +1,633 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\ViewDataTable;
use Piwik\API\Request as ApiRequest;
use Piwik\Metrics;
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}
* 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
* {
* /**
* * My custom property. It is overridable.
* *\/
* public $my_custom_property = false;
*
* /**
* * 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 Config
{
/**
* The list of ViewDataTable properties that are 'Client Side Properties'.
*/
public $clientSideProperties = array(
'show_limit_control'
);
/**
* The list of ViewDataTable properties that can be overriden by query parameters.
*/
public $overridableProperties = array(
'show_goals',
'show_exclude_low_population',
'show_flatten_table',
'show_table',
'show_table_all_columns',
'show_footer',
'show_footer_icons',
'show_all_views_icons',
'show_active_view_icon',
'show_related_reports',
'show_limit_control',
'show_search',
'enable_sort',
'show_bar_chart',
'show_pie_chart',
'show_tag_cloud',
'show_export_as_rss_feed',
'show_ecommerce',
'search_recursive',
'show_export_as_image_icon',
'show_pagination_control',
'show_offset_information',
'hide_annotations_view',
'export_limit'
);
/**
* Controls what footer icons are displayed on the bottom left of the DataTable view.
* The value of this property must be an array of footer icon groups. Footer icon groups
* have set of properties, including an array of arrays describing footer icons. For
* example:
*
* array(
* array( // footer icon group 1
* 'class' => 'footerIconGroup1CssClass',
* 'buttons' => array(
* 'id' => 'myid',
* 'title' => 'My Tooltip',
* 'icon' => 'path/to/my/icon.png'
* )
* ),
* array( // footer icon group 2
* 'class' => 'footerIconGroup2CssClass',
* 'buttons' => array(...)
* )
* )
*
* By default, when a user clicks on a footer icon, Piwik will assume the 'id' is
* a viewDataTable ID and try to reload the DataTable w/ the new viewDataTable. You
* can provide your own footer icon behavior by adding an appropriate handler via
* DataTable.registerFooterIconHandler in your JavaScript code.
*
* The default value of this property is not set here and will show the 'Normal Table'
* icon, the 'All Columns' icon, the 'Goals Columns' icon and all jqPlot graph columns,
* unless other properties tell the view to exclude them.
*/
public $footer_icons = false;
/**
* Controls whether the buttons and UI controls around the visualization or shown or
* if just the visualization alone is shown.
*/
public $show_visualization_only = false;
/**
* Controls whether the goals footer icon is shown.
*/
public $show_goals = false;
/**
* Array property mapping DataTable column names with their internationalized names.
*
* The default value for this property is set elsewhere. It will contain translations
* of common metrics.
*/
public $translations = array();
/**
* Controls whether the 'Exclude Low Population' option (visible in the popup that displays after
* clicking the 'cog' icon) is shown.
*/
public $show_exclude_low_population = true;
/**
* Whether to show the 'Flatten' option (visible in the popup that displays after clicking the
* 'cog' icon).
*/
public $show_flatten_table = true;
/**
* Controls whether the footer icon that allows users to switch to the 'normal' DataTable view
* is shown.
*/
public $show_table = true;
/**
* Controls whether the 'All Columns' footer icon is shown.
*/
public $show_table_all_columns = true;
/**
* Controls whether the entire view footer is shown.
*/
public $show_footer = true;
/**
* Controls whether the row that contains all footer icons & the limit selector is shown.
*/
public $show_footer_icons = true;
/**
* Array property that determines which columns will be shown. Columns not in this array
* should not appear in ViewDataTable visualizations.
*
* Example: `array('label', 'nb_visits', 'nb_uniq_visitors')`
*
* If this value is empty it will be defaulted to `array('label', 'nb_visits')` or
* `array('label', 'nb_uniq_visitors')` if the report contains a nb_uniq_visitors column
* after data is loaded.
*/
public $columns_to_display = array();
/**
* Controls whether graph and non core viewDataTable footer icons are shown or not.
*/
public $show_all_views_icons = true;
/**
* Controls whether to display a tiny upside-down caret over the currently active view icon.
*/
public $show_active_view_icon = true;
/**
* Related reports are listed below a datatable view. When clicked, the original report will
* change to the clicked report and the list will change so the original report can be
* navigated back to.
*/
public $related_reports = array();
/**
* "Related Reports" is displayed by default before listing the Related reports,
* The string can be changed.
*/
public $related_reports_title;
/**
* The report title. Used with related reports so report headings can be changed when switching
* reports.
*
* This must be set if related reports are added.
*/
public $title = '';
/**
* Controls whether a report's related reports are listed with the view or not.
*/
public $show_related_reports = true;
/**
* Contains the documentation for a report.
*/
public $documentation = false;
/**
* Array property containing custom data to be saved in JSON in the data-params HTML attribute
* of a data table div. This data can be used by JavaScript DataTable classes.
*
* e.g. array('typeReferrer' => ...)
*
* It can then be accessed in the twig templates by clientSideParameters.typeReferrer
*/
public $custom_parameters = array();
/**
* Controls whether the limit dropdown (which allows users to change the number of data shown)
* is always shown or not.
*
* Normally shown only if pagination is enabled.
*/
public $show_limit_control = true;
/**
* Controls whether the search box under the datatable is shown.
*/
public $show_search = true;
/**
* Controls whether the user can sort DataTables by clicking on table column headings.
*/
public $enable_sort = true;
/**
* Controls whether the footer icon that allows users to view data as a bar chart is shown.
*/
public $show_bar_chart = true;
/**
* Controls whether the footer icon that allows users to view data as a pie chart is shown.
*/
public $show_pie_chart = true;
/**
* Controls whether the footer icon that allows users to view data as a tag cloud is shown.
*/
public $show_tag_cloud = true;
/**
* Controls whether the user is allowed to export data as an RSS feed or not.
*/
public $show_export_as_rss_feed = true;
/**
* Controls whether the 'Ecoommerce Orders'/'Abandoned Cart' footer icons are shown or not.
*/
public $show_ecommerce = false;
/**
* Stores an HTML message (if any) to display under the datatable view.
*/
public $show_footer_message = false;
/**
* Array property that stores documentation for individual metrics.
*
* E.g. `array('nb_visits' => '...', ...)`
*
* By default this is set to values retrieved from report metadata (via API.getReportMetadata API method).
*/
public $metrics_documentation = array();
/**
* Row metadata name that contains the tooltip for the specific row.
*/
public $tooltip_metadata_name = false;
/**
* The URL to the report the view is displaying. Modifying this means clicking back to this report
* from a Related Report will go to a different URL. Can be used to load an entire page instead
* of a single report when going back to the original report.
*
* The URL used to request the report without generic filters.
*/
public $self_url = '';
/**
* CSS class to use in the output HTML div. This is added in addition to the visualization CSS
* class.
*/
public $datatable_css_class = false;
/**
* The JavaScript class to instantiate after the result HTML is obtained. This class handles all
* interactive behavior for the DataTable view.
*/
public $datatable_js_type = 'DataTable';
/**
* If true, searching through the DataTable will search through all subtables.
*/
public $search_recursive = false;
/**
* The unit of the displayed column. Valid if only one non-label column is displayed.
*/
public $y_axis_unit = false;
/**
* Controls whether to show the 'Export as Image' footer icon.
*/
public $show_export_as_image_icon = false;
/**
* Array of DataTable filters that should be run before displaying a DataTable. Elements
* of this array can either be a closure or an array with at most three elements, including:
* - the filter name (or a closure)
* - an array of filter parameters
* - a boolean indicating if the filter is a priority filter or not
*
* Priority filters are run before queued filters. These filters should be filters that
* add/delete rows.
*
* If a closure is used, the view is appended as a parameter.
*/
public $filters = array();
/**
* Contains the controller action to call when requesting subtables of the current report.
*
* By default, this is set to the controller action used to request the report.
*/
public $subtable_controller_action = '';
/**
* Controls whether the 'prev'/'next' links are shown in the DataTable footer. These links
* change the 'filter_offset' query parameter, thus allowing pagination.
*/
public $show_pagination_control = true;
/**
* Controls whether offset information (ie, '5-10 of 20') is shown under the datatable.
*/
public $show_offset_information = true;
/**
* Controls whether annotations are shown or not.
*/
public $hide_annotations_view = true;
/**
* The filter_limit query parameter value to use in export links.
*
* Defaulted to the value of the `[General] API_datatable_default_limit` INI config option.
*/
public $export_limit = '';
/**
* @ignore
*/
public $report_id = '';
/**
* @ignore
*/
public $controllerName;
/**
* @ignore
*/
public $controllerAction;
/**
* Constructor.
*/
public function __construct()
{
$this->export_limit = \Piwik\Config::getInstance()->General['API_datatable_default_limit'];
$this->translations = array_merge(
Metrics::getDefaultMetrics(),
Metrics::getDefaultProcessedMetrics()
);
}
/**
* @ignore
*/
public function setController($controllerName, $controllerAction)
{
$this->controllerName = $controllerName;
$this->controllerAction = $controllerAction;
$this->report_id = $controllerName . '.' . $controllerAction;
$this->loadDocumentation();
}
/** Load documentation from the API */
private function loadDocumentation()
{
$this->metrics_documentation = array();
$report = API::getInstance()->getMetadata(0, $this->controllerName, $this->controllerAction);
$report = $report[0];
if (isset($report['metricsDocumentation'])) {
$this->metrics_documentation = $report['metricsDocumentation'];
}
if (isset($report['documentation'])) {
$this->documentation = $report['documentation'];
}
}
/**
* 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)
{
foreach ($propertyNames as $propertyName) {
$this->clientSideProperties[] = $propertyName;
}
}
/**
* 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)
{
foreach ($propertyNames as $propertyName) {
$this->overridableProperties[] = $propertyName;
}
}
/**
* 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()
{
return get_object_vars($this);
}
/**
* @ignore
*/
public function setDefaultColumnsToDisplay($columns, $hasNbVisits, $hasNbUniqVisitors)
{
if ($hasNbVisits || $hasNbUniqVisitors) {
$columnsToDisplay = array('label');
// if unique visitors data is available, show it, otherwise just visits
if ($hasNbUniqVisitors) {
$columnsToDisplay[] = 'nb_uniq_visitors';
} else {
$columnsToDisplay[] = 'nb_visits';
}
} else {
$columnsToDisplay = $columns;
}
$this->columns_to_display = array_filter($columnsToDisplay);
}
/**
* @ignore
*/
public function getFiltersToRun()
{
$priorityFilters = array();
$presentationFilters = array();
foreach ($this->filters as $filterInfo) {
if ($filterInfo instanceof \Closure) {
$nameOrClosure = $filterInfo;
$parameters = array();
$priority = false;
} else {
@list($nameOrClosure, $parameters, $priority) = $filterInfo;
}
if ($priority) {
$priorityFilters[] = array($nameOrClosure, $parameters);
} else {
$presentationFilters[] = array($nameOrClosure, $parameters);
}
}
return array($priorityFilters, $presentationFilters);
}
/**
* 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 $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')`.
*/
public function addRelatedReport($relatedReport, $title, $queryParams = array())
{
list($module, $action) = explode('.', $relatedReport);
// don't add the related report if it references this report
if ($this->controllerName == $module
&& $this->controllerAction == $action) {
if(empty($queryParams)) {
return;
}
}
$url = ApiRequest::getBaseReportUrl($module, $action, $queryParams);
$this->related_reports[$url] = $title;
}
/**
* 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'
* )
* ```
*/
public function addRelatedReports($relatedReports)
{
foreach ($relatedReports as $report => $title) {
$this->addRelatedReport($report, $title);
}
}
/**
* 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'"`.
*/
public function addTranslation($columnName, $translation)
{
$this->translations[$columnName] = $translation;
}
/**
* Associates multiple translations with metrics.
*
* See {@link $translations} and {@link addTranslation()}.
*
* @param array $translations An array of column name => text mappings, eg,
* ```
* array(
* 'nb_visits' => 'Visits',
* 'goal_1_nb_conversions' => "Conversions for 'My Goal'"
* )
* ```
*/
public function addTranslations($translations)
{
foreach ($translations as $key => $translation) {
$this->addTranslation($key, $translation);
}
}
}

View file

@ -0,0 +1,174 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\ViewDataTable;
use Piwik\API\Proxy;
use Piwik\Common;
use Piwik\Piwik;
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()
* {
* $view = Factory::build('table', 'MyPlugin.myReport');
* $view->config->show_limit_control = true;
* $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.
* public function myReportShownDifferently()
* {
* $view = Factory::build('table', 'MyPlugin.myReport', 'MyPlugin.myReportShownDifferently');
* $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.
* public function myReportShownAsABarGraph()
* {
* $view = Factory::build('graphVerticalBar', 'MyPlugin.myReport', 'MyPlugin.myReportShownAsABarGraph',
* $forceDefault = true);
* return $view->render();
* }
*
*
* @api
*/
class Factory
{
/**
* Cache for getDefaultTypeViewDataTable result.
*
* @var array
*/
private static $defaultViewTypes = null;
/**
* 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
* 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.
* @throws \Exception
* @return \Piwik\Plugin\ViewDataTable
*/
public static function build($defaultType = null, $apiAction = false, $controllerAction = false, $forceDefault = false)
{
if (false === $controllerAction) {
$controllerAction = $apiAction;
}
$defaultViewType = self::getDefaultViewTypeForReport($apiAction);
if (!$forceDefault && !empty($defaultViewType)) {
$defaultType = $defaultViewType;
}
$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;
}
$visualizations = Manager::getAvailableViewDataTables();
if (array_key_exists($type, $visualizations)) {
return new $visualizations[$type]($controllerAction, $apiAction);
}
if (class_exists($type)) {
return new $type($controllerAction, $apiAction);
}
if (array_key_exists($defaultType, $visualizations)) {
return new $visualizations[$defaultType]($controllerAction, $apiAction);
}
if (array_key_exists(HtmlTable::ID, $visualizations)) {
return new $visualizations[HtmlTable::ID]($controllerAction, $apiAction);
}
throw new \Exception('No visualization found to render ViewDataTable');
}
/**
* Returns the default viewDataTable ID to use when determining which visualization to use.
*/
private static function getDefaultViewTypeForReport($apiAction)
{
$defaultViewTypes = self::getDefaultTypeViewDataTable();
return isset($defaultViewTypes[$apiAction]) ? $defaultViewTypes[$apiAction] : false;
}
/**
* Returns a list of default viewDataTables ID to use when determining which visualization to use for multiple
* reports.
*/
private static function getDefaultTypeViewDataTable()
{
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.
*/
Piwik::postEvent('ViewDataTable.getDefaultType', array(&self::$defaultViewTypes));
}
return self::$defaultViewTypes;
}
}

View file

@ -0,0 +1,273 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\ViewDataTable;
use Piwik\Common;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
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;
/**
* ViewDataTable Manager.
*
*/
class Manager
{
/**
* Returns the viewDataTable IDs of a visualization's class lineage.
*
* @see self::getVisualizationClassLineage
*
* @param string $klass The visualization class.
*
* @return array
*/
public static function getIdsWithInheritance($klass)
{
$klasses = Common::getClassLineage($klass);
$result = array();
foreach ($klasses as $klass) {
try {
$result[] = $klass::getViewDataTableId();
} catch (\Exception $e) {
// in case $klass did not define an id: eg Plugin\ViewDataTable
continue;
}
}
return $result;
}
/**
* Returns all registered visualization classes. Uses the 'Visualization.getAvailable'
* event to retrieve visualizations.
*
* @return array Array mapping visualization IDs with their associated visualization classes.
* @throws \Exception If a visualization class does not exist or if a duplicate visualization ID
* is found.
* @return array
*/
public static function getAvailableViewDataTables()
{
/** @var string[] $visualizations */
$visualizations = array();
/**
* 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.
*/
Piwik::postEvent('ViewDataTable.addViewDataTable', array(&$visualizations));
$result = array();
foreach ($visualizations as $viz) {
if (!class_exists($viz)) {
throw new \Exception("Invalid visualization class '$viz' found in Visualization.getAvailableVisualizations.");
}
if (!is_subclass_of($viz, '\\Piwik\\Plugin\\ViewDataTable')) {
throw new \Exception("ViewDataTable class '$viz' does not extend Plugin/ViewDataTable");
}
$vizId = $viz::getViewDataTableId();
if (isset($result[$vizId])) {
throw new \Exception("ViewDataTable ID '$vizId' is already in use!");
}
$result[$vizId] = $viz;
}
return $result;
}
/**
* Returns all available visualizations that are not part of the CoreVisualizations plugin.
*
* @return array Array mapping visualization IDs with their associated visualization classes.
*/
public static function getNonCoreViewDataTables()
{
$result = array();
foreach (static::getAvailableViewDataTables() as $vizId => $vizClass) {
if (false === strpos($vizClass, 'Piwik\\Plugins\\CoreVisualizations')
&& false === strpos($vizClass, 'Piwik\\Plugins\\Goals\\Visualizations\\Goals')) {
$result[$vizId] = $vizClass;
}
}
return $result;
}
/**
* This method determines the default set of footer icons to display below a report.
*
* $result has the following format:
*
* ```
* array(
* array( // footer icon group 1
* 'class' => 'footerIconGroup1CssClass',
* 'buttons' => array(
* 'id' => 'myid',
* 'title' => 'My Tooltip',
* 'icon' => 'path/to/my/icon.png'
* )
* ),
* array( // footer icon group 2
* 'class' => 'footerIconGroup2CssClass',
* 'buttons' => array(...)
* ),
* ...
* )
* ```
*/
public static function configureFooterIcons(ViewDataTable $view)
{
$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']);
if (!empty($normalViewIcons['buttons'])) {
$result[] = $normalViewIcons;
}
// add insight views
$insightsViewIcons = array(
'class' => 'tableInsightViews',
'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);
}
}
$nonCoreVisualizations = static::getNonCoreViewDataTables();
foreach ($nonCoreVisualizations as $id => $klass) {
if ($klass::canDisplayViewDataTable($view)) {
$footerIcon = static::getFooterIconFor($id);
if (Insight::ID == $footerIcon['id']) {
$insightsViewIcons['buttons'][] = static::getFooterIconFor($id);
} else {
$graphViewIcons['buttons'][] = static::getFooterIconFor($id);
}
}
}
$graphViewIcons['buttons'] = array_filter($graphViewIcons['buttons']);
if (!empty($insightsViewIcons['buttons'])) {
$result[] = $insightsViewIcons;
}
if (!empty($graphViewIcons['buttons'])) {
$result[] = $graphViewIcons;
}
return $result;
}
/**
* Returns an array with information necessary for adding the viewDataTable to the footer.
*
* @param string $viewDataTableId
*
* @return array
*/
private static function getFooterIconFor($viewDataTableId)
{
$tables = static::getAvailableViewDataTables();
if (!array_key_exists($viewDataTableId, $tables)) {
return;
}
$klass = $tables[$viewDataTableId];
return array(
'id' => $klass::getViewDataTableId(),
'title' => Piwik::translate($klass::FOOTER_ICON_TITLE),
'icon' => $klass::FOOTER_ICON,
);
}
}

View file

@ -0,0 +1,137 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\ViewDataTable;
use Piwik\API\Request as ApiRequest;
use Piwik\Common;
use Piwik\DataTable;
use Piwik\Period;
class Request
{
/**
* @var null|\Piwik\ViewDataTable\RequestConfig
*/
public $requestConfig;
public function __construct($requestConfig)
{
$this->requestConfig = $requestConfig;
}
/**
* Function called by the ViewDataTable objects in order to fetch data from the API.
* The function init() must have been called before, so that the object knows which API module and action to call.
* 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())
{
// 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);
// and get the DataTable structure
$dataTable = $request->process();
return $dataTable;
}
/**
* @return array URL to call the API, eg. "method=Referrers.getKeywords&period=day&date=yesterday"...
*/
public function getRequestArray()
{
// we prepare the array to give to the API Request
// we setup the method and format variable
// - we request the method to call to get this specific DataTable
// - the format = original specifies that we want to get the original DataTable structure itself, not rendered
$requestArray = array(
'method' => $this->requestConfig->apiMethodToRequestDataTable,
'format' => 'original'
);
$toSetEventually = array(
'filter_limit',
'keep_summary_row',
'filter_sort_column',
'filter_sort_order',
'filter_excludelowpop',
'filter_excludelowpop_value',
'filter_column',
'filter_pattern',
);
foreach ($toSetEventually as $varToSet) {
$value = $this->getDefaultOrCurrent($varToSet);
if (false !== $value) {
$requestArray[$varToSet] = $value;
}
}
$segment = ApiRequest::getRawSegmentFromRequest();
if (!empty($segment)) {
$requestArray['segment'] = $segment;
}
if (ApiRequest::shouldLoadExpanded()) {
$requestArray['expanded'] = 1;
}
$requestArray = array_merge($requestArray, $this->requestConfig->request_parameters_to_modify);
if (!empty($requestArray['filter_limit'])
&& $requestArray['filter_limit'] === 0
) {
unset($requestArray['filter_limit']);
}
return $requestArray;
}
/**
* Returns, for a given parameter, the value of this parameter in the REQUEST array.
* If not set, returns the default value for this parameter @see getDefault()
*
* @param string $nameVar
* @return string|mixed Value of this parameter
*/
protected function getDefaultOrCurrent($nameVar)
{
if (isset($_GET[$nameVar])) {
return Common::sanitizeInputValue($_GET[$nameVar]);
}
$default = $this->getDefault($nameVar);
return $default;
}
/**
* Returns the default value for a given parameter.
* For example, these default values can be set using the disable* methods.
*
* @param string $nameVar
* @return mixed
*/
protected function getDefault($nameVar)
{
if (isset($this->requestConfig->$nameVar)) {
return $this->requestConfig->$nameVar;
}
return false;
}
}

View file

@ -0,0 +1,301 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
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}
* 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
* {
* /**
* * My custom property. It is overridable.
* *\/
* public $my_custom_property = false;
*
* /**
* * 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
{
/**
* The list of request parameters that are 'Client Side Parameters'.
*/
public $clientSideParameters = array(
'filter_excludelowpop',
'filter_excludelowpop_value',
'filter_pattern',
'filter_column',
'filter_offset'
);
/**
* The list of ViewDataTable properties that can be overriden by query parameters.
*/
public $overridableProperties = array(
'filter_sort_column',
'filter_sort_order',
'filter_limit',
'filter_offset',
'filter_pattern',
'filter_column',
'filter_excludelowpop',
'filter_excludelowpop_value',
'disable_generic_filters',
'disable_queued_filters'
);
/**
* Controls which column to sort the DataTable by before truncating and displaying.
*
* Default value: If the report contains nb_uniq_visitors and nb_uniq_visitors is a
* displayed column, then the default value is 'nb_uniq_visitors'.
* Otherwise, it is 'nb_visits'.
*/
public $filter_sort_column = false;
/**
* Controls the sort order. Either 'asc' or 'desc'.
*
* Default value: 'desc'
*/
public $filter_sort_order = 'desc';
/**
* The number of items to truncate the data set to before rendering the DataTable view.
*
* Default value: false
*/
public $filter_limit = false;
/**
* The number of items from the start of the data set that should be ignored.
*
* Default value: 0
*/
public $filter_offset = 0;
/**
* A regex pattern to use to filter the DataTable before it is shown.
*
* @see also self::FILTER_PATTERN_COLUMN
*
* Default value: false
*/
public $filter_pattern = false;
/**
* The column to apply a filter pattern to.
*
* @see also self::FILTER_PATTERN
*
* Default value: false
*/
public $filter_column = false;
/**
* Stores the column name to filter when filtering out rows with low values.
*
* Default value: false
*/
public $filter_excludelowpop = false;
/**
* Stores the value considered 'low' when filtering out rows w/ low values.
*
* Default value: false
* @var \Closure|string
*/
public $filter_excludelowpop_value = false;
/**
* An array property that contains query parameter name/value overrides for API requests made
* by ViewDataTable.
*
* E.g. array('idSite' => ..., 'period' => 'month')
*
* Default value: array()
*/
public $request_parameters_to_modify = array();
/**
* Whether to run generic filters on the DataTable before rendering or not.
*
* @see Piwik\API\DataTableGenericFilter
*
* Default value: false
*/
public $disable_generic_filters = false;
/**
* Whether to run ViewDataTable's list of queued filters or not.
*
* _NOTE: Priority queued filters are always run._
*
* Default value: false
*/
public $disable_queued_filters = false;
/**
* returns 'Plugin.apiMethodName' used for this ViewDataTable,
* eg. 'Actions.getPageUrls'
*
* @var string
*/
public $apiMethodToRequestDataTable = '';
/**
* If the current dataTable refers to a subDataTable (eg. keywordsBySearchEngineId for id=X) this variable is set to the Id
*
* @var bool|int
*/
public $idSubtable = false;
public function getProperties()
{
return get_object_vars($this);
}
/**
* 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)
{
foreach ($propertyNames as $propertyName) {
$this->clientSideParameters[] = $propertyName;
}
}
/**
* 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)
{
foreach ($propertyNames as $propertyName) {
$this->overridableProperties[] = $propertyName;
}
}
public function setDefaultSort($columnsToDisplay, $hasNbUniqVisitors)
{
// default sort order to visits/visitors data
if ($hasNbUniqVisitors && in_array('nb_uniq_visitors', $columnsToDisplay)) {
$this->filter_sort_column = 'nb_uniq_visitors';
} else {
$this->filter_sort_column = 'nb_visits';
}
$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);
return $module;
}
public function getApiMethodToRequest()
{
list($module, $method) = explode('.', $this->apiMethodToRequestDataTable);
return $method;
}
}