PageRenderTime 99ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Actions/API.php

https://github.com/CodeYellowBV/piwik
PHP | 605 lines | 386 code | 61 blank | 158 comment | 32 complexity | 3e9a92f64c70a1334e44eb9f233f79ac MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik\Plugins\Actions;
  10. use Exception;
  11. use Piwik\API\Request;
  12. use Piwik\Archive;
  13. use Piwik\Common;
  14. use Piwik\DataTable;
  15. use Piwik\Date;
  16. use Piwik\Metrics;
  17. use Piwik\Piwik;
  18. use Piwik\Plugins\CustomVariables\API as APICustomVariables;
  19. use Piwik\Tracker\Action;
  20. use Piwik\Tracker\ActionSiteSearch;
  21. use Piwik\Tracker\PageUrl;
  22. /**
  23. * The Actions API lets you request reports for all your Visitor Actions: Page URLs, Page titles (Piwik Events),
  24. * File Downloads and Clicks on external websites.
  25. *
  26. * For example, "getPageTitles" will return all your page titles along with standard <a href='http://piwik.org/docs/analytics-api/reference/#toc-metric-definitions' target='_blank'>Actions metrics</a> for each row.
  27. *
  28. * It is also possible to request data for a specific Page Title with "getPageTitle"
  29. * and setting the parameter pageName to the page title you wish to request.
  30. * Similarly, you can request metrics for a given Page URL via "getPageUrl", a Download file via "getDownload"
  31. * and an outlink via "getOutlink".
  32. *
  33. * Note: pageName, pageUrl, outlinkUrl, downloadUrl parameters must be URL encoded before you call the API.
  34. * @method static \Piwik\Plugins\Actions\API getInstance()
  35. */
  36. class API extends \Piwik\Plugin\API
  37. {
  38. /**
  39. * Returns the list of metrics (pages, downloads, outlinks)
  40. *
  41. * @param int $idSite
  42. * @param string $period
  43. * @param string $date
  44. * @param bool|string $segment
  45. * @param bool|array $columns
  46. * @return DataTable
  47. */
  48. public function get($idSite, $period, $date, $segment = false, $columns = false)
  49. {
  50. Piwik::checkUserHasViewAccess($idSite);
  51. $archive = Archive::build($idSite, $period, $date, $segment);
  52. $metrics = Archiver::$actionsAggregateMetrics;
  53. $metrics['Actions_avg_time_generation'] = 'avg_time_generation';
  54. // get requested columns
  55. $columns = Piwik::getArrayFromApiParameter($columns);
  56. if (!empty($columns)) {
  57. // get the columns that are available and requested
  58. $columns = array_intersect($columns, array_values($metrics));
  59. $columns = array_values($columns); // make sure indexes are right
  60. $nameReplace = array();
  61. foreach ($columns as $i => $column) {
  62. $fullColumn = array_search($column, $metrics);
  63. $columns[$i] = $fullColumn;
  64. $nameReplace[$fullColumn] = $column;
  65. }
  66. if (false !== ($avgGenerationTimeRequested = array_search('Actions_avg_time_generation', $columns))) {
  67. unset($columns[$avgGenerationTimeRequested]);
  68. $avgGenerationTimeRequested = true;
  69. }
  70. } else {
  71. // get all columns
  72. unset($metrics['Actions_avg_time_generation']);
  73. $columns = array_keys($metrics);
  74. $nameReplace = & $metrics;
  75. $avgGenerationTimeRequested = true;
  76. }
  77. if ($avgGenerationTimeRequested) {
  78. $tempColumns[] = Archiver::METRIC_SUM_TIME_RECORD_NAME;
  79. $tempColumns[] = Archiver::METRIC_HITS_TIMED_RECORD_NAME;
  80. $columns = array_merge($columns, $tempColumns);
  81. $columns = array_unique($columns);
  82. $nameReplace[Archiver::METRIC_SUM_TIME_RECORD_NAME] = 'sum_time_generation';
  83. $nameReplace[Archiver::METRIC_HITS_TIMED_RECORD_NAME] = 'nb_hits_with_time_generation';
  84. }
  85. $table = $archive->getDataTableFromNumeric($columns);
  86. // replace labels (remove Actions_)
  87. $table->filter('ReplaceColumnNames', array($nameReplace));
  88. // compute avg generation time
  89. if ($avgGenerationTimeRequested) {
  90. $table->filter('ColumnCallbackAddColumnQuotient', array('avg_time_generation', 'sum_time_generation', 'nb_hits_with_time_generation', 3));
  91. $table->deleteColumns(array('sum_time_generation', 'nb_hits_with_time_generation'));
  92. }
  93. return $table;
  94. }
  95. /**
  96. * @param int $idSite
  97. * @param string $period
  98. * @param Date $date
  99. * @param bool $segment
  100. * @param bool $expanded
  101. * @param bool|int $idSubtable
  102. * @param bool|int $depth
  103. *
  104. * @return DataTable|DataTable\Map
  105. */
  106. public function getPageUrls($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false,
  107. $depth = false)
  108. {
  109. $dataTable = $this->getDataTableFromArchive('Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $idSubtable, $depth);
  110. $this->filterPageDatatable($dataTable);
  111. $this->filterActionsDataTable($dataTable, $expanded);
  112. return $dataTable;
  113. }
  114. /**
  115. * @param int $idSite
  116. * @param string $period
  117. * @param Date $date
  118. * @param bool $segment
  119. * @param bool $expanded
  120. * @param bool $idSubtable
  121. *
  122. * @return DataTable|DataTable\Map
  123. */
  124. public function getPageUrlsFollowingSiteSearch($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
  125. {
  126. $dataTable = $this->getPageUrls($idSite, $period, $date, $segment, $expanded, $idSubtable);
  127. $this->keepPagesFollowingSearch($dataTable);
  128. return $dataTable;
  129. }
  130. /**
  131. * @param int $idSite
  132. * @param string $period
  133. * @param Date $date
  134. * @param bool $segment
  135. * @param bool $expanded
  136. * @param bool $idSubtable
  137. *
  138. * @return DataTable|DataTable\Map
  139. */
  140. public function getPageTitlesFollowingSiteSearch($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
  141. {
  142. $dataTable = $this->getPageTitles($idSite, $period, $date, $segment, $expanded, $idSubtable);
  143. $this->keepPagesFollowingSearch($dataTable);
  144. return $dataTable;
  145. }
  146. /**
  147. * @param DataTable $dataTable
  148. */
  149. protected function keepPagesFollowingSearch($dataTable)
  150. {
  151. // Keep only pages which are following site search
  152. $dataTable->filter('ColumnCallbackDeleteRow', array(
  153. 'nb_hits_following_search',
  154. function ($value) {
  155. return $value <= 0;
  156. }
  157. ));
  158. }
  159. /**
  160. * Returns a DataTable with analytics information for every unique entry page URL, for
  161. * the specified site, period & segment.
  162. */
  163. public function getEntryPageUrls($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
  164. {
  165. $dataTable = $this->getPageUrls($idSite, $period, $date, $segment, $expanded, $idSubtable);
  166. $this->filterNonEntryActions($dataTable);
  167. return $dataTable;
  168. }
  169. /**
  170. * Returns a DataTable with analytics information for every unique exit page URL, for
  171. * the specified site, period & segment.
  172. */
  173. public function getExitPageUrls($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
  174. {
  175. $dataTable = $this->getPageUrls($idSite, $period, $date, $segment, $expanded, $idSubtable);
  176. $this->filterNonExitActions($dataTable);
  177. return $dataTable;
  178. }
  179. public function getPageUrl($pageUrl, $idSite, $period, $date, $segment = false)
  180. {
  181. $callBackParameters = array('Actions_actions_url', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
  182. $dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $pageUrl, Action::TYPE_PAGE_URL);
  183. $this->filterPageDatatable($dataTable);
  184. $this->filterActionsDataTable($dataTable);
  185. return $dataTable;
  186. }
  187. public function getPageTitles($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
  188. {
  189. $dataTable = $this->getDataTableFromArchive('Actions_actions', $idSite, $period, $date, $segment, $expanded, $idSubtable);
  190. $this->filterPageDatatable($dataTable);
  191. $this->filterActionsDataTable($dataTable, $expanded);
  192. return $dataTable;
  193. }
  194. /**
  195. * Returns a DataTable with analytics information for every unique entry page title
  196. * for the given site, time period & segment.
  197. */
  198. public function getEntryPageTitles($idSite, $period, $date, $segment = false, $expanded = false,
  199. $idSubtable = false)
  200. {
  201. $dataTable = $this->getPageTitles($idSite, $period, $date, $segment, $expanded, $idSubtable);
  202. $this->filterNonEntryActions($dataTable);
  203. return $dataTable;
  204. }
  205. /**
  206. * Returns a DataTable with analytics information for every unique exit page title
  207. * for the given site, time period & segment.
  208. */
  209. public function getExitPageTitles($idSite, $period, $date, $segment = false, $expanded = false,
  210. $idSubtable = false)
  211. {
  212. $dataTable = $this->getPageTitles($idSite, $period, $date, $segment, $expanded, $idSubtable);
  213. $this->filterNonExitActions($dataTable);
  214. return $dataTable;
  215. }
  216. public function getPageTitle($pageName, $idSite, $period, $date, $segment = false)
  217. {
  218. $callBackParameters = array('Actions_actions', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
  219. $dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $pageName, Action::TYPE_PAGE_TITLE);
  220. $this->filterPageDatatable($dataTable);
  221. $this->filterActionsDataTable($dataTable);
  222. return $dataTable;
  223. }
  224. public function getDownloads($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
  225. {
  226. $dataTable = $this->getDataTableFromArchive('Actions_downloads', $idSite, $period, $date, $segment, $expanded, $idSubtable);
  227. $this->filterActionsDataTable($dataTable, $expanded);
  228. return $dataTable;
  229. }
  230. public function getDownload($downloadUrl, $idSite, $period, $date, $segment = false)
  231. {
  232. $callBackParameters = array('Actions_downloads', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
  233. $dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $downloadUrl, Action::TYPE_DOWNLOAD);
  234. $this->filterActionsDataTable($dataTable);
  235. return $dataTable;
  236. }
  237. public function getOutlinks($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false)
  238. {
  239. $dataTable = $this->getDataTableFromArchive('Actions_outlink', $idSite, $period, $date, $segment, $expanded, $idSubtable);
  240. $this->filterActionsDataTable($dataTable, $expanded);
  241. return $dataTable;
  242. }
  243. public function getOutlink($outlinkUrl, $idSite, $period, $date, $segment = false)
  244. {
  245. $callBackParameters = array('Actions_outlink', $idSite, $period, $date, $segment, $expanded = false, $idSubtable = false);
  246. $dataTable = $this->getFilterPageDatatableSearch($callBackParameters, $outlinkUrl, Action::TYPE_OUTLINK);
  247. $this->filterActionsDataTable($dataTable);
  248. return $dataTable;
  249. }
  250. public function getSiteSearchKeywords($idSite, $period, $date, $segment = false)
  251. {
  252. $dataTable = $this->getSiteSearchKeywordsRaw($idSite, $period, $date, $segment);
  253. $dataTable->deleteColumn(Metrics::INDEX_SITE_SEARCH_HAS_NO_RESULT);
  254. $this->filterPageDatatable($dataTable);
  255. $this->filterActionsDataTable($dataTable);
  256. $this->addPagesPerSearchColumn($dataTable);
  257. return $dataTable;
  258. }
  259. /**
  260. * Visitors can search, and then click "next" to view more results. This is the average number of search results pages viewed for this keyword.
  261. *
  262. * @param DataTable|DataTable\Simple|DataTable\Map $dataTable
  263. * @param string $columnToRead
  264. */
  265. protected function addPagesPerSearchColumn($dataTable, $columnToRead = 'nb_hits')
  266. {
  267. $dataTable->filter('ColumnCallbackAddColumnQuotient', array('nb_pages_per_search', $columnToRead, 'nb_visits', $precision = 1));
  268. }
  269. protected function getSiteSearchKeywordsRaw($idSite, $period, $date, $segment)
  270. {
  271. $dataTable = $this->getDataTableFromArchive('Actions_sitesearch', $idSite, $period, $date, $segment, $expanded = false);
  272. return $dataTable;
  273. }
  274. public function getSiteSearchNoResultKeywords($idSite, $period, $date, $segment = false)
  275. {
  276. $dataTable = $this->getSiteSearchKeywordsRaw($idSite, $period, $date, $segment);
  277. // Delete all rows that have some results
  278. $dataTable->filter('ColumnCallbackDeleteRow',
  279. array(
  280. Metrics::INDEX_SITE_SEARCH_HAS_NO_RESULT,
  281. function ($value) {
  282. return $value < 1;
  283. }
  284. ));
  285. $dataTable->deleteRow(DataTable::ID_SUMMARY_ROW);
  286. $dataTable->deleteColumn(Metrics::INDEX_SITE_SEARCH_HAS_NO_RESULT);
  287. $this->filterPageDatatable($dataTable);
  288. $this->filterActionsDataTable($dataTable);
  289. $this->addPagesPerSearchColumn($dataTable);
  290. return $dataTable;
  291. }
  292. /**
  293. * @param int $idSite
  294. * @param string $period
  295. * @param Date $date
  296. * @param bool $segment
  297. *
  298. * @return DataTable|DataTable\Map
  299. */
  300. public function getSiteSearchCategories($idSite, $period, $date, $segment = false)
  301. {
  302. Actions::checkCustomVariablesPluginEnabled();
  303. $customVariables = APICustomVariables::getInstance()->getCustomVariables($idSite, $period, $date, $segment, $expanded = false, $_leavePiwikCoreVariables = true);
  304. $customVarNameToLookFor = ActionSiteSearch::CVAR_KEY_SEARCH_CATEGORY;
  305. $dataTable = new DataTable();
  306. // Handle case where date=last30&period=day
  307. // FIXMEA: this logic should really be refactored somewhere, this is ugly!
  308. if ($customVariables instanceof DataTable\Map) {
  309. $dataTable = $customVariables->getEmptyClone();
  310. $customVariableDatatables = $customVariables->getDataTables();
  311. $dataTables = $dataTable->getDataTables();
  312. foreach ($customVariableDatatables as $key => $customVariableTableForDate) {
  313. // we do not enter the IF, in the case idSite=1,3 AND period=day&date=datefrom,dateto,
  314. if ($customVariableTableForDate instanceof DataTable
  315. && $customVariableTableForDate->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX)
  316. ) {
  317. $row = $customVariableTableForDate->getRowFromLabel($customVarNameToLookFor);
  318. if ($row) {
  319. $dateRewrite = $customVariableTableForDate->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart()->toString();
  320. $idSubtable = $row->getIdSubDataTable();
  321. $categories = APICustomVariables::getInstance()->getCustomVariablesValuesFromNameId($idSite, $period, $dateRewrite, $idSubtable, $segment);
  322. $dataTable->addTable($categories, $key);
  323. }
  324. }
  325. }
  326. } elseif ($customVariables instanceof DataTable) {
  327. $row = $customVariables->getRowFromLabel($customVarNameToLookFor);
  328. if ($row) {
  329. $idSubtable = $row->getIdSubDataTable();
  330. $dataTable = APICustomVariables::getInstance()->getCustomVariablesValuesFromNameId($idSite, $period, $date, $idSubtable, $segment);
  331. }
  332. }
  333. $this->filterActionsDataTable($dataTable);
  334. $this->addPagesPerSearchColumn($dataTable, $columnToRead = 'nb_actions');
  335. return $dataTable;
  336. }
  337. /**
  338. * Will search in the DataTable for a Label matching the searched string
  339. * and return only the matching row, or an empty datatable
  340. */
  341. protected function getFilterPageDatatableSearch($callBackParameters, $search, $actionType, $table = false,
  342. $searchTree = false)
  343. {
  344. if ($searchTree === false) {
  345. // build the query parts that are searched inside the tree
  346. if ($actionType == Action::TYPE_PAGE_TITLE) {
  347. $searchedString = Common::unsanitizeInputValue($search);
  348. } else {
  349. $idSite = $callBackParameters[1];
  350. try {
  351. $searchedString = PageUrl::excludeQueryParametersFromUrl($search, $idSite);
  352. } catch (Exception $e) {
  353. $searchedString = $search;
  354. }
  355. }
  356. ArchivingHelper::reloadConfig();
  357. $searchTree = ArchivingHelper::getActionExplodedNames($searchedString, $actionType);
  358. }
  359. if ($table === false) {
  360. // fetch the data table
  361. $table = call_user_func_array(array($this, 'getDataTableFromArchive'), $callBackParameters);
  362. if ($table instanceof DataTable\Map) {
  363. // search an array of tables, e.g. when using date=last30
  364. // note that if the root is an array, we filter all children
  365. // if an array occurs inside the nested table, we only look for the first match (see below)
  366. $dataTableMap = $table->getEmptyClone();
  367. foreach ($table->getDataTables() as $label => $subTable) {
  368. $newSubTable = $this->doFilterPageDatatableSearch($callBackParameters, $subTable, $searchTree);
  369. $dataTableMap->addTable($newSubTable, $label);
  370. }
  371. return $dataTableMap;
  372. }
  373. }
  374. return $this->doFilterPageDatatableSearch($callBackParameters, $table, $searchTree);
  375. }
  376. /**
  377. * This looks very similar to LabelFilter.php should it be refactored somehow? FIXME
  378. */
  379. protected function doFilterPageDatatableSearch($callBackParameters, $table, $searchTree)
  380. {
  381. // filter a data table array
  382. if ($table instanceof DataTable\Map) {
  383. foreach ($table->getDataTables() as $subTable) {
  384. $filteredSubTable = $this->doFilterPageDatatableSearch($callBackParameters, $subTable, $searchTree);
  385. if ($filteredSubTable->getRowsCount() > 0) {
  386. // match found in a sub table, return and stop searching the others
  387. return $filteredSubTable;
  388. }
  389. }
  390. // nothing found in all sub tables
  391. return new DataTable;
  392. }
  393. // filter regular data table
  394. if ($table instanceof DataTable) {
  395. // search for the first part of the tree search
  396. $search = array_shift($searchTree);
  397. $row = $table->getRowFromLabel($search);
  398. if ($row === false) {
  399. // not found
  400. $result = new DataTable;
  401. $result->setAllTableMetadata($table->getAllTableMetadata());
  402. return $result;
  403. }
  404. // end of tree search reached
  405. if (count($searchTree) == 0) {
  406. $result = new DataTable();
  407. $result->addRow($row);
  408. $result->setAllTableMetadata($table->getAllTableMetadata());
  409. return $result;
  410. }
  411. // match found on this level and more levels remaining: go deeper
  412. $idSubTable = $row->getIdSubDataTable();
  413. $callBackParameters[6] = $idSubTable;
  414. /**
  415. * @var \Piwik\Period $period
  416. */
  417. $period = $table->getMetadata('period');
  418. if (!empty($period)) {
  419. $callBackParameters[3] = $period->getDateStart() . ',' . $period->getDateEnd();
  420. }
  421. $table = call_user_func_array(array($this, 'getDataTableFromArchive'), $callBackParameters);
  422. return $this->doFilterPageDatatableSearch($callBackParameters, $table, $searchTree);
  423. }
  424. throw new Exception("For this API function, DataTable " . get_class($table) . " is not supported");
  425. }
  426. /**
  427. * Common filters for Page URLs and Page Titles
  428. *
  429. * @param DataTable|DataTable\Simple|DataTable\Map $dataTable
  430. */
  431. protected function filterPageDatatable($dataTable)
  432. {
  433. $columnsToRemove = array('bounce_rate');
  434. $dataTable->queueFilter('ColumnDelete', array($columnsToRemove));
  435. // Average time on page = total time on page / number visits on that page
  436. $dataTable->queueFilter('ColumnCallbackAddColumnQuotient',
  437. array('avg_time_on_page',
  438. 'sum_time_spent',
  439. 'nb_visits',
  440. 0)
  441. );
  442. // Bounce rate = single page visits on this page / visits started on this page
  443. $dataTable->queueFilter('ColumnCallbackAddColumnPercentage',
  444. array('bounce_rate',
  445. 'entry_bounce_count',
  446. 'entry_nb_visits',
  447. 0));
  448. // % Exit = Number of visits that finished on this page / visits on this page
  449. $dataTable->queueFilter('ColumnCallbackAddColumnPercentage',
  450. array('exit_rate',
  451. 'exit_nb_visits',
  452. 'nb_visits',
  453. 0)
  454. );
  455. // Handle performance analytics
  456. $hasTimeGeneration = (array_sum($dataTable->getColumn(Metrics::INDEX_PAGE_SUM_TIME_GENERATION)) > 0);
  457. if ($hasTimeGeneration) {
  458. // Average generation time = total generation time / number of pageviews
  459. $precisionAvgTimeGeneration = 3;
  460. $dataTable->queueFilter('ColumnCallbackAddColumnQuotient',
  461. array('avg_time_generation',
  462. 'sum_time_generation',
  463. 'nb_hits_with_time_generation',
  464. $precisionAvgTimeGeneration)
  465. );
  466. $dataTable->queueFilter('ColumnDelete', array(array('sum_time_generation')));
  467. } else {
  468. // No generation time: remove it from the API output and add it to empty_columns metadata, so that
  469. // the columns can also be removed from the view
  470. $dataTable->filter('ColumnDelete', array(array(
  471. Metrics::INDEX_PAGE_SUM_TIME_GENERATION,
  472. Metrics::INDEX_PAGE_NB_HITS_WITH_TIME_GENERATION,
  473. Metrics::INDEX_PAGE_MIN_TIME_GENERATION,
  474. Metrics::INDEX_PAGE_MAX_TIME_GENERATION
  475. )));
  476. if ($dataTable instanceof DataTable) {
  477. $emptyColumns = $dataTable->getMetadata(DataTable::EMPTY_COLUMNS_METADATA_NAME);
  478. if (!is_array($emptyColumns)) {
  479. $emptyColumns = array();
  480. }
  481. $emptyColumns[] = 'sum_time_generation';
  482. $emptyColumns[] = 'avg_time_generation';
  483. $emptyColumns[] = 'min_time_generation';
  484. $emptyColumns[] = 'max_time_generation';
  485. $dataTable->setMetadata(DataTable::EMPTY_COLUMNS_METADATA_NAME, $emptyColumns);
  486. }
  487. }
  488. }
  489. /**
  490. * Common filters for all Actions API
  491. *
  492. * @param DataTable|DataTable\Simple|DataTable\Map $dataTable
  493. * @param bool $expanded
  494. */
  495. protected function filterActionsDataTable($dataTable, $expanded = false)
  496. {
  497. // Must be applied before Sort in this case, since the DataTable can contain both int and strings indexes
  498. // (in the transition period between pre 1.2 and post 1.2 datatable structure)
  499. $dataTable->filter('ReplaceColumnNames');
  500. $dataTable->filter('Sort', array('nb_visits', 'desc', $naturalSort = false, $expanded));
  501. $dataTable->queueFilter('ReplaceSummaryRowLabel');
  502. }
  503. /**
  504. * Removes DataTable rows referencing actions that were never the first action of a visit.
  505. *
  506. * @param DataTable $dataTable
  507. */
  508. private function filterNonEntryActions($dataTable)
  509. {
  510. $dataTable->filter('ColumnCallbackDeleteRow',
  511. array('entry_nb_visits',
  512. function ($visits) {
  513. return !strlen($visits);
  514. }
  515. )
  516. );
  517. }
  518. /**
  519. * Removes DataTable rows referencing actions that were never the last action of a visit.
  520. *
  521. * @param DataTable $dataTable
  522. */
  523. private function filterNonExitActions($dataTable)
  524. {
  525. $dataTable->filter('ColumnCallbackDeleteRow',
  526. array('exit_nb_visits',
  527. function ($visits) {
  528. return !strlen($visits);
  529. })
  530. );
  531. }
  532. protected function getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded = false, $idSubtable = null, $depth = null)
  533. {
  534. $skipAggregationOfSubTables = false;
  535. if ($period == 'range'
  536. && empty($idSubtable)
  537. && empty($expanded)
  538. && !Request::shouldLoadFlatten()
  539. ) {
  540. $skipAggregationOfSubTables = false;
  541. }
  542. return Archive::getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $idSubtable, $skipAggregationOfSubTables, $depth);
  543. }
  544. }