diff --git a/Classes/Command/UpdateDataCommand.php b/Classes/Command/UpdateDataCommand.php index 4aa4f07..67494ab 100644 --- a/Classes/Command/UpdateDataCommand.php +++ b/Classes/Command/UpdateDataCommand.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace DanielSiepmann\Tracking\Command; use DanielSiepmann\Tracking\Domain\Repository\Pageview; +use DanielSiepmann\Tracking\Domain\Repository\Recordview; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; @@ -35,33 +36,58 @@ class UpdateDataCommand extends Command /** * @var Pageview */ - private $repository; + private $pageviews; - public function __construct(Pageview $repository) - { - $this->repository = $repository; + /** + * @var Recordview + */ + private $recordviews; + + public function __construct( + Pageview $pageviews, + Recordview $recordviews + ) { + $this->pageviews = $pageviews; + $this->recordviews = $recordviews; parent::__construct(); } protected function configure(): void { - $this->setDescription('Updates existing data.'); - $this->setHelp('In case some more data can be extracted of the existing data.'); + $this->setHelp('Converts legacy data to new format if necessary. Runs incrementel to work with large data sets.'); } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); - $io->progressStart($this->repository->countAll()); - foreach ($this->repository->findAll() as $pageView) { - $this->repository->update($pageView); - $io->progressAdvance(); - } - - $io->progressFinish(); + $io->writeln('Updating: Pageviews'); + $this->update($this->pageviews, $io); + $io->writeln('Updating: Recordviews'); + $this->update($this->recordviews, $io); return 0; } + + /** + * @param Pageview|Recordview $repository + */ + private function update( + $repository, + SymfonyStyle $io + ): void { + $count = $repository->findLegacyCount(); + if ($count === 0) { + $io->writeln('No more data to update.'); + return; + } + + $io->progressStart($count); + foreach ($repository->findLegacy() as $data) { + $repository->update($data); + $io->progressAdvance(); + } + $io->progressFinish(); + } } diff --git a/Classes/Dashboard/Provider/Demand.php b/Classes/Dashboard/Provider/Demand.php new file mode 100644 index 0000000..c412f8f --- /dev/null +++ b/Classes/Dashboard/Provider/Demand.php @@ -0,0 +1,181 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Dashboard\Provider; + +use DanielSiepmann\Tracking\Dashboard\Provider\Demand\Tag; +use TYPO3\CMS\Core\Database\Connection; +use TYPO3\CMS\Core\Database\Query\QueryBuilder; + +class Demand +{ + /** + * @var int + */ + private $days; + + /** + * @var int + */ + private $maxResults; + + /** + * @var int[] + */ + private $pagesToExclude; + + /** + * @var int[] + */ + private $languageLimitation; + + /** + * @var Tag[] + */ + private $tagConstraints; + + /** + * @param int[] $pagesToExclude + * @param int[] $languageLimitation + * @param Tag[] $tagConstraints + */ + public function __construct( + int $days = 31, + int $maxResults = 6, + array $pagesToExclude = [], + array $languageLimitation = [], + array $tagConstraints = [] + ) { + $this->days = $days; + $this->maxResults = $maxResults; + $this->pagesToExclude = array_map('intval', $pagesToExclude); + $this->languageLimitation = array_map('intval', $languageLimitation); + $this->tagConstraints = $tagConstraints; + } + + public function getDays(): int + { + return $this->days; + } + + public function getMaxResults(): int + { + return $this->maxResults; + } + + /** + * @return int[] + */ + public function getPagesToExclude(): array + { + return $this->pagesToExclude; + } + + /** + * @return int[] + */ + public function getLanguageLimitation(): array + { + return $this->languageLimitation; + } + + /** + * @return Tag[] + */ + public function getTagConstraints(): array + { + return $this->tagConstraints; + } + + public function addJoins( + QueryBuilder $queryBuilder, + string $tableName + ): void { + if ($this->getTagConstraints() !== []) { + $queryBuilder->leftJoin( + $tableName, + 'tx_tracking_tag', + 'tx_tracking_tag', + (string) $queryBuilder->expr()->andX( + $queryBuilder->expr()->eq( + 'tx_tracking_tag.record_table_name', + $queryBuilder->createNamedParameter($tableName) + ), + $queryBuilder->expr()->eq( + 'tx_tracking_tag.record_uid', + $queryBuilder->quoteIdentifier($tableName . '.uid') + ) + ) + ); + } + } + + /** + * @return string[] + */ + public function getConstraints( + QueryBuilder $queryBuilder, + string $tableName + ): array { + $constraints = []; + + if ($this->getPagesToExclude() !== []) { + $constraints[] = (string) $queryBuilder->expr()->notIn( + $tableName . '.pid', + $queryBuilder->createNamedParameter( + $this->getPagesToExclude(), + Connection::PARAM_INT_ARRAY + ) + ); + } + + if ($this->getLanguageLimitation() !== []) { + $constraints[] = (string) $queryBuilder->expr()->in( + $tableName . '.sys_language_uid', + $queryBuilder->createNamedParameter( + $this->getLanguageLimitation(), + Connection::PARAM_INT_ARRAY + ) + ); + } + + foreach ($this->getTagConstraints() as $tagConstraint) { + $constraints[] = (string) $queryBuilder->expr()->andX( + $queryBuilder->expr()->eq( + 'tx_tracking_tag.name', + $queryBuilder->createNamedParameter( + $tagConstraint->getName() + ) + ), + $queryBuilder->expr()->eq( + 'tx_tracking_tag.value', + $queryBuilder->createNamedParameter( + $tagConstraint->getValue() + ) + ) + ); + } + + return $constraints; + } +} diff --git a/Classes/Dashboard/Provider/Demand/Tag.php b/Classes/Dashboard/Provider/Demand/Tag.php new file mode 100644 index 0000000..e4ee471 --- /dev/null +++ b/Classes/Dashboard/Provider/Demand/Tag.php @@ -0,0 +1,64 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Dashboard\Provider\Demand; + +class Tag +{ + /** + * @var string + */ + private $name; + + /** + * @var string + */ + private $value; + + public function __construct( + string $name, + string $value + ) { + // TODO: Add Validate + $this->name = $name; + $this->value = $value; + } + + public static function createFromArray(array $parameters): self + { + return new self( + $parameters['name'], + $parameters['value'] + ); + } + + public function getName(): string + { + return $this->name; + } + + public function getValue(): string + { + return $this->value; + } +} diff --git a/Classes/Dashboard/Provider/NewestPageviews.php b/Classes/Dashboard/Provider/NewestPageviews.php index 0609db2..5f1b178 100644 --- a/Classes/Dashboard/Provider/NewestPageviews.php +++ b/Classes/Dashboard/Provider/NewestPageviews.php @@ -35,63 +35,35 @@ class NewestPageviews implements ListDataProviderInterface private $queryBuilder; /** - * @var int + * @var Demand */ - private $maxResults; - - /** - * @var array - */ - private $pagesToExclude; - - /** - * @var array - */ - private $languageLimitation; + private $demand; public function __construct( QueryBuilder $queryBuilder, - int $maxResults = 6, - array $pagesToExclude = [], - array $languageLimitation = [] + Demand $demand ) { $this->queryBuilder = $queryBuilder; - $this->maxResults = $maxResults; - $this->pagesToExclude = $pagesToExclude; - $this->languageLimitation = $languageLimitation; + $this->demand = $demand; } public function getItems(): array { $preparedItems = []; - $constraints = []; - if (count($this->pagesToExclude)) { - $constraints[] = $this->queryBuilder->expr()->notIn( - 'tx_tracking_pageview.pid', - $this->queryBuilder->createNamedParameter( - $this->pagesToExclude, - Connection::PARAM_INT_ARRAY - ) - ); - } + $constraints = $this->demand->getConstraints( + $this->queryBuilder, + 'tx_tracking_pageview' + ); - if (count($this->languageLimitation)) { - $constraints[] = $this->queryBuilder->expr()->in( - 'tx_tracking_pageview.sys_language_uid', - $this->queryBuilder->createNamedParameter( - $this->languageLimitation, - Connection::PARAM_INT_ARRAY - ) - ); - } + $this->demand->addJoins($this->queryBuilder, 'tx_tracking_pageview'); $this->queryBuilder ->select('url', 'user_agent') ->from('tx_tracking_pageview') ->orderBy('crdate', 'desc') ->addOrderBy('uid', 'desc') - ->setMaxResults($this->maxResults); + ->setMaxResults($this->demand->getMaxResults()); if ($constraints !== []) { $this->queryBuilder->where(...$constraints); diff --git a/Classes/Dashboard/Provider/PageviewsPerDay.php b/Classes/Dashboard/Provider/PageviewsPerDay.php index f44165b..c4c377b 100644 --- a/Classes/Dashboard/Provider/PageviewsPerDay.php +++ b/Classes/Dashboard/Provider/PageviewsPerDay.php @@ -43,38 +43,24 @@ class PageviewsPerDay implements ChartDataProviderInterface private $queryBuilder; /** - * @var int + * @var Demand */ - private $days; - - /** - * @var array - */ - private $pagesToExclude; + private $demand; /** * @var string */ private $dateFormat; - /** - * @var array - */ - private $languageLimitation; - public function __construct( LanguageService $languageService, QueryBuilder $queryBuilder, - int $days = 31, - array $pagesToExclude = [], - array $languageLimitation = [], + Demand $demand, string $dateFormat = 'Y-m-d' ) { $this->languageService = $languageService; $this->queryBuilder = $queryBuilder; - $this->days = $days; - $this->pagesToExclude = $pagesToExclude; - $this->languageLimitation = $languageLimitation; + $this->demand = $demand; $this->dateFormat = $dateFormat; } @@ -102,13 +88,13 @@ class PageviewsPerDay implements ChartDataProviderInterface $labels = []; $data = []; - for ($daysBefore = $this->days; $daysBefore >= 0; $daysBefore--) { + for ($daysBefore = $this->demand->getDays(); $daysBefore >= 0; $daysBefore--) { $label = date($this->dateFormat, (int) strtotime('-' . $daysBefore . ' day')); $labels[$label] = $label; $data[$label] = 0; } - $start = (int) strtotime('-' . $this->days . ' day 0:00:00'); + $start = (int) strtotime('-' . $this->demand->getDays() . ' day 0:00:00'); $end = (int) strtotime('tomorrow midnight'); @@ -125,32 +111,19 @@ class PageviewsPerDay implements ChartDataProviderInterface private function getPageviewsInPeriod(int $start, int $end): array { $constraints = [ - $this->queryBuilder->expr()->gte('crdate', $start), - $this->queryBuilder->expr()->lte('crdate', $end), + $this->queryBuilder->expr()->gte('tx_tracking_pageview.crdate', $start), + $this->queryBuilder->expr()->lte('tx_tracking_pageview.crdate', $end), ]; - if (count($this->pagesToExclude)) { - $constraints[] = $this->queryBuilder->expr()->notIn( - 'tx_tracking_pageview.pid', - $this->queryBuilder->createNamedParameter( - $this->pagesToExclude, - Connection::PARAM_INT_ARRAY - ) - ); - } + $constraints = array_merge($constraints, $this->demand->getConstraints( + $this->queryBuilder, + 'tx_tracking_pageview' + )); - if (count($this->languageLimitation)) { - $constraints[] = $this->queryBuilder->expr()->in( - 'tx_tracking_pageview.sys_language_uid', - $this->queryBuilder->createNamedParameter( - $this->languageLimitation, - Connection::PARAM_INT_ARRAY - ) - ); - } + $this->demand->addJoins($this->queryBuilder, 'tx_tracking_pageview'); $this->queryBuilder - ->addSelectLiteral('COUNT(*) as "count"') + ->addSelectLiteral('COUNT(tx_tracking_pageview.uid) as "count"') ->from('tx_tracking_pageview') ->where(...$constraints) ->groupBy('label') @@ -158,9 +131,9 @@ class PageviewsPerDay implements ChartDataProviderInterface ; if ($this->queryBuilder->getConnection()->getDatabasePlatform()->getName() === 'sqlite') { - $this->queryBuilder->addSelectLiteral('date(crdate, "unixepoch") as "label"'); + $this->queryBuilder->addSelectLiteral('date(tx_tracking_pageview.crdate, "unixepoch") as "label"'); } else { - $this->queryBuilder->addSelectLiteral('FROM_UNIXTIME(crdate, "%Y-%m-%d") as "label"'); + $this->queryBuilder->addSelectLiteral('FROM_UNIXTIME(tx_tracking_pageview.crdate, "%Y-%m-%d") as "label"'); } return $this->queryBuilder->execute()->fetchAll(); diff --git a/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php b/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php index 23da1ee..bfc61f2 100644 --- a/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php +++ b/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php @@ -36,30 +36,16 @@ class PageviewsPerOperatingSystem implements ChartDataProviderInterface private $queryBuilder; /** - * @var int + * @var Demand */ - private $days; - - /** - * @var int - */ - private $maxResults; - - /** - * @var array - */ - private $languageLimitation; + private $demand; public function __construct( QueryBuilder $queryBuilder, - int $days = 31, - int $maxResults = 6, - array $languageLimitation = [] + Demand $demand ) { $this->queryBuilder = $queryBuilder; - $this->days = $days; - $this->maxResults = $maxResults; - $this->languageLimitation = $languageLimitation; + $this->demand = $demand; } public function getChartData(): array @@ -85,33 +71,42 @@ class PageviewsPerOperatingSystem implements ChartDataProviderInterface $constraints = [ $this->queryBuilder->expr()->gte( 'tx_tracking_pageview.crdate', - strtotime('-' . $this->days . ' day 0:00:00') + strtotime('-' . $this->demand->getDays() . ' day 0:00:00') ), $this->queryBuilder->expr()->neq( - 'tx_tracking_pageview.operating_system', + 'operating_system', $this->queryBuilder->createNamedParameter('') ), ]; - if (count($this->languageLimitation)) { - $constraints[] = $this->queryBuilder->expr()->in( - 'tx_tracking_pageview.sys_language_uid', - $this->queryBuilder->createNamedParameter( - $this->languageLimitation, - Connection::PARAM_INT_ARRAY - ) - ); - } + $constraints = array_merge($constraints, $this->demand->getConstraints( + $this->queryBuilder, + 'tx_tracking_pageview' + )); + + $this->demand->addJoins($this->queryBuilder, 'tx_tracking_pageview'); $result = $this->queryBuilder - ->selectLiteral('count(operating_system) as total') - ->addSelect('operating_system') + ->addSelect('tag.value as operating_system') + ->addSelectLiteral( + 'count(' . $this->queryBuilder->quoteIdentifier('operating_system') . ') as total' + ) ->from('tx_tracking_pageview') + ->leftJoin( + 'tx_tracking_pageview', + 'tx_tracking_tag', + 'tag', + (string) $this->queryBuilder->expr()->andX( + $this->queryBuilder->expr()->eq('tx_tracking_pageview.uid', $this->queryBuilder->quoteIdentifier('tag.record_uid')), + $this->queryBuilder->expr()->eq('tag.name', $this->queryBuilder->createNamedParameter('os')), + $this->queryBuilder->expr()->eq('tag.record_table_name', $this->queryBuilder->createNamedParameter('tx_tracking_pageview')) + ) + ) ->where(...$constraints) - ->groupBy('tx_tracking_pageview.operating_system') + ->groupBy('operating_system') ->orderBy('total', 'desc') ->addOrderBy('operating_system', 'asc') - ->setMaxResults($this->maxResults) + ->setMaxResults($this->demand->getMaxResults()) ->execute() ->fetchAll(); diff --git a/Classes/Dashboard/Provider/PageviewsPerPage.php b/Classes/Dashboard/Provider/PageviewsPerPage.php index e07cf32..f1aaed5 100644 --- a/Classes/Dashboard/Provider/PageviewsPerPage.php +++ b/Classes/Dashboard/Provider/PageviewsPerPage.php @@ -45,39 +45,18 @@ class PageviewsPerPage implements ChartDataProviderInterface private $pageRepository; /** - * @var int + * @var Demand */ - private $days; - - /** - * @var int - */ - private $maxResults; - - /** - * @var array - */ - private $pagesToExclude; - - /** - * @var array - */ - private $languageLimitation; + private $demand; public function __construct( QueryBuilder $queryBuilder, PageRepository $pageRepository, - int $days = 31, - int $maxResults = 6, - array $pagesToExclude = [], - array $languageLimitation = [] + Demand $demand ) { $this->queryBuilder = $queryBuilder; $this->pageRepository = $pageRepository; - $this->days = $days; - $this->maxResults = $maxResults; - $this->pagesToExclude = $pagesToExclude; - $this->languageLimitation = $languageLimitation; + $this->demand = $demand; } public function getChartData(): array @@ -99,45 +78,33 @@ class PageviewsPerPage implements ChartDataProviderInterface { $labels = []; $data = []; - $constraints = [ - $this->queryBuilder->expr()->gte( + (string) $this->queryBuilder->expr()->gte( 'tx_tracking_pageview.crdate', - strtotime('-' . $this->days . ' day 0:00:00') + strtotime('-' . $this->demand->getDays() . ' day 0:00:00') ), ]; - if (count($this->pagesToExclude)) { - $constraints[] = $this->queryBuilder->expr()->notIn( - 'tx_tracking_pageview.pid', - $this->queryBuilder->createNamedParameter( - $this->pagesToExclude, - Connection::PARAM_INT_ARRAY - ) - ); - } - - if (count($this->languageLimitation)) { - $constraints[] = $this->queryBuilder->expr()->in( - 'tx_tracking_pageview.sys_language_uid', - $this->queryBuilder->createNamedParameter( - $this->languageLimitation, - Connection::PARAM_INT_ARRAY - ) - ); - } + $constraints = array_merge($constraints, $this->demand->getConstraints( + $this->queryBuilder, + 'tx_tracking_pageview' + )); + $this->demand->addJoins( + $this->queryBuilder, + 'tx_tracking_pageview' + ); $result = $this->queryBuilder ->selectLiteral( - $this->queryBuilder->expr()->count('pid', 'total'), - $this->queryBuilder->expr()->max('uid', 'latest') + $this->queryBuilder->expr()->count('tx_tracking_pageview.pid', 'total'), + $this->queryBuilder->expr()->max('tx_tracking_pageview.uid', 'latest') ) - ->addSelect('pid') + ->addSelect('tx_tracking_pageview.pid') ->from('tx_tracking_pageview') ->where(...$constraints) - ->groupBy('pid') + ->groupBy('tx_tracking_pageview.pid') ->orderBy('total', 'desc') ->addOrderBy('latest', 'desc') - ->setMaxResults($this->maxResults) + ->setMaxResults($this->demand->getMaxResults()) ->execute() ->fetchAll(); @@ -159,8 +126,8 @@ class PageviewsPerPage implements ChartDataProviderInterface private function getRecordTitle(int $uid): string { $record = BackendUtility::getRecord('pages', $uid); - if (count($this->languageLimitation) === 1 && $record !== null) { - $record = $this->pageRepository->getRecordOverlay('pages', $record, $this->languageLimitation[0]); + if (count($this->demand->getLanguageLimitation()) === 1 && $record !== null) { + $record = $this->pageRepository->getRecordOverlay('pages', $record, $this->demand->getLanguageLimitation()[0]); } if (is_array($record) === false) { diff --git a/Classes/Dashboard/Provider/Recordviews.php b/Classes/Dashboard/Provider/Recordviews.php index c0f7122..dca3eb4 100644 --- a/Classes/Dashboard/Provider/Recordviews.php +++ b/Classes/Dashboard/Provider/Recordviews.php @@ -49,24 +49,9 @@ class Recordviews implements ChartDataProviderInterface private $queryBuilder; /** - * @var int + * @var Demand */ - private $days; - - /** - * @var int - */ - private $maxResults; - - /** - * @var array - */ - private $pagesToExclude; - - /** - * @var array - */ - private $languageLimitation; + private $demand; /** * @var array @@ -81,19 +66,13 @@ class Recordviews implements ChartDataProviderInterface public function __construct( PageRepository $pageRepository, QueryBuilder $queryBuilder, - int $days = 31, - int $maxResults = 6, - array $pagesToExclude = [], - array $languageLimitation = [], + Demand $demand, array $recordTableLimitation = [], array $recordTypeLimitation = [] ) { $this->pageRepository = $pageRepository; $this->queryBuilder = $queryBuilder; - $this->days = $days; - $this->pagesToExclude = $pagesToExclude; - $this->languageLimitation = $languageLimitation; - $this->maxResults = $maxResults; + $this->demand = $demand; $this->recordTableLimitation = $recordTableLimitation; $this->recordTypeLimitation = $recordTypeLimitation; } @@ -152,30 +131,10 @@ class Recordviews implements ChartDataProviderInterface $constraints = [ $this->queryBuilder->expr()->gte( 'tx_tracking_recordview.crdate', - strtotime('-' . $this->days . ' day 0:00:00') + strtotime('-' . $this->demand->getDays() . ' day 0:00:00') ) ]; - if (count($this->pagesToExclude)) { - $constraints[] = $this->queryBuilder->expr()->notIn( - 'tx_tracking_recordview.pid', - $this->queryBuilder->createNamedParameter( - $this->pagesToExclude, - Connection::PARAM_INT_ARRAY - ) - ); - } - - 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', @@ -186,6 +145,15 @@ class Recordviews implements ChartDataProviderInterface ); } + $constraints = array_merge($constraints, $this->demand->getConstraints( + $this->queryBuilder, + 'tx_tracking_recordview' + )); + $this->demand->addJoins( + $this->queryBuilder, + 'tx_tracking_recordview' + ); + $result = $this->queryBuilder ->selectLiteral( $this->queryBuilder->expr()->count('record', 'total'), @@ -197,7 +165,7 @@ class Recordviews implements ChartDataProviderInterface ->groupBy('record', 'record_uid', 'record_table_name') ->orderBy('total', 'desc') ->addOrderBy('latest', 'desc') - ->setMaxResults($this->maxResults) + ->setMaxResults($this->demand->getMaxResults()) ->execute(); while ($row = $result->fetch()) { @@ -212,8 +180,8 @@ class Recordviews implements ChartDataProviderInterface $recordTypeField = $GLOBALS['TCA'][$table]['ctrl']['type'] ?? ''; $record = BackendUtility::getRecord($table, $uid); - if (count($this->languageLimitation) === 1 && $record !== null) { - $record = $this->pageRepository->getRecordOverlay($table, $record, $this->languageLimitation[0]); + if (count($this->demand->getLanguageLimitation()) === 1 && $record !== null) { + $record = $this->pageRepository->getRecordOverlay($table, $record, $this->demand->getLanguageLimitation()[0]); } if (is_array($record) === false) { diff --git a/Classes/Domain/Extractors/Bots.php b/Classes/Domain/Extractors/Bots.php new file mode 100644 index 0000000..73292a3 --- /dev/null +++ b/Classes/Domain/Extractors/Bots.php @@ -0,0 +1,88 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Domain\Extractors; + +use DanielSiepmann\Tracking\Domain\Extractors\Bots\CustomBotParser; +use DanielSiepmann\Tracking\Domain\Model\Pageview; +use DanielSiepmann\Tracking\Domain\Model\Recordview; +use DeviceDetector\DeviceDetector; + +class Bots implements PageviewExtractor, RecordviewExtractor +{ + /** + * @var CustomBotParser + */ + private $customBotParser; + + public function __construct( + CustomBotParser $customBotParser + ) { + $this->customBotParser = $customBotParser; + } + + public function extractTagFromPageview(Pageview $pageview): array + { + return $this->getTagsForUserAgent($pageview->getUserAgent()); + } + + public function extractTagFromRecordview(Recordview $recordview): array + { + return $this->getTagsForUserAgent($recordview->getUserAgent()); + } + + /** + * @return Tag[] + */ + private function getTagsForUserAgent(string $userAgent): array + { + $botNameTag = new Tag('bot_name', $this->getBotName($userAgent)); + + if ($botNameTag->getValue() !== '') { + return [ + new Tag('bot', 'yes'), + $botNameTag, + ]; + } + return [new Tag('bot', 'no')]; + } + + private function getBotName(string $userAgent): string + { + $deviceDetector = new DeviceDetector(); + $deviceDetector->addBotParser($this->customBotParser); + $deviceDetector->setUserAgent($userAgent); + $deviceDetector->parse(); + + if ($deviceDetector->isBot() === false) { + return ''; + } + + $bot = $deviceDetector->getBot(); + if (is_array($bot) === false) { + return ''; + } + + return $bot['name'] ?? ''; + } +} diff --git a/Classes/Domain/Extractors/Bots/CustomBotParser.php b/Classes/Domain/Extractors/Bots/CustomBotParser.php new file mode 100644 index 0000000..de619e2 --- /dev/null +++ b/Classes/Domain/Extractors/Bots/CustomBotParser.php @@ -0,0 +1,56 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Domain\Extractors\Bots; + +use DeviceDetector\Parser\Bot; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +class CustomBotParser extends Bot +{ + protected $parserName = 'customBots'; + + /** + * @var string + */ + protected $dirName = ''; + + public function __construct() + { + parent::__construct(); + + $fixtureFile = GeneralUtility::getFileAbsFileName('EXT:tracking/Configuration/Bots.yaml'); + $this->fixtureFile = basename($fixtureFile); + $this->dirName = dirname($fixtureFile); + } + + protected function getRegexesDirectory(): string + { + return $this->dirName; + } + + public function parse(): ?array + { + return parent::parse(); + } +} diff --git a/Classes/Domain/Model/Extractor.php b/Classes/Domain/Extractors/OperatingSystem.php similarity index 68% rename from Classes/Domain/Model/Extractor.php rename to Classes/Domain/Extractors/OperatingSystem.php index 1bea76e..b01ca42 100644 --- a/Classes/Domain/Model/Extractor.php +++ b/Classes/Domain/Extractors/OperatingSystem.php @@ -3,7 +3,7 @@ declare(strict_types=1); /* - * Copyright (C) 2020 Daniel Siepmann + * Copyright (C) 2021 Daniel Siepmann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,17 +21,25 @@ declare(strict_types=1); * 02110-1301, USA. */ -namespace DanielSiepmann\Tracking\Domain\Model; +namespace DanielSiepmann\Tracking\Domain\Extractors; -/** - * API to extract further info out of an model. - */ -class Extractor +use DanielSiepmann\Tracking\Domain\Model\Pageview; +use DanielSiepmann\Tracking\Domain\Model\Recordview; + +class OperatingSystem implements PageviewExtractor, RecordviewExtractor { - public static function getOperatingSystem(HasUserAgent $model): string + public function extractTagFromPageview(Pageview $pageview): array { - $userAgent = $model->getUserAgent(); + return [new Tag('os', $this->getOperatingSystem($pageview->getUserAgent()))]; + } + public function extractTagFromRecordview(Recordview $recordview): array + { + return [new Tag('os', $this->getOperatingSystem($recordview->getUserAgent()))]; + } + + private function getOperatingSystem(string $userAgent): string + { if (mb_stripos($userAgent, 'Android') !== false) { return 'Android'; } @@ -57,6 +65,6 @@ class Extractor return 'iOS'; } - return ''; + return 'Unkown'; } } diff --git a/Classes/Domain/Model/HasUserAgent.php b/Classes/Domain/Extractors/PageviewExtractor.php similarity index 73% rename from Classes/Domain/Model/HasUserAgent.php rename to Classes/Domain/Extractors/PageviewExtractor.php index 6c3a686..d2afaca 100644 --- a/Classes/Domain/Model/HasUserAgent.php +++ b/Classes/Domain/Extractors/PageviewExtractor.php @@ -21,9 +21,17 @@ declare(strict_types=1); * 02110-1301, USA. */ -namespace DanielSiepmann\Tracking\Domain\Model; +namespace DanielSiepmann\Tracking\Domain\Extractors; -interface HasUserAgent +use DanielSiepmann\Tracking\Domain\Model\Pageview; + +/** + * API to extract further info out of an model. + */ +interface PageviewExtractor { - public function getUserAgent(): string; + /** + * @return Tag[] + */ + public function extractTagFromPageview(Pageview $pageview): array; } diff --git a/Classes/Domain/Extractors/RecordviewExtractor.php b/Classes/Domain/Extractors/RecordviewExtractor.php new file mode 100644 index 0000000..2855edd --- /dev/null +++ b/Classes/Domain/Extractors/RecordviewExtractor.php @@ -0,0 +1,37 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Domain\Extractors; + +use DanielSiepmann\Tracking\Domain\Model\Recordview; + +/** + * API to extract further info out of an model. + */ +interface RecordviewExtractor +{ + /** + * @return Tag[] + */ + public function extractTagFromRecordview(Recordview $recordview): array; +} diff --git a/Classes/Domain/Extractors/Registry.php b/Classes/Domain/Extractors/Registry.php new file mode 100644 index 0000000..df22d48 --- /dev/null +++ b/Classes/Domain/Extractors/Registry.php @@ -0,0 +1,74 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Domain\Extractors; + +use DanielSiepmann\Tracking\Domain\Model\Pageview; +use DanielSiepmann\Tracking\Domain\Model\Recordview; + +class Registry +{ + /** + * @var PageviewExtractor[] + */ + protected $pageviewExtractors = []; + + /** + * @var RecordviewExtractor[] + */ + protected $recordviewExtractors = []; + + public function addPageviewExtractor(PageviewExtractor $extractor): void + { + $this->pageviewExtractors[] = $extractor; + } + + public function addRecordviewExtractor(RecordviewExtractor $extractor): void + { + $this->recordviewExtractors[] = $extractor; + } + + /** + * @return Tag[] + */ + public function getTagsForPageview(Pageview $pageview): array + { + $tags = []; + foreach ($this->pageviewExtractors as $extractor) { + $tags = array_merge($tags, $extractor->extractTagFromPageview($pageview)); + } + return $tags; + } + + /** + * @return Tag[] + */ + public function getTagsForRecordview(Recordview $recordview): array + { + $tags = []; + foreach ($this->recordviewExtractors as $extractor) { + $tags = array_merge($tags, $extractor->extractTagFromRecordview($recordview)); + } + return $tags; + } +} diff --git a/Classes/Domain/Extractors/Tag.php b/Classes/Domain/Extractors/Tag.php new file mode 100644 index 0000000..b869355 --- /dev/null +++ b/Classes/Domain/Extractors/Tag.php @@ -0,0 +1,57 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Domain\Extractors; + +class Tag +{ + /** + * E.g. "os" or "bot", some unique identifier. + * + * @var string + */ + protected $name = ''; + + /** + * @var string + */ + protected $value = ''; + + public function __construct( + string $name, + string $value + ) { + $this->name = $name; + $this->value = $value; + } + + public function getName(): string + { + return $this->name; + } + + public function getValue(): string + { + return $this->value; + } +} diff --git a/Classes/Domain/Model/Pageview.php b/Classes/Domain/Model/Pageview.php index a09fca8..b0f723c 100644 --- a/Classes/Domain/Model/Pageview.php +++ b/Classes/Domain/Model/Pageview.php @@ -25,7 +25,7 @@ namespace DanielSiepmann\Tracking\Domain\Model; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; -class Pageview implements HasUserAgent +class Pageview { /** * @var int @@ -114,9 +114,4 @@ class Pageview implements HasUserAgent { return $this->userAgent; } - - public function getOperatingSystem(): string - { - return Extractor::getOperatingSystem($this); - } } diff --git a/Classes/Domain/Model/Recordview.php b/Classes/Domain/Model/Recordview.php index 46407fd..039b0b8 100644 --- a/Classes/Domain/Model/Recordview.php +++ b/Classes/Domain/Model/Recordview.php @@ -25,8 +25,13 @@ namespace DanielSiepmann\Tracking\Domain\Model; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; -class Recordview implements HasUserAgent +class Recordview { + /** + * @var int + */ + private $uid = 0; + /** * @var int */ @@ -69,8 +74,10 @@ class Recordview implements HasUserAgent string $url, string $userAgent, int $recordUid, - string $tableName + string $tableName, + int $uid = 0 ) { + $this->uid = $uid; $this->pageUid = $pageUid; $this->language = $language; $this->crdate = $crdate; @@ -80,6 +87,11 @@ class Recordview implements HasUserAgent $this->tableName = $tableName; } + public function getUid(): int + { + return $this->uid; + } + public function getPageUid(): int { return $this->pageUid; @@ -114,9 +126,4 @@ class Recordview implements HasUserAgent { return $this->tableName; } - - public function getOperatingSystem(): string - { - return Extractor::getOperatingSystem($this); - } } diff --git a/Classes/Domain/Recordview/Factory.php b/Classes/Domain/Recordview/Factory.php index f8d9cfe..28a0354 100644 --- a/Classes/Domain/Recordview/Factory.php +++ b/Classes/Domain/Recordview/Factory.php @@ -30,6 +30,7 @@ use Psr\Http\Message\ServerRequestInterface; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use TYPO3\CMS\Core\Routing\PageArguments; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; +use TYPO3\CMS\Core\Site\SiteFinder; class Factory { @@ -38,9 +39,16 @@ class Factory */ private $expressionFactory; + /** + * @var SiteFinder + */ + private $siteFinder; + public function __construct( + SiteFinder $siteFinder, ExpressionFactory $expressionFactory ) { + $this->siteFinder = $siteFinder; $this->expressionFactory = $expressionFactory; } @@ -75,6 +83,20 @@ class Factory ); } + public function fromDbRow(array $dbRow): Recordview + { + return new Recordview( + $dbRow['pid'], + $this->siteFinder->getSiteByPageId($dbRow['pid'])->getLanguageById($dbRow['sys_language_uid']), + new \DateTimeImmutable('@' . $dbRow['crdate']), + $dbRow['url'], + $dbRow['user_agent'], + $dbRow['record_uid'], + $dbRow['record_table_name'], + $dbRow['uid'] + ); + } + private static function getLanguage(ServerRequestInterface $request): SiteLanguage { $language = $request->getAttribute('language'); diff --git a/Classes/Domain/Repository/Pageview.php b/Classes/Domain/Repository/Pageview.php index 856c568..d4ad93b 100644 --- a/Classes/Domain/Repository/Pageview.php +++ b/Classes/Domain/Repository/Pageview.php @@ -25,6 +25,7 @@ namespace DanielSiepmann\Tracking\Domain\Repository; use DanielSiepmann\Tracking\Domain\Model\Pageview as Model; use DanielSiepmann\Tracking\Domain\Pageview\Factory; +use DanielSiepmann\Tracking\Extension; use TYPO3\CMS\Core\Database\Connection; class Pageview @@ -39,33 +40,50 @@ class Pageview */ private $factory; + /** + * @var Tag + */ + private $tagRepository; + public function __construct( Connection $connection, - Factory $factory + Factory $factory, + Tag $tagRepository ) { $this->connection = $connection; $this->factory = $factory; + $this->tagRepository = $tagRepository; } - public function countAll(): int - { - $result = $this->connection->createQueryBuilder() - ->count('uid') - ->from('tx_tracking_pageview') - ->execute() - ->fetchColumn(); - - if (is_numeric($result)) { - return (int) $result; - } - - return 0; - } - - public function findAll(): \Generator + public function findLegacyCount(): int { $queryBuilder = $this->connection->createQueryBuilder(); - $pageViews = $queryBuilder->select('*')->from('tx_tracking_pageview')->execute(); + $queryBuilder->count('*'); + $queryBuilder->from('tx_tracking_pageview'); + $queryBuilder->where($queryBuilder->expr()->neq('compatible_version', $queryBuilder->createNamedParameter(Extension::getCompatibleVersionNow()))); + $queryBuilder->setMaxResults(Extension::getMaximumRowsForUpdate()); + + $pageViews = $queryBuilder->execute()->fetchColumn(); + if (is_numeric($pageViews) === false) { + return 0; + } + + if ($pageViews > Extension::getMaximumRowsForUpdate()) { + return Extension::getMaximumRowsForUpdate(); + } + return (int) $pageViews; + } + + public function findLegacy(): \Generator + { + $queryBuilder = $this->connection->createQueryBuilder(); + $queryBuilder->select('*'); + $queryBuilder->from('tx_tracking_pageview'); + $queryBuilder->where($queryBuilder->expr()->neq('compatible_version', $queryBuilder->createNamedParameter(Extension::getCompatibleVersionNow()))); + $test = Extension::getCompatibleVersionNow(); + $queryBuilder->setMaxResults(Extension::getMaximumRowsForUpdate()); + + $pageViews = $queryBuilder->execute(); while ($pageView = $pageViews->fetch()) { if (is_array($pageView) === false) { @@ -87,6 +105,8 @@ class Pageview $this->getFieldsFromModel($pageview), ['uid' => $pageview->getUid()] ); + + $this->tagRepository->updateForPageview($pageview); } public function add(Model $pageview): void @@ -95,6 +115,11 @@ class Pageview 'tx_tracking_pageview', $this->getFieldsFromModel($pageview) ); + + $this->tagRepository->addForPageview( + $pageview, + (int) $this->connection->lastInsertId('tx_tracking_pageview') + ); } private function getFieldsFromModel(Model $pageview): array @@ -107,7 +132,7 @@ class Pageview 'sys_language_uid' => $pageview->getLanguage()->getLanguageId(), 'url' => $pageview->getUrl(), 'user_agent' => $pageview->getUserAgent(), - 'operating_system' => $pageview->getOperatingSystem(), + 'compatible_version' => Extension::getCompatibleVersionNow(), ]; } } diff --git a/Classes/Domain/Repository/Recordview.php b/Classes/Domain/Repository/Recordview.php index 15edb4f..e669a1d 100644 --- a/Classes/Domain/Repository/Recordview.php +++ b/Classes/Domain/Repository/Recordview.php @@ -24,8 +24,13 @@ declare(strict_types=1); namespace DanielSiepmann\Tracking\Domain\Repository; use DanielSiepmann\Tracking\Domain\Model\Recordview as Model; +use DanielSiepmann\Tracking\Domain\Recordview\Factory; +use DanielSiepmann\Tracking\Extension; use TYPO3\CMS\Core\Database\Connection; +// TODO: Move common code to API class. +// Call API Class with table name + class Recordview { /** @@ -33,10 +38,77 @@ class Recordview */ private $connection; + /** + * @var Factory + */ + private $factory; + + /** + * @var Tag + */ + private $tagRepository; + public function __construct( - Connection $connection + Connection $connection, + Factory $factory, + Tag $tagRepository ) { $this->connection = $connection; + $this->factory = $factory; + $this->tagRepository = $tagRepository; + } + + public function findLegacyCount(): int + { + $queryBuilder = $this->connection->createQueryBuilder(); + $queryBuilder->count('*'); + $queryBuilder->from('tx_tracking_recordview'); + $queryBuilder->where($queryBuilder->expr()->neq('compatible_version', $queryBuilder->createNamedParameter(Extension::getCompatibleVersionNow()))); + $queryBuilder->setMaxResults(Extension::getMaximumRowsForUpdate()); + + $recordviews = $queryBuilder->execute()->fetchColumn(); + if (is_numeric($recordviews) === false) { + return 0; + } + + if ($recordviews > Extension::getMaximumRowsForUpdate()) { + return Extension::getMaximumRowsForUpdate(); + } + return (int) $recordviews; + } + + public function findLegacy(): \Generator + { + $queryBuilder = $this->connection->createQueryBuilder(); + $queryBuilder->select('*'); + $queryBuilder->from('tx_tracking_recordview'); + $queryBuilder->where($queryBuilder->expr()->neq('compatible_version', $queryBuilder->createNamedParameter(Extension::getCompatibleVersionNow()))); + $queryBuilder->setMaxResults(Extension::getMaximumRowsForUpdate()); + + $recordviews = $queryBuilder->execute(); + + while ($pageView = $recordviews->fetch()) { + if (is_array($pageView) === false) { + continue; + } + + yield $this->factory->fromDbRow($pageView); + } + } + + public function update(Model $model): void + { + if ($model->getUid() === 0) { + throw new \InvalidArgumentException('Can not update recordview if uid is 0.', 1585770573); + } + + $this->connection->update( + 'tx_tracking_recordview', + $this->getFieldsFromModel($model), + ['uid' => $model->getUid()] + ); + + $this->tagRepository->updateForRecordview($model); } public function add(Model $recordview): void @@ -45,6 +117,11 @@ class Recordview 'tx_tracking_recordview', $this->getFieldsFromModel($recordview) ); + + $this->tagRepository->addForRecordview( + $recordview, + (int) $this->connection->lastInsertId('tx_tracking_recordview') + ); } private function getFieldsFromModel(Model $recordview): array @@ -56,10 +133,10 @@ class Recordview 'sys_language_uid' => $recordview->getLanguage()->getLanguageId(), 'url' => $recordview->getUrl(), 'user_agent' => $recordview->getUserAgent(), - 'operating_system' => $recordview->getOperatingSystem(), 'record_uid' => $recordview->getRecordUid(), 'record_table_name' => $recordview->getTableName(), 'record' => $recordview->getTableName() . '_' . $recordview->getRecordUid(), + 'compatible_version' => Extension::getCompatibleVersionNow(), ]; } } diff --git a/Classes/Domain/Repository/Tag.php b/Classes/Domain/Repository/Tag.php new file mode 100644 index 0000000..8399f51 --- /dev/null +++ b/Classes/Domain/Repository/Tag.php @@ -0,0 +1,119 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Domain\Repository; + +use DanielSiepmann\Tracking\Domain\Extractors\Registry; +use DanielSiepmann\Tracking\Domain\Extractors\Tag as Model; +use DanielSiepmann\Tracking\Domain\Model\Pageview; +use DanielSiepmann\Tracking\Domain\Model\Recordview; +use DanielSiepmann\Tracking\Extension; +use TYPO3\CMS\Core\Database\Connection; + +class Tag +{ + /** + * @var Connection + */ + private $connection; + + /** + * @var Registry + */ + private $extractorRegistry; + + public function __construct( + Connection $connection, + Registry $extractorRegistry + ) { + $this->connection = $connection; + $this->extractorRegistry = $extractorRegistry; + } + + public function addForPageview( + Pageview $pageview, + int $recordUid + ): void { + foreach ($this->extractorRegistry->getTagsForPageview($pageview) as $tag) { + $this->connection->insert( + 'tx_tracking_tag', + [ + 'pid' => $pageview->getPageUid(), + 'crdate' => $pageview->getCrdate()->format('U'), + 'tstamp' => $pageview->getCrdate()->format('U'), + 'record_uid' => $recordUid, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => $tag->getName(), + 'value' => $tag->getValue(), + ] + ); + } + } + + public function updateForPageview( + Pageview $pageview + ): void { + $this->connection->delete( + 'tx_tracking_tag', + [ + 'record_uid' => $pageview->getUid(), + 'record_table_name' => 'tx_tracking_pageview', + ] + ); + $this->addForPageview($pageview, $pageview->getUid()); + } + + public function addForRecordview( + Recordview $recordview, + int $recordUid + ): void { + foreach ($this->extractorRegistry->getTagsForRecordview($recordview) as $tag) { + $this->connection->insert( + 'tx_tracking_tag', + [ + 'pid' => $recordview->getPageUid(), + 'crdate' => $recordview->getCrdate()->format('U'), + 'tstamp' => $recordview->getCrdate()->format('U'), + 'record_uid' => $recordUid, + 'record_table_name' => 'tx_tracking_recordview', + 'name' => $tag->getName(), + 'value' => $tag->getValue(), + 'compatible_version' => Extension::getCompatibleVersionNow(), + ] + ); + } + } + + public function updateForRecordview( + Recordview $recordview + ): void { + $this->connection->delete( + 'tx_tracking_tag', + [ + 'record_uid' => $recordview->getUid(), + 'record_table_name' => 'tx_tracking_recordview', + ] + ); + $this->addForRecordview($recordview, $recordview->getUid()); + } +} diff --git a/Classes/Extension.php b/Classes/Extension.php index 4b005d2..d297a62 100644 --- a/Classes/Extension.php +++ b/Classes/Extension.php @@ -28,4 +28,15 @@ final class Extension public const EXT_KEY = 'tracking'; public const LANGUAGE_PATH = 'LLL:EXT:' . self::EXT_KEY . '/Resources/Private/Language/locallang.xlf'; + + public static function getCompatibleVersionNow(): string + { + return 'v2.0.0'; + } + + public static function getMaximumRowsForUpdate(): int + { + // TODO: Make configurable + return 3500; + } } diff --git a/Configuration/Bots.yaml b/Configuration/Bots.yaml new file mode 100644 index 0000000..77d9d2f --- /dev/null +++ b/Configuration/Bots.yaml @@ -0,0 +1,18 @@ +- regex: 'nettle' + name: 'Nettle' +- regex: 'crusty' + name: 'Crusty' +- regex: 'Faraday' + name: 'Faraday' +- regex: 'newspaper' + name: 'Newspaper' +- regex: 'uni-passau' + name: 'Uni Passau' +- regex: 'Upflow' + name: 'Upflow' +- regex: 'MauiBot' + name: 'Maui Bot' +- regex: 'Java' + name: 'Java' +- regex: 'python-requests' + name: 'Python Requests' diff --git a/Configuration/Services.php b/Configuration/Services.php new file mode 100644 index 0000000..4f2ce42 --- /dev/null +++ b/Configuration/Services.php @@ -0,0 +1,40 @@ +registerForAutoconfiguration(PageviewExtractor::class)->addTag('tracking.extractor.pageview'); + $containerBuilder->registerForAutoconfiguration(RecordviewExtractor::class)->addTag('tracking.extractor.recordview'); + $containerBuilder->addCompilerPass(new class() implements CompilerPassInterface { + public function process(ContainerBuilder $containerBuilder): void + { + $registry = $containerBuilder->findDefinition(Registry::class); + foreach ($containerBuilder->findTaggedServiceIds('tracking.extractor.pageview') as $id => $tags) { + $definition = $containerBuilder->findDefinition($id); + if (!$definition->isAutoconfigured() || $definition->isAbstract()) { + continue; + } + + $registry->addMethodCall('addPageviewExtractor', [$definition]); + } + foreach ($containerBuilder->findTaggedServiceIds('tracking.extractor.recordview') as $id => $tags) { + $definition = $containerBuilder->findDefinition($id); + if (!$definition->isAutoconfigured() || $definition->isAbstract()) { + continue; + } + + $registry->addMethodCall('addRecordviewExtractor', [$definition]); + } + } + }); +}; + diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index df8bb13..e3a915f 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -43,6 +43,14 @@ services: arguments: - 'tx_tracking_recordview' + dbconnection.tx_tracking_tag: + class: 'TYPO3\CMS\Core\Database\Connection' + factory: + - '@TYPO3\CMS\Core\Database\ConnectionPool' + - 'getConnectionForTable' + arguments: + - 'tx_tracking_tag' + DanielSiepmann\Tracking\Domain\Repository\Pageview: public: true arguments: @@ -53,18 +61,17 @@ services: arguments: - '@dbconnection.tx_tracking_recordview' + DanielSiepmann\Tracking\Domain\Repository\Tag: + public: true + arguments: + - '@dbconnection.tx_tracking_tag' + DanielSiepmann\Tracking\Middleware\Pageview: public: true arguments: $rule: > not (context.getAspect("backend.user").isLoggedIn()) and not (context.getAspect("frontend.preview").isPreview()) - and traverse(request.getHeader("User-Agent"), '0') - and not (request.getHeader("User-Agent")[0] matches "/^TYPO3|TYPO3 linkvalidator/") - 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/") - and not (request.getHeader("User-Agent")[0] matches "/UptimeRobot|Pingdom/") DanielSiepmann\Tracking\Middleware\Recordview: public: true @@ -75,3 +82,4 @@ services: tags: - name: 'console.command' command: 'tracking:updatedata' + description: 'Updates existing data.' diff --git a/Configuration/TCA/tx_tracking_pageview.php b/Configuration/TCA/tx_tracking_pageview.php index 89c39ae..8c61f09 100644 --- a/Configuration/TCA/tx_tracking_pageview.php +++ b/Configuration/TCA/tx_tracking_pageview.php @@ -17,7 +17,7 @@ return [ ], 'types' => [ '0' => [ - 'showitem' => 'sys_language_uid, pid, url, user_agent, operating_system, type, crdate', + 'showitem' => 'sys_language_uid, pid, url, user_agent, tags, type, crdate', ], ], 'columns' => [ @@ -56,10 +56,13 @@ return [ 'readOnly' => true, ], ], - 'operating_system' => [ - 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.operating_system', + 'tags' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.tags', 'config' => [ - 'type' => 'input', + 'type' => 'inline', + 'foreign_table' => 'tx_tracking_tag', + 'foreign_field' => 'record_uid', + 'foreign_table_field' => 'record_table_name', 'readOnly' => true, ], ], diff --git a/Configuration/TCA/tx_tracking_recordview.php b/Configuration/TCA/tx_tracking_recordview.php index 98085c0..fffe3cf 100644 --- a/Configuration/TCA/tx_tracking_recordview.php +++ b/Configuration/TCA/tx_tracking_recordview.php @@ -17,7 +17,7 @@ return [ ], 'types' => [ '0' => [ - 'showitem' => 'sys_language_uid, pid, record, url, user_agent, operating_system, crdate', + 'showitem' => 'sys_language_uid, pid, record, url, user_agent, tags, crdate', ], ], 'columns' => [ @@ -56,13 +56,6 @@ return [ 'readOnly' => true, ], ], - 'operating_system' => [ - 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.recordview.operating_system', - 'config' => [ - 'type' => 'input', - 'readOnly' => true, - ], - ], 'url' => [ 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.recordview.url', 'config' => [ @@ -82,5 +75,15 @@ return [ 'size' => 1, ], ], + 'tags' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.recordview.tags', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_tracking_tag', + 'foreign_field' => 'record_uid', + 'foreign_table_field' => 'record_table_name', + 'readOnly' => true, + ], + ], ], ]; diff --git a/Configuration/TCA/tx_tracking_tag.php b/Configuration/TCA/tx_tracking_tag.php new file mode 100644 index 0000000..88795e8 --- /dev/null +++ b/Configuration/TCA/tx_tracking_tag.php @@ -0,0 +1,67 @@ + [ + 'label' => 'name', + 'label_alt' => 'value', + 'label_alt_force' => true, + 'default_sortby' => 'crdate DESC', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'hideTable' => true, + 'title' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.tag', + ], + 'types' => [ + '0' => [ + 'showitem' => 'pid, record_uid, record_table_name, name, value', + ], + ], + 'columns' => [ + 'pid' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.tag.pid', + 'config' => [ + // TYPO3 v10 does no longer allow to resolve PID relations, e.g. via select or group + // This will break internal PID handling. + 'type' => 'input', + 'readOnly' => true, + ], + ], + 'record_uid' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.tag.record_uid', + 'config' => [ + 'type' => 'input', + 'eval' => 'int', + 'readOnly' => true, + ], + ], + 'record_table_name' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.tag.record_table_name', + 'config' => [ + 'type' => 'input', + 'readOnly' => true, + ], + ], + 'crdate' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.tag.crdate', + 'config' => [ + 'type' => 'input', + 'eval' => 'datetime', + ], + ], + 'name' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.tag.name', + 'config' => [ + 'type' => 'input', + 'readOnly' => true, + ], + ], + 'value' => [ + 'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.tag.value', + 'config' => [ + 'type' => 'input', + 'readOnly' => true, + ], + ], + ], +]; diff --git a/Documentation/Changelog/2.0.0.rst b/Documentation/Changelog/2.0.0.rst new file mode 100644 index 0000000..18ce3c3 --- /dev/null +++ b/Documentation/Changelog/2.0.0.rst @@ -0,0 +1,65 @@ +2.0.0 +===== + +Breaking +-------- + +* No longer has ``operating_system`` database column. + +* No longer ships default rule to not track requests from bots. + Does track them as bots now. + + How to update: + + Remove custom adjustments from :file:`Services.yaml` regarding bot detection. + Instead extend built in bot extraction and adjust custom widgets to exclude those + bots. + + Execute the provided command (scheduler task) to update existing data. + Bots and operating system will be extracted from stored user agent. + + See: :ref:`tags`. + +* Existing widgets will no longer work with custom configuration. + Configuration needs to be adjusted. + + .. todo:: document how to migrate + +* Widgets will not work with old data. + How to migrate data: + + Execute the provided scheduler task. + It will incrementally update pageviews and recordviews. + 3500 records of each will be updated per each run. + Roughly executing every 10 minutes seems to be a good idea. + +Features +-------- + +* Added support for tags + + Tags can now be added to :ref:`pageview` and :ref:`recordview`. + The extension ships with some out of the box, but further can be added, see + :ref:`tags`. + + Resolves: :issue:`46`. + + Sponsored by: https://www.werkraum-media.de/ + +* Uses ``matomo/device-detector`` library to detect bots. + Some known bots are added on top. + +Fixes +----- + +Nothing + +Tasks +----- + +Nothing + +Deprecation +----------- + +Nothing diff --git a/Documentation/Index.rst b/Documentation/Index.rst index 80225d0..3236356 100644 --- a/Documentation/Index.rst +++ b/Documentation/Index.rst @@ -41,6 +41,8 @@ The extension allows to track :ref:`pageview`, as well as views to specific TYPO3 records via :ref:`recordview`, e.g. records from EXT:news or EXT:tt_address. +Each of them can be extended with arbitrary tags extracted from request. + Missing features ---------------- @@ -90,4 +92,6 @@ in order to extract further information from them with future updates. Installation Pageview Recordview + Tags + UpdateExistingRecords Changelog diff --git a/Documentation/Pageview.rst b/Documentation/Pageview.rst index c6393ca..431167c 100644 --- a/Documentation/Pageview.rst +++ b/Documentation/Pageview.rst @@ -43,12 +43,6 @@ Let us examine an concrete example:: $rule: > not (context.getAspect("backend.user").isLoggedIn()) and not (context.getAspect("frontend.preview").isPreview()) - and traverse(request.getHeader("User-Agent"), '0') - and not (request.getHeader("User-Agent")[0] matches "/^TYPO3|TYPO3 linkvalidator/") - and not (request.getHeader("User-Agent")[0] matches "/^Codeception Testing/") - and not (request.getHeader("User-Agent")[0] matches "/Wget|curl|Go-http-client/") - and not (request.getHeader("User-Agent")[0] matches "/bot|spider|Slurp|Sogou|NextCloud-News|Feedly|XING FeedReader|SEOkicks|Seekport Crawler|ia_archiver|TrendsmapResolver|Nuzzel/") - and not (request.getHeader("User-Agent")[0] matches "/mattermost|Slackbot|WhatsApp/") The first paragraph will not be explained, check out :ref:`t3coreapi:configure-dependency-injection-in-extensions` instead. @@ -71,8 +65,7 @@ Check `PSR-7: HTTP message interfaces 0 and not (context.getAspect("backend.user").isLoggedIn()) and not (context.getAspect("frontend.preview").isPreview()) - and traverse(request.getHeader("User-Agent"), '0') - and not (request.getHeader("User-Agent")[0] matches "/^TYPO3|TYPO3 linkvalidator/") - and not (request.getHeader("User-Agent")[0] matches "/Wget|curl|Go-http-client/") - and not (request.getHeader("User-Agent")[0] matches "/bot|spider|Slurp|Sogou|NextCloud-News|Feedly|XING FeedReader|SEOkicks|Seekport Crawler|ia_archiver|TrendsmapResolver|Nuzzel/") - and not (request.getHeader("User-Agent")[0] matches "/mattermost|Slackbot|WhatsApp/") recordUid: 'traverse(request.getQueryParams(), "tx_news_pi1", "news")' tableName: 'tx_news_domain_model_news' diff --git a/Documentation/Tags.rst b/Documentation/Tags.rst new file mode 100644 index 0000000..8d07667 --- /dev/null +++ b/Documentation/Tags.rst @@ -0,0 +1,35 @@ +.. _tags: + +Tags +===== + +Tags are attached to all tracking information like :ref:`pageview` and :ref:`recordview`. +An example for a single record would be: ``bot:"yes",bot_name:"Slack",os:"Unkown"``. + +Tags are extracted whenever a new record is saved, also during :ref:`updateExistingRecords`. + +The extension provides some extractors to attach tags out of the box. +Further can be provided by foreign extensions or sites. +Each extractor has to implement either ``DanielSiepmann\Tracking\Domain\Extractors\PageviewExtractor`` and \ or ``DanielSiepmann\Tracking\Domain\Extractors\RecordviewExtractor`` interface. + +This allows to add arbitrary data as tags to each tracking record. +Those can then be used to generate reports or build widgets. + +Existing extractors +------------------- + +The following are provided out of the box. +One can replace them using :file:`Services.yaml`. + +Operating System +^^^^^^^^^^^^^^^^ + +Contains old logic to detect operating system of requests. +The operating system is added as ``os`` tag, e.g.: ``os:"Macintosh"``. + +Bots +^^^^ + +Contains old logic to detect bots of requests. +The bot is added either as ``bot:"no"``. +If a bot is detected it is added as ``bot:"yes"`` combined with its name ``bot_name:"Slack"``. diff --git a/Documentation/UpdateExistingRecords.rst b/Documentation/UpdateExistingRecords.rst new file mode 100644 index 0000000..bfcf62c --- /dev/null +++ b/Documentation/UpdateExistingRecords.rst @@ -0,0 +1,5 @@ +.. highlight:: php +.. _updateExistingRecords: + +Update existing records +======================= diff --git a/Resources/Private/Language/locallang_tca.xlf b/Resources/Private/Language/locallang_tca.xlf index 4043044..c522c7f 100644 --- a/Resources/Private/Language/locallang_tca.xlf +++ b/Resources/Private/Language/locallang_tca.xlf @@ -27,8 +27,8 @@ User agent - - Operating System + + Tags @@ -55,8 +55,24 @@ User agent - - Operating System + + Tags + + + + PID + + + Foreign Record UID + + + Foreign Record Table Name + + + Name + + + Value diff --git a/Tests/Functional/Command/UpdateDataCommandTest.php b/Tests/Functional/Command/UpdateDataCommandTest.php index ac85d23..cc452d6 100644 --- a/Tests/Functional/Command/UpdateDataCommandTest.php +++ b/Tests/Functional/Command/UpdateDataCommandTest.php @@ -1,6 +1,6 @@ @@ -21,13 +21,16 @@ namespace DanielSiepmann\Tracking\Tests\Functional\Command; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional\Command; + use DanielSiepmann\Tracking\Command\UpdateDataCommand; +use DanielSiepmann\Tracking\Extension; 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 + * @covers \DanielSiepmann\Tracking\Command\UpdateDataCommand */ class UpdateDataCommandTest extends TestCase { @@ -44,18 +47,112 @@ class UpdateDataCommandTest extends TestCase */ public function updatesAllEntriesWithMissingOperatingSystem(): void { - $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml'); + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/UpdateDataCommandTest/WithMissingOperatingSystem.xml'); $subject = GeneralUtility::makeInstance(UpdateDataCommand::class); $tester = new CommandTester($subject); $tester->execute([], ['capture_stderr_separately' => true]); - static::assertSame(0, $tester->getStatusCode()); + self::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']); + $records = $this->getAllRecords('tx_tracking_tag'); + self::assertCount(8, $records); + self::assertSame([ + 'uid'=> '1', + 'pid'=> '1', + 'tstamp'=> '1630649915', + 'crdate'=> '1630649915', + 'cruser_id'=> '0', + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[0])); + self::assertSame([ + 'uid'=> '2', + 'pid'=> '1', + 'tstamp'=> '1630649915', + 'crdate'=> '1630649915', + 'cruser_id'=> '0', + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'Linux', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[1])); + self::assertSame([ + 'uid'=> '3', + 'pid'=> '1', + 'tstamp'=> '1630649916', + 'crdate'=> '1630649916', + 'cruser_id'=> '0', + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[2])); + self::assertSame([ + 'uid'=> '4', + 'pid'=> '1', + 'tstamp'=> '1630649916', + 'crdate'=> '1630649916', + 'cruser_id'=> '0', + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'Android', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[3])); + self::assertSame([ + 'uid'=> '5', + 'pid'=> '1', + 'tstamp'=> '1630649915', + 'crdate'=> '1630649915', + 'cruser_id'=> '0', + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_recordview', + 'name' => 'bot', + 'value' => 'no', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[4])); + self::assertSame([ + 'uid'=> '6', + 'pid'=> '1', + 'tstamp'=> '1630649915', + 'crdate'=> '1630649915', + 'cruser_id'=> '0', + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_recordview', + 'name' => 'os', + 'value' => 'Linux', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[5])); + self::assertSame([ + 'uid'=> '7', + 'pid'=> '1', + 'tstamp'=> '1630649916', + 'crdate'=> '1630649916', + 'cruser_id'=> '0', + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_recordview', + 'name' => 'bot', + 'value' => 'no', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[6])); + self::assertSame([ + 'uid'=> '8', + 'pid'=> '1', + 'tstamp'=> '1630649916', + 'crdate'=> '1630649916', + 'cruser_id'=> '0', + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_recordview', + 'name' => 'os', + 'value' => 'Android', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[7])); } /** @@ -63,18 +160,64 @@ class UpdateDataCommandTest extends TestCase */ public function doesNotChangeExistingOperatingSystem(): void { - $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithOperatingSystem.xml'); + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/UpdateDataCommandTest/WithOperatingSystem.xml'); $subject = GeneralUtility::makeInstance(UpdateDataCommand::class); $tester = new CommandTester($subject); $tester->execute([], ['capture_stderr_separately' => true]); - static::assertSame(0, $tester->getStatusCode()); + self::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']); + $records = $this->getAllRecords('tx_tracking_tag'); + self::assertCount(4, $records); + self::assertSame([ + 'uid' => '3', + 'pid' => '1', + 'tstamp'=> '1630649915', + 'crdate'=> '1630649915', + 'cruser_id' => '0', + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[0])); + self::assertSame([ + 'uid' => '4', + 'pid' => '1', + 'tstamp'=> '1630649915', + 'crdate'=> '1630649915', + 'cruser_id' => '0', + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'Linux', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[1])); + self::assertSame([ + 'uid' => '5', + 'pid' => '1', + 'tstamp'=> '1630649916', + 'crdate'=> '1630649916', + 'cruser_id' => '0', + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[2])); + self::assertSame([ + 'uid' => '6', + 'pid' => '1', + 'tstamp'=> '1630649916', + 'crdate'=> '1630649916', + 'cruser_id' => '0', + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'Android', + 'compatible_version' => Extension::getCompatibleVersionNow(), + ], array_map('strval', $records[3])); } /** @@ -88,9 +231,38 @@ class UpdateDataCommandTest extends TestCase $tester = new CommandTester($subject); $tester->execute([], ['capture_stderr_separately' => true]); - static::assertSame(0, $tester->getStatusCode()); + self::assertSame(0, $tester->getStatusCode()); $records = $this->getAllRecords('tx_tracking_pageview'); - static::assertCount(0, $records); + self::assertCount(0, $records); + + $records = $this->getAllRecords('tx_tracking_tag'); + self::assertCount(0, $records); + } + + /** + * @test + */ + public function doesNothingIfAllRecordsAreCompatible(): void + { + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/UpdateDataCommandTest/WithCompatibleVersion.xml'); + + $subject = GeneralUtility::makeInstance(UpdateDataCommand::class); + $tester = new CommandTester($subject); + $tester->execute([], ['capture_stderr_separately' => true]); + + self::assertSame(0, $tester->getStatusCode()); + + $records = $this->getAllRecords('tx_tracking_pageview'); + self::assertCount(1, $records); + + $records = $this->getAllRecords('tx_tracking_recordview'); + self::assertCount(1, $records); + + $records = $this->getAllRecords('tx_tracking_tag'); + self::assertCount(4, $records); + foreach ($records as $record) { + self::assertSame(1663773639, $record['crdate']); + } } } diff --git a/Tests/Functional/Dashboard/Provider/NewestPageviewsTest.php b/Tests/Functional/Dashboard/Provider/NewestPageviewsTest.php index 7ebdfcf..c0f4cab 100644 --- a/Tests/Functional/Dashboard/Provider/NewestPageviewsTest.php +++ b/Tests/Functional/Dashboard/Provider/NewestPageviewsTest.php @@ -1,6 +1,6 @@ @@ -21,13 +21,16 @@ namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; + +use DanielSiepmann\Tracking\Dashboard\Provider\Demand; 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 + * @covers \DanielSiepmann\Tracking\Dashboard\Provider\NewestPageviews */ class NewestPageviewsTest extends TestCase { @@ -51,10 +54,11 @@ class NewestPageviewsTest extends TestCase } $subject = new NewestPageviews( - GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + new Demand() ); - static::assertSame([ + self::assertSame([ 'Url 10 - User-Agent 10', 'Url 9 - User-Agent 9', 'Url 8 - User-Agent 8', @@ -81,10 +85,10 @@ class NewestPageviewsTest extends TestCase $subject = new NewestPageviews( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 2 + new Demand(31, 2) ); - static::assertSame([ + self::assertSame([ 'Url 10 - User-Agent 10', 'Url 9 - User-Agent 9', ], $subject->getItems()); @@ -107,11 +111,10 @@ class NewestPageviewsTest extends TestCase $subject = new NewestPageviews( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 6, - [9] + new Demand(31, 6, [9]) ); - static::assertSame([ + self::assertSame([ 'Url 10 - User-Agent 10', 'Url 8 - User-Agent 8', 'Url 7 - User-Agent 7', @@ -139,12 +142,10 @@ class NewestPageviewsTest extends TestCase $subject = new NewestPageviews( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 6, - [], - [1] + new Demand(31, 6, [], [1]) ); - static::assertSame([ + self::assertSame([ 'Url 9 - User-Agent 9', 'Url 7 - User-Agent 7', 'Url 5 - User-Agent 5', @@ -152,4 +153,6 @@ class NewestPageviewsTest extends TestCase 'Url 1 - User-Agent 1', ], $subject->getItems()); } + + // TODO: Add tests for new feature regarding tags } diff --git a/Tests/Functional/Dashboard/Provider/PageviewsPerDayTest.php b/Tests/Functional/Dashboard/Provider/PageviewsPerDayTest.php index acf8f09..307920f 100644 --- a/Tests/Functional/Dashboard/Provider/PageviewsPerDayTest.php +++ b/Tests/Functional/Dashboard/Provider/PageviewsPerDayTest.php @@ -1,6 +1,6 @@ @@ -21,6 +21,10 @@ namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; + +use DanielSiepmann\Tracking\Dashboard\Provider\Demand; +use DanielSiepmann\Tracking\Dashboard\Provider\Demand\Tag; use DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerDay; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Localization\LanguageService; @@ -28,7 +32,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; /** - * @covers DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerDay + * @covers \DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerDay */ class PageviewsPerDayTest extends TestCase { @@ -51,12 +55,13 @@ class PageviewsPerDayTest extends TestCase $subject = new PageviewsPerDay( GeneralUtility::makeInstance(LanguageService::class), - GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + new Demand() ); $result = $subject->getChartData(); - static::assertCount(32, $result['labels']); - static::assertCount(32, $result['datasets'][0]['data']); + self::assertCount(32, $result['labels']); + self::assertCount(32, $result['datasets'][0]['data']); } /** @@ -76,12 +81,12 @@ class PageviewsPerDayTest extends TestCase $subject = new PageviewsPerDay( GeneralUtility::makeInstance(LanguageService::class), GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 3 + new Demand(3) ); $result = $subject->getChartData(); - static::assertCount(4, $result['labels']); - static::assertSame([ + self::assertCount(4, $result['labels']); + self::assertSame([ 1, 1, 1, @@ -106,13 +111,12 @@ class PageviewsPerDayTest extends TestCase $subject = new PageviewsPerDay( GeneralUtility::makeInstance(LanguageService::class), GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 3, - [2] + new Demand(3, 0, [2]) ); $result = $subject->getChartData(); - static::assertCount(4, $result['labels']); - static::assertSame([ + self::assertCount(4, $result['labels']); + self::assertSame([ 1, 0, 1, @@ -131,18 +135,16 @@ class PageviewsPerDayTest extends TestCase $subject = new PageviewsPerDay( GeneralUtility::makeInstance(LanguageService::class), GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 1, - [], - [], + new Demand(1, 0, [], []), 'd.m.Y' ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ date('d.m.Y', strtotime('-1 day')), date('d.m.Y'), ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } /** @@ -162,13 +164,11 @@ class PageviewsPerDayTest extends TestCase $subject = new PageviewsPerDay( GeneralUtility::makeInstance(LanguageService::class), GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 11, - [], - [1] + new Demand(11, 0, [], [1]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 0 => 0, 1 => 0, 2 => 1, @@ -183,4 +183,140 @@ class PageviewsPerDayTest extends TestCase 11 => 0, ], $result['datasets'][0]['data']); } + + /** + * @test + */ + public function respectedConfiguredTagRuleToNotIncludeBots(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i * 20, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'record_uid' => $i * 20, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'crdate' => strtotime('-' . $i . ' days'), + ]); + + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i * 300, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'record_uid' => $i * 300, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'yes', + 'crdate' => strtotime('-' . $i . ' days'), + ]); + } + + $subject = new PageviewsPerDay( + GeneralUtility::makeInstance(LanguageService::class), + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + new Demand(2, 0, [], [], [ + Tag::createFromArray([ + 'name' => 'bot', + 'value' => 'no', + ]), + ]) + ); + + $result = $subject->getChartData(); + self::assertSame([ + 0 => 2, + 1 => 2, + 2 => 0, + ], $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedConfiguredTagRuleToIncludeBots(): void + { + $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + for ($i = 1; $i <= 10; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i * 20, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'record_uid' => $i * 20, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'crdate' => strtotime('-' . $i . ' days'), + ]); + + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i * 300, + 'crdate' => strtotime('-' . $i . ' days'), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'record_uid' => $i * 300, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'yes', + 'crdate' => strtotime('-' . $i . ' days'), + ]); + } + + $subject = new PageviewsPerDay( + GeneralUtility::makeInstance(LanguageService::class), + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + new Demand(2, 0, [], [], [ + Tag::createFromArray([ + 'name' => 'bot', + 'value' => 'yes', + ]), + ]) + ); + + $result = $subject->getChartData(); + self::assertSame([ + 0 => 1, + 1 => 1, + 2 => 0, + ], $result['datasets'][0]['data']); + } } diff --git a/Tests/Functional/Dashboard/Provider/PageviewsPerOperatingSystemTest.php b/Tests/Functional/Dashboard/Provider/PageviewsPerOperatingSystemTest.php index 2adbbe2..c288d79 100644 --- a/Tests/Functional/Dashboard/Provider/PageviewsPerOperatingSystemTest.php +++ b/Tests/Functional/Dashboard/Provider/PageviewsPerOperatingSystemTest.php @@ -1,6 +1,6 @@ @@ -21,13 +21,16 @@ namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; + +use DanielSiepmann\Tracking\Dashboard\Provider\Demand; 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 + * @covers \DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerOperatingSystem */ class PageviewsPerOperatingSystemTest extends TestCase { @@ -41,20 +44,36 @@ class PageviewsPerOperatingSystemTest extends TestCase public function listsSixResultsForLast31DaysByDefault(): void { $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); + $connection->insert('tx_tracking_pageview', [ + 'pid' => 1, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => 1, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System ' . 1, + ]); for ($i = 1; $i <= 10; $i++) { $connection->insert('tx_tracking_pageview', [ 'pid' => $i, - 'operating_system' => 'System ' . $i, 'crdate' => time(), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System ' . $i, + ]); } $subject = new PageviewsPerOperatingSystem( - GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + new Demand() ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'System 1', 'System 10', 'System 2', @@ -62,7 +81,14 @@ class PageviewsPerOperatingSystemTest extends TestCase 'System 4', 'System 5', ], $result['labels']); - static::assertCount(6, $result['datasets'][0]['data']); + self::assertSame([ + '2', + '1', + '1', + '1', + '1', + '1', + ], array_map('strval', $result['datasets'][0]['data'])); } /** @@ -74,36 +100,61 @@ class PageviewsPerOperatingSystemTest extends TestCase $connection = $this->getConnectionPool()->getConnectionForTable('tx_tracking_pageview'); $connection->insert('tx_tracking_pageview', [ 'pid' => 1, - 'operating_system' => 'System 1', 'crdate' => time(), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System 1', + ]); $connection->insert('tx_tracking_pageview', [ 'pid' => 2, - 'operating_system' => 'System 2', 'crdate' => time(), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System 2', + ]); $connection->insert('tx_tracking_pageview', [ 'pid' => 3, - 'operating_system' => 'System 3', 'crdate' => time(), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => '3', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System 3', + ]); $connection->insert('tx_tracking_pageview', [ - 'pid' => 2, - 'operating_system' => 'System 2', + 'pid' => 3, 'crdate' => time(), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => '4', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System 2', + ]); $subject = new PageviewsPerOperatingSystem( - GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview') + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + new Demand() ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'System 2', 'System 1', 'System 3', ], $result['labels']); - static::assertCount(3, $result['datasets'][0]['data']); + self::assertSame([ + '2', + '1', + '1', + ], array_map('strval', $result['datasets'][0]['data'])); } /** @@ -115,31 +166,49 @@ class PageviewsPerOperatingSystemTest extends TestCase $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_tag', [ + 'record_uid' => '1', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System 1', + ]); $connection->insert('tx_tracking_pageview', [ 'pid' => 2, - 'operating_system' => 'System 2', 'crdate' => strtotime('-2 days'), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => '2', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System 2', + ]); $connection->insert('tx_tracking_pageview', [ 'pid' => 3, - 'operating_system' => 'System 3', 'crdate' => strtotime('-1 days'), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => '3', + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System 3', + ]); $subject = new PageviewsPerOperatingSystem( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 2 + new Demand(2) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'System 2', 'System 3', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertSame([ + '1', + '1', + ], array_map('strval', $result['datasets'][0]['data'])); } /** @@ -152,25 +221,34 @@ class PageviewsPerOperatingSystemTest extends TestCase for ($i = 1; $i <= 10; $i++) { $connection->insert('tx_tracking_pageview', [ 'pid' => $i, - 'operating_system' => 'System ' . $i, 'crdate' => time(), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System ' . $i, + ]); } $subject = new PageviewsPerOperatingSystem( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 31, - 4 + new Demand(31, 4) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'System 1', 'System 10', 'System 2', 'System 3', ], $result['labels']); - static::assertCount(4, $result['datasets'][0]['data']); + self::assertSame([ + '1', + '1', + '1', + '1', + ], array_map('strval', $result['datasets'][0]['data'])); } /** @@ -184,26 +262,37 @@ class PageviewsPerOperatingSystemTest extends TestCase $connection->insert('tx_tracking_pageview', [ 'pid' => $i, 'sys_language_uid' => $i % 2, - 'operating_system' => 'System ' . $i, 'crdate' => time(), ]); + $connection->insert('tx_tracking_tag', [ + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'os', + 'value' => 'System ' . $i, + ]); } $subject = new PageviewsPerOperatingSystem( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - 31, - 6, - [1] + new Demand(31, 6, [], [1]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'System 1', 'System 3', 'System 5', 'System 7', 'System 9', ], $result['labels']); - static::assertCount(5, $result['datasets'][0]['data']); + self::assertSame([ + '1', + '1', + '1', + '1', + '1', + ], array_map('strval', $result['datasets'][0]['data'])); } + + // TODO: Add tests for new feature regarding tags } diff --git a/Tests/Functional/Dashboard/Provider/PageviewsPerPageTest.php b/Tests/Functional/Dashboard/Provider/PageviewsPerPageTest.php index 74084de..555db45 100644 --- a/Tests/Functional/Dashboard/Provider/PageviewsPerPageTest.php +++ b/Tests/Functional/Dashboard/Provider/PageviewsPerPageTest.php @@ -1,6 +1,6 @@ @@ -21,6 +21,10 @@ namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; + +use DanielSiepmann\Tracking\Dashboard\Provider\Demand; +use DanielSiepmann\Tracking\Dashboard\Provider\Demand\Tag; use DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerPage; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Domain\Repository\PageRepository; @@ -28,7 +32,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; /** - * @covers DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerPage + * @covers \DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerPage */ class PageviewsPerPageTest extends TestCase { @@ -46,17 +50,19 @@ class PageviewsPerPageTest extends TestCase for ($i = 1; $i <= 10; $i++) { $connection->insert('tx_tracking_pageview', [ 'pid' => $i, + 'uid' => $i, 'crdate' => time(), ]); } $subject = new PageviewsPerPage( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - GeneralUtility::makeInstance(PageRepository::class) + GeneralUtility::makeInstance(PageRepository::class), + new Demand() ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Page 10', 'Page 9', 'Page 8', @@ -64,7 +70,7 @@ class PageviewsPerPageTest extends TestCase 'Page 6', 'Page 5', ], $result['labels']); - static::assertCount(6, $result['datasets'][0]['data']); + self::assertCount(6, $result['datasets'][0]['data']); } /** @@ -93,16 +99,17 @@ class PageviewsPerPageTest extends TestCase $subject = new PageviewsPerPage( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), - GeneralUtility::makeInstance(PageRepository::class) + GeneralUtility::makeInstance(PageRepository::class), + new Demand() ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Page 2', 'Page 3', 'Page 1', ], $result['labels']); - static::assertCount(3, $result['datasets'][0]['data']); + self::assertCount(3, $result['datasets'][0]['data']); } /** @@ -128,15 +135,15 @@ class PageviewsPerPageTest extends TestCase $subject = new PageviewsPerPage( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), GeneralUtility::makeInstance(PageRepository::class), - 2 + new Demand(2) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Page 3', 'Page 2', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } /** @@ -156,18 +163,17 @@ class PageviewsPerPageTest extends TestCase $subject = new PageviewsPerPage( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), GeneralUtility::makeInstance(PageRepository::class), - 31, - 4 + new Demand(31, 4) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Page 10', 'Page 9', 'Page 8', 'Page 7', ], $result['labels']); - static::assertCount(4, $result['datasets'][0]['data']); + self::assertCount(4, $result['datasets'][0]['data']); } /** @@ -187,19 +193,17 @@ class PageviewsPerPageTest extends TestCase $subject = new PageviewsPerPage( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), GeneralUtility::makeInstance(PageRepository::class), - 31, - 6, - [1, 2, 3, 4, 5, 6] + new Demand(31, 6, [1, 2, 3, 4, 5, 6]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Page 10', 'Page 9', 'Page 8', 'Page 7', ], $result['labels']); - static::assertCount(4, $result['datasets'][0]['data']); + self::assertCount(4, $result['datasets'][0]['data']); } /** @@ -235,18 +239,15 @@ class PageviewsPerPageTest extends TestCase $subject = new PageviewsPerPage( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), GeneralUtility::makeInstance(PageRepository::class), - 31, - 6, - [], - [1] + new Demand(31, 6, [], [1]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Page 2', 'Page 1', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } /** @@ -282,18 +283,141 @@ class PageviewsPerPageTest extends TestCase $subject = new PageviewsPerPage( GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), GeneralUtility::makeInstance(PageRepository::class), - 31, - 6, - [], - [1, '0'] + new Demand(31, 6, [], [1, 0]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Page 2', 'Page 1', 'Page 3', ], $result['labels']); - static::assertCount(3, $result['datasets'][0]['data']); + self::assertCount(3, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedConfiguredTagRuleToNotIncludeBots(): 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, + 'uid' => $i, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'uid' => $i, + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'crdate' => time(), + ]); + } + for ($i = 11; $i <= 20; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'uid' => $i, + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'yes', + 'crdate' => time(), + ]); + } + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class), + new Demand(31, 6, [], [], [ + Tag::createFromArray([ + 'name' => 'bot', + 'value' => 'no', + ]), + ]) + ); + + $result = $subject->getChartData(); + self::assertSame([ + 'Page 10', + 'Page 9', + 'Page 8', + 'Page 7', + 'Page 6', + 'Page 5', + ], $result['labels']); + self::assertCount(6, $result['datasets'][0]['data']); + } + + /** + * @test + */ + public function respectedConfiguredTagRuleToIncludeBots(): 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, + 'uid' => $i, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'uid' => $i, + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'no', + 'crdate' => time(), + ]); + } + for ($i = 11; $i <= 20; $i++) { + $connection->insert('tx_tracking_pageview', [ + 'pid' => $i, + 'uid' => $i, + 'crdate' => time(), + ]); + $connection->insert('tx_tracking_tag', [ + 'pid' => $i, + 'uid' => $i, + 'record_uid' => $i, + 'record_table_name' => 'tx_tracking_pageview', + 'name' => 'bot', + 'value' => 'yes', + 'crdate' => time(), + ]); + } + + $subject = new PageviewsPerPage( + GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_tracking_pageview'), + GeneralUtility::makeInstance(PageRepository::class), + new Demand(31, 6, [], [], [ + Tag::createFromArray([ + 'name' => 'bot', + 'value' => 'yes', + ]), + ]) + ); + + $result = $subject->getChartData(); + self::assertSame([ + 'Page 20', + 'Page 19', + 'Page 18', + 'Page 17', + 'Page 16', + 'Page 15', + ], $result['labels']); + self::assertCount(6, $result['datasets'][0]['data']); } } diff --git a/Tests/Functional/Dashboard/Provider/RecordviewsTest.php b/Tests/Functional/Dashboard/Provider/RecordviewsTest.php index 79d4dbe..ee7c337 100644 --- a/Tests/Functional/Dashboard/Provider/RecordviewsTest.php +++ b/Tests/Functional/Dashboard/Provider/RecordviewsTest.php @@ -1,6 +1,6 @@ @@ -21,13 +21,16 @@ namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; + +use DanielSiepmann\Tracking\Dashboard\Provider\Demand; use DanielSiepmann\Tracking\Dashboard\Provider\Recordviews; 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 + * @covers \DanielSiepmann\Tracking\Dashboard\Provider\Recordviews */ class RecordviewsTest extends TestCase { @@ -53,11 +56,12 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), - $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview') + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), + new Demand() ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 10', 'Category 9', 'Category 8', @@ -65,7 +69,7 @@ class RecordviewsTest extends TestCase 'Category 6', 'Category 5', ], $result['labels']); - static::assertCount(6, $result['datasets'][0]['data']); + self::assertCount(6, $result['datasets'][0]['data']); } /** @@ -103,16 +107,16 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 2 + new Demand(2) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 2', 'Category 3', 'Category 1', ], $result['labels']); - static::assertCount(3, $result['datasets'][0]['data']); + self::assertCount(3, $result['datasets'][0]['data']); } /** @@ -144,15 +148,15 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 2 + new Demand(2) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 3', 'Category 2', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } /** @@ -174,16 +178,15 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 31, - 2 + new Demand(31, 2) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 10', 'Category 9', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } /** @@ -206,20 +209,18 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 31, - 6, - [1, 2, 3, 4, 5] + new Demand(31, 6, [1, 2, 3, 4, 5]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 10', 'Category 9', 'Category 8', 'Category 7', 'Category 6', ], $result['labels']); - static::assertCount(5, $result['datasets'][0]['data']); + self::assertCount(5, $result['datasets'][0]['data']); } /** @@ -247,20 +248,17 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 31, - 6, - [], - [], + new Demand(31, 6), ['sys_category'] ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 3', 'Category 2', 'Category 1', ], $result['labels']); - static::assertCount(3, $result['datasets'][0]['data']); + self::assertCount(3, $result['datasets'][0]['data']); } /** @@ -286,20 +284,17 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 31, - 6, - [], - [], + new Demand(31, 6), [], ['1', 2] ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Content element 2', 'Content element 1', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } /** @@ -334,20 +329,15 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 31, - 6, - [], - [1], - [], - [] + new Demand(31, 6, [], [1]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 2', 'Kategorie 1', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } /** @@ -382,19 +372,16 @@ class RecordviewsTest extends TestCase $subject = new Recordviews( GeneralUtility::makeInstance(PageRepository::class), $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), - 31, - 6, - [], - [1, 0], - [], - [] + new Demand(31, 6, [], [1, 0]) ); $result = $subject->getChartData(); - static::assertSame([ + self::assertSame([ 'Category 1', 'Category 2', ], $result['labels']); - static::assertCount(2, $result['datasets'][0]['data']); + self::assertCount(2, $result['datasets'][0]['data']); } + + // TODO: Add tests for new feature regarding tags } diff --git a/Tests/Functional/Domain/Extractors/BotsTest.php b/Tests/Functional/Domain/Extractors/BotsTest.php new file mode 100644 index 0000000..8a92f09 --- /dev/null +++ b/Tests/Functional/Domain/Extractors/BotsTest.php @@ -0,0 +1,183 @@ + + * + * 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. + */ + +namespace DanielSiepmann\Tracking\Tests\Functional\Domain\Extractors; + +use DanielSiepmann\Tracking\Domain\Extractors\Bots; +use DanielSiepmann\Tracking\Domain\Extractors\Bots\CustomBotParser; +use DanielSiepmann\Tracking\Domain\Model\Extractor; +use DanielSiepmann\Tracking\Domain\Model\Pageview; +use DanielSiepmann\Tracking\Domain\Model\Recordview; +use DeviceDetector\DeviceDetector; +use Prophecy\PhpUnit\ProphecyTrait; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; + +/** + * @covers \DanielSiepmann\Tracking\Domain\Extractors\Bots + */ +class BotsTest extends TestCase +{ + use ProphecyTrait; + + protected $testExtensionsToLoad = [ + 'typo3conf/ext/tracking', + ]; + + /** + * @test + * @dataProvider possibleUserStringWithBots + * @testdox Bot $expectedBot is extracted from Pageview UserAgent string: $userAgent + */ + public function returnsBotForPageview(string $userAgent, string $expectedBot): void + { + $model = $this->prophesize(Pageview::class); + $model->getUserAgent()->willReturn($userAgent); + + $extractor = new Bots(new CustomBotParser()); + $tags = $extractor->extractTagFromPageview($model->reveal()); + + self::assertCount(2, $tags); + self::assertSame('bot', $tags[0]->getName()); + self::assertSame('yes', $tags[0]->getValue()); + self::assertSame('bot_name', $tags[1]->getName()); + self::assertSame($expectedBot, $tags[1]->getValue()); + } + + /** + * @test + * @dataProvider possibleUserStringWithBots + * @testdox Bot $expectedBot is extracted from Recordview UserAgent string: $userAgent + */ + public function returnsBotForRecordview(string $userAgent, string $expectedBot): void + { + $model = $this->prophesize(Recordview::class); + $model->getUserAgent()->willReturn($userAgent); + + $extractor = new Bots(new CustomBotParser()); + $tags = $extractor->extractTagFromRecordview($model->reveal()); + + self::assertCount(2, $tags); + self::assertSame('bot', $tags[0]->getName()); + self::assertSame('yes', $tags[0]->getValue()); + self::assertSame('bot_name', $tags[1]->getName()); + self::assertSame($expectedBot, $tags[1]->getValue()); + } + + public function possibleUserStringWithBots(): array + { + return [ + 0 => [ + 'userAgent' => 'nettle (+https://www.nettle.sk)', + 'expectedBot' => 'Nettle', + ], + 1 => [ + 'userAgent' => 'MauiBot (crawler.feedback+wc@gmail.com)', + 'expectedBot' => 'Generic Bot', + ], + 2 => [ + 'userAgent' => 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)', + 'expectedBot' => 'Facebook External Hit', + ], + 3 => [ + 'userAgent' => 'Java/11.0.10', + 'expectedBot' => 'Java', + ], + 4 => [ + 'userAgent' => 'newspaper/0.2.8', + 'expectedBot' => 'Newspaper', + ], + 5 => [ + 'userAgent' => 'Tiny Tiny RSS/21.05-326850845 (http://tt-rss.org/)', + 'expectedBot' => 'Tiny Tiny RSS', + ], + 6 => [ + 'userAgent' => 'BacklinkCrawler (http://www.backlinktest.com/crawler.html)', + 'expectedBot' => 'BacklinkCrawler', + ], + 7 => [ + 'userAgent' => 'CCBot/2.0 (https://commoncrawl.org/faq/)', + 'expectedBot' => 'ccBot crawler', + ], + 8 => [ + 'userAgent' => 'Tiny Tiny RSS/21.04-e8f78181f (http://tt-rss.org/)', + 'expectedBot' => 'Tiny Tiny RSS', + ], + 9 => [ + 'userAgent' => 'ltx71 - (http://ltx71.com/)', + 'expectedBot' => 'LTX71', + ], + 10 => [ + 'userAgent' => 'FeedFetcher-Google; (+http://www.google.com/feedfetcher.html)', + 'expectedBot' => 'Googlebot', + ], + 11 => [ + 'userAgent' => 'colly - https://github.com/gocolly/colly', + 'expectedBot' => 'colly', + ], + 12 => [ + 'userAgent' => 'WordPress.com; https://serdargunes.wordpress.com', + 'expectedBot' => 'WordPress', + ], + 13 => [ + 'userAgent' => 'Tiny Tiny RSS/21.03-2f402d598 (http://tt-rss.org/)', + 'expectedBot' => 'Tiny Tiny RSS', + ], + 14 => [ + 'userAgent' => 'netEstate NE Crawler (+http://www.website-datenbank.de/)', + 'expectedBot' => 'netEstate', + ], + 15 => [ + 'userAgent' => 'python-requests/2.18.1', + 'expectedBot' => 'Python Requests', + ], + 16 => [ + 'userAgent' => 'PocketParser/2.0 (+https://getpocket.com/pocketparser_ua)', + 'expectedBot' => 'PocketParser', + ], + 17 => [ + 'userAgent' => 'Faraday v0.17.3', + 'expectedBot' => 'Faraday', + ], + 18 => [ + 'userAgent' => 'hgfAlphaXCrawl/0.1 (+https://www.fim.uni-passau.de/data-science/forschung/open-search)', + 'expectedBot' => 'Generic Bot', + ], + 19 => [ + 'userAgent' => 'Upflow/1.0', + 'expectedBot' => 'Upflow', + ], + 20 => [ + 'userAgent' => 'crusty/0.12.0', + 'expectedBot' => 'Crusty', + ], + 21 => [ + 'userAgent' => 'TelegramBot (like TwitterBot)', + 'expectedBot' => 'TelegramBot', + ], + 22 => [ + 'userAgent' => 'python-requests/2.25.1', + 'expectedBot' => 'Python Requests', + ], + ]; + } +} diff --git a/Tests/Functional/Domain/Recordview/FactoryTest.php b/Tests/Functional/Domain/Recordview/FactoryTest.php index a1977e2..6231458 100644 --- a/Tests/Functional/Domain/Recordview/FactoryTest.php +++ b/Tests/Functional/Domain/Recordview/FactoryTest.php @@ -1,6 +1,6 @@ @@ -21,6 +21,8 @@ namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Recordview; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Recordview; + use DanielSiepmann\Tracking\Domain\Model\RecordRule; use DanielSiepmann\Tracking\Domain\Model\Recordview; use DanielSiepmann\Tracking\Domain\Recordview\Factory; @@ -31,7 +33,7 @@ use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; /** - * @covers DanielSiepmann\Tracking\Domain\Recordview\Factory + * @covers \DanielSiepmann\Tracking\Domain\Recordview\Factory */ class FactoryTest extends FunctionalTestCase { @@ -67,7 +69,7 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertInstanceOf(Recordview::class, $result); + self::assertInstanceOf(Recordview::class, $result); } /** @@ -96,7 +98,7 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertSame('Some User Agent', $result->getUserAgent()); + self::assertSame('Some User Agent', $result->getUserAgent()); } /** @@ -125,7 +127,7 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertSame('https://example.com', $result->getUrl()); + self::assertSame('https://example.com', $result->getUrl()); } /** @@ -154,7 +156,7 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertInstanceOf(\DateTimeImmutable::class, $result->getCrdate()); + self::assertInstanceOf(\DateTimeImmutable::class, $result->getCrdate()); } /** @@ -183,7 +185,7 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertSame($language->reveal(), $result->getLanguage()); + self::assertSame($language->reveal(), $result->getLanguage()); } /** @@ -212,7 +214,7 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertSame(10, $result->getPageUid()); + self::assertSame(10, $result->getPageUid()); } /** @@ -241,7 +243,7 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertSame(20, $result->getRecordUid()); + self::assertSame(20, $result->getRecordUid()); } /** @@ -270,6 +272,6 @@ class FactoryTest extends FunctionalTestCase $subject = $this->get(Factory::class); $result = $subject->fromRequest($request->reveal(), $rule->reveal()); - static::assertSame('sys_category', $result->getTableName()); + self::assertSame('sys_category', $result->getTableName()); } } diff --git a/Tests/Functional/Fixtures/Pages.xml b/Tests/Functional/Fixtures/Pages.xml index 20d3076..103fb79 100644 --- a/Tests/Functional/Fixtures/Pages.xml +++ b/Tests/Functional/Fixtures/Pages.xml @@ -58,4 +58,54 @@ 10 Page 10 + + 1 + 12 + Page 12 + + + 1 + 13 + Page 13 + + + 1 + 14 + Page 14 + + + 1 + 15 + Page 15 + + + 1 + 16 + Page 16 + + + 1 + 17 + Page 17 + + + 1 + 18 + Page 18 + + + 1 + 19 + Page 19 + + + 1 + 20 + Page 20 + + + 1 + 21 + Page 21 + diff --git a/Tests/Functional/Fixtures/Typo3FeaturesTest/PageWithRecords.xml b/Tests/Functional/Fixtures/Typo3FeaturesTest/PageWithRecords.xml index 6167f58..83a167e 100644 --- a/Tests/Functional/Fixtures/Typo3FeaturesTest/PageWithRecords.xml +++ b/Tests/Functional/Fixtures/Typo3FeaturesTest/PageWithRecords.xml @@ -10,7 +10,6 @@ 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 diff --git a/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml b/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml deleted file mode 100644 index 88a86ea..0000000 --- a/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithMissingOperatingSystem.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - 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 deleted file mode 100644 index e8cb0ae..0000000 --- a/Tests/Functional/Fixtures/UpdateDataCommandTest/PageviewsWithOperatingSystem.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - 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/UpdateDataCommandTest/WithCompatibleVersion.xml b/Tests/Functional/Fixtures/UpdateDataCommandTest/WithCompatibleVersion.xml new file mode 100644 index 0000000..fa891de --- /dev/null +++ b/Tests/Functional/Fixtures/UpdateDataCommandTest/WithCompatibleVersion.xml @@ -0,0 +1,68 @@ + + + + 0 + 1 + + + + 1 + 1 + 1630649915 + 0 + 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 + v2.0.0 + + + 1 + 1 + 1630649915 + 0 + 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 + sys_category + v2.0.0 + + + 1 + 1 + 1663773639 + 1 + tx_tracking_pageview + bot + no + v2.0.0 + + + 1 + v2 + 1663773639 + 1 + tx_tracking_pageview + os + Linux + v2.0.0 + + + 1 + 3 + 1663773639 + 1 + tx_tracking_recordview + bot + no + v2.0.0 + + + 1 + 4 + 1663773639 + 1 + tx_tracking_recordview + os + Linux + v2.0.0 + + diff --git a/Tests/Functional/Fixtures/UpdateDataCommandTest/WithMissingOperatingSystem.xml b/Tests/Functional/Fixtures/UpdateDataCommandTest/WithMissingOperatingSystem.xml new file mode 100644 index 0000000..26a472f --- /dev/null +++ b/Tests/Functional/Fixtures/UpdateDataCommandTest/WithMissingOperatingSystem.xml @@ -0,0 +1,48 @@ + + + + 0 + 1 + + + + 1 + 1 + 1630649915 + 1630649915 + 0 + 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 + 1630649916 + 1630649916 + 0 + https://example.com/path + Dalvik/2.1.0 (Linux; U; Android 9; ONEPLUS A3003 Build/PKQ1.181203.001) + + + 1 + 1 + 1630649915 + 1630649915 + 0 + 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 + sys_category + + + 1 + 2 + 1630649916 + 1630649916 + 0 + https://example.com/path + Dalvik/2.1.0 (Linux; U; Android 9; ONEPLUS A3003 Build/PKQ1.181203.001) + 1 + sys_category + + diff --git a/Tests/Functional/Fixtures/UpdateDataCommandTest/WithOperatingSystem.xml b/Tests/Functional/Fixtures/UpdateDataCommandTest/WithOperatingSystem.xml new file mode 100644 index 0000000..198d18b --- /dev/null +++ b/Tests/Functional/Fixtures/UpdateDataCommandTest/WithOperatingSystem.xml @@ -0,0 +1,50 @@ + + + + 0 + 1 + + + + 1 + 1 + 1630649915 + 1630649915 + 0 + 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 + 1 + 1630649915 + 1630649915 + 0 + 1 + tx_tracking_pageview + os + Linux + 2.0.0 + + + 1 + 2 + 1630649916 + 1630649916 + 0 + https://example.com/path + Dalvik/2.1.0 (Linux; U; Android 9; ONEPLUS A3003 Build/PKQ1.181203.001) + + + 1 + 2 + 1630649916 + 1630649916 + 0 + 2 + tx_tracking_pageview + os + Android + 2.0.0 + + diff --git a/Tests/Functional/PageviewTest.php b/Tests/Functional/PageviewTest.php index 6e9e34d..a5b1284 100644 --- a/Tests/Functional/PageviewTest.php +++ b/Tests/Functional/PageviewTest.php @@ -1,6 +1,6 @@ @@ -21,6 +21,8 @@ namespace DanielSiepmann\Tracking\Tests\Functional; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional; + use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest; use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; @@ -62,12 +64,68 @@ class PageviewTest extends TestCase $records = $this->getAllRecords('tx_tracking_pageview'); self::assertCount(1, $records); - self::assertSame('1', (string)$records[0]['pid']); - self::assertSame('1', (string)$records[0]['uid']); + self::assertSame(1, $records[0]['pid']); + self::assertSame(1, $records[0]['uid']); self::assertSame('http://localhost/?id=1', $records[0]['url']); self::assertSame('Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0', $records[0]['user_agent']); - self::assertSame('Macintosh', $records[0]['operating_system']); self::assertSame('0', (string)$records[0]['type']); + + $records = $this->getAllRecords('tx_tracking_tag'); + self::assertCount(2, $records); + + self::assertSame(1, $records[0]['pid']); + self::assertSame(1, $records[0]['record_uid']); + self::assertSame('tx_tracking_pageview', $records[0]['record_table_name']); + self::assertSame('bot', $records[0]['name']); + self::assertSame('no', $records[0]['value']); + + self::assertSame(1, $records[1]['pid']); + self::assertSame(1, $records[1]['record_uid']); + self::assertSame('tx_tracking_pageview', $records[1]['record_table_name']); + self::assertSame('os', $records[1]['name']); + self::assertSame('Macintosh', $records[1]['value']); + } + + /** + * @test + */ + public function trackedWithBotResolvedToTags(): void + { + $request = new InternalRequest(); + $request = $request->withPageId(1); + $request = $request->withHeader('User-Agent', 'Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)'); + $response = $this->executeFrontendRequest($request); + + self::assertSame(200, $response->getStatusCode()); + + $records = $this->getAllRecords('tx_tracking_pageview'); + self::assertCount(1, $records); + self::assertSame(1, $records[0]['pid']); + self::assertSame(1, $records[0]['uid']); + self::assertSame('http://localhost/?id=1', $records[0]['url']); + self::assertSame('Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)', $records[0]['user_agent']); + self::assertSame('0', (string)$records[0]['type']); + + $records = $this->getAllRecords('tx_tracking_tag'); + self::assertCount(3, $records); + + self::assertSame(1, $records[0]['pid']); + self::assertSame(1, $records[0]['record_uid']); + self::assertSame('tx_tracking_pageview', $records[0]['record_table_name']); + self::assertSame('bot', $records[0]['name']); + self::assertSame('yes', $records[0]['value']); + + self::assertSame(1, $records[1]['pid']); + self::assertSame(1, $records[1]['record_uid']); + self::assertSame('tx_tracking_pageview', $records[1]['record_table_name']); + self::assertSame('bot_name', $records[1]['name']); + self::assertSame('Slackbot', $records[1]['value']); + + self::assertSame(1, $records[2]['pid']); + self::assertSame(1, $records[2]['record_uid']); + self::assertSame('tx_tracking_pageview', $records[2]['record_table_name']); + self::assertSame('os', $records[2]['name']); + self::assertSame('Unkown', $records[2]['value']); } /** @@ -85,7 +143,7 @@ class PageviewTest extends TestCase self::assertSame(200, $response->getStatusCode()); - $records = $this->getAllRecords('tx_tracking_pageview'); - self::assertCount(0, $records); + self::assertCount(0, $this->getAllRecords('tx_tracking_pageview')); + self::assertCount(0, $this->getAllRecords('tx_tracking_tag')); } } diff --git a/Tests/Functional/RecordviewTest.php b/Tests/Functional/RecordviewTest.php index ce72cf0..2514058 100644 --- a/Tests/Functional/RecordviewTest.php +++ b/Tests/Functional/RecordviewTest.php @@ -1,6 +1,6 @@ @@ -21,6 +21,8 @@ namespace DanielSiepmann\Tracking\Tests\Functional; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional; + use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest; use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; @@ -54,6 +56,7 @@ class RecordviewTest extends TestCase */ public function trackedWhenAllowed(): void { + $this->setUpBackendUserFromFixture(1); $request = new InternalRequest(); $request = $request->withPageId(1); $request = $request->withQueryParameter('topic_id', 1); @@ -64,14 +67,28 @@ class RecordviewTest extends TestCase $records = $this->getAllRecords('tx_tracking_recordview'); self::assertCount(1, $records); - self::assertSame('1', (string)$records[0]['pid']); - self::assertSame('1', (string)$records[0]['uid']); + self::assertSame(1, $records[0]['pid']); + self::assertSame(1, $records[0]['uid']); self::assertSame('http://localhost/?id=1&topic_id=1', $records[0]['url']); self::assertSame('Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0', $records[0]['user_agent']); - self::assertSame('Macintosh', $records[0]['operating_system']); self::assertSame('sys_category_1', $records[0]['record']); - self::assertSame('1', (string)$records[0]['record_uid']); + self::assertSame(1, $records[0]['record_uid']); self::assertSame('sys_category', $records[0]['record_table_name']); + + $records = $this->getAllRecords('tx_tracking_tag'); + self::assertCount(4, $records); + + self::assertSame(1, $records[2]['pid']); + self::assertSame(1, $records[2]['record_uid']); + self::assertSame('tx_tracking_recordview', $records[2]['record_table_name']); + self::assertSame('bot', $records[2]['name']); + self::assertSame('no', $records[2]['value']); + + self::assertSame(1, $records[3]['pid']); + self::assertSame(1, $records[3]['record_uid']); + self::assertSame('tx_tracking_recordview', $records[3]['record_table_name']); + self::assertSame('os', $records[3]['name']); + self::assertSame('Macintosh', $records[3]['value']); } /** diff --git a/Tests/Functional/Typo3FeaturesTest.php b/Tests/Functional/Typo3FeaturesTest.php index 95e5864..3d1f246 100644 --- a/Tests/Functional/Typo3FeaturesTest.php +++ b/Tests/Functional/Typo3FeaturesTest.php @@ -1,6 +1,6 @@ @@ -21,13 +21,15 @@ namespace DanielSiepmann\Tracking\Tests\Functional; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Functional; + use DanielSiepmann\Tracking\Functional\CopyingPageWithRecordsWorks; use TYPO3\CMS\Core\DataHandling\DataHandler; use TYPO3\CMS\Core\Localization\LanguageServiceFactory; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; /** - * @covers \DanielSiepmann\Tracking\Functional\CopyingPageWithRecordsWorks + * @covers \DanielSiepmann\Tracking\Hooks\DataHandler * @testdox This extension works with TYPO3 feature: */ class Typo3FeaturesTest extends TestCase diff --git a/Tests/Unit/Domain/Model/ExtractorTest.php b/Tests/Unit/Domain/Extractors/OperatingSystemTest.php similarity index 67% rename from Tests/Unit/Domain/Model/ExtractorTest.php rename to Tests/Unit/Domain/Extractors/OperatingSystemTest.php index 740330e..11bc74c 100644 --- a/Tests/Unit/Domain/Model/ExtractorTest.php +++ b/Tests/Unit/Domain/Extractors/OperatingSystemTest.php @@ -1,6 +1,6 @@ @@ -21,32 +21,54 @@ namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Model; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Extractors; + +use DanielSiepmann\Tracking\Domain\Extractors\OperatingSystem; use DanielSiepmann\Tracking\Domain\Model\Extractor; -use DanielSiepmann\Tracking\Domain\Model\HasUserAgent; +use DanielSiepmann\Tracking\Domain\Model\Pageview; +use DanielSiepmann\Tracking\Domain\Model\Recordview; use Prophecy\PhpUnit\ProphecyTrait; use TYPO3\TestingFramework\Core\Unit\UnitTestCase as TestCase; /** - * @covers DanielSiepmann\Tracking\Domain\Model\Extractor + * @covers \DanielSiepmann\Tracking\Domain\Extractors\OperatingSystem */ -class ExtractorTest extends TestCase +class OperatingSystemTest extends TestCase { use ProphecyTrait; /** * @test * @dataProvider possibleUserStringWithOperatingSystems - * @testdox Operating system $expectedOperatingSystem is extracted from UserAgent string: $userAgent + * @testdox Operating system $expectedOperatingSystem is extracted from Pageview UserAgent string: $userAgent */ - public function returnsOperatingSystem(string $userAgent, string $expectedOperatingSystem): void + public function returnsOperatingSystemForPageview(string $userAgent, string $expectedOperatingSystem): void { - $model = $this->prophesize(HasUserAgent::class); + $model = $this->prophesize(Pageview::class); $model->getUserAgent()->willReturn($userAgent); - static::assertSame( - $expectedOperatingSystem, - Extractor::getOperatingSystem($model->reveal()) - ); + $extractor = new OperatingSystem(); + $tags = $extractor->extractTagFromPageview($model->reveal()); + + self::assertCount(1, $tags); + self::assertSame($expectedOperatingSystem, $tags[0]->getValue()); + } + + /** + * @test + * @dataProvider possibleUserStringWithOperatingSystems + * @testdox Operating system $expectedOperatingSystem is extracted from Recordview UserAgent string: $userAgent + */ + public function returnsOperatingSystemForRecordview(string $userAgent, string $expectedOperatingSystem): void + { + $model = $this->prophesize(Recordview::class); + $model->getUserAgent()->willReturn($userAgent); + + $extractor = new OperatingSystem(); + $tags = $extractor->extractTagFromRecordview($model->reveal()); + + self::assertCount(1, $tags); + self::assertSame($expectedOperatingSystem, $tags[0]->getValue()); } public function possibleUserStringWithOperatingSystems(): array @@ -62,11 +84,11 @@ class ExtractorTest extends TestCase ], [ 'userAgent' => 'Apache-HttpClient/4.5.2 (Java/1.8.0_151)', - 'expectedOperatingSystem' => '', + 'expectedOperatingSystem' => 'Unkown', ], [ 'userAgent' => 'AwarioSmartBot/1.0 (+https://awario.com/bots.html; bots@awario.com)', - 'expectedOperatingSystem' => '', + 'expectedOperatingSystem' => 'Unkown', ], [ 'userAgent' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', diff --git a/Tests/Unit/Domain/Model/PageviewTest.php b/Tests/Unit/Domain/Model/PageviewTest.php index 780973d..b287fe9 100644 --- a/Tests/Unit/Domain/Model/PageviewTest.php +++ b/Tests/Unit/Domain/Model/PageviewTest.php @@ -1,6 +1,6 @@ @@ -21,13 +21,15 @@ namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Model; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Model; + use DanielSiepmann\Tracking\Domain\Model\Pageview; use Prophecy\PhpUnit\ProphecyTrait; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\TestingFramework\Core\Unit\UnitTestCase as TestCase; /** - * @covers DanielSiepmann\Tracking\Domain\Model\Pageview + * @covers \DanielSiepmann\Tracking\Domain\Model\Pageview */ class PageviewTest extends TestCase { @@ -49,7 +51,7 @@ class PageviewTest extends TestCase '' ); - static::assertInstanceOf(Pageview::class, $subject); + self::assertInstanceOf(Pageview::class, $subject); } /** @@ -68,7 +70,7 @@ class PageviewTest extends TestCase '' ); - static::assertSame(500, $subject->getPageUid()); + self::assertSame(500, $subject->getPageUid()); } /** @@ -87,7 +89,7 @@ class PageviewTest extends TestCase '' ); - static::assertSame($language->reveal(), $subject->getLanguage()); + self::assertSame($language->reveal(), $subject->getLanguage()); } /** @@ -107,7 +109,7 @@ class PageviewTest extends TestCase '' ); - static::assertSame($crdate, $subject->getCrdate()); + self::assertSame($crdate, $subject->getCrdate()); } /** @@ -126,7 +128,7 @@ class PageviewTest extends TestCase '' ); - static::assertSame(999, $subject->getPageType()); + self::assertSame(999, $subject->getPageType()); } /** @@ -145,7 +147,7 @@ class PageviewTest extends TestCase '' ); - static::assertSame('https://example.com/path.html', $subject->getUrl()); + self::assertSame('https://example.com/path.html', $subject->getUrl()); } /** @@ -164,7 +166,7 @@ class PageviewTest extends TestCase 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0' ); - static::assertSame( + self::assertSame( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0', $subject->getUserAgent() ); @@ -186,7 +188,7 @@ class PageviewTest extends TestCase 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0' ); - static::assertSame( + self::assertSame( 0, $subject->getUid() ); @@ -209,31 +211,9 @@ class PageviewTest extends TestCase 10 ); - static::assertSame( + self::assertSame( 10, $subject->getUid() ); } - - /** - * @test - */ - public function returnsOperatingSystem(): void - { - $language = $this->prophesize(SiteLanguage::class); - - $subject = new Pageview( - 0, - $language->reveal(), - new \DateTimeImmutable(), - 0, - '', - 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36' - ); - - static::assertSame( - 'Linux', - $subject->getOperatingSystem() - ); - } } diff --git a/Tests/Unit/Domain/Model/RecordRuleTest.php b/Tests/Unit/Domain/Model/RecordRuleTest.php index e61a5e3..0d4b7d5 100644 --- a/Tests/Unit/Domain/Model/RecordRuleTest.php +++ b/Tests/Unit/Domain/Model/RecordRuleTest.php @@ -1,6 +1,6 @@ @@ -21,11 +21,13 @@ namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Model; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Model; + use DanielSiepmann\Tracking\Domain\Model\RecordRule; use TYPO3\TestingFramework\Core\Unit\UnitTestCase as TestCase; /** - * @covers DanielSiepmann\Tracking\Domain\Model\RecordRule + * @covers \DanielSiepmann\Tracking\Domain\Model\RecordRule */ class RecordRuleTest extends TestCase { @@ -40,7 +42,7 @@ class RecordRuleTest extends TestCase '' ); - static::assertInstanceOf(RecordRule::class, $subject); + self::assertInstanceOf(RecordRule::class, $subject); } /** @@ -55,7 +57,7 @@ class RecordRuleTest extends TestCase 'tableName' => '', ]); - static::assertInstanceOf(RecordRule::class, $subject); + self::assertInstanceOf(RecordRule::class, $subject); } /** @@ -76,9 +78,9 @@ class RecordRuleTest extends TestCase ], ]); - static::assertCount(2, $result); - static::assertInstanceOf(RecordRule::class, $result[0]); - static::assertInstanceOf(RecordRule::class, $result[1]); + self::assertCount(2, $result); + self::assertInstanceOf(RecordRule::class, $result[0]); + self::assertInstanceOf(RecordRule::class, $result[1]); } /** @@ -92,7 +94,7 @@ class RecordRuleTest extends TestCase '' ); - static::assertSame('match expression', $subject->getMatchesExpression()); + self::assertSame('match expression', $subject->getMatchesExpression()); } /** @@ -106,7 +108,7 @@ class RecordRuleTest extends TestCase '' ); - static::assertSame('match expression', $subject->getUidExpression()); + self::assertSame('match expression', $subject->getUidExpression()); } /** @@ -120,6 +122,6 @@ class RecordRuleTest extends TestCase 'table_name' ); - static::assertSame('table_name', $subject->getTableName()); + self::assertSame('table_name', $subject->getTableName()); } } diff --git a/Tests/Unit/Domain/Model/RecordviewTest.php b/Tests/Unit/Domain/Model/RecordviewTest.php index 20e0850..a7c06e9 100644 --- a/Tests/Unit/Domain/Model/RecordviewTest.php +++ b/Tests/Unit/Domain/Model/RecordviewTest.php @@ -1,6 +1,6 @@ @@ -21,13 +21,15 @@ namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Model; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Model; + use DanielSiepmann\Tracking\Domain\Model\Recordview; use Prophecy\PhpUnit\ProphecyTrait; use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\TestingFramework\Core\Unit\UnitTestCase as TestCase; /** - * @covers DanielSiepmann\Tracking\Domain\Model\Recordview + * @covers \DanielSiepmann\Tracking\Domain\Model\Recordview */ class RecordviewTest extends TestCase { @@ -50,7 +52,7 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertInstanceOf(Recordview::class, $subject); + self::assertInstanceOf(Recordview::class, $subject); } /** @@ -70,7 +72,7 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertSame(500, $subject->getPageUid()); + self::assertSame(500, $subject->getPageUid()); } /** @@ -90,7 +92,7 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertSame($language->reveal(), $subject->getLanguage()); + self::assertSame($language->reveal(), $subject->getLanguage()); } /** @@ -111,7 +113,7 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertSame($crdate, $subject->getCrdate()); + self::assertSame($crdate, $subject->getCrdate()); } /** @@ -131,7 +133,7 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertSame('https://example.com/path.html', $subject->getUrl()); + self::assertSame('https://example.com/path.html', $subject->getUrl()); } /** @@ -151,7 +153,7 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertSame( + self::assertSame( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0', $subject->getUserAgent() ); @@ -174,7 +176,7 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertSame( + self::assertSame( 10, $subject->getRecordUid() ); @@ -197,32 +199,9 @@ class RecordviewTest extends TestCase 'sys_category' ); - static::assertSame( + self::assertSame( 'sys_category', $subject->getTableName() ); } - - /** - * @test - */ - public function returnsOperatingSystem(): void - { - $language = $this->prophesize(SiteLanguage::class); - - $subject = new Recordview( - 0, - $language->reveal(), - new \DateTimeImmutable(), - '', - 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', - 10, - 'sys_category' - ); - - static::assertSame( - 'Linux', - $subject->getOperatingSystem() - ); - } } diff --git a/Tests/Unit/Domain/Pageview/FactoryTest.php b/Tests/Unit/Domain/Pageview/FactoryTest.php index 51b7966..97c978d 100644 --- a/Tests/Unit/Domain/Pageview/FactoryTest.php +++ b/Tests/Unit/Domain/Pageview/FactoryTest.php @@ -1,6 +1,6 @@ @@ -21,6 +21,8 @@ namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Pageview; * 02110-1301, USA. */ +namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Pageview; + use DanielSiepmann\Tracking\Domain\Model\Pageview; use DanielSiepmann\Tracking\Domain\Pageview\Factory; use Prophecy\PhpUnit\ProphecyTrait; @@ -33,7 +35,7 @@ use TYPO3\CMS\Core\Site\SiteFinder; use TYPO3\TestingFramework\Core\Unit\UnitTestCase as TestCase; /** - * @covers DanielSiepmann\Tracking\Domain\Pageview\Factory + * @covers \DanielSiepmann\Tracking\Domain\Pageview\Factory */ class FactoryTest extends TestCase { @@ -59,7 +61,7 @@ class FactoryTest extends TestCase $subject = new Factory($this->prophesize(SiteFinder::class)->reveal()); $result = $subject->fromRequest($request->reveal()); - static::assertInstanceOf(Pageview::class, $result); + self::assertInstanceOf(Pageview::class, $result); } /** @@ -84,7 +86,7 @@ class FactoryTest extends TestCase $subject = new Factory($this->prophesize(SiteFinder::class)->reveal()); $result = $subject->fromRequest($request->reveal()); - static::assertSame( + self::assertSame( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0', $result->getUserAgent() ); @@ -110,7 +112,7 @@ class FactoryTest extends TestCase $subject = new Factory($this->prophesize(SiteFinder::class)->reveal()); $result = $subject->fromRequest($request->reveal()); - static::assertSame( + self::assertSame( 'https://example.com/path?query=params&some=more#anchor', $result->getUrl() ); @@ -136,7 +138,7 @@ class FactoryTest extends TestCase $subject = new Factory($this->prophesize(SiteFinder::class)->reveal()); $result = $subject->fromRequest($request->reveal()); - static::assertSame( + self::assertSame( 50, $result->getPageType() ); @@ -162,7 +164,7 @@ class FactoryTest extends TestCase $subject = new Factory($this->prophesize(SiteFinder::class)->reveal()); $result = $subject->fromRequest($request->reveal()); - static::assertInstanceOf(\DateTimeImmutable::class, $result->getCrdate()); + self::assertInstanceOf(\DateTimeImmutable::class, $result->getCrdate()); } /** @@ -185,7 +187,7 @@ class FactoryTest extends TestCase $subject = new Factory($this->prophesize(SiteFinder::class)->reveal()); $result = $subject->fromRequest($request->reveal()); - static::assertInstanceOf(SiteLanguage::class, $result->getLanguage()); + self::assertInstanceOf(SiteLanguage::class, $result->getLanguage()); } /** @@ -208,7 +210,7 @@ class FactoryTest extends TestCase $subject = new Factory($this->prophesize(SiteFinder::class)->reveal()); $result = $subject->fromRequest($request->reveal()); - static::assertSame( + self::assertSame( 10, $result->getPageUid() ); @@ -237,13 +239,13 @@ class FactoryTest extends TestCase 'user_agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', ]); - static::assertInstanceOf(Pageview::class, $result); - static::assertSame(1, $result->getUid()); - static::assertSame(2, $result->getPageUid()); - static::assertSame($siteLanguage->reveal(), $result->getLanguage()); - static::assertSame('1533906435', $result->getCrdate()->format('U')); - static::assertSame(0, $result->getPageType()); - static::assertSame('https://example.com/path', $result->getUrl()); - static::assertSame('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', $result->getUserAgent()); + self::assertInstanceOf(Pageview::class, $result); + self::assertSame(1, $result->getUid()); + self::assertSame(2, $result->getPageUid()); + self::assertSame($siteLanguage->reveal(), $result->getLanguage()); + self::assertSame('1533906435', $result->getCrdate()->format('U')); + self::assertSame(0, $result->getPageType()); + self::assertSame('https://example.com/path', $result->getUrl()); + self::assertSame('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', $result->getUserAgent()); } } diff --git a/Tests/Unit/Domain/Repository/PageviewTest.php b/Tests/Unit/Domain/Repository/PageviewTest.php deleted file mode 100644 index 7b4f844..0000000 --- a/Tests/Unit/Domain/Repository/PageviewTest.php +++ /dev/null @@ -1,231 +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\Domain\Model\Pageview as Model; -use DanielSiepmann\Tracking\Domain\Pageview\Factory; -use DanielSiepmann\Tracking\Domain\Repository\Pageview; -use Doctrine\DBAL\Statement; -use Prophecy\PhpUnit\ProphecyTrait; -use TYPO3\CMS\Core\Database\Connection; -use TYPO3\CMS\Core\Database\Query\QueryBuilder; -use TYPO3\CMS\Core\Site\Entity\SiteLanguage; -use TYPO3\TestingFramework\Core\Unit\UnitTestCase as TestCase; - -/** - * @covers DanielSiepmann\Tracking\Domain\Repository\Pageview - */ -class PageviewTest extends TestCase -{ - use ProphecyTrait; - - /** - * @test - */ - public function modelCanBeAdded(): void - { - $connection = $this->prophesize(Connection::class); - $factory = $this->prophesize(Factory::class); - - $dateTime = $this->prophesize(\DateTimeImmutable::class); - $dateTime->format('U')->willReturn(1582660189); - - $language = $this->prophesize(SiteLanguage::class); - $language->getLanguageId()->willReturn(2); - - $model = $this->prophesize(Model::class); - $model->getPageUid()->willReturn(10); - $model->getCrdate()->willReturn($dateTime->reveal()); - $model->getPageType()->willReturn(999); - $model->getLanguage()->willReturn($language->reveal()); - $model->getUrl()->willReturn('https://example.com/path.html'); - $model->getUserAgent()->willReturn('Mozilla/5.0 (Windows NT 10.0) Gecko/20100101 Firefox/74.0'); - $model->getOperatingSystem()->willReturn('Linux'); - - $connection->insert( - 'tx_tracking_pageview', - [ - 'pid' => 10, - 'crdate' => 1582660189, - 'tstamp' => 1582660189, - 'type' => 999, - 'sys_language_uid' => 2, - 'url' => 'https://example.com/path.html', - 'user_agent' => 'Mozilla/5.0 (Windows NT 10.0) Gecko/20100101 Firefox/74.0', - 'operating_system' => 'Linux', - ] - )->willReturn(1)->shouldBeCalledTimes(1); - - $subject = new Pageview($connection->reveal(), $factory->reveal()); - $subject->add($model->reveal()); - } - - /** - * @test - */ - public function throwsExceptionIfModelToUodateHasNoUid(): void - { - $connection = $this->prophesize(Connection::class); - $factory = $this->prophesize(Factory::class); - - $model = $this->prophesize(Model::class); - $model->getUid()->willReturn(0); - - $subject = new Pageview($connection->reveal(), $factory->reveal()); - $this->expectExceptionMessage('Can not update pageview if uid is 0.'); - $subject->update($model->reveal()); - } - - /** - * @test - */ - public function modelCanBeUpdated(): void - { - $connection = $this->prophesize(Connection::class); - $factory = $this->prophesize(Factory::class); - - $dateTime = $this->prophesize(\DateTimeImmutable::class); - $dateTime->format('U')->willReturn(1582660189); - - $language = $this->prophesize(SiteLanguage::class); - $language->getLanguageId()->willReturn(2); - - $model = $this->prophesize(Model::class); - $model->getUid()->willReturn(1); - $model->getPageUid()->willReturn(10); - $model->getCrdate()->willReturn($dateTime->reveal()); - $model->getPageType()->willReturn(999); - $model->getLanguage()->willReturn($language->reveal()); - $model->getUrl()->willReturn('https://example.com/path.html'); - $model->getUserAgent()->willReturn('Mozilla/5.0 (Windows NT 10.0) Gecko/20100101 Firefox/74.0'); - $model->getOperatingSystem()->willReturn('Linux'); - - $connection->update( - 'tx_tracking_pageview', - [ - 'pid' => 10, - 'crdate' => 1582660189, - 'tstamp' => 1582660189, - 'type' => 999, - 'sys_language_uid' => 2, - 'url' => 'https://example.com/path.html', - 'user_agent' => 'Mozilla/5.0 (Windows NT 10.0) Gecko/20100101 Firefox/74.0', - 'operating_system' => 'Linux', - ], - [ - 'uid' => 1 - ] - )->willReturn(1)->shouldBeCalledTimes(1); - - $subject = new Pageview($connection->reveal(), $factory->reveal()); - $subject->update($model->reveal()); - } - - /** - * @test - */ - public function returnsACountOfAllModels(): void - { - $statement = $this->prophesize(Statement::class); - $statement->fetchColumn()->willReturn(10); - - $queryBuilder = $this->prophesize(QueryBuilder::class); - $queryBuilder->count('uid')->willReturn($queryBuilder->reveal()); - $queryBuilder->from('tx_tracking_pageview')->willReturn($queryBuilder->reveal()); - $queryBuilder->execute()->willReturn($statement->reveal()); - - $connection = $this->prophesize(Connection::class); - $connection->createQueryBuilder()->willReturn($queryBuilder->reveal()); - - $factory = $this->prophesize(Factory::class); - - $subject = new Pageview($connection->reveal(), $factory->reveal()); - static::assertSame(10, $subject->countAll()); - } - - /** - * @test - */ - public function returnsAllModells(): void - { - $statement = $this->prophesize(Statement::class); - $statement->fetch()->willReturn( - [ - 'pid' => '10', - 'crdate' => '1595948372', - 'type' => '0', - 'sys_language_uid' => '0', - 'url' => 'https://example.com/path/file.html', - 'user_agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', - ], - [ - 'pid' => '9', - 'crdate' => '1595948376', - 'type' => '0', - 'sys_language_uid' => '0', - 'url' => 'https://example.com/path/file.html', - 'user_agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', - ], - false - ); - - $queryBuilder = $this->prophesize(QueryBuilder::class); - $queryBuilder->select('*')->willReturn($queryBuilder->reveal()); - $queryBuilder->from('tx_tracking_pageview')->willReturn($queryBuilder->reveal()); - $queryBuilder->execute()->willReturn($statement->reveal()); - - $connection = $this->prophesize(Connection::class); - $connection->createQueryBuilder()->willReturn($queryBuilder->reveal()); - - $model1 = $this->prophesize(Model::class); - $model1->getPageUid()->willReturn(10); - $model2 = $this->prophesize(Model::class); - $model2->getPageUid()->willReturn(9); - - $factory = $this->prophesize(Factory::class); - $factory->fromDbRow([ - 'pid' => '10', - 'crdate' => '1595948372', - 'type' => '0', - 'sys_language_uid' => '0', - 'url' => 'https://example.com/path/file.html', - 'user_agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', - ])->willReturn($model1->reveal()); - $factory->fromDbRow([ - 'pid' => '9', - 'crdate' => '1595948376', - 'type' => '0', - 'sys_language_uid' => '0', - 'url' => 'https://example.com/path/file.html', - 'user_agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36', - ])->willReturn($model2->reveal()); - - $subject = new Pageview($connection->reveal(), $factory->reveal()); - static::assertCount(2, $subject->findAll()); - - $pageUid = 10; - foreach ($subject->findAll() as $model) { - static::assertSame($pageUid, $model->getPageUid()); - --$pageUid; - } - } -} diff --git a/Tests/Unit/Domain/Repository/RecordviewTest.php b/Tests/Unit/Domain/Repository/RecordviewTest.php deleted file mode 100644 index 2e57035..0000000 --- a/Tests/Unit/Domain/Repository/RecordviewTest.php +++ /dev/null @@ -1,80 +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\Domain\Model\Recordview as Model; -use DanielSiepmann\Tracking\Domain\Repository\Recordview; -use Prophecy\PhpUnit\ProphecyTrait; -use TYPO3\CMS\Core\Database\Connection; -use TYPO3\CMS\Core\Site\Entity\SiteLanguage; -use TYPO3\TestingFramework\Core\Unit\UnitTestCase as TestCase; - -/** - * @covers DanielSiepmann\Tracking\Domain\Repository\Recordview - */ -class RecordviewTest extends TestCase -{ - use ProphecyTrait; - - /** - * @test - */ - public function modelCanBeAdded(): void - { - $connection = $this->prophesize(Connection::class); - - $dateTime = $this->prophesize(\DateTimeImmutable::class); - $dateTime->format('U')->willReturn(1582660189); - - $language = $this->prophesize(SiteLanguage::class); - $language->getLanguageId()->willReturn(2); - - $model = $this->prophesize(Model::class); - $model->getPageUid()->willReturn(10); - $model->getCrdate()->willReturn($dateTime->reveal()); - $model->getLanguage()->willReturn($language->reveal()); - $model->getUrl()->willReturn('https://example.com/path.html'); - $model->getUserAgent()->willReturn('Mozilla/5.0 (Windows NT 10.0) Gecko/20100101 Firefox/74.0'); - $model->getOperatingSystem()->willReturn('Linux'); - $model->getRecordUid()->willReturn(10); - $model->getTableName()->willReturn('sys_category'); - - $connection->insert( - 'tx_tracking_recordview', - [ - 'pid' => 10, - 'crdate' => 1582660189, - 'tstamp' => 1582660189, - 'sys_language_uid' => 2, - 'url' => 'https://example.com/path.html', - 'user_agent' => 'Mozilla/5.0 (Windows NT 10.0) Gecko/20100101 Firefox/74.0', - 'operating_system' => 'Linux', - 'record_uid' => 10, - 'record_table_name' => 'sys_category', - 'record' => 'sys_category_10', - ] - )->willReturn(1)->shouldBeCalledTimes(1); - - $subject = new Recordview($connection->reveal()); - $subject->add($model->reveal()); - } -} diff --git a/composer.json b/composer.json index f083a0e..1747ad7 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ "symfony/expression-language": "^5.2", "typo3/cms-backend": "^10.4 || ^11.5", "typo3/cms-core": "^10.4 || ^11.5", - "typo3/cms-dashboard": "^10.4 || ^11.5" + "typo3/cms-dashboard": "^10.4 || ^11.5", + "matomo/device-detector": "^6.0" }, "require-dev": { "phpunit/phpunit": "^9.0", diff --git a/ext_tables.sql b/ext_tables.sql index 5a57184..9b7fe41 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -1,21 +1,34 @@ CREATE TABLE tx_tracking_pageview ( url text, user_agent text, - operating_system varchar(255) DEFAULT '' NOT NULL, type int(11) unsigned DEFAULT '0' NOT NULL, + compatible_version varchar(11) DEFAULT 'v1.1.4' NOT NULL, KEY page_views_per_page (pid,uid,crdate), KEY language (l10n_parent,sys_language_uid), + KEY compatible_version (compatible_version), ); CREATE TABLE tx_tracking_recordview ( url text, user_agent text, - operating_system varchar(255) DEFAULT '' NOT NULL, record varchar(255) DEFAULT '' NOT NULL, record_uid int(11) unsigned DEFAULT '0' NOT NULL, record_table_name varchar(255) DEFAULT '' NOT NULL, + compatible_version varchar(11) DEFAULT 'v1.1.4' NOT NULL, KEY record_views_per_page (pid,uid,crdate), KEY language (l10n_parent,sys_language_uid), + KEY compatible_version (compatible_version), +); + +CREATE TABLE tx_tracking_tag ( + record_uid int(11) unsigned DEFAULT '0' NOT NULL, + record_table_name varchar(255) DEFAULT '' NOT NULL, + name varchar(255) DEFAULT '' NOT NULL, + value longtext DEFAULT '' NOT NULL, + compatible_version varchar(11) DEFAULT 'v2.0.0' NOT NULL, + + KEY combined_identifier (record_uid,record_table_name,name,value), + KEY compatible_version (compatible_version), );