Newer
Older
mattpiwik
a validé
<?php
/**
* Piwik - Open source web analytics
mattpiwik
a validé
* @link http://piwik.org
mattpiwik
a validé
*/
namespace Piwik;
mattab
a validé
use Piwik\Metrics;
use Piwik\Period\Range;
use Piwik\Date;
use Piwik\DataTable;
use Piwik\Url;
use Piwik\ViewDataTable\VisualizationPropertiesProxy;
mattpiwik
a validé
/**
* This class is used to load (from the API) and customize the output of a given DataTable.
* The main() method will create an object implementing ViewInterface
mattpiwik
a validé
* You can customize the dataTable using the disable* methods.
benakamoorthi
a validé
* You can also customize the dataTable rendering using row metadata:
* - 'html_label_prefix': If this metadata is present on a row, it's contents will be prepended
* the label in the HTML output.
* - 'html_label_suffix': If this metadata is present on a row, it's contents will be appended
* after the label in the HTML output.
mattpiwik
a validé
* Example:
* In the Controller of the plugin VisitorInterest
* <pre>
* function getNumberOfVisitsPerVisitDuration( $fetch = false)
mattpiwik
a validé
* {
* $view = ViewDataTable::factory( 'cloud' );
* $view->init( $this->pluginName, __FUNCTION__, 'VisitorInterest.getNumberOfVisitsPerVisitDuration' );
* $view->setColumnsToDisplay( array('label','nb_visits') );
* $view->disableSort();
* $view->disableExcludeLowPopulation();
* $view->disableOffsetInformation();
* return $this->renderView($view, $fetch);
* }
mattpiwik
a validé
* </pre>
* @see \Piwik\ViewDataTable\Properties - for core DataTable display properties.
mattpiwik
a validé
* @see factory() for all the available output (cloud tags, html table, pie chart, vertical bar chart)
* @subpackage ViewDataTable
mattpiwik
a validé
*/
class ViewDataTable
mattpiwik
a validé
{
/**
* TODO
* TODO: change to private
*/
protected $visualization;
Benaka Moorthi
a validé
* Cache for getAllReportDisplayProperties result.
*
* @var array
Benaka Moorthi
a validé
public static $reportPropertiesCache = null;
/**
* Flag used to make sure the main() is only executed once
*
* @var bool
*/
protected $mainAlreadyExecuted = false;
/**
* Array of properties that are available in the view
* Used to store UI properties, eg. "show_footer", "show_search", etc.
*
* @var array
*/
protected $viewProperties = array();
/**
* If the current dataTable refers to a subDataTable (eg. keywordsBySearchEngineId for id=X) this variable is set to the Id
*
* @var bool|int
*/
protected $idSubtable = false;
/**
* DataTable loaded from the API for this ViewDataTable.
*
* @var DataTable
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
*/
protected $dataTable = null;
/**
* List of filters to apply after the data has been loaded from the API
*
* @var array
*/
protected $queuedFilters = array();
/**
* List of filter to apply just before the 'Generic' filters
* These filters should delete rows from the table
* @var array
*/
protected $queuedFiltersPriority = array();
/**
* @see init()
* @var string
*/
protected $currentControllerAction;
/**
* @see init()
* @var string
*/
protected $currentControllerName;
/**
* This view should be an implementation of the Interface ViewInterface
* The $view object should be created in the main() method.
*
*/
protected $view = null;
/**
Benaka Moorthi
a validé
* Default constructor.
public function __construct($visualization = null)
Benaka Moorthi
a validé
{
$this->visualization = $visualization;
$this->viewProperties['visualization_properties'] = new VisualizationPropertiesProxy(null);
Benaka Moorthi
a validé
$this->viewProperties['datatable_template'] = '@CoreHome/_dataTable';
Benaka Moorthi
a validé
$this->viewProperties['show_goals'] = false;
$this->viewProperties['show_ecommerce'] = false;
$this->viewProperties['show_search'] = true;
$this->viewProperties['show_table'] = true;
$this->viewProperties['show_table_all_columns'] = true;
$this->viewProperties['show_all_views_icons'] = true;
Benaka Moorthi
a validé
$this->viewProperties['show_active_view_icon'] = true;
Benaka Moorthi
a validé
$this->viewProperties['hide_annotations_view'] = true;
$this->viewProperties['show_bar_chart'] = true;
$this->viewProperties['show_pie_chart'] = true;
$this->viewProperties['show_tag_cloud'] = true;
$this->viewProperties['show_export_as_image_icon'] = false;
$this->viewProperties['show_export_as_rss_feed'] = true;
$this->viewProperties['show_exclude_low_population'] = true;
$this->viewProperties['show_offset_information'] = true;
$this->viewProperties['show_pagination_control'] = true;
$this->viewProperties['show_limit_control'] = false;
$this->viewProperties['show_footer'] = true;
$this->viewProperties['show_related_reports'] = true;
$this->viewProperties['exportLimit'] = Config::getInstance()->General['API_datatable_default_limit'];
Benaka Moorthi
a validé
$this->viewProperties['highlight_summary_row'] = false;
$this->viewProperties['metadata'] = array();
$this->viewProperties['relatedReports'] = array();
$this->viewProperties['title'] = 'unknown';
$this->viewProperties['tooltip_metadata_name'] = false;
$this->viewProperties['enable_sort'] = true;
$this->viewProperties['disable_generic_filters'] = false;
$this->viewProperties['disable_queued_filters'] = false;
$this->viewProperties['keep_summary_row'] = false;
$this->viewProperties['filter_excludelowpop'] = false;
$this->viewProperties['filter_excludelowpop_value'] = false;
$this->viewProperties['filter_pattern'] = false;
$this->viewProperties['filter_column'] = false;
$this->viewProperties['filter_limit'] = false;
$this->viewProperties['filter_sort_column'] = false;
$this->viewProperties['filter_sort_order'] = false;
$this->viewProperties['custom_parameters'] = array();
$this->viewProperties['translations'] = array_merge(
mattab
a validé
Metrics::getDefaultMetrics(),
Metrics::getDefaultProcessedMetrics()
Benaka Moorthi
a validé
);
Benaka Moorthi
a validé
$this->viewProperties['request_parameters_to_modify'] = array();
Benaka Moorthi
a validé
$this->viewProperties['documentation'] = false;
$this->viewProperties['subtable_controller_action'] = false;
$this->viewProperties['datatable_css_class'] = $this->getDefaultDataTableCssClass();
$this->viewProperties['selectable_columns'] = array(); // TODO: only valid for graphs... shouldn't be here.
$this->viewProperties['columns_to_display'] = array();
Benaka Moorthi
a validé
$columns = Common::getRequestVar('columns', false);
Benaka Moorthi
a validé
if ($columns !== false) {
$this->viewProperties['columns_to_display'] = Piwik::getArrayFromApiParameter($columns);
array_unshift($this->viewProperties['columns_to_display'], 'label');
Benaka Moorthi
a validé
}
}
Benaka Moorthi
a validé
/**
* Gets a view property by reference.
*
* @param string $name A valid view property name. @see Properties for all
Benaka Moorthi
a validé
* valid view properties.
* @return mixed
Benaka Moorthi
a validé
*/
public function &__get($name)
{
Benaka Moorthi
a validé
return $this->viewProperties[$name];
}
/**
* Sets a view property.
*
* @param string $name A valid view property name. @see Properties for all
Benaka Moorthi
a validé
* valid view properties.
* @param mixed $value
* @return mixed Returns $value.
Benaka Moorthi
a validé
*/
public function __set($name, $value)
{
Benaka Moorthi
a validé
return $this->viewProperties[$name] = $value;
}
* TODO
public function main()
{
if ($this->mainAlreadyExecuted) {
return;
}
$this->mainAlreadyExecuted = true;
try {
$this->loadDataTableFromAPI();
} catch (\Piwik\NoAccessException $e) {
throw $e;
Piwik::log("Failed to get data from API: " . $e->getMessage());
$this->loadingError = array('message' => $e->getMessage());
}
$this->postDataTableLoadedFromAPI();
$this->view = $this->buildView($this->visualization);
}
/**
* Unique string ID that defines the format of the dataTable, eg. "pieChart", "table", etc.
*
* @return string
*/
protected function getViewDataTableId()
{
if (method_exists($this->visualization, 'getViewDataTableId')) {
return $this->visualization->getViewDataTableId();
}
return false;
}
/**
* Returns a Piwik_ViewDataTable_* object.
* By default it will return a ViewDataTable_Html
* If there is a viewDataTable parameter in the URL, a ViewDataTable of this 'viewDataTable' type will be returned.
* If defaultType is specified and if there is no 'viewDataTable' in the URL, a ViewDataTable of this $defaultType will be returned.
* If force is set to true, a ViewDataTable of the $defaultType will be returned in all cases.
*
* @param string $defaultType Any of these: table, cloud, graphPie, graphVerticalBar, graphEvolution, sparkline, generateDataChart*
Benaka Moorthi
a validé
* @param string|bool $apiAction
* @param string|bool $controllerAction
Benaka Moorthi
a validé
static public function factory($defaultType = null, $apiAction = false, $controllerAction = false)
Benaka Moorthi
a validé
if ($apiAction !== false) {
$defaultProperties = self::getDefaultPropertiesForReport($apiAction);
Benaka Moorthi
a validé
if (isset($defaultProperties['default_view_type'])) {
$defaultType = $defaultProperties['default_view_type'];
}
Benaka Moorthi
a validé
if ($controllerAction === false) {
$controllerAction = $apiAction;
}
Benaka Moorthi
a validé
}
Benaka Moorthi
a validé
if ($defaultType === null) {
$defaultType = 'table';
}
$type = Common::getRequestVar('viewDataTable', $defaultType, 'string');
switch ($type) {
case 'cloud':
break;
case 'graphPie':
$result = new ViewDataTable\GenerateGraphHTML\ChartPie();
break;
case 'graphVerticalBar':
$result = new ViewDataTable\GenerateGraphHTML\ChartVerticalBar();
break;
case 'graphEvolution':
$result = new ViewDataTable\GenerateGraphHTML\ChartEvolution();
break;
case 'sparkline':
break;
case 'tableAllColumns':
break;
case 'tableGoals':
break;
case 'table':
default:
$result = new ViewDataTable(new Visualization\HtmlTable());
break;
}
Benaka Moorthi
a validé
Benaka Moorthi
a validé
if ($apiAction !== false) {
list($plugin, $controllerAction) = explode('.', $controllerAction);
Benaka Moorthi
a validé
$subtableAction = $controllerAction;
if (isset($defaultProperties['subtable_action'])) {
$subtableAction = $defaultProperties['subtable_action'];
}
Benaka Moorthi
a validé
$result->init($plugin, $controllerAction, $apiAction, $subtableAction, $defaultProperties);
Benaka Moorthi
a validé
}
Benaka Moorthi
a validé
return $result;
}
Benaka Moorthi
a validé
/**
* Returns the list of view properties that can be overridden by query parameters.
*
Benaka Moorthi
a validé
* @return array
*/
public function getOverridableProperties()
{
return array(
'show_search',
'show_table',
'show_table_all_columns',
'show_all_views_icons',
Benaka Moorthi
a validé
'show_active_view_icon',
Benaka Moorthi
a validé
'hide_annotations_view',
'show_barchart',
'show_piechart',
'show_tag_cloud',
'show_export_as_image_icon',
'show_export_as_rss_feed',
'show_exclude_low_population',
'show_offset_information',
'show_pagination_control',
'show_footer',
'show_related_reports',
'columns'
);
}
Benaka Moorthi
a validé
/**
* Returns the list of view properties that should be sent with the HTML response
* as JSON. These properties can be manipulated via the ViewDataTable UI.
*
Benaka Moorthi
a validé
* @return array
*/
public function getJavaScriptProperties()
{
$result = array(
Benaka Moorthi
a validé
'enable_sort',
'disable_generic_filters',
'disable_queued_filters',
'keep_summary_row',
'filter_excludelowpop',
'filter_excludelowpop_value',
'filter_pattern',
'filter_column',
'filter_limit',
'filter_sort_column',
'filter_sort_order',
);
if (method_exists($this->visualization, 'getJavaScriptProperties')) {
$result = array_merge($result, $this->visualization->getJavaScriptProperties());
}
return $result;
}
/**
* Inits the object given the $currentControllerName, $currentControllerAction of
* the calling controller action, eg. 'Referers' 'getLongListOfKeywords'.
* The initialization also requires the $apiMethodToRequestDataTable of the API method
* to call in order to get the DataTable, eg. 'Referers.getKeywords'.
* The optional $controllerActionCalledWhenRequestSubTable defines the method name of the API to call when there is a idSubtable.
* This value would be used by the javascript code building the GET request to the API.
*
* Example:
* For the keywords listing, a click on the row loads the subTable of the Search Engines for this row.
* In this case $controllerActionCalledWhenRequestSubTable = 'getSearchEnginesFromKeywordId'.
* The GET request will hit 'Referers.getSearchEnginesFromKeywordId'.
*
* @param string $currentControllerName eg. 'Referers'
* @param string $currentControllerAction eg. 'getKeywords'
* @param string $apiMethodToRequestDataTable eg. 'Referers.getKeywords'
* @param string $controllerActionCalledWhenRequestSubTable eg. 'getSearchEnginesFromKeywordId'
* @param array $defaultProperties
*/
public function init($currentControllerName,
$currentControllerAction,
$apiMethodToRequestDataTable,
Benaka Moorthi
a validé
$controllerActionCalledWhenRequestSubTable = null,
$defaultProperties = array())
{
$this->currentControllerName = $currentControllerName;
$this->currentControllerAction = $currentControllerAction;
Benaka Moorthi
a validé
$this->viewProperties['subtable_controller_action'] = $controllerActionCalledWhenRequestSubTable;
$this->idSubtable = Common::getRequestVar('idSubtable', false, 'int');
Benaka Moorthi
a validé
foreach ($defaultProperties as $name => $value) {
$this->setViewProperty($name, $value);
}
$queryParams = Url::getArrayFromCurrentQueryString();
Benaka Moorthi
a validé
foreach ($this->getOverridableProperties() as $name) {
if (isset($queryParams[$name])) {
$this->setViewProperty($name, $queryParams[$name]);
}
}
$this->viewProperties['show_footer_icons'] = ($this->idSubtable == false);
Benaka Moorthi
a validé
$this->viewProperties['apiMethodToRequestDataTable'] = $apiMethodToRequestDataTable;
Benaka Moorthi
a validé
$this->viewProperties['report_id'] = $currentControllerName . '.' . $currentControllerAction;
$this->viewProperties['self_url'] = $this->getBaseReportUrl($currentControllerName, $currentControllerAction);
Benaka Moorthi
a validé
// the exclude low population threshold value is sometimes obtained by requesting data.
// to avoid issuing unecessary requests when display properties are determined by metadata,
// we allow it to be a closure.
if (isset($this->viewProperties['filter_excludelowpop_value'])
&& $this->viewProperties['filter_excludelowpop_value'] instanceof \Closure
Benaka Moorthi
a validé
) {
$function = $this->viewProperties['filter_excludelowpop_value'];
$this->viewProperties['filter_excludelowpop_value'] = $function();
}
Benaka Moorthi
a validé
$this->loadDocumentation();
/**
* Forces the View to use a given template.
* Usually the template to use is set in the specific ViewDataTable_*
* But some users may want to force this template to some other value
*
Benaka Moorthi
a validé
* TODO: after visualization refactor, should remove this.
*
* @param string $tpl eg .'@MyPlugin/templateToUse'
*/
public function setTemplate($tpl)
{
Benaka Moorthi
a validé
$this->viewProperties['datatable_template'] = $tpl;
}
/**
* Returns the View_Interface.
* You can then call render() on this object.
*
* @throws \Exception if the view object was not created
*/
public function getView()
{
if (is_null($this->view)) {
throw new \Exception('The $this->view object has not been created.
It should be created in the main() method of the ViewDataTable_* subclass you are using.');
}
return $this->view;
}
public function getCurrentControllerAction()
{
return $this->currentControllerAction;
}
public function getCurrentControllerName()
{
return $this->currentControllerName;
}
/**
* Returns the DataTable loaded from the API
*
* @return DataTable
*/
public function getDataTable()
{
if (is_null($this->dataTable)) {
throw new \Exception("The DataTable object has not yet been created");
}
return $this->dataTable;
}
/**
* To prevent calling an API multiple times, the DataTable can be set directly.
* It won't be loaded again from the API in this case
*
* @param $dataTable
* @return void $dataTable DataTable
*/
public function setDataTable($dataTable)
{
$this->dataTable = $dataTable;
}
Benaka Moorthi
a validé
/**
* Returns the defaut view properties for a report, if any.
Benaka Moorthi
a validé
* Plugins can associate callbacks with the ViewDataTable.getReportDisplayProperties
* event to set the default properties of reports.
Benaka Moorthi
a validé
* @return array
*/
private static function getDefaultPropertiesForReport($apiAction)
{
Benaka Moorthi
a validé
$reportDisplayProperties = self::getAllReportDisplayProperties();
return isset($reportDisplayProperties[$apiAction]) ? $reportDisplayProperties[$apiAction] : array();
Benaka Moorthi
a validé
}
Benaka Moorthi
a validé
/**
* Returns the list of display properties for all available reports.
*
* @return array
*/
private static function getAllReportDisplayProperties()
{
if (self::$reportPropertiesCache === null) {
self::$reportPropertiesCache = array();
Piwik_PostEvent('ViewDataTable.getReportDisplayProperties', array(&self::$reportPropertiesCache));
}
return self::$reportPropertiesCache;
Benaka Moorthi
a validé
}
/**
* Sets a view property by name. This function handles special view properties
* like 'translations' & 'relatedReports' that store arrays.
*
Benaka Moorthi
a validé
* @param string $name
* @param mixed $value For array properties, $value can be a comma separated string.
*/
private function setViewProperty($name, $value)
{
if (isset($this->viewProperties[$name])
&& is_array($this->viewProperties[$name])
&& is_string($value)
) {
$value = Piwik::getArrayFromApiParameter($value);
}
Benaka Moorthi
a validé
if ($name == 'translations') {
$this->viewProperties[$name] = array_merge($this->viewProperties[$name], $value);
} else if ($name == 'relatedReports') {
$this->addRelatedReports($value);
Benaka Moorthi
a validé
} else if ($name == 'filters') {
foreach ($value as $filterInfo) {
if (!is_array($filterInfo)) {
$this->queueFilter($filterInfo);
} else {
@list($filter, $params, $isPriority) = $filterInfo;
$this->queueFilter($filter, $params, $isPriority);
}
}
} else {
$this->viewProperties[$name] = $value;
}
}
/**
* 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.
*/
protected function loadDataTableFromAPI()
{
if (!is_null($this->dataTable)) {
// data table is already there
// this happens when setDataTable has been used
return;
}
Benaka Moorthi
a validé
// we build the request (URL) to call the API
$requestArray = $this->getRequestArray();
// we make the request to the API
// and get the DataTable structure
$dataTable = $request->process();
$this->dataTable = $dataTable;
}
/**
* Checks that the API returned a normal DataTable (as opposed to DataTable_Array)
* @return void
*/
protected function checkStandardDataTable()
{
Piwik::checkObjectTypeIs($this->dataTable, array('\Piwik\DataTable'));
}
/**
* Hook called after the dataTable has been loaded from the API
* Can be used to add, delete or modify the data freshly loaded
*
* @return bool
*/
protected function postDataTableLoadedFromAPI()
{
$this->overrideViewProperties();
if (empty($this->dataTable)) {
return false;
}
Benaka Moorthi
a validé
// default columns_to_display to label, nb_uniq_visitors/nb_visits if those columns exist in the
// dataset. otherwise, default to all columns in dataset.
Benaka Moorthi
a validé
$columns = $this->dataTable->getColumns();
if (empty($this->viewProperties['columns_to_display'])) {
if ($this->dataTableColumnsContains($columns, array('nb_visits', 'nb_uniq_visitors'))) {
$columnsToDisplay = array('label');
// if unique visitors data is available, show it, otherwise just visits
if ($this->dataTableColumnsContains($columns, 'nb_uniq_visitors')) {
$columnsToDisplay[] = 'nb_uniq_visitors';
Benaka Moorthi
a validé
} else {
Benaka Moorthi
a validé
$columnsToDisplay[] = 'nb_visits';
Benaka Moorthi
a validé
}
Benaka Moorthi
a validé
} else {
$columnsToDisplay = $columns;
Benaka Moorthi
a validé
}
Benaka Moorthi
a validé
$this->viewProperties['columns_to_display'] = array_filter($columnsToDisplay);
}
Benaka Moorthi
a validé
Benaka Moorthi
a validé
$this->removeEmptyColumnsFromDisplay();
// default sort order to visits/visitors data
if (empty($this->viewProperties['filter_sort_column'])) {
if ($this->dataTableColumnsContains($columns, 'nb_uniq_visitors')) {
$this->viewProperties['filter_sort_column'] = 'nb_uniq_visitors';
} else {
$this->viewProperties['filter_sort_column'] = 'nb_visits';
Benaka Moorthi
a validé
}
Benaka Moorthi
a validé
$this->viewProperties['filter_sort_order'] = 'desc';
Benaka Moorthi
a validé
}
// deal w/ table metadata
if ($this->dataTable instanceof DataTable) {
$this->viewProperties['metadata'] = $this->dataTable->getAllTableMetadata();
if (isset($this->viewProperties['metadata'][DataTable::ARCHIVED_DATE_METADATA_NAME])) {
$this->viewProperties['metadata'][DataTable::ARCHIVED_DATE_METADATA_NAME] =
$this->makePrettyArchivedOnText();
}
}
// First, filters that delete rows
foreach ($this->queuedFiltersPriority as $filter) {
$filterName = $filter[0];
Benaka Moorthi
a validé
$filterParameters = $filter[1];
Benaka Moorthi
a validé
$filterParameters[] = $this;
}
$this->dataTable->filter($filterName, $filterParameters);
}
if (!$this->areGenericFiltersDisabled()) {
// Second, generic filters (Sort, Limit, Replace Column Names, etc.)
Benaka Moorthi
a validé
$requestArray = $this->getRequestArray();
$request = API\Request::getRequestArrayFromString($requestArray);
if ($this->viewProperties['enable_sort'] === false) {
$request['filter_sort_column'] = $request['filter_sort_order'] = '';
}
$genericFilter = new API\DataTableGenericFilter($request);
$genericFilter->filter($this->dataTable);
}
if (!$this->areQueuedFiltersDisabled()) {
// Finally, apply datatable filters that were queued (should be 'presentation' filters that
// do not affect the number of rows)
foreach ($this->queuedFilters as $filter) {
$filterName = $filter[0];
Benaka Moorthi
a validé
$filterParameters = $filter[1];
if ($filterName instanceof \Closure) {
Benaka Moorthi
a validé
$filterParameters[] = $this;
}
Benaka Moorthi
a validé
$this->dataTable->filter($filterName, $filterParameters);
}
}
return true;
}
/**
* Returns true if generic filters have been disabled, false if otherwise.
*
* @return bool
*/
private 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 $this->disableGenericFilters() was called, generic filters are disabled
Benaka Moorthi
a validé
if (isset($this->viewProperties['disable_generic_filters'])
&& $this->viewProperties['disable_generic_filters'] === true
) {
return true;
}
return false;
}
/**
* Returns true if queued filters have been disabled, false if otherwise.
*
* @return bool
*/
private function areQueuedFiltersDisabled()
{
Benaka Moorthi
a validé
return isset($this->viewProperties['disable_queued_filters'])
&& $this->viewProperties['disable_queued_filters'];
}
/**
* Returns prettified and translated text that describes when a report was last updated.
*
* @return string
*/
private function makePrettyArchivedOnText()
{
$dateText = $this->viewProperties['metadata'][DataTable::ARCHIVED_DATE_METADATA_NAME];
$date = Date::factory($dateText);
$today = mktime(0, 0, 0);
if ($date->getTimestamp() > $today) {
$elapsedSeconds = time() - $date->getTimestamp();
$timeAgo = Piwik::getPrettyTimeFromSeconds($elapsedSeconds);
return Piwik_Translate('CoreHome_ReportGeneratedXAgo', $timeAgo);
}
$prettyDate = $date->getLocalized("%longYear%, %longMonth% %day%") . $date->toString('S');
return Piwik_Translate('CoreHome_ReportGeneratedOn', $prettyDate);
}
/**
* @return string URL to call the API, eg. "method=Referers.getKeywords&period=day&date=yesterday"...
*/
Benaka Moorthi
a validé
protected function getRequestArray()
Benaka Moorthi
a validé
// 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
Benaka Moorthi
a validé
$requestArray = array(
'method' => $this->viewProperties['apiMethodToRequestDataTable'],
'format' => 'original',
'disable_generic_filters' => Common::getRequestVar('disable_generic_filters', 1, 'int')
Benaka Moorthi
a validé
);
$toSetEventually = array(
'filter_limit',
'keep_summary_row',
'filter_sort_column',
'filter_sort_order',
'filter_excludelowpop',
'filter_excludelowpop_value',
'filter_column',
'filter_pattern',
'disable_queued_filters',
);
foreach ($toSetEventually as $varToSet) {
$value = $this->getDefaultOrCurrent($varToSet);
if (false !== $value) {
Benaka Moorthi
a validé
$requestArray[$varToSet] = $value;
}
}
Benaka Moorthi
a validé
$segment = \Piwik\API\Request::getRawSegmentFromRequest();
Benaka Moorthi
a validé
$requestArray['segment'] = $segment;
if (self::shouldLoadExpanded()) {
$requestArray['expanded'] = 1;
}
Benaka Moorthi
a validé
$requestArray = array_merge($requestArray, $this->viewProperties['request_parameters_to_modify']);
Benaka Moorthi
a validé
return $requestArray;
}
/**
* This functions reads the customization values for the DataTable and returns an array (name,value) to be printed in Javascript.
* This array defines things such as:
* - name of the module & action to call to request data for this table
* - optional filters information, eg. filter_limit and filter_offset
* - etc.
*
* The values are loaded:
* - from the generic filters that are applied by default @see Piwik_API_DataTableGenericFilter.php::getGenericFiltersInformation()
* - from the values already available in the GET array
* - from the values set using methods from this class (eg. setSearchPattern(), setLimit(), etc.)
*
* @return array eg. array('show_offset_information' => 0, 'show_...
*/
protected function getJavascriptVariablesToSet()
{
// build javascript variables to set
$javascriptVariablesToSet = array();
$genericFilters = API\DataTableGenericFilter::getGenericFiltersInformation();
foreach ($genericFilters as $filter) {
foreach ($filter as $filterVariableName => $filterInfo) {
// if there is a default value for this filter variable we set it
// so that it is propagated to the javascript
if (isset($filterInfo[1])) {
$javascriptVariablesToSet[$filterVariableName] = $filterInfo[1];
// we set the default specified column and Order to sort by
// when this javascript variable is not set already
// for example during an AJAX call this variable will be set in the URL
// so this will not be executed (and the default sorted not be used as the sorted column might have changed in the meanwhile)
if (false !== ($defaultValue = $this->getDefault($filterVariableName))) {
$javascriptVariablesToSet[$filterVariableName] = $defaultValue;
}
}
}
}
Benaka Moorthi
a validé
foreach ($this->viewProperties['custom_parameters'] as $name => $value) {
$javascriptVariablesToSet[$name] = $value;
}
foreach ($_GET as $name => $value) {
try {
$requestValue = Common::getRequestVar($name);
$requestValue = '';
}
$javascriptVariablesToSet[$name] = $requestValue;
}
// at this point there are some filters values we may have not set,
// case of the filter without default values and parameters set directly in this class
// for example setExcludeLowPopulation
Benaka Moorthi
a validé
// we go through all the $this->viewProperties array and set the variables not set yet
foreach ($this->getJavaScriptProperties() as $name) {
if (!isset($javascriptVariablesToSet[$name])
&& !empty($this->viewProperties[$name])
) {
$javascriptVariablesToSet[$name] = $this->viewProperties[$name];
}
}
if ($this->dataTable instanceof DataTable) {
// we override the filter_sort_column with the column used for sorting,
// which can be different from the one specified (eg. if the column doesn't exist)
$javascriptVariablesToSet['filter_sort_column'] = $this->dataTable->getSortedByColumnName();
// datatable can return "2" but we want to write "nb_visits" in the js
mattab
a validé
if (isset(Metrics::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']])) {
$javascriptVariablesToSet['filter_sort_column'] = Metrics::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']];
}
}
$javascriptVariablesToSet['module'] = $this->currentControllerName;
$javascriptVariablesToSet['action'] = $this->currentControllerAction;
if (!isset($javascriptVariablesToSet['viewDataTable'])) {
$javascriptVariablesToSet['viewDataTable'] = $this->getViewDataTableId();
}
Benaka Moorthi
a validé
$javascriptVariablesToSet['controllerActionCalledWhenRequestSubTable'] = $this->viewProperties['subtable_controller_action'];
if ($this->dataTable &&
// Set doesn't have the method
!($this->dataTable instanceof DataTable\Map)
&& empty($javascriptVariablesToSet['totalRows'])
) {
$javascriptVariablesToSet['totalRows'] = $this->dataTable->getRowsCountBeforeLimitFilter();
}
// we escape the values that will be displayed in the javascript footer of each datatable
// to make sure there is no malicious code injected (the value are already htmlspecialchar'ed as they
// are loaded with Common::getRequestVar()
foreach ($javascriptVariablesToSet as &$value) {
if (is_array($value)) {
$value = array_map('addslashes', $value);
} else {
$value = addslashes($value);
}
}
$deleteFromJavascriptVariables = array(
'filter_excludelowpop',
'filter_excludelowpop_value',
);
foreach ($deleteFromJavascriptVariables as $name) {
if (isset($javascriptVariablesToSet[$name])) {
unset($javascriptVariablesToSet[$name]);
}
}
$rawSegment = \Piwik\API\Request::getRawSegmentFromRequest();
if(!empty($rawSegment)) {
$javascriptVariablesToSet['segment'] = $rawSegment;
}
return $javascriptVariablesToSet;
}
/**
* 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)
{
Benaka Moorthi
a validé
if (!isset($this->viewProperties[$nameVar])) {
return false;
}
Benaka Moorthi
a validé
return $this->viewProperties[$nameVar];
/** Load documentation from the API */
private function loadDocumentation()
{
Benaka Moorthi
a validé
$this->viewProperties['metrics_documentation'] = array();
$report = Piwik_API_API::getInstance()->getMetadata(0, $this->currentControllerName, $this->currentControllerAction);
$report = $report[0];
if (isset($report['metricsDocumentation'])) {
Benaka Moorthi
a validé
$this->viewProperties['metrics_documentation'] = $report['metricsDocumentation'];
}
if (isset($report['documentation'])) {
Benaka Moorthi
a validé
$this->viewProperties['documentation'] = $report['documentation'];
}
}
private function removeEmptyColumnsFromDisplay()
{
if (empty($this->dataTable)) {