diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bab92bb..a00cd33 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -58,5 +58,8 @@ jobs: - name: Code Quality (by PHPStan) run: ./vendor/bin/phpstan analyse - - name: PHPUnit Tests + - name: PHPUnit Unit Tests run: ./vendor/bin/phpunit --testdox + + - name: PHPUnit Functional Tests + run: ./vendor/bin/phpunit -c Tests/Functional/phpunit.xml.dist --testdox diff --git a/Classes/Dashboard/Provider/NewestPageviews.php b/Classes/Dashboard/Provider/NewestPageviews.php index b8653c9..cafa707 100644 --- a/Classes/Dashboard/Provider/NewestPageviews.php +++ b/Classes/Dashboard/Provider/NewestPageviews.php @@ -71,6 +71,7 @@ class NewestPageviews implements ListDataProviderInterface ->select('url', 'user_agent') ->from('tx_tracking_pageview') ->orderBy('crdate', 'desc') + ->addOrderBy('uid', 'desc') ->setMaxResults($this->maxResults); if ($constraints !== []) { diff --git a/Classes/Dashboard/Provider/PageviewsPerDay.php b/Classes/Dashboard/Provider/PageviewsPerDay.php index 9856b18..0dc2e29 100644 --- a/Classes/Dashboard/Provider/PageviewsPerDay.php +++ b/Classes/Dashboard/Provider/PageviewsPerDay.php @@ -62,9 +62,9 @@ class PageviewsPerDay implements ChartDataProviderInterface array $pagesToExclude = [], string $dateFormat = 'Y-m-d' ) { + $this->languageService = $languageService; $this->queryBuilder = $queryBuilder; $this->days = $days; - $this->languageService = $languageService; $this->pagesToExclude = $pagesToExclude; $this->dateFormat = $dateFormat; } @@ -98,10 +98,6 @@ class PageviewsPerDay implements ChartDataProviderInterface $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); } diff --git a/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php b/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php index 2507de8..3dda1a9 100644 --- a/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php +++ b/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php @@ -77,10 +77,6 @@ class PageviewsPerOperatingSystem implements ChartDataProviderInterface 'tx_tracking_pageview.crdate', strtotime('-' . $this->days . ' day 0:00:00') ), - $this->queryBuilder->expr()->lte( - 'tx_tracking_pageview.crdate', - time() - ), $this->queryBuilder->expr()->neq( 'tx_tracking_pageview.operating_system', $this->queryBuilder->createNamedParameter('') @@ -94,6 +90,7 @@ class PageviewsPerOperatingSystem implements ChartDataProviderInterface ->where(... $constraints) ->groupBy('tx_tracking_pageview.operating_system') ->orderBy('total', 'desc') + ->addOrderBy('operating_system', 'asc') ->setMaxResults($this->maxResults) ->execute() ->fetchAll(); diff --git a/Classes/Dashboard/Provider/PageviewsPerPage.php b/Classes/Dashboard/Provider/PageviewsPerPage.php index b92775e..fb94704 100644 --- a/Classes/Dashboard/Provider/PageviewsPerPage.php +++ b/Classes/Dashboard/Provider/PageviewsPerPage.php @@ -23,8 +23,10 @@ namespace DanielSiepmann\Tracking\Dashboard\Provider; use DanielSiepmann\Tracking\Extension; use Doctrine\DBAL\ParameterType; +use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\Query\QueryBuilder; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Dashboard\WidgetApi; use TYPO3\CMS\Dashboard\Widgets\ChartDataProviderInterface; @@ -35,6 +37,11 @@ class PageviewsPerPage implements ChartDataProviderInterface */ private $queryBuilder; + /** + * @var PageRepository + */ + private $pageRepository; + /** * @var int */ @@ -50,16 +57,25 @@ class PageviewsPerPage implements ChartDataProviderInterface */ private $pagesToExclude; + /** + * @var array + */ + private $languageLimitation; + public function __construct( QueryBuilder $queryBuilder, + PageRepository $pageRepository, int $days = 31, int $maxResults = 6, - array $pagesToExclude = [] + array $pagesToExclude = [], + array $languageLimitation = [] ) { $this->queryBuilder = $queryBuilder; + $this->pageRepository = $pageRepository; $this->days = $days; - $this->pagesToExclude = $pagesToExclude; $this->maxResults = $maxResults; + $this->pagesToExclude = $pagesToExclude; + $this->languageLimitation = $languageLimitation; } public function getChartData(): array @@ -87,10 +103,6 @@ class PageviewsPerPage implements ChartDataProviderInterface 'tx_tracking_pageview.crdate', strtotime('-' . $this->days . ' day 0:00:00') ), - $this->queryBuilder->expr()->lte( - 'tx_tracking_pageview.crdate', - time() - ), ]; if (count($this->pagesToExclude)) { $constraints[] = $this->queryBuilder->expr()->notIn( @@ -102,9 +114,19 @@ class PageviewsPerPage implements ChartDataProviderInterface ); } + if (count($this->languageLimitation)) { + $constraints[] = $this->queryBuilder->expr()->in( + 'tx_tracking_pageview.sys_language_uid', + $this->queryBuilder->createNamedParameter( + $this->languageLimitation, + Connection::PARAM_INT_ARRAY + ) + ); + } + $result = $this->queryBuilder ->selectLiteral('count(tx_tracking_pageview.pid) as total') - ->addSelect('pages.title', 'pages.uid') + ->addSelect('pages.uid', 'tx_tracking_pageview.sys_language_uid') ->from('tx_tracking_pageview') ->leftJoin( 'tx_tracking_pageview', @@ -118,12 +140,13 @@ class PageviewsPerPage implements ChartDataProviderInterface ->where(... $constraints) ->groupBy('tx_tracking_pageview.pid') ->orderBy('total', 'desc') + ->addOrderBy('tx_tracking_pageview.uid', 'desc') ->setMaxResults($this->maxResults) ->execute() ->fetchAll(); foreach ($result as $row) { - $labels[] = mb_strimwidth($row['title'], 0, 25, '…'); + $labels[] = $this->getRecordTitle($row['uid'], $row['sys_language_uid']); $data[] = $row['total']; } @@ -132,4 +155,14 @@ class PageviewsPerPage implements ChartDataProviderInterface $data, ]; } + + private function getRecordTitle(int $uid, int $sysLanguageUid): string + { + $record = BackendUtility::getRecord('pages', $uid); + if ($sysLanguageUid > 0 && count($this->languageLimitation) === 1 && $record !== null) { + $record = $this->pageRepository->getRecordOverlay('pages', $record, $sysLanguageUid); + } + + return BackendUtility::getRecordTitle('pages', $record, true); + } } diff --git a/Classes/Dashboard/Provider/Recordviews.php b/Classes/Dashboard/Provider/Recordviews.php index a9a25be..bd72070 100644 --- a/Classes/Dashboard/Provider/Recordviews.php +++ b/Classes/Dashboard/Provider/Recordviews.php @@ -24,12 +24,14 @@ namespace DanielSiepmann\Tracking\Dashboard\Provider; use DanielSiepmann\Tracking\Extension; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Statement; +use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\Connection; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Query\QueryBuilder; use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction; use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction; use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Dashboard\WidgetApi; use TYPO3\CMS\Dashboard\Widgets\ChartDataProviderInterface; @@ -40,6 +42,11 @@ class Recordviews implements ChartDataProviderInterface */ private $connectionPool; + /** + * @var PageRepository + */ + private $pageRepository; + /** * @var QueryBuilder */ @@ -60,6 +67,11 @@ class Recordviews implements ChartDataProviderInterface */ private $pagesToExclude; + /** + * @var array + */ + private $languageLimitation; + /** * @var array */ @@ -72,17 +84,21 @@ class Recordviews implements ChartDataProviderInterface public function __construct( ConnectionPool $connectionPool, + PageRepository $pageRepository, QueryBuilder $queryBuilder, int $days = 31, int $maxResults = 6, array $pagesToExclude = [], + array $languageLimitation = [], array $recordTableLimitation = [], array $recordTypeLimitation = [] ) { $this->connectionPool = $connectionPool; + $this->pageRepository = $pageRepository; $this->queryBuilder = $queryBuilder; $this->days = $days; $this->pagesToExclude = $pagesToExclude; + $this->languageLimitation = $languageLimitation; $this->maxResults = $maxResults; $this->recordTableLimitation = $recordTableLimitation; $this->recordTypeLimitation = $recordTypeLimitation; @@ -109,7 +125,11 @@ class Recordviews implements ChartDataProviderInterface $data = []; foreach ($this->getRecordviewsRecords() as $recordview) { - $record = $this->getRecord($recordview['record_uid'], $recordview['record_table_name']); + $record = $this->getRecord( + $recordview['record_uid'], + $recordview['record_table_name'], + $recordview['sys_language_uid'] + ); if ( $this->recordTypeLimitation !== [] @@ -134,11 +154,7 @@ class Recordviews implements ChartDataProviderInterface $this->queryBuilder->expr()->gte( 'tx_tracking_recordview.crdate', strtotime('-' . $this->days . ' day 0:00:00') - ), - $this->queryBuilder->expr()->lte( - 'tx_tracking_recordview.crdate', - time() - ), + ) ]; if (count($this->pagesToExclude)) { @@ -151,6 +167,16 @@ class Recordviews implements ChartDataProviderInterface ); } + if (count($this->languageLimitation)) { + $constraints[] = $this->queryBuilder->expr()->in( + 'tx_tracking_recordview.sys_language_uid', + $this->queryBuilder->createNamedParameter( + $this->languageLimitation, + Connection::PARAM_INT_ARRAY + ) + ); + } + if (count($this->recordTableLimitation)) { $constraints[] = $this->queryBuilder->expr()->in( 'tx_tracking_recordview.record_table_name', @@ -163,11 +189,12 @@ class Recordviews implements ChartDataProviderInterface $result = $this->queryBuilder ->selectLiteral('count(record) as total') - ->addSelect('record_uid', 'record_table_name') + ->addSelect('record_uid', 'record_table_name', 'sys_language_uid') ->from('tx_tracking_recordview') ->where(... $constraints) ->groupBy('record') ->orderBy('total', 'desc') + ->addOrderBy('uid', 'desc') ->setMaxResults($this->maxResults) ->execute(); @@ -176,31 +203,20 @@ class Recordviews implements ChartDataProviderInterface } } - private function getRecord(int $recordUid, string $recordTable): array - { - $titlefield = $GLOBALS['TCA'][$recordTable]['ctrl']['label']; - $recordTypeField = $GLOBALS['TCA'][$recordTable]['ctrl']['type'] ?? ''; + private function getRecord( + int $uid, + string $table, + int $sysLanguageUid + ): array { + $recordTypeField = $GLOBALS['TCA'][$table]['ctrl']['type'] ?? ''; - $queryBuilder = $this->connectionPool->getQueryBuilderForTable($recordTable); - - $queryBuilder->getRestrictions() - ->removeByType(StartTimeRestriction::class) - ->removeByType(EndTimeRestriction::class) - ->removeByType(HiddenRestriction::class) - ; - - $queryBuilder->select($titlefield) - ->from($recordTable) - ->where('uid = ' . $recordUid); - - if ($recordTypeField !== '') { - $queryBuilder->addSelect($recordTypeField); + $record = BackendUtility::getRecord($table, $uid); + if ($sysLanguageUid > 0 && count($this->languageLimitation) === 1 && $record !== null) { + $record = $this->pageRepository->getRecordOverlay($table, $record, $sysLanguageUid); } - $record = $queryBuilder->execute()->fetch(); - return [ - 'title' => $record[$titlefield], + 'title' => BackendUtility::getRecordTitle($table, $record, true), 'type' => $record[$recordTypeField] ?? '', ]; } diff --git a/Documentation/PageviewWidgets/PageviewsPerDay.rst b/Documentation/PageviewWidgets/PageviewsPerDay.rst index 192b35b..956e07f 100644 --- a/Documentation/PageviewWidgets/PageviewsPerDay.rst +++ b/Documentation/PageviewWidgets/PageviewsPerDay.rst @@ -24,7 +24,6 @@ Default widget configuration. DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerDay: arguments: $queryBuilder: '@querybuilder.tx_tracking_pageview' - $blackListedPages: [1, 11, 38] $pagesToExclude: [1, 11, 38] dashboard.widget.danielsiepmann.tracking.pageViewsPerDay: diff --git a/Documentation/PageviewWidgets/PageviewsPerPage.rst b/Documentation/PageviewWidgets/PageviewsPerPage.rst index ab32f8c..b5ca6e1 100644 --- a/Documentation/PageviewWidgets/PageviewsPerPage.rst +++ b/Documentation/PageviewWidgets/PageviewsPerPage.rst @@ -66,3 +66,13 @@ Options This becomes handy if certain pages are called in order to show specific records. In those cases the pages will be called very often but don't provide much benefit and can be excluded. Use this in combination with :ref:`recordview` to show the records instead. + +.. option:: $languageLimitation + + Array of ``sys_language_uid``'s to include. + Defaults to empty array, all languages are shown. + + Allows to limit results to specific lanuages. + All entries tracked when visiting page with this language are shown. + If multiple languages are shown, default system language labels are used. + If only a single lanugage is allowed, record labels are translated to that language. diff --git a/Documentation/RecordviewWidgets/Recordviews.rst b/Documentation/RecordviewWidgets/Recordviews.rst index 516f331..954572e 100644 --- a/Documentation/RecordviewWidgets/Recordviews.rst +++ b/Documentation/RecordviewWidgets/Recordviews.rst @@ -101,3 +101,13 @@ Options Using this option offers a way to limit records e.g. to specific types of news or address records. + +.. option:: $languageLimitation + + Array of ``sys_language_uid``'s to include. + Defaults to empty array, all languages are shown. + + Allows to limit results to specific lanuages. + All entries tracked when visiting page with this language are shown. + If multiple languages are shown, default system language labels are used. + If only a single lanugage is allowed, record labels are translated to that language. diff --git a/Tests/Functional/Command/UpdateDataCommandTest.php b/Tests/Functional/Command/UpdateDataCommandTest.php new file mode 100644 index 0000000..ac85d23 --- /dev/null +++ b/Tests/Functional/Command/UpdateDataCommandTest.php @@ -0,0 +1,96 @@ + + * + * 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\Command\UpdateDataCommand; +use Symfony\Component\Console\Tester\CommandTester; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; + +/** + * @covers DanielSiepmann\Tracking\Command\UpdateDataCommand + */ +class UpdateDataCommandTest extends TestCase +{ + protected $testExtensionsToLoad = [ + 'typo3conf/ext/tracking', + ]; + + protected $pathsToLinkInTestInstance = [ + 'typo3conf/ext/tracking/Tests/Functional/Fixtures/sites' => 'typo3conf/sites', + ]; + + /** + * @test + */ + public function updatesAllEntriesWithMissingOperatingSystem(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml'); + + $subject = GeneralUtility::makeInstance(UpdateDataCommand::class); + $tester = new CommandTester($subject); + $tester->execute([], ['capture_stderr_separately' => true]); + + static::assertSame(0, $tester->getStatusCode()); + + $records = $this->getAllRecords('tx_tracking_pageview'); + static::assertCount(2, $records); + static::assertSame('Linux', $records[0]['operating_system']); + static::assertSame('Android', $records[1]['operating_system']); + } + + /** + * @test + */ + public function doesNotChangeExistingOperatingSystem(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithOperatingSystem.xml'); + + $subject = GeneralUtility::makeInstance(UpdateDataCommand::class); + $tester = new CommandTester($subject); + $tester->execute([], ['capture_stderr_separately' => true]); + + static::assertSame(0, $tester->getStatusCode()); + + $records = $this->getAllRecords('tx_tracking_pageview'); + static::assertCount(2, $records); + static::assertSame('Linux', $records[0]['operating_system']); + static::assertSame('Android', $records[1]['operating_system']); + } + + /** + * @test + */ + public function doesNothingIfNoRecordExists(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + + $subject = GeneralUtility::makeInstance(UpdateDataCommand::class); + $tester = new CommandTester($subject); + $tester->execute([], ['capture_stderr_separately' => true]); + + static::assertSame(0, $tester->getStatusCode()); + + $records = $this->getAllRecords('tx_tracking_pageview'); + static::assertCount(0, $records); + } +} diff --git a/Tests/Functional/Dashboard/Provider/NewestPageviewsTest.php b/Tests/Functional/Dashboard/Provider/NewestPageviewsTest.php new file mode 100644 index 0000000..bb70fcf --- /dev/null +++ b/Tests/Functional/Dashboard/Provider/NewestPageviewsTest.php @@ -0,0 +1,123 @@ + + * + * 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 TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; + +/** + * @covers DanielSiepmann\Tracking\Dashboard\Provider\NewestPageviews + */ +class NewestPageviewsTest extends TestCase +{ + protected $testExtensionsToLoad = [ + 'typo3conf/ext/tracking', + ]; + + /** + * @test + */ + public function returnsRecentSixPageviews(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'url' => 'Url ' . $i, + 'user_agent' => 'User-Agent ' . $i, + 'crdate' => $i, + ]); + } + + $subject = new NewestPageviews( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + ); + + static::assertSame([ + 'Url 10 - User-Agent 10', + 'Url 9 - User-Agent 9', + 'Url 8 - User-Agent 8', + 'Url 7 - User-Agent 7', + 'Url 6 - User-Agent 6', + 'Url 5 - User-Agent 5', + ], $subject->getItems()); + } + + /** + * @test + */ + public function respectsMaxResults(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'url' => 'Url ' . $i, + 'user_agent' => 'User-Agent ' . $i, + 'crdate' => $i, + ]); + } + + $subject = new NewestPageviews( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + 2 + ); + + static::assertSame([ + 'Url 10 - User-Agent 10', + 'Url 9 - User-Agent 9', + ], $subject->getItems()); + } + + /** + * @test + */ + public function respectsPagesToExclude(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'url' => 'Url ' . $i, + 'user_agent' => 'User-Agent ' . $i, + 'crdate' => $i, + ]); + } + + $subject = new NewestPageviews( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + 6, + [9] + ); + + static::assertSame([ + 'Url 10 - User-Agent 10', + 'Url 8 - User-Agent 8', + 'Url 7 - User-Agent 7', + 'Url 6 - User-Agent 6', + 'Url 5 - User-Agent 5', + 'Url 4 - User-Agent 4', + ], $subject->getItems()); + } +} diff --git a/Tests/Functional/Dashboard/Provider/PageviewsPerDayTest.php b/Tests/Functional/Dashboard/Provider/PageviewsPerDayTest.php new file mode 100644 index 0000000..f811c10 --- /dev/null +++ b/Tests/Functional/Dashboard/Provider/PageviewsPerDayTest.php @@ -0,0 +1,146 @@ + + * + * 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\PageviewsPerDay; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Localization\LanguageService; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; + +/** + * @covers DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerDay + */ +class PageviewsPerDayTest extends TestCase +{ + protected $testExtensionsToLoad = [ + 'typo3conf/ext/tracking', + ]; + + /** + * @test + */ + public function listsResultsForLast31DaysByDefault(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + } + + $subject = new PageviewsPerDay( + GeneralUtility::makeInstance(LanguageService::class), + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + ); + + $result = $subject->getChartData(); + static::assertCount(32, $result['labels']); + static::assertCount(32, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedNumberOfDays(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + } + + $subject = new PageviewsPerDay( + GeneralUtility::makeInstance(LanguageService::class), + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + 3 + ); + + $result = $subject->getChartData(); + static::assertCount(4, $result['labels']); + static::assertSame([ + 1, + 1, + 1, + 0, + ], $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedExcludedPages(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + } + + $subject = new PageviewsPerDay( + GeneralUtility::makeInstance(LanguageService::class), + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + 3, + [2] + ); + + $result = $subject->getChartData(); + static::assertCount(4, $result['labels']); + static::assertSame([ + 1, + 0, + 1, + 0, + ], $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedDateFormat(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + + $subject = new PageviewsPerDay( + GeneralUtility::makeInstance(LanguageService::class), + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + 1, + [], + 'd.m.Y' + ); + + $result = $subject->getChartData(); + static::assertSame([ + date('d.m.Y', strtotime('-1 day')), + date('d.m.Y'), + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } +} diff --git a/Tests/Functional/Dashboard/Provider/PageviewsPerOperatingSystemTest.php b/Tests/Functional/Dashboard/Provider/PageviewsPerOperatingSystemTest.php new file mode 100644 index 0000000..311f534 --- /dev/null +++ b/Tests/Functional/Dashboard/Provider/PageviewsPerOperatingSystemTest.php @@ -0,0 +1,175 @@ + + * + * 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\PageviewsPerOperatingSystem; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; + +/** + * @covers DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerOperatingSystem + */ +class PageviewsPerOperatingSystemTest extends TestCase +{ + protected $testExtensionsToLoad = [ + 'typo3conf/ext/tracking', + ]; + + /** + * @test + */ + public function listsSixResultsForLast31DaysByDefault(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'operating_system' => 'System ' . $i, + 'crdate' => time(), + ]); + } + + $subject = new PageviewsPerOperatingSystem( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'System 1', + 'System 10', + 'System 2', + 'System 3', + 'System 4', + 'System 5', + ], $result['labels']); + static::assertCount(6, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedOrdering(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'operating_system' => 'System 1', + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'operating_system' => 'System 2', + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 3, + 'operating_system' => 'System 3', + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'operating_system' => 'System 2', + 'crdate' => time(), + ]); + + $subject = new PageviewsPerOperatingSystem( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'System 2', + 'System 1', + 'System 3', + ], $result['labels']); + static::assertCount(3, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedNumberOfDays(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'operating_system' => 'System 1', + 'crdate' => strtotime('-3 days'), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'operating_system' => 'System 2', + 'crdate' => strtotime('-2 days'), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 3, + 'operating_system' => 'System 3', + 'crdate' => strtotime('-1 days'), + ]); + + $subject = new PageviewsPerOperatingSystem( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + 2 + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'System 2', + 'System 3', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedMaxResults(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'operating_system' => 'System ' . $i, + 'crdate' => time(), + ]); + } + + $subject = new PageviewsPerOperatingSystem( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + 31, + 4 + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'System 1', + 'System 10', + 'System 2', + 'System 3', + ], $result['labels']); + static::assertCount(4, $result['datasets'][0]['data']); + } +} diff --git a/Tests/Functional/Dashboard/Provider/PageviewsPerPageTest.php b/Tests/Functional/Dashboard/Provider/PageviewsPerPageTest.php new file mode 100644 index 0000000..abaf8ae --- /dev/null +++ b/Tests/Functional/Dashboard/Provider/PageviewsPerPageTest.php @@ -0,0 +1,299 @@ + + * + * 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\PageviewsPerPage; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; + +/** + * @covers DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerPage + */ +class PageviewsPerPageTest extends TestCase +{ + protected $testExtensionsToLoad = [ + 'typo3conf/ext/tracking', + ]; + + /** + * @test + */ + public function listsSixResultsForLast31DaysByDefault(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'crdate' => time(), + ]); + } + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class) + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Page 10', + 'Page 9', + 'Page 8', + 'Page 7', + 'Page 6', + 'Page 5', + ], $result['labels']); + static::assertCount(6, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedOrdering(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 3, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'crdate' => time(), + ]); + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class) + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Page 2', + 'Page 3', + 'Page 1', + ], $result['labels']); + static::assertCount(3, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedNumberOfDays(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'crdate' => strtotime('-3 days'), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'crdate' => strtotime('-2 days'), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 3, + 'crdate' => strtotime('-1 days'), + ]); + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class), + 2 + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Page 3', + 'Page 2', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedMaxResults(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'crdate' => time(), + ]); + } + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class), + 31, + 4 + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Page 10', + 'Page 9', + 'Page 8', + 'Page 7', + ], $result['labels']); + static::assertCount(4, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedExcludedPages(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'crdate' => time(), + ]); + } + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class), + 31, + 6, + [1,2,3,4,5,6] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Page 10', + 'Page 9', + 'Page 8', + 'Page 7', + ], $result['labels']); + static::assertCount(4, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function localizedRecordTitlesIfLimitedToSingleLanguage(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'sys_language_uid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'sys_language_uid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 3, + 'crdate' => time(), + ]); + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class), + 31, + 6, + [], + [1] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Page 2', + 'Seite 1', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function defaultLanguageTitleIsUsedIfMultipleLanguagesAreAllowed(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Pages.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'sys_language_uid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 2, + 'sys_language_uid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 3, + 'crdate' => time(), + ]); + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class), + 31, + 6, + [], + [1, '0'] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Page 2', + 'Page 1', + 'Page 3', + ], $result['labels']); + static::assertCount(3, $result['datasets'][0]['data']); + } +} diff --git a/Tests/Functional/Dashboard/Provider/RecordviewsTest.php b/Tests/Functional/Dashboard/Provider/RecordviewsTest.php new file mode 100644 index 0000000..1dfb91e --- /dev/null +++ b/Tests/Functional/Dashboard/Provider/RecordviewsTest.php @@ -0,0 +1,437 @@ + + * + * 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\Recordviews; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Domain\Repository\PageRepository; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; + +/** + * @covers DanielSiepmann\Tracking\Dashboard\Provider\Recordviews + */ +class RecordviewsTest extends TestCase +{ + protected $testExtensionsToLoad = [ + 'typo3conf/ext/tracking', + ]; + + /** + * @test + */ + public function listsSixResultsForLast31DaysByDefault(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'sys_category_' . $i, + 'record_uid' => $i, + 'record_table_name' => 'sys_category', + ]); + } + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview') + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 10', + 'Category 9', + 'Category 8', + 'Category 7', + 'Category 6', + 'Category 5', + ], $result['labels']); + static::assertCount(6, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedOrdering(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'sys_category_1', + 'record_uid' => 1, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'sys_category_2', + 'record_uid' => 2, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'sys_category_3', + 'record_uid' => 3, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'sys_category_2', + 'record_uid' => 2, + 'record_table_name' => 'sys_category', + ]); + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 2 + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 2', + 'Category 3', + 'Category 1', + ], $result['labels']); + static::assertCount(3, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedNumberOfDays(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => strtotime('-3 days'), + 'record' => 'sys_category_1', + 'record_uid' => 1, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => strtotime('-2 days'), + 'record' => 'sys_category_2', + 'record_uid' => 2, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => strtotime('-1 day'), + 'record' => 'sys_category_3', + 'record_uid' => 3, + 'record_table_name' => 'sys_category', + ]); + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 2 + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 3', + 'Category 2', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedMaxResults(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'sys_category_' . $i, + 'record_uid' => $i, + 'record_table_name' => 'sys_category', + ]); + } + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 31, + 2 + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 10', + 'Category 9', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedExcludedPages(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_recordview', [ + 'pid' => $i, + 'crdate' => time(), + 'record' => 'sys_category_' . $i, + 'record_uid' => $i, + 'record_table_name' => 'sys_category', + ]); + } + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 31, + 6, + [1,2,3,4,5] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 10', + 'Category 9', + 'Category 8', + 'Category 7', + 'Category 6', + ], $result['labels']); + static::assertCount(5, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectLimitesTables(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + for ($i = 1; $i <= 3; $i++) { + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'sys_category_' . $i, + 'record_uid' => $i, + 'record_table_name' => 'sys_category', + ]); + } + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'tt_content_1', + 'record_uid' => 1, + 'record_table_name' => 'tt_content', + ]); + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 31, + 6, + [], + [], + ['sys_category'] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 3', + 'Category 2', + 'Category 1', + ], $result['labels']); + static::assertCount(3, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectsLimitedTypes(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + for ($i = 1; $i <= 3; $i++) { + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'record' => 'tt_content_' . $i, + 'record_uid' => $i, + 'record_table_name' => 'tt_content', + ]); + $connection->insert('tt_content', [ + 'uid' => $i, + 'CType' => $i, + 'header' => 'Content element ' . $i, + ]); + } + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 31, + 6, + [], + [], + [], + ['1',2] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Content element 2', + 'Content element 1', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function localizedRecordTitlesIfLimitedToSingleLanguage(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'sys_language_uid' => 0, + 'record' => 'sys_category_1', + 'record_uid' => 1, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'sys_language_uid' => 1, + 'record' => 'sys_category_1', + 'record_uid' => 1, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'sys_language_uid' => 1, + 'record' => 'sys_category_2', + 'record_uid' => 2, + 'record_table_name' => 'sys_category', + ]); + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 31, + 6, + [], + [1], + [], + [] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 2', + 'Kategorie 1', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function defaultLanguageTitleIsUsedIfMultipleLanguagesAreAllowed(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/SysCategories.xml'); + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_recordview'); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'sys_language_uid' => 0, + 'record' => 'sys_category_1', + 'record_uid' => 1, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'sys_language_uid' => 1, + 'record' => 'sys_category_1', + 'record_uid' => 1, + 'record_table_name' => 'sys_category', + ]); + $connection->insert('tx_tracking_recordview', [ + 'crdate' => time(), + 'sys_language_uid' => 1, + 'record' => 'sys_category_2', + 'record_uid' => 2, + 'record_table_name' => 'sys_category', + ]); + + $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); + /* @var ConnectionPool $connectionPool */ + + $subject = new Recordviews( + $connectionPool, + GeneralUtility::makeInstance(PageRepository::class), + $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + 31, + 6, + [], + [1, 0], + [], + [] + ); + + $result = $subject->getChartData(); + static::assertSame([ + 'Category 1', + 'Category 2', + ], $result['labels']); + static::assertCount(2, $result['datasets'][0]['data']); + } +} diff --git a/Tests/Functional/Fixtures/Pages.xml b/Tests/Functional/Fixtures/Pages.xml new file mode 100644 index 0000000..de52539 --- /dev/null +++ b/Tests/Functional/Fixtures/Pages.xml @@ -0,0 +1,60 @@ + + + + 1 + 1 + Page 1 + + + 1 + 11 + Seite 1 + 1 + 1 + + + 1 + 2 + Page 2 + + + 1 + 3 + Page 3 + + + 1 + 4 + Page 4 + + + 1 + 5 + Page 5 + + + 1 + 6 + Page 6 + + + 1 + 7 + Page 7 + + + 1 + 8 + Page 8 + + + 1 + 9 + Page 9 + + + 1 + 10 + Page 10 + + diff --git a/Tests/Functional/Fixtures/SysCategories.xml b/Tests/Functional/Fixtures/SysCategories.xml new file mode 100644 index 0000000..d7eb56a --- /dev/null +++ b/Tests/Functional/Fixtures/SysCategories.xml @@ -0,0 +1,49 @@ + + + + 1 + Category 1 + + + 11 + Kategorie 1 + 1 + 1 + + + 2 + Category 2 + + + 3 + Category 3 + + + 4 + Category 4 + + + 5 + Category 5 + + + 6 + Category 6 + + + 7 + Category 7 + + + 8 + Category 8 + + + 9 + Category 9 + + + 10 + Category 10 + + diff --git a/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml b/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml new file mode 100644 index 0000000..88a86ea --- /dev/null +++ b/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml @@ -0,0 +1,22 @@ + + + + 0 + 1 + + + + 1 + 1 + https://example.com/path + Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36 + + + + 1 + 2 + https://example.com/path + Dalvik/2.1.0 (Linux; U; Android 9; ONEPLUS A3003 Build/PKQ1.181203.001) + + + diff --git a/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithOperatingSystem.xml b/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithOperatingSystem.xml new file mode 100644 index 0000000..e8cb0ae --- /dev/null +++ b/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithOperatingSystem.xml @@ -0,0 +1,22 @@ + + + + 0 + 1 + + + + 1 + 1 + https://example.com/path + Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36 + Linux + + + 1 + 2 + https://example.com/path + Dalvik/2.1.0 (Linux; U; Android 9; ONEPLUS A3003 Build/PKQ1.181203.001) + Android + + diff --git a/Tests/Functional/Fixtures/sites/example/config.yaml b/Tests/Functional/Fixtures/sites/example/config.yaml new file mode 100644 index 0000000..53e8851 --- /dev/null +++ b/Tests/Functional/Fixtures/sites/example/config.yaml @@ -0,0 +1,16 @@ +base: 'https://example.com' +languages: + - + title: English + enabled: true + languageId: '0' + base: / + typo3Language: default + locale: en_US.utf8 + iso-639-1: en + navigationTitle: English + hreflang: en-us + direction: ltr + flag: us + websiteTitle: '' +rootPageId: 1 diff --git a/Tests/Functional/phpunit.xml.dist b/Tests/Functional/phpunit.xml.dist new file mode 100644 index 0000000..444932f --- /dev/null +++ b/Tests/Functional/phpunit.xml.dist @@ -0,0 +1,32 @@ + + + + + . + + + + + + ../../Classes/Command + ../../Classes/Dashboard + + + + + + + diff --git a/Tests/Unit/Dashboard/Provider/NewestPageviewsTest.php b/Tests/Unit/Dashboard/Provider/NewestPageviewsTest.php deleted file mode 100644 index 16abb8b..0000000 --- a/Tests/Unit/Dashboard/Provider/NewestPageviewsTest.php +++ /dev/null @@ -1,185 +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. - */ - -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 defaultsToNoExcludedPages(): 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 respectsExcludedPages(): 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() - ); - } -} diff --git a/composer.json b/composer.json index 96ca114..0d1f379 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,8 @@ "symfony/expression-language": "^5.0", "typo3/cms-core": "^10.4", "symfony/console": "^5.0", - "typo3/cms-dashboard": "^10.4" + "typo3/cms-dashboard": "^10.4", + "typo3/cms-backend": "^10.4" }, "require-dev": { "squizlabs/php_codesniffer": "^3.5", @@ -44,7 +45,9 @@ "phpstan/extension-installer": "^1.0", "jangregor/phpstan-prophecy": "^0.6.2", "maglnet/composer-require-checker": "^2.1", - "phpspec/prophecy-phpunit": "^2.0" + "phpspec/prophecy-phpunit": "^2.0", + "typo3/testing-framework": "^6.3", + "saschaegerer/phpstan-typo3": "^0.13.1" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/phpstan.neon b/phpstan.neon index a81c62b..22b9fa5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,9 +3,21 @@ parameters: paths: - Classes - Tests - checkGenericClassInNonGenericObjectType: false checkMissingIterableValueType: false + reportUnmatchedIgnoredErrors: true ignoreErrors: - '#Cannot call method fetch\(\) on Doctrine\\DBAL\\Driver\\Statement\|int\.#' - '#Cannot call method fetchAll\(\) on Doctrine\\DBAL\\Driver\\Statement\|int\.#' - '#Cannot call method fetchColumn\(\) on Doctrine\\DBAL\\Driver\\Statement\|int\.#' + - + message: '#\$timestamp of function date expects int, int\|false given\.#' + path: Classes/Dashboard/Provider/PageviewsPerDay.php + count: 1 + - + message: '#Parameter \#1 \$start of method DanielSiepmann\\Tracking\\Dashboard\\Provider\\PageviewsPerDay::getPageviewsInPeriod\(\) expects int, int\|false given\.#' + path: Classes/Dashboard/Provider/PageviewsPerDay.php + count: 1 + - + message: '#Parameter \#2 \$end of method DanielSiepmann\\Tracking\\Dashboard\\Provider\\PageviewsPerDay::getPageviewsInPeriod\(\) expects int, int\|false given\.#' + path: Classes/Dashboard/Provider/PageviewsPerDay.php + count: 1 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4ae4c2d..32764a1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -20,7 +20,8 @@ - Classes + Classes/Domain + Classes/Middleware