From c25f396c2452760b9c40c95b6889a3abdfcb317e Mon Sep 17 00:00:00 2001 From: Thomas Steur Date: Wed, 5 Mar 2014 00:53:31 +0100 Subject: [PATCH] refs #57 started to work on movers and shakers and lots of minor improvements --- core/Twig.php | 10 + plugins/Insights/API.php | 235 +++++++++++++----- plugins/Insights/Controller.php | 26 +- .../DataTable/Filter/ExcludeLowValue.php | 28 ++- plugins/Insights/DataTable/Filter/Insight.php | 89 ++++--- plugins/Insights/Insights.php | 3 +- plugins/Insights/Visualizations/Insight.php | 4 +- plugins/Insights/lang/en.json | 9 +- .../stylesheets/insightVisualization.less | 7 + plugins/Insights/templates/index.twig | 5 - .../Insights/templates/insightControls.twig | 50 ++-- .../templates/insightVisualization.twig | 52 +--- .../Insights/templates/overviewWidget.twig | 37 +++ plugins/Insights/templates/table_header.twig | 13 + plugins/Insights/templates/table_row.twig | 15 ++ .../tests/FilterExcludeLowValueTest.php | 33 ++- plugins/Insights/tests/FilterInsightTest.php | 23 ++ 17 files changed, 439 insertions(+), 200 deletions(-) delete mode 100644 plugins/Insights/templates/index.twig create mode 100644 plugins/Insights/templates/overviewWidget.twig create mode 100644 plugins/Insights/templates/table_header.twig create mode 100644 plugins/Insights/templates/table_row.twig diff --git a/core/Twig.php b/core/Twig.php index fd266d0b7bb..4da7a364f83 100644 --- a/core/Twig.php +++ b/core/Twig.php @@ -9,6 +9,7 @@ namespace Piwik; use Exception; +use Piwik\Period\Range; use Piwik\Translate; use Piwik\Visualization\Sparkline; use Piwik\View\RenderTokenParser; @@ -63,6 +64,7 @@ public function __construct() $this->addFilter_truncate(); $this->addFilter_notificiation(); $this->addFilter_percentage(); + $this->addFilter_prettyDate(); $this->twig->addFilter(new Twig_SimpleFilter('implode', 'implode')); $this->twig->addFilter(new Twig_SimpleFilter('ucwords', 'ucwords')); @@ -187,6 +189,14 @@ protected function addFilter_notificiation() $this->twig->addFilter($notificationFunction); } + protected function addFilter_prettyDate() + { + $prettyDate = new Twig_SimpleFilter('prettyDate', function ($dateString, $period) { + return Range::factory($period, $dateString)->getLocalizedShortString(); + }); + $this->twig->addFilter($prettyDate); + } + protected function addFilter_percentage() { $percentage = new Twig_SimpleFilter('percentage', function ($string, $totalValue, $precision = 1) { diff --git a/plugins/Insights/API.php b/plugins/Insights/API.php index f29d301c7ad..9a95624fcf7 100644 --- a/plugins/Insights/API.php +++ b/plugins/Insights/API.php @@ -31,39 +31,57 @@ class API extends \Piwik\Plugin\API const ORDER_BY_ABSOLUTE = 'absolute'; const ORDER_BY_IMPORTANCE = 'importance'; - public function getInsightsOverview($idSite, $period, $date) + private $reportIds = array( + 'Actions_getPageUrls', + 'Actions_getPageTitles', + 'Actions_getDownloads', + 'Referrers_getAll', + 'Referrers_getKeywords', + 'Referrers_getCampaigns', + 'Referrers_getSocials', + 'Referrers_getSearchEngines', + 'UserCountry_getCountry', + ); + + public function getInsightsOverview($idSite, $period, $date, $segment = false) { Piwik::checkUserHasViewAccess(array($idSite)); + $reportTableIds = array(); + /** @var DataTable[] $tables */ - $reports = array( - 'Actions_getPageUrls', - 'Actions_getPageTitles', - 'Actions_getDownloads', - 'Referrers_getAll', - 'Referrers_getKeywords', - 'Referrers_getCampaigns', - 'Referrers_getSocials', - 'Referrers_getSearchEngines', - 'UserCountry_getCountry', - ); - // post event to add other reports? + $tables = array(); + foreach ($this->reportIds as $reportId) { + $firstTableId = DataTable\Manager::getInstance()->getMostRecentTableId(); + $table = $this->getInsights($idSite, $period, $date, $reportId, $segment, 3, 3, '', 2, 25); + $reportTableIds[] = $table->getId(); + $this->deleteDataTables($firstTableId, $reportTableIds); - $reportTableIds = array(); - $dataTableManager = DataTable\Manager::getInstance(); + $tables[] = $table; + } + + $map = new DataTable\Map(); + + foreach ($tables as $table) { + $map->addTable($table, $table->getMetadata('reportName')); + } + + return $map; + } + public function getOverallMoversAndShakers($idSite, $period, $date, $segment = false) + { + Piwik::checkUserHasViewAccess(array($idSite)); + + $reportTableIds = array(); + + /** @var DataTable[] $tables */ $tables = array(); - foreach ($reports as $report) { - $firstTableId = $dataTableManager->getMostRecentTableId(); - $table = $this->getInsightOverview($idSite, $period, $date, $report); + foreach ($this->reportIds as $reportId) { + $firstTableId = DataTable\Manager::getInstance()->getMostRecentTableId(); + $table = $this->getMoversAndShakers($idSite, $period, $date, $reportId, $segment, 4, 4); $reportTableIds[] = $table->getId(); - $lastTableId = $dataTableManager->getMostRecentTableId(); - - for ($index = $firstTableId; $index <= $lastTableId; $index++) { - if (!in_array($index, $reportTableIds)) { - $dataTableManager->deleteTable($index); - } - } + $this->deleteDataTables($firstTableId, $reportTableIds); $tables[] = $table; } @@ -77,18 +95,21 @@ public function getInsightsOverview($idSite, $period, $date) return $map; } - public function getInsightOverview($idSite, $period, $date, $reportUniqueId, $segment = false, $limitIncreaser = 4, - $limitDecreaser = 4, $minVisitsPercent = 3, $minGrowthPercent = 25, $orderBy = 'absolute', - $considerMovers = true, $considerNew = true, $considerDisappeared = false) + public function getMoversAndShakers($idSite, $period, $date, $reportUniqueId, $segment = false, + $limitIncreaser = 4, $limitDecreaser = 4) { + $orderBy = 'absolute'; + $minVisitsPercent = 2; + $minGrowthPercent = 30; + $minMoversPercent = 2; + $minNewPercent = 2; + $minDisappearedPercent = 2; + Piwik::checkUserHasViewAccess(array($idSite)); $metric = 'nb_visits'; - // consider disappeared if impact > 10%? - - $totalValue = $this->getTotalValue($idSite, $period, $date, $metric); - $minVisits = $this->getMinVisits($totalValue, $minVisitsPercent); + $totalValue = $this->getTotalValue($idSite, $period, $date, $metric); $report = $this->getReportByUniqueId($idSite, $reportUniqueId); $currentReport = $this->requestReport($idSite, $period, $date, $report, $metric, $segment); @@ -97,28 +118,29 @@ public function getInsightOverview($idSite, $period, $date, $reportUniqueId, $se // for faster performance just compare against last week? $pastDate = Date::factory($date); $pastDate = $pastDate->subDay(7); - $lastDate = $pastDate->toString(); - $lastReport = $this->requestReport($idSite, 'week', $lastDate, $report, $metric, $segment); + $pastDate = $pastDate->toString(); + $lastReport = $this->requestReport($idSite, 'week', $pastDate, $report, $metric, $segment); $lastReport->filter('Piwik\Plugins\Insights\DataTable\Filter\Average', array($metric, 7)); + $lastDate = Range::factory('week', $pastDate); + $lastDate = $lastDate->getRangeString(); } else { $pastDate = Range::getLastDate($date, $period); if (empty($pastDate[0])) { - return new DataTable(); + throw new \Exception('Not possible to calculate movers and shakers for this date/period combination'); } $lastDate = $pastDate[0]; $lastReport = $this->requestReport($idSite, $period, $lastDate, $report, $metric, $segment); } - return $this->buildInsightsReport($period, $date, $limitIncreaser, $limitDecreaser, $minGrowthPercent, $orderBy, $currentReport, $lastReport, $metric, $considerMovers, $considerNew, $considerDisappeared, $minVisits, $report, $lastDate, $totalValue); + return $this->buildDataTable($report, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minVisitsPercent, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser); } - // force $limitX and ignore minVisitsPercent, minGrowthPercent public function getInsights( - $idSite, $period, $date, $reportUniqueId, $limitIncreaser = 5, $limitDecreaser = 5, + $idSite, $period, $date, $reportUniqueId, $segment = false, $limitIncreaser = 5, $limitDecreaser = 5, $filterBy = '', $minVisitsPercent = 2, $minGrowthPercent = 20, - $comparedToXPeriods = 1, $orderBy = 'absolute', $segment = false) + $comparedToXPeriods = 1, $orderBy = 'absolute') { Piwik::checkUserHasViewAccess(array($idSite)); @@ -127,33 +149,36 @@ public function getInsights( $lastDate = Range::getDateXPeriodsAgo(abs($comparedToXPeriods), $date, $period); + if (empty($lastDate[0])) { + throw new \Exception('Not possible to calculate movers and shakers for this date/period combination'); + } + $currentReport = $this->requestReport($idSite, $period, $date, $report, $metric, $segment); $lastReport = $this->requestReport($idSite, $period, $lastDate[0], $report, $metric, $segment); $totalValue = $this->getRelevantTotalValue($idSite, $period, $date, $currentReport, $metric); - $minVisits = $this->getMinVisits($totalValue, $minVisitsPercent); - $considerMovers = false; - $considerNew = false; - $considerDisappeared = false; + $minMoversPercent = -1; + $minNewPercent = -1; + $minDisappearedPercent = -1; switch ($filterBy) { case self::FILTER_BY_MOVERS: - $considerMovers = true; + $minMoversPercent = 0; break; case self::FILTER_BY_NEW: - $considerNew = true; + $minNewPercent = 0; break; case self::FILTER_BY_DISAPPEARED: - $considerDisappeared = true; + $minDisappearedPercent = 0; break; default: - $considerMovers = true; - $considerNew = true; - $considerDisappeared = true; + $minMoversPercent = 0; + $minNewPercent = 0; + $minDisappearedPercent = 0; } - return $this->buildInsightsReport($period, $date, $limitIncreaser, $limitDecreaser, $minGrowthPercent, $orderBy, $currentReport, $lastReport, $metric, $considerMovers, $considerNew, $considerDisappeared, $minVisits, $report, $lastDate[0], $totalValue); + return $this->buildDataTable($report, $period, $date, $lastDate[0], $metric, $currentReport, $lastReport, $totalValue, $minVisitsPercent, $minMoversPercent, $minNewPercent, $minDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser); } private function requestReport($idSite, $period, $date, $report, $metric, $segment) @@ -197,9 +222,9 @@ private function getOrderByColumn($orderBy) return $orderByColumn; } - private function getMinVisits($totalValue, $minVisitsPercent) + private function getMinVisits($totalValue, $percent) { - $minVisits = ceil(($totalValue / 100) * $minVisitsPercent); + $minVisits = ceil(($totalValue / 100) * $percent); return (int) $minVisits; } @@ -218,8 +243,9 @@ private function getRelevantTotalValue($idSite, $period, $date, DataTable $curre private function getTotalValue($idSite, $period, $date, $metric) { - $visits = VisitsSummaryAPI::getInstance()->get($idSite, $period, $date, false, array($metric)); + $visits = VisitsSummaryAPI::getInstance()->get($idSite, $period, $date, false, array($metric)); $totalValue = $visits->getFirstRow()->getColumn($metric); + return $totalValue; } @@ -236,8 +262,36 @@ private function getMetricTotalValue(DataTable $currentReport, $metric) return $totalValue; } - private function buildInsightsReport($period, $date, $limitIncreaser, $limitDecreaser, $minGrowthPercent, $orderBy, $currentReport, $lastReport, $metric, $considerMovers, $considerNew, $considerDisappeared, $minVisits, $report, $lastDate, $totalValue) + /** + * @param array $reportMetadata + * @param string $period + * @param string $date + * @param string $lastDate + * @param string $metric + * @param DataTable $currentReport + * @param DataTable $lastReport + * @param int $totalValue + * @param int $minVisitsPercent Row must have at least min percent visits of totalVisits + * @param int $minVisitsMoversPercent Exclude rows who moved and the difference is not at least min percent + * visits of totalVisits. -1 excludes movers. + * @param int $minVisitsNewPercent Exclude rows who are new and the difference is not at least min percent + * visits of totalVisits. -1 excludes all new. + * @param int $minVisitsDisappearedPercent Exclude rows who are disappeared and the difference is not at least min + * percent visits of totalVisits. -1 excludes all disappeared. + * @param int $minGrowthPercent The actual growth of a row must be at least percent compared to the + * previous value (not total value) + * @param string $orderBy Order by absolute, relative, importance + * @param int $limitIncreaser + * @param int $limitDecreaser + * @return DataTable + */ + private function buildDataTable($reportMetadata, $period, $date, $lastDate, $metric, $currentReport, $lastReport, $totalValue, $minVisitsPercent, $minVisitsMoversPercent, $minVisitsNewPercent, $minVisitsDisappearedPercent, $minGrowthPercent, $orderBy, $limitIncreaser, $limitDecreaser) { + $minVisits = $this->getMinVisits($totalValue, $minVisitsPercent); + $minChangeMovers = 0; + $minIncreaseNew = 0; + $minDecreaseDisappeared = 0; + $dataTable = new DataTable(); $dataTable->filter( 'Piwik\Plugins\Insights\DataTable\Filter\Insight', @@ -245,9 +299,9 @@ private function buildInsightsReport($period, $date, $limitIncreaser, $limitDecr $currentReport, $lastReport, $metric, - $considerMovers, - $considerNew, - $considerDisappeared + $considerMovers = (-1 !== $minVisitsMoversPercent), + $considerNew = (-1 !== $minVisitsNewPercent), + $considerDisappeared = (-1 !== $minVisitsDisappearedPercent) ) ); @@ -255,7 +309,7 @@ private function buildInsightsReport($period, $date, $limitIncreaser, $limitDecr 'Piwik\Plugins\Insights\DataTable\Filter\MinGrowth', array( 'growth_percent_numeric', - $minGrowthPercent + $minGrowthPercent, ) ); @@ -267,6 +321,42 @@ private function buildInsightsReport($period, $date, $limitIncreaser, $limitDecr ) ); + if ($minVisitsNewPercent) { + $minIncreaseNew = $this->getMinVisits($totalValue, $minVisitsNewPercent); + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue', + array( + 'difference', + $minIncreaseNew, + 'isNew' + ) + ); + } + + if ($minVisitsMoversPercent) { + $minChangeMovers = $this->getMinVisits($totalValue, $minVisitsMoversPercent); + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue', + array( + 'difference', + $minChangeMovers, + 'isMover' + ) + ); + } + + if ($minVisitsDisappearedPercent) { + $minDecreaseDisappeared = $this->getMinVisits($totalValue, $minVisitsDisappearedPercent); + $dataTable->filter( + 'Piwik\Plugins\Insights\DataTable\Filter\ExcludeLowValue', + array( + 'difference', + $minDecreaseDisappeared, + 'isDisappeared' + ) + ); + } + $dataTable->filter( 'Piwik\Plugins\Insights\DataTable\Filter\OrderBy', array( @@ -284,14 +374,22 @@ private function buildInsightsReport($period, $date, $limitIncreaser, $limitDecr ); $dataTable->setMetadataValues(array( - 'reportName' => $report['name'], - 'metricName' => $report['metrics'][$metric], + 'reportName' => $reportMetadata['name'], + 'metricName' => $reportMetadata['metrics'][$metric], 'date' => $date, 'lastDate' => $lastDate, 'period' => $period, - 'report' => $report, + 'report' => $reportMetadata, 'totalValue' => $totalValue, - 'minVisits' => $minVisits + 'minValue' => $minVisits, + 'minChangeMovers' => $minChangeMovers, + 'minIncreaseNew' => $minIncreaseNew, + 'minDecreaseDisappeared' => $minDecreaseDisappeared, + 'minValuePercent' => $minVisitsPercent, + 'minGrowthPercent' => $minGrowthPercent, + 'minVisitsMoversPercent' => $minVisitsMoversPercent, + 'minVisitsNewPercent' => $minVisitsNewPercent, + 'minVisitsDisappearedPercent' => $minVisitsDisappearedPercent )); return $dataTable; @@ -301,6 +399,19 @@ private function getReportByUniqueId($idSite, $reportUniqueId) { $processedReport = new ProcessedReport(); $report = $processedReport->getReportMetadataByUniqueId($idSite, $reportUniqueId); + return $report; } + + private function deleteDataTables($firstTableId, $dataTableIdsToBeIgnored) + { + $dataTableManager = DataTable\Manager::getInstance(); + $lastTableId = $dataTableManager->getMostRecentTableId(); + + for ($index = $firstTableId; $index <= $lastTableId; $index++) { + if (!in_array($index, $dataTableIdsToBeIgnored)) { + $dataTableManager->deleteTable($index); + } + } + } } diff --git a/plugins/Insights/Controller.php b/plugins/Insights/Controller.php index 8526052215c..b9431f5a3c7 100644 --- a/plugins/Insights/Controller.php +++ b/plugins/Insights/Controller.php @@ -18,7 +18,21 @@ class Controller extends \Piwik\Plugin\Controller { - public function getInsightOverview() + public function getInsightsOverview() + { + $view = $this->prepareWidget($apiReport = 'getInsightsOverview'); + + return $view->render(); + } + + public function getOverallMoversAndShakers() + { + $view = $this->prepareWidget($apiReport = 'getOverallMoversAndShakers'); + + return $view->render(); + } + + private function prepareWidget($apiReport) { $idSite = Common::getRequestVar('idSite', null, 'int'); $period = Common::getRequestVar('period', null, 'string'); @@ -26,18 +40,14 @@ public function getInsightOverview() Piwik::checkUserHasViewAccess(array($idSite)); - $view = new View('@Insights/index.twig'); + $view = new View('@Insights/overviewWidget.twig'); $this->setBasicVariablesView($view); - $view->moversAndShakers = API::getInstance()->getInsightsOverview($idSite, $period, $date); - $view->showNoDataMessage = false; - $view->showInsightsControls = false; + $view->reports = API::getInstance()->$apiReport($idSite, $period, $date); $view->properties = array( - 'show_increase' => true, - 'show_decrease' => true, 'order_by' => 'absolute' ); - return $view->render(); + return $view; } } diff --git a/plugins/Insights/DataTable/Filter/ExcludeLowValue.php b/plugins/Insights/DataTable/Filter/ExcludeLowValue.php index aea5d1d9ead..2d2c3ede4b0 100644 --- a/plugins/Insights/DataTable/Filter/ExcludeLowValue.php +++ b/plugins/Insights/DataTable/Filter/ExcludeLowValue.php @@ -14,11 +14,21 @@ class ExcludeLowValue extends DataTable\BaseFilter { private $minimumValue; private $columnToRead; + private $columnToCheckToBeTrue; - public function __construct($table, $columnToRead, $minimumValue) + /** + * @param DataTable $table + * @param string $columnToRead + * @param int $minimumValue + * @param string $columnToCheckToBeTrue if set, we will delete a row only if this column evaluates to true. If + * column does not evaluate to true we will not delete the row even if + * the value is lower than the minimumValue. + */ + public function __construct($table, $columnToRead, $minimumValue, $columnToCheckToBeTrue = '') { $this->columnToRead = $columnToRead; $this->minimumValue = $minimumValue; + $this->columnToCheckToBeTrue = $columnToCheckToBeTrue; } public function filter($table) @@ -27,11 +37,17 @@ public function filter($table) return; } - $minimumValue = $this->minimumValue; - $isValueLowPopulation = function ($value) use ($minimumValue) { - return $value < $minimumValue; - }; + foreach ($table->getRows() as $key => $row) { - $table->filter('ColumnCallbackDeleteRow', array($this->columnToRead, $isValueLowPopulation)); + if ($this->columnToCheckToBeTrue && !$row->getColumn($this->columnToCheckToBeTrue)) { + continue; + } + + $value = $row->getColumn($this->columnToRead); + + if ($this->minimumValue > $value) { + $table->deleteRow($key); + } + } } } \ No newline at end of file diff --git a/plugins/Insights/DataTable/Filter/Insight.php b/plugins/Insights/DataTable/Filter/Insight.php index 44d767cccf8..699d9a6614e 100644 --- a/plugins/Insights/DataTable/Filter/Insight.php +++ b/plugins/Insights/DataTable/Filter/Insight.php @@ -30,53 +30,69 @@ public function __construct($table, $currentDataTable, $pastDataTable, $columnTo public function filter($table) { - foreach ($this->currentDataTable->getRows() as $key => $row) { - $pastRow = $this->getPastRowFromCurrent($row); - $oldValue = 0; + foreach ($this->currentDataTable->getRows() as $row) { + $this->addRowIfNewOrMover($table, $row); + } - if (!$pastRow && !$this->considerNew) { - continue; + if ($this->considerDisappeared) { + foreach ($this->pastDataTable->getRows() as $row) { + $this->addRowIfDisappeared($table, $row); } + } + } - if ($pastRow && $this->considerMovers) { - $oldValue = $pastRow->getColumn($this->columnValueToRead); - } elseif ($pastRow) { - continue; - } + private function addRowIfDisappeared(DataTable $table, DataTable\Row $row) + { + if ($this->getRowFromTable($this->currentDataTable, $row)) { + return; + } - $difference = $this->getDividend($row); - if ($difference === false) { - continue; - } + $newValue = 0; + $oldValue = $row->getColumn($this->columnValueToRead); + $difference = $newValue - $oldValue; + + if ($oldValue == 0 && $newValue == 0) { + $growthPercentage = '0%'; + } else { + $growthPercentage = '-100%'; + } - $newValue = $row->getColumn($this->columnValueToRead); - $divisor = $this->getDivisor($row); + $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference, $isDisappeared = true); + } - $growthPercentage = $this->formatValue($difference, $divisor); + private function addRowIfNewOrMover(DataTable $table, DataTable\Row $row) + { + $pastRow = $this->getPastRowFromCurrent($row); - $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference); + if (!$pastRow && !$this->considerNew) { + return; + } elseif ($pastRow && !$this->considerMovers) { + return; } - if ($this->considerDisappeared) { - foreach ($this->pastDataTable->getRows() as $key => $row) { + $isNew = false; + $isMover = false; + $isDisappeared = false; + + if (!$pastRow) { + $isNew = true; + $oldValue = 0; + } else { + $isMover = true; + $oldValue = $pastRow->getColumn($this->columnValueToRead); + } - if ($this->getRowFromTable($this->currentDataTable, $row)) { - continue; - } + $difference = $this->getDividend($row); + if ($difference === false) { + return; + } - $newValue = 0; - $oldValue = $row->getColumn($this->columnValueToRead); - $difference = $newValue - $oldValue; + $newValue = $row->getColumn($this->columnValueToRead); + $divisor = $this->getDivisor($row); - if ($oldValue == 0 && $newValue == 0) { - $growthPercentage = '0%'; - } else { - $growthPercentage = '-100%'; - } + $growthPercentage = $this->formatValue($difference, $divisor); - $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference); - } - } + $this->addRow($table, $row, $growthPercentage, $newValue, $oldValue, $difference, $isDisappeared, $isNew, $isMover); } private function getRowFromTable(DataTable $table, DataTable\Row $row) @@ -84,7 +100,7 @@ private function getRowFromTable(DataTable $table, DataTable\Row $row) return $table->getRowFromLabel($row->getColumn('label')); } - private function addRow(DataTable $table, DataTable\Row $row, $growthPercentage, $newValue, $oldValue, $difference) + private function addRow(DataTable $table, DataTable\Row $row, $growthPercentage, $newValue, $oldValue, $difference, $disappeared = false, $isNew = false, $isMover = false) { $columns = $row->getColumns(); $columns['growth_percent'] = $growthPercentage; @@ -94,6 +110,9 @@ private function addRow(DataTable $table, DataTable\Row $row, $growthPercentage, $columns['value_new'] = $newValue; $columns['difference'] = $difference; $columns['importance'] = abs($difference); + $columns['isDisappeared'] = $disappeared; + $columns['isNew'] = $isNew; + $columns['isMover'] = $isMover; $table->addRowFromArray(array(DataTable\Row::COLUMNS => $columns)); } diff --git a/plugins/Insights/Insights.php b/plugins/Insights/Insights.php index 1753b32aa8c..9c915ce99d0 100644 --- a/plugins/Insights/Insights.php +++ b/plugins/Insights/Insights.php @@ -34,7 +34,8 @@ public function getAvailableVisualizations(&$visualizations) public function addWidgets() { - WidgetsList::add('Insights_Category', 'Insights_OverviewWidgetTitle', 'Insights', 'getInsightOverview'); + WidgetsList::add('Insights_WidgetCategory', 'Insights_OverviewWidgetTitle', 'Insights', 'getInsightsOverview'); + WidgetsList::add('Insights_WidgetCategory', 'Insights_MoversAndShakersWidgetTitle', 'Insights', 'getOverallMoversAndShakers'); } public function getStylesheetFiles(&$stylesheets) diff --git a/plugins/Insights/Visualizations/Insight.php b/plugins/Insights/Visualizations/Insight.php index f16c913b0fb..cd68023deaf 100644 --- a/plugins/Insights/Visualizations/Insight.php +++ b/plugins/Insights/Visualizations/Insight.php @@ -25,7 +25,7 @@ class Insight extends Visualization { const ID = 'insightsVisualization'; const TEMPLATE_FILE = '@Insights/insightVisualization.twig'; - const FOOTER_ICON_TITLE = 'InsightsVisualization'; + const FOOTER_ICON_TITLE = 'Insights'; const FOOTER_ICON = 'plugins/Insights/images/idea.png'; public function beforeLoadDataTable() @@ -80,8 +80,6 @@ public function isThereDataToDisplay() public function afterAllFiltersAreApplied() { - $this->assignTemplateVar('showNoDataMessage', true); - $this->assignTemplateVar('showInsightsControls', true); $this->assignTemplateVar('period', Common::getRequestVar('period', null, 'string')); } diff --git a/plugins/Insights/lang/en.json b/plugins/Insights/lang/en.json index acc356241a8..f142b6add02 100644 --- a/plugins/Insights/lang/en.json +++ b/plugins/Insights/lang/en.json @@ -1,7 +1,12 @@ { "Insights": { "OverviewWidgetTitle": "Insights Overview", - "Category": "Insights", - "NoResultMatchesCriteria": "No rows match the criteria" + "WidgetCategory": "Insights", + "NoResultMatchesCriteria": "No rows match the criteria", + "MoversAndShakersWidgetTitle": "Movers and Shakers", + "TitleConsideredVisits": "Considered rows having at least %s visits (%s%% of %s visits) with a growth of at least %s%% compared to %s.", + "TitleConsideredChanges": "Considered movers only if they increased or decreased by more than %s visits, new entries only if they increase by more than %s visits, and disappeared rows if they decreased by more than %s visits.", + "TitleReportBasedOn": "Based on %s %s, rows less than %s %s were ignored", + "TitleRowChangeDetails": "'%s' changed from %s (%s) to %s (%s) %s" } } \ No newline at end of file diff --git a/plugins/Insights/stylesheets/insightVisualization.less b/plugins/Insights/stylesheets/insightVisualization.less index b559c9e36a7..a5ed362414b 100644 --- a/plugins/Insights/stylesheets/insightVisualization.less +++ b/plugins/Insights/stylesheets/insightVisualization.less @@ -25,4 +25,11 @@ .notGrown { color:red; } + + table td { + &.labelodd, &.labeleven { + + background-image: none; + } + } } \ No newline at end of file diff --git a/plugins/Insights/templates/index.twig b/plugins/Insights/templates/index.twig deleted file mode 100644 index fc91a813306..00000000000 --- a/plugins/Insights/templates/index.twig +++ /dev/null @@ -1,5 +0,0 @@ -{% for dataTable in moversAndShakers.getDataTables() %} - - {% include "@Insights/insightVisualization.twig" %} - -{% endfor %} \ No newline at end of file diff --git a/plugins/Insights/templates/insightControls.twig b/plugins/Insights/templates/insightControls.twig index d976ecccf8c..d2d3779bd61 100644 --- a/plugins/Insights/templates/insightControls.twig +++ b/plugins/Insights/templates/insightControls.twig @@ -1,5 +1,5 @@
- Minimum impact of + Minimum visits of @@ -25,28 +25,30 @@ {% endfor %} - compared to - {% if period == 'day' %} - - {% elseif period == 'month' %} - + {% if period == 'day' or period == 'month' %} + compared to + {% if period == 'day' %} + + {% elseif period == 'month' %} + + {% endif %} {% endif %}
diff --git a/plugins/Insights/templates/insightVisualization.twig b/plugins/Insights/templates/insightVisualization.twig index 9c9f72c479c..1ca0fac5ecc 100644 --- a/plugins/Insights/templates/insightVisualization.twig +++ b/plugins/Insights/templates/insightVisualization.twig @@ -1,54 +1,24 @@ -
+{% set metadata = dataTable.getAllTableMetadata%} +{% set consideredVisits = 'Insights_TitleConsideredVisits'|translate(metadata.minValue, metadata.minValuePercent, metadata.totalValue, metadata.minGrowthPercent, metadata.lastDate|prettyDate(metadata.period)) %} + +
{% if dataTable.getRowsCount > 0 %} - - - - - + {% include "@Insights/table_header.twig" %} - - - {% for row in dataTable.getRows %} - - - {% if row.getColumn('grown') %} - - - {% else %} - - - {% endif %} - - {% endfor %} + + {% for row in dataTable.getRows %} + {% include "@Insights/table_row.twig" %} + {% endfor %}
- {{ dataTable.getMetadata('reportName') }} - - {{ dataTable.getMetadata('metricName') }} - - {{ 'MultiSites_Evolution'|translate }} -
- - {{ row.getColumn('label') }} - - +{{ row.getColumn('difference') }} - +{{ row.getColumn('growth_percent') }} - {{ row.getColumn('difference') }} - {{ row.getColumn('growth_percent') }} -
- {% elseif showNoDataMessage %} + {% else %}
{{ 'Insights_NoResultMatchesCriteria'|translate }}
{% endif %} - {% if showInsightsControls %} - {% include "@Insights/insightControls.twig" %} - {% endif %} + {% include "@Insights/insightControls.twig" %}
\ No newline at end of file diff --git a/plugins/Insights/templates/overviewWidget.twig b/plugins/Insights/templates/overviewWidget.twig new file mode 100644 index 00000000000..ca6898b3988 --- /dev/null +++ b/plugins/Insights/templates/overviewWidget.twig @@ -0,0 +1,37 @@ +{% set allMetadata = reports.getFirstRow.getAllTableMetadata %} + +{% set consideredVisits = 'Insights_TitleConsideredVisits'|translate(allMetadata.minValue, allMetadata.minValuePercent, allMetadata.totalValue, allMetadata.minGrowthPercent, allMetadata.lastDate|prettyDate(allMetadata.period)) %} +{% set consideredChanges = '' %} + +{% if allMetadata.minChangeMovers or allMetadata.minIncreaseNew or allMetadata.minDecreaseDisappeared %} + {% set consideredChanges = 'Insights_TitleConsideredChanges'|translate(allMetadata.minChangeMovers, allMetadata.minIncreaseNew, allMetadata.minDecreaseDisappeared) %} +{% endif %} + +
+ {% if reports.getColumns|length > 0 %} + + + {% for dataTable in reports.getDataTables() if dataTable.getRowsCount > 0 %} + {% set metadata = dataTable.getAllTableMetadata %} + + + {% include "@Insights/table_header.twig" %} + + + + {% for row in dataTable.getRows %} + {% include "@Insights/table_row.twig" %} + {% endfor %} + + + {% endfor %} +
+ + {% else %} + +
+ {{ 'Insights_NoResultMatchesCriteria'|translate }} +
+ + {% endif %} +
\ No newline at end of file diff --git a/plugins/Insights/templates/table_header.twig b/plugins/Insights/templates/table_header.twig new file mode 100644 index 00000000000..7226f884504 --- /dev/null +++ b/plugins/Insights/templates/table_header.twig @@ -0,0 +1,13 @@ + + + {{ metadata.reportName }} + + + {{ metadata.metricName }} + + + {{ 'MultiSites_Evolution'|translate }} + + \ No newline at end of file diff --git a/plugins/Insights/templates/table_row.twig b/plugins/Insights/templates/table_row.twig new file mode 100644 index 00000000000..bd3b04a2e73 --- /dev/null +++ b/plugins/Insights/templates/table_row.twig @@ -0,0 +1,15 @@ + + + + {{ row.getColumn('label') }} + + + + {% if row.getColumn('grown') %} + +{{ row.getColumn('difference') }} + +{{ row.getColumn('growth_percent') }} + {% else %} + {{ row.getColumn('difference') }} + {{ row.getColumn('growth_percent') }} + {% endif %} + \ No newline at end of file diff --git a/plugins/Insights/tests/FilterExcludeLowValueTest.php b/plugins/Insights/tests/FilterExcludeLowValueTest.php index e9080c85da3..45ddf8075e7 100644 --- a/plugins/Insights/tests/FilterExcludeLowValueTest.php +++ b/plugins/Insights/tests/FilterExcludeLowValueTest.php @@ -29,17 +29,17 @@ public function setUp() { $this->table = new DataTable(); $this->table->addRowsFromArray(array( - array(Row::COLUMNS => array('label' => 'val1', 'growth' => 22)), - array(Row::COLUMNS => array('label' => 'val2', 'growth' => 14)), - array(Row::COLUMNS => array('label' => 'val3', 'growth' => 18)), - array(Row::COLUMNS => array('label' => 'val4', 'growth' => 20)), - array(Row::COLUMNS => array('label' => 'val5', 'growth' => 22)), - array(Row::COLUMNS => array('label' => 'val6', 'growth' => 25)), - array(Row::COLUMNS => array('label' => 'val7', 'growth' => 17)), - array(Row::COLUMNS => array('label' => 'val8', 'growth' => 20)), - array(Row::COLUMNS => array('label' => 'val9', 'growth' => 0)), - array(Row::COLUMNS => array('label' => 'val10', 'growth' => 15)), - array(Row::COLUMNS => array('label' => 'val11', 'growth' => 16)) + array(Row::COLUMNS => array('label' => 'val1', 'growth' => 22, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val2', 'growth' => 14, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val3', 'growth' => 18, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val4', 'growth' => 20, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val5', 'growth' => 22, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val6', 'growth' => 25, 'isFooBar' => true)), + array(Row::COLUMNS => array('label' => 'val7', 'growth' => 17, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val8', 'growth' => 20, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val9', 'growth' => 0, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val10', 'growth' => 15, 'isFooBar' => false)), + array(Row::COLUMNS => array('label' => 'val11', 'growth' => 16, 'isFooBar' => true)) )); } @@ -74,15 +74,22 @@ public function testShouldRemoveAllIfMinValueIsTooHigh() $this->assertOrder(array()); } + public function testShouldRemoveValuesOnlyIfColumnToCheckIsTrue() + { + $this->excludeLowValues(21, 'isFooBar'); + + $this->assertOrder(array('val1', 'val3', 'val5', 'val6', 'val7', 'val8', 'val9', 'val10')); + } + private function assertOrder($expectedOrder) { $this->assertEquals($expectedOrder, $this->table->getColumn('label')); $this->assertEquals(count($expectedOrder), $this->table->getRowsCount()); } - private function excludeLowValues($minimumValue) + private function excludeLowValues($minimumValue, $columnToCheck = null) { - $filter = new ExcludeLowValue($this->table, 'growth', $minimumValue); + $filter = new ExcludeLowValue($this->table, 'growth', $minimumValue, $columnToCheck); $filter->filter($this->table); } diff --git a/plugins/Insights/tests/FilterInsightTest.php b/plugins/Insights/tests/FilterInsightTest.php index 4a6431ce8aa..f122f93aa79 100644 --- a/plugins/Insights/tests/FilterInsightTest.php +++ b/plugins/Insights/tests/FilterInsightTest.php @@ -148,6 +148,29 @@ public function testShouldDetectWhetherColumGrownOrNot() $this->assertColumnValues($values); } + public function testShouldDetectWhetherRowIsNewMoverOrDisappeared() + { + $this->applyInsightConsiderAll(); + + $values = array( + array('label' => 'val1', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val2', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val3', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val4', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val5', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val6', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val7', 'isNew' => true, 'isMover' => false, 'isDisappeared' => false), + array('label' => 'val8', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val9', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val10', 'isNew' => false, 'isMover' => true, 'isDisappeared' => false), + array('label' => 'val102', 'isNew' => false, 'isMover' => false, 'isDisappeared' => true), + array('label' => 'val109', 'isNew' => false, 'isMover' => false, 'isDisappeared' => true), + array('label' => 'val107', 'isNew' => false, 'isMover' => false, 'isDisappeared' => true) + ); + + $this->assertColumnValues($values); + } + public function testShouldCalculateDifferenceAndGrowthPercentage() { $this->applyInsightConsiderAll();