diff --git a/Classes/Dashboard/Widgets/NewestPageviewsList.php b/Classes/Dashboard/Provider/NewestPageviews.php similarity index 55% rename from Classes/Dashboard/Widgets/NewestPageviewsList.php rename to Classes/Dashboard/Provider/NewestPageviews.php index b2c2d07..4350a42 100644 --- a/Classes/Dashboard/Widgets/NewestPageviewsList.php +++ b/Classes/Dashboard/Provider/NewestPageviews.php @@ -1,6 +1,6 @@ @@ -21,67 +21,57 @@ namespace DanielSiepmann\Tracking\Dashboard\Widgets; * 02110-1301, USA. */ -use DanielSiepmann\Tracking\Extension; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\Query\QueryBuilder; -use TYPO3\CMS\Core\Utility\ArrayUtility; -use TYPO3\CMS\Dashboard\Widgets\AbstractListWidget; +use TYPO3\CMS\Dashboard\Widgets\Interfaces\ListDataProviderInterface; -class NewestPageviewsList extends AbstractListWidget +class NewestPageviews implements ListDataProviderInterface { - protected $title = Extension::LANGUAGE_PATH . ':dashboard.widgets.newestPageviewsList.title'; - - protected $description = Extension::LANGUAGE_PATH . ':dashboard.widgets.newestPageviewsList.description'; - - protected $width = 2; - - protected $height = 4; - /** * @var QueryBuilder */ - protected $queryBuilder; + private $queryBuilder; /** - * @var \ArrayObject + * @var int */ - private $settings; + private $maxResults; + + /** + * @var array + */ + private $blackListedPages; public function __construct( - string $identifier, QueryBuilder $queryBuilder, - \ArrayObject $settings + int $maxResults = 6, + array $blackListedPages = [] ) { - parent::__construct($identifier); - $this->queryBuilder = $queryBuilder; - $this->settings = $settings; + $this->maxResults = $maxResults; + $this->blackListedPages = $blackListedPages; } - public function renderWidgetContent(): string + public function getItems(): array { - $this->generateItems(); - return parent::renderWidgetContent(); - } + $preparedItems = []; - protected function generateItems(): void - { $constraints = []; - if (count($this->settings['blackListedPages'])) { + if (count($this->blackListedPages)) { $constraints[] = $this->queryBuilder->expr()->notIn( 'tx_tracking_pageview.pid', $this->queryBuilder->createNamedParameter( - $this->settings['blackListedPages'], + $this->blackListedPages, Connection::PARAM_INT_ARRAY ) ); } $this->queryBuilder - ->select('*') + ->select('url', 'user_agent') ->from('tx_tracking_pageview') ->orderBy('crdate', 'desc') - ->setMaxResults($this->settings['maxResults']); + ->setMaxResults($this->maxResults); if ($constraints !== []) { $this->queryBuilder->where(... $constraints); @@ -89,14 +79,13 @@ class NewestPageviewsList extends AbstractListWidget $items = $this->queryBuilder->execute()->fetchAll(); foreach ($items as $item) { - $this->items[] = [ - 'link' => $item['url'], - 'title' => sprintf( - '%s - %s', - $item['url'], - $item['user_agent'] - ), - ]; + $preparedItems[] = sprintf( + '%s - %s', + $item['url'], + $item['user_agent'] + ); } + + return $preparedItems; } } diff --git a/Classes/Dashboard/Widgets/PageViewsBar.php b/Classes/Dashboard/Provider/PageviewsPerDay.php similarity index 60% rename from Classes/Dashboard/Widgets/PageViewsBar.php rename to Classes/Dashboard/Provider/PageviewsPerDay.php index dd8831c..34dfda1 100644 --- a/Classes/Dashboard/Widgets/PageViewsBar.php +++ b/Classes/Dashboard/Provider/PageviewsPerDay.php @@ -1,6 +1,6 @@ @@ -24,52 +24,63 @@ namespace DanielSiepmann\Tracking\Dashboard\Widgets; use DanielSiepmann\Tracking\Extension; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\Query\QueryBuilder; -use TYPO3\CMS\Core\Utility\ArrayUtility; -use TYPO3\CMS\Dashboard\Widgets\AbstractBarChartWidget; +use TYPO3\CMS\Core\Localization\LanguageService; +use TYPO3\CMS\Dashboard\WidgetApi; +use TYPO3\CMS\Dashboard\Widgets\Interfaces\ChartDataProviderInterface; -class PageViewsBar extends AbstractBarChartWidget +class PageviewsPerDay implements ChartDataProviderInterface { - protected $title = Extension::LANGUAGE_PATH . ':dashboard.widgets.pageViewsBar.title'; - - protected $description = Extension::LANGUAGE_PATH . ':dashboard.widgets.pageViewsBar.description'; - - protected $width = 2; - - protected $height = 4; + /** + * @var LanguageService + */ + private $languageService; /** * @var QueryBuilder */ - protected $queryBuilder; + private $queryBuilder; /** - * @var \ArrayObject + * @var int */ - private $settings; + private $days; + + /** + * @var array + */ + private $blackListedPages; + + /** + * @var string + */ + private $dateFormat; public function __construct( - string $identifier, + LanguageService $languageService, QueryBuilder $queryBuilder, - \ArrayObject $settings + int $days = 31, + array $blackListedPages = [], + string $dateFormat = 'Y-m-d' ) { - parent::__construct($identifier); - $this->queryBuilder = $queryBuilder; - $this->settings = $settings; + $this->days = $days; + $this->languageService = $languageService; + $this->blackListedPages = $blackListedPages; + $this->dateFormat = $dateFormat; } - protected function prepareChartData(): void + public function getChartData(): array { - list($labels, $data) = $this->calculateDataForLastDays((int) $this->settings['periodInDays']); + list($labels, $data) = $this->calculateData(); - $this->chartData = [ + return [ 'labels' => $labels, 'datasets' => [ [ - 'label' => $this->getLanguageService()->sL( - 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:widgets.pageViewsBar.chart.dataSet.0' + 'label' => $this->languageService->sL( + Extension::LANGUAGE_PATH . 'widgets.pageViewsBar.chart.dataSet.0' ), - 'backgroundColor' => $this->chartColors[0], + 'backgroundColor' => WidgetApi::getDefaultChartColors()[0], 'border' => 0, 'data' => $data ] @@ -77,18 +88,42 @@ class PageViewsBar extends AbstractBarChartWidget ]; } - protected function getPageViewsInPeriod(int $start, int $end): int + private function calculateData(): array + { + $labels = []; + $data = []; + + for ($daysBefore = $this->days; $daysBefore >= 0; $daysBefore--) { + $timeForLabel = strtotime('-' . $daysBefore . ' day'); + $startPeriod = strtotime('-' . $daysBefore . ' day 0:00:00'); + $endPeriod = strtotime('-' . $daysBefore . ' day 23:59:59'); + + if ($timeForLabel === false || $startPeriod === false || $endPeriod === false) { + continue; + } + + $labels[] = date($this->dateFormat, $timeForLabel); + $data[] = $this->getPageviewsInPeriod($startPeriod, $endPeriod); + } + + return [ + $labels, + $data, + ]; + } + + private function getPageviewsInPeriod(int $start, int $end): int { $constraints = [ $this->queryBuilder->expr()->gte('crdate', $start), $this->queryBuilder->expr()->lte('crdate', $end), ]; - if (count($this->settings['blackListedPages'])) { + if (count($this->blackListedPages)) { $constraints[] = $this->queryBuilder->expr()->notIn( 'tx_tracking_pageview.pid', $this->queryBuilder->createNamedParameter( - $this->settings['blackListedPages'], + $this->blackListedPages, Connection::PARAM_INT_ARRAY ) ); @@ -101,30 +136,4 @@ class PageViewsBar extends AbstractBarChartWidget ->execute() ->fetchColumn(); } - - protected function calculateDataForLastDays(int $days): array - { - $labels = []; - $data = []; - - $format = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] ?: 'Y-m-d'; - - for ($daysBefore = $days; $daysBefore >= 0; $daysBefore--) { - $timeForLabel = strtotime('-' . $daysBefore . ' day'); - $startPeriod = strtotime('-' . $daysBefore . ' day 0:00:00'); - $endPeriod = strtotime('-' . $daysBefore . ' day 23:59:59'); - - if ($timeForLabel === false || $startPeriod === false || $endPeriod === false) { - continue; - } - - $labels[] = date($format, $timeForLabel); - $data[] = $this->getPageViewsInPeriod($startPeriod, $endPeriod); - } - - return [ - $labels, - $data, - ]; - } } diff --git a/Classes/Dashboard/Widgets/PageViewsPerPageDoughnut.php b/Classes/Dashboard/Provider/PageviewsPerPage.php similarity index 66% rename from Classes/Dashboard/Widgets/PageViewsPerPageDoughnut.php rename to Classes/Dashboard/Provider/PageviewsPerPage.php index 46d6ec2..e8b72d1 100644 --- a/Classes/Dashboard/Widgets/PageViewsPerPageDoughnut.php +++ b/Classes/Dashboard/Provider/PageviewsPerPage.php @@ -1,6 +1,6 @@ @@ -25,64 +25,78 @@ use DanielSiepmann\Tracking\Extension; use Doctrine\DBAL\ParameterType; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\Query\QueryBuilder; -use TYPO3\CMS\Dashboard\Widgets\AbstractDoughnutChartWidget; +use TYPO3\CMS\Dashboard\WidgetApi; +use TYPO3\CMS\Dashboard\Widgets\Interfaces\ChartDataProviderInterface; -class PageViewsPerPageDoughnut extends AbstractDoughnutChartWidget +class PageviewsPerPage implements ChartDataProviderInterface { - protected $title = Extension::LANGUAGE_PATH . ':dashboard.widgets.pageViewsPerPageDoughnut.title'; - - protected $description = Extension::LANGUAGE_PATH . ':dashboard.widgets.pageViewsPerPageDoughnut.description'; - /** * @var QueryBuilder */ - protected $queryBuilder; + private $queryBuilder; /** - * @var \ArrayObject + * @var int */ - private $settings; + private $days; + + /** + * @var int + */ + private $maxResults; + + /** + * @var array + */ + private $blackListedPages; public function __construct( - string $identifier, QueryBuilder $queryBuilder, - \ArrayObject $settings + int $days = 31, + int $maxResults = 6, + array $blackListedPages = [] ) { - parent::__construct($identifier); - $this->queryBuilder = $queryBuilder; - $this->settings = $settings; + $this->days = $days; + $this->blackListedPages = $blackListedPages; + $this->maxResults = $maxResults; } - protected function prepareChartData(): void + public function getChartData(): array { - list($labels, $data) = $this->getPageViewsPerPage((int) $this->settings['periodInDays']); + list($labels, $data) = $this->getPageviewsPerPage(); - $this->chartData = [ + return [ 'labels' => $labels, 'datasets' => [ [ - 'backgroundColor' => $this->chartColors, + 'backgroundColor' => WidgetApi::getDefaultChartColors(), 'data' => $data, ] ], ]; } - private function getPageViewsPerPage(int $days): array + private function getPageviewsPerPage(): array { $labels = []; $data = []; $constraints = [ - $this->queryBuilder->expr()->gte('tx_tracking_pageview.crdate', strtotime('-' . $days . ' day 0:00:00')), - $this->queryBuilder->expr()->lte('tx_tracking_pageview.crdate', time()), + $this->queryBuilder->expr()->gte( + 'tx_tracking_pageview.crdate', + strtotime('-' . $this->days . ' day 0:00:00') + ), + $this->queryBuilder->expr()->lte( + 'tx_tracking_pageview.crdate', + time() + ), ]; - if (count($this->settings['blackListedPages'])) { + if (count($this->blackListedPages)) { $constraints[] = $this->queryBuilder->expr()->notIn( 'tx_tracking_pageview.pid', $this->queryBuilder->createNamedParameter( - $this->settings['blackListedPages'], + $this->blackListedPages, Connection::PARAM_INT_ARRAY ) ); @@ -104,7 +118,7 @@ class PageViewsPerPageDoughnut extends AbstractDoughnutChartWidget ->where(... $constraints) ->groupBy('tx_tracking_pageview.pid') ->orderBy('total', 'desc') - ->setMaxResults($this->settings['maxResults']) + ->setMaxResults($this->maxResults) ->execute() ->fetchAll(); diff --git a/Classes/Dashboard/Widgets/SettingsFactory.php b/Classes/Dashboard/Widgets/SettingsFactory.php deleted file mode 100644 index 37cb84d..0000000 --- a/Classes/Dashboard/Widgets/SettingsFactory.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -class SettingsFactory -{ - /** - * @var array - */ - private $defaults = [ - 'pageViewsBar' => [ - 'periodInDays' => 31, - 'blackListedPages' => [], - 'maxResults' => 6, - ], - 'pageViewsPerPageDoughnut' => [ - 'periodInDays' => 31, - 'blackListedPages' => [], - 'maxResults' => 6, - ], - 'newestPageviewsList' => [ - 'blackListedPages' => [], - 'maxResults' => 6, - ], - ]; - - public function fromArray(string $widgetIdentifier, array $settings): \ArrayObject - { - $settingsToUse = $this->defaults[$widgetIdentifier] ?? []; - - ArrayUtility::mergeRecursiveWithOverrule($settingsToUse, $settings); - - return new \ArrayObject($settingsToUse); - } -} diff --git a/Configuration/Backend/DashboardWidgets.yaml b/Configuration/Backend/DashboardWidgets.yaml new file mode 100644 index 0000000..8c85103 --- /dev/null +++ b/Configuration/Backend/DashboardWidgets.yaml @@ -0,0 +1,67 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + DanielSiepmann\Tracking\Dashboard\: + resource: '../Classes/Dashboard/*' + + DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerDay: + arguments: + $queryBuilder: '@querybuilder.tx_tracking_pageview' + + dashboard.widget.danielsiepmann_tracking.pageViewsPerDay: + class: 'TYPO3\CMS\Dashboard\Widgets\BarChartWidget' + arguments: + $view: '@dashboard.views.widget' + $dataProvider: '@DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerDay' + tags: + - name: 'dashboard.widget' + identifier: 'pageViewsBar' + groupNames: 'tracking' + iconIdentifier: 'content-widget-chart-bar' + title: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.pageViewsBar.title' + description: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.pageViewsBar.description' + additionalCssClasses: 'dashboard-item--chart' + height: 'medium' + width: 'small' + + DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerPage: + arguments: + $queryBuilder: '@querybuilder.tx_tracking_pageview' + + dashboard.widget.danielsiepmann_tracking.pageViewsPerPage: + class: 'TYPO3\CMS\Dashboard\Widgets\DoughnutChartWidget' + arguments: + $view: '@dashboard.views.widget' + $dataProvider: '@DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerPage' + tags: + - name: 'dashboard.widget' + identifier: 'pageViewsPerPageDoughnut' + groupNames: 'tracking' + iconIdentifier: 'content-widget-chart-bar' + title: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.pageViewsPerPageDoughnut.title' + description: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.pageViewsPerPageDoughnut.description' + additionalCssClasses: 'dashboard-item--chart' + height: 'medium' + width: 'small' + + DanielSiepmann\Tracking\Dashboard\Provider\NewestPageviews: + arguments: + $queryBuilder: '@querybuilder.tx_tracking_pageview' + + dashboard.widget.danielsiepmann_tracking.newestPageviews: + class: 'TYPO3\CMS\Dashboard\Widgets\ListWidget' + arguments: + $view: '@dashboard.views.widget' + $dataProvider: '@DanielSiepmann\Tracking\Dashboard\Provider\NewestPageviews' + tags: + - name: 'dashboard.widget' + identifier: 'newestPageviewsList' + groupNames: 'tracking' + iconIdentifier: 'content-widget-list' + title: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.newestPageviewsList.title' + description: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.newestPageviewsList.description' + height: 'medium' + width: 'small' diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index 38d6e73..ae6fdbc 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -1,3 +1,6 @@ +imports: + - { resource: Backend/DashboardWidgets.yaml } + services: _defaults: autowire: true @@ -6,50 +9,28 @@ services: DanielSiepmann\Tracking\: resource: '../Classes/*' + exclude: '../Classes/Dashboard/*' - # Virtual services - - DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsBar: - factory: - - '@DanielSiepmann\Tracking\Dashboard\Widgets\SettingsFactory' - - 'fromArray' - arguments: - $widgetIdentifier: 'pageViewsBar' - $settings: [] - DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsPerPageDoughnut: - factory: - - '@DanielSiepmann\Tracking\Dashboard\Widgets\SettingsFactory' - - 'fromArray' - arguments: - $widgetIdentifier: 'pageViewsPerPageDoughnut' - $settings: [] - DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\NewestPageviewsList: - factory: - - '@DanielSiepmann\Tracking\Dashboard\Widgets\SettingsFactory' - - 'fromArray' - arguments: - $widgetIdentifier: 'newestPageviewsList' - $settings: [] - - DanielSiepmann\Tracking\DI\DatabaseConnection\Pageview: + dbconnection.tx_tracking_pageview: + class: 'TYPO3\CMS\Core\Database\Connection' factory: - '@TYPO3\CMS\Core\Database\ConnectionPool' - 'getConnectionForTable' arguments: - 'tx_tracking_pageview' - DanielSiepmann\Tracking\DI\QueryBuilder\PageView: + + querybuilder.tx_tracking_pageview: + class: 'TYPO3\CMS\Core\Database\Query\QueryBuilder' factory: - '@TYPO3\CMS\Core\Database\ConnectionPool' - 'getQueryBuilderForTable' arguments: - 'tx_tracking_pageview' - # Existing classes - DanielSiepmann\Tracking\Domain\Repository\Pageview: public: true arguments: - - '@DanielSiepmann\Tracking\DI\DatabaseConnection\Pageview' + - '@dbconnection.tx_tracking_pageview' DanielSiepmann\Tracking\Middleware\Pageview: public: true @@ -60,38 +41,3 @@ services: and not (request.getHeader("User-Agent")[0] matches "/Wget|curl|Go-http-client/") and not (request.getHeader("User-Agent")[0] matches "/Googlebot|Bingbot|bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Sogou|Exabot|NextCloud-News|Feedly|XING FeedReader|CCBot|SemrushBot|SEOkicks|Twitterbot|Seekport Crawler|SemanticScholarBot|ia_archiver|PaperLiBot|TrendsmapResolver|AhrefsBot|Nuzzel/") and not (request.getHeader("User-Agent")[0] matches "/mattermost|Slackbot|WhatsApp/") - - # Dashboard Widgets - - DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsBar: - class: 'DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsBar' - arguments: - $identifier: 'pageViewsBar' - $queryBuilder: '@DanielSiepmann\Tracking\DI\QueryBuilder\PageView' - $settings: '@DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsBar' - tags: - - name: 'dashboard.widget' - identifier: 'pageViewsBar' - widgetGroups: 'tracking' - - DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsPerPageDoughnut: - class: 'DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsPerPageDoughnut' - arguments: - $identifier: 'pageViewsPerPageDoughnut' - $queryBuilder: '@DanielSiepmann\Tracking\DI\QueryBuilder\PageView' - $settings: '@DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsPerPageDoughnut' - tags: - - name: 'dashboard.widget' - identifier: 'pageViewsPerPageDoughnut' - widgetGroups: 'tracking' - - DanielSiepmann\Tracking\Dashboard\Widgets\NewestPageviewsList: - class: 'DanielSiepmann\Tracking\Dashboard\Widgets\NewestPageviewsList' - arguments: - $identifier: 'newestPageviewsList' - $queryBuilder: '@DanielSiepmann\Tracking\DI\QueryBuilder\PageView' - $settings: '@DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\NewestPageviewsList' - tags: - - name: 'dashboard.widget' - identifier: 'newestPageviewsList' - widgetGroups: 'tracking' diff --git a/Tests/Unit/Dashboard/Provider/NewestPageviewsTest.php b/Tests/Unit/Dashboard/Provider/NewestPageviewsTest.php new file mode 100644 index 0000000..178297e --- /dev/null +++ b/Tests/Unit/Dashboard/Provider/NewestPageviewsTest.php @@ -0,0 +1,185 @@ + + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use DanielSiepmann\Tracking\Dashboard\Provider\NewestPageviews; +use Doctrine\DBAL\Driver\Statement; +use PHPUnit\Framework\TestCase; +use Prophecy\Argument; +use Prophecy\PhpUnit\ProphecyTrait; +use TYPO3\CMS\Core\Database\Connection; +use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder; +use TYPO3\CMS\Core\Database\Query\QueryBuilder; + +/** + * @covers DanielSiepmann\Tracking\Dashboard\Provider\NewestPageviews + */ +class NewestPageviewsTest extends TestCase +{ + use ProphecyTrait; + + /** + * @test + */ + public function defaultsToMaxResultsOf6(): void + { + $statement = $this->prophesize(Statement::class); + $statement->fetchAll()->willReturn([]); + + $queryBuilder = $this->prophesize(QueryBuilder::class); + $queryBuilder->select(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->from(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->orderBy(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->setMaxResults(6)->willReturn($queryBuilder->reveal())->shouldBeCalled(); + $queryBuilder->execute()->willReturn($statement->reveal()); + + $subject = new NewestPageviews($queryBuilder->reveal()); + $subject->getItems(); + } + + /** + * @test + */ + public function respectsMaxResults(): void + { + $statement = $this->prophesize(Statement::class); + $statement->fetchAll()->willReturn([]); + + $queryBuilder = $this->prophesize(QueryBuilder::class); + $queryBuilder->select(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->from(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->orderBy(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->setMaxResults(1)->willReturn($queryBuilder->reveal())->shouldBeCalled(); + $queryBuilder->execute()->willReturn($statement->reveal()); + + $subject = new NewestPageviews($queryBuilder->reveal(), 1); + $subject->getItems(); + } + + /** + * @test + */ + public function defaultsToNoBlackListedPages(): void + { + $statement = $this->prophesize(Statement::class); + $statement->fetchAll()->willReturn([]); + + $queryBuilder = $this->prophesize(QueryBuilder::class); + $queryBuilder->select(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->from(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->orderBy(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->setMaxResults(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->execute()->willReturn($statement->reveal()); + + $queryBuilder->where()->shouldNotBeCalled(); + + $subject = new NewestPageviews($queryBuilder->reveal()); + $subject->getItems(); + } + + /** + * @test + */ + public function respectsBlackListedPages(): void + { + $expressionBuilder = $this->prophesize(ExpressionBuilder::class); + $queryBuilder = $this->prophesize(QueryBuilder::class); + $statement = $this->prophesize(Statement::class); + + $statement->fetchAll()->willReturn([]); + + $expressionBuilder->notIn( + 'tx_tracking_pageview.pid', + '10, 11' + )->willReturn('tx_tracking_pageview.pid NOT IN (10, 11)')->shouldBeCalled(); + $queryBuilder->createNamedParameter( + [10, 11], + Connection::PARAM_INT_ARRAY + )->willReturn('10, 11')->shouldBeCalled(); + $queryBuilder->where( + 'tx_tracking_pageview.pid NOT IN (10, 11)' + )->willReturn($queryBuilder->reveal())->shouldBeCalled(); + + $queryBuilder->expr()->willReturn($expressionBuilder->reveal()); + $queryBuilder->select(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->from(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->orderBy(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->setMaxResults(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->execute()->willReturn($statement->reveal()); + + $subject = new NewestPageviews($queryBuilder->reveal(), 6, [10, 11]); + $subject->getItems(); + } + + /** + * @test + */ + public function runsQueryWithExpectedValues(): void + { + $statement = $this->prophesize(Statement::class); + $statement->fetchAll()->willReturn([]); + + $queryBuilder = $this->prophesize(QueryBuilder::class); + $queryBuilder->select('url', 'user_agent')->willReturn($queryBuilder->reveal())->shouldBeCalled(); + $queryBuilder->from('tx_tracking_pageview')->willReturn($queryBuilder->reveal())->shouldBeCalled(); + $queryBuilder->orderBy('crdate', 'desc')->willReturn($queryBuilder->reveal())->shouldBeCalled(); + $queryBuilder->setMaxResults(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->execute()->willReturn($statement->reveal()); + + $subject = new NewestPageviews($queryBuilder->reveal()); + $subject->getItems(); + } + + /** + * @test + */ + public function returnsSimpleList(): void + { + $statement = $this->prophesize(Statement::class); + $statement->fetchAll()->willReturn([ + [ + 'url' => 'https://example.com/path/file.html', + 'user_agent' => 'Mozilla/5.0 (user agent)', + ], + [ + 'url' => 'https://example.com/path/file2.html', + 'user_agent' => 'Mozilla/5.0 (another user agent)', + ], + ]); + + $queryBuilder = $this->prophesize(QueryBuilder::class); + $queryBuilder->select(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->from(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->orderBy(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->setMaxResults(Argument::cetera())->willReturn($queryBuilder->reveal()); + $queryBuilder->execute()->willReturn($statement->reveal()); + + $subject = new NewestPageviews($queryBuilder->reveal()); + static::assertSame( + [ + 'https://example.com/path/file.html - Mozilla/5.0 (user agent)', + 'https://example.com/path/file2.html - Mozilla/5.0 (another user agent)', + ], + $subject->getItems() + ); + } +}