mirror of
https://github.com/DanielSiepmann/tracking.git
synced 2024-11-22 05:56:08 +01:00
Add operating system to page view record
Extract operating system from user agent and store it in database record. Another widget is added which displays the page views per operating system. An command is provided which will update existing data.
This commit is contained in:
parent
8e2cadef08
commit
44ca6a2d3c
16 changed files with 665 additions and 24 deletions
65
Classes/Command/UpdateDataCommand.php
Normal file
65
Classes/Command/UpdateDataCommand.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace DanielSiepmann\Tracking\Command;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||
*
|
||||
* 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\Repository\Pageview;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class UpdateDataCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var Pageview
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
public function __construct(Pageview $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
|
||||
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.');
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
111
Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php
Normal file
111
Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace DanielSiepmann\Tracking\Dashboard\Provider;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||
*
|
||||
* 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 TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Dashboard\WidgetApi;
|
||||
use TYPO3\CMS\Dashboard\Widgets\ChartDataProviderInterface;
|
||||
|
||||
class PageviewsPerOperatingSystem implements ChartDataProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var QueryBuilder
|
||||
*/
|
||||
private $queryBuilder;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $days;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $maxResults;
|
||||
|
||||
public function __construct(
|
||||
QueryBuilder $queryBuilder,
|
||||
int $days = 31,
|
||||
int $maxResults = 6
|
||||
) {
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->days = $days;
|
||||
$this->maxResults = $maxResults;
|
||||
}
|
||||
|
||||
public function getChartData(): array
|
||||
{
|
||||
list($labels, $data) = $this->getPageViewsPerPage();
|
||||
|
||||
return [
|
||||
'labels' => $labels,
|
||||
'datasets' => [
|
||||
[
|
||||
'backgroundColor' => WidgetApi::getDefaultChartColors(),
|
||||
'data' => $data,
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function getPageViewsPerPage(): array
|
||||
{
|
||||
$labels = [];
|
||||
$data = [];
|
||||
|
||||
$constraints = [
|
||||
$this->queryBuilder->expr()->gte(
|
||||
'tx_tracking_pageview.crdate',
|
||||
strtotime('-' . $this->days . ' day 0:00:00')
|
||||
),
|
||||
$this->queryBuilder->expr()->lte(
|
||||
'tx_tracking_pageview.crdate',
|
||||
time()
|
||||
),
|
||||
$this->queryBuilder->expr()->neq(
|
||||
'tx_tracking_pageview.operating_system',
|
||||
$this->queryBuilder->createNamedParameter('')
|
||||
),
|
||||
];
|
||||
|
||||
$result = $this->queryBuilder
|
||||
->selectLiteral('count(operating_system) as total')
|
||||
->addSelect('operating_system')
|
||||
->from('tx_tracking_pageview')
|
||||
->where(... $constraints)
|
||||
->groupBy('tx_tracking_pageview.operating_system')
|
||||
->orderBy('total', 'desc')
|
||||
->setMaxResults($this->maxResults)
|
||||
->execute()
|
||||
->fetchAll();
|
||||
|
||||
foreach ($result as $row) {
|
||||
$labels[] = mb_strimwidth($row['operating_system'], 0, 50, '…');
|
||||
$data[] = $row['total'];
|
||||
}
|
||||
|
||||
return [
|
||||
$labels,
|
||||
$data,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -123,7 +123,7 @@ class PageviewsPerPage implements ChartDataProviderInterface
|
|||
->fetchAll();
|
||||
|
||||
foreach ($result as $row) {
|
||||
$labels[] = mb_strimwidth($row['title'], 0, 50, '…') . ' [' . $row['uid'] . ']';
|
||||
$labels[] = mb_strimwidth($row['title'], 0, 25, '…');
|
||||
$data[] = $row['total'];
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,11 @@ use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
|||
|
||||
class Pageview
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $uid = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
@ -61,8 +66,10 @@ class Pageview
|
|||
\DateTimeImmutable $crdate,
|
||||
int $pageType,
|
||||
string $url,
|
||||
string $userAgent
|
||||
string $userAgent,
|
||||
int $uid = 0
|
||||
) {
|
||||
$this->uid = $uid;
|
||||
$this->pageUid = $pageUid;
|
||||
$this->language = $language;
|
||||
$this->crdate = $crdate;
|
||||
|
@ -71,6 +78,11 @@ class Pageview
|
|||
$this->userAgent = $userAgent;
|
||||
}
|
||||
|
||||
public function getUid(): int
|
||||
{
|
||||
return $this->uid;
|
||||
}
|
||||
|
||||
public function getPageUid(): int
|
||||
{
|
||||
return $this->pageUid;
|
||||
|
@ -100,4 +112,34 @@ class Pageview
|
|||
{
|
||||
return $this->userAgent;
|
||||
}
|
||||
|
||||
public function getOperatingSystem(): string
|
||||
{
|
||||
if (mb_stripos($this->userAgent, 'Android') !== false) {
|
||||
return 'Android';
|
||||
}
|
||||
if (mb_stripos($this->userAgent, 'Windows') !== false) {
|
||||
return 'Windows';
|
||||
}
|
||||
if (mb_stripos($this->userAgent, 'Linux') !== false) {
|
||||
return 'Linux';
|
||||
}
|
||||
if (mb_stripos($this->userAgent, 'Macintosh') !== false) {
|
||||
return 'Macintosh';
|
||||
}
|
||||
if (mb_stripos($this->userAgent, 'CrOS') !== false) {
|
||||
return 'Google Chrome OS';
|
||||
}
|
||||
if (mb_stripos($this->userAgent, 'OpenBSD') !== false) {
|
||||
return 'OpenBSD';
|
||||
}
|
||||
if (
|
||||
mb_stripos($this->userAgent, 'iPad') !== false
|
||||
|| mb_stripos($this->userAgent, 'iphone') !== false
|
||||
) {
|
||||
return 'iOS';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,20 @@ namespace DanielSiepmann\Tracking\Domain\Pageview;
|
|||
use DanielSiepmann\Tracking\Domain\Model\Pageview;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Routing\PageArguments;
|
||||
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||
use TYPO3\CMS\Core\Site\SiteFinder;
|
||||
|
||||
class Factory implements FromRequest
|
||||
{
|
||||
/**
|
||||
* @var SiteFinder
|
||||
*/
|
||||
private $siteFinder;
|
||||
|
||||
public function __construct(SiteFinder $siteFinder)
|
||||
{
|
||||
$this->siteFinder = $siteFinder;
|
||||
}
|
||||
|
||||
public static function fromRequest(ServerRequestInterface $request): Pageview
|
||||
{
|
||||
return new PageView(
|
||||
|
@ -40,6 +50,19 @@ class Factory implements FromRequest
|
|||
);
|
||||
}
|
||||
|
||||
public function fromDbRow(array $dbRow): Pageview
|
||||
{
|
||||
return new PageView(
|
||||
$dbRow['pid'],
|
||||
$this->siteFinder->getSiteByPageId($dbRow['pid'])->getLanguageById($dbRow['sys_language_uid']),
|
||||
new \DateTimeImmutable('@' . $dbRow['crdate']),
|
||||
$dbRow['type'],
|
||||
$dbRow['url'],
|
||||
$dbRow['user_agent'],
|
||||
$dbRow['uid']
|
||||
);
|
||||
}
|
||||
|
||||
private static function getRouting(ServerRequestInterface $request): PageArguments
|
||||
{
|
||||
return $request->getAttribute('routing');
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace DanielSiepmann\Tracking\Domain\Repository;
|
|||
*/
|
||||
|
||||
use DanielSiepmann\Tracking\Domain\Model\Pageview as Model;
|
||||
use DanielSiepmann\Tracking\Domain\Pageview\Factory;
|
||||
use Doctrine\DBAL\Driver\Statement;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
|
||||
class Pageview
|
||||
|
@ -31,16 +33,64 @@ class Pageview
|
|||
*/
|
||||
private $connection;
|
||||
|
||||
public function __construct(Connection $connection)
|
||||
{
|
||||
/**
|
||||
* @var Factory
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
public function __construct(
|
||||
Connection $connection,
|
||||
Factory $factory
|
||||
) {
|
||||
$this->connection = $connection;
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
public function countAll(): int
|
||||
{
|
||||
return $this->connection->createQueryBuilder()
|
||||
->count('uid')
|
||||
->from('tx_tracking_pageview')
|
||||
->execute()
|
||||
->fetchColumn();
|
||||
}
|
||||
|
||||
public function findAll(): \Generator
|
||||
{
|
||||
$queryBuilder = $this->connection->createQueryBuilder();
|
||||
$pageViews = $queryBuilder->select('*')->from('tx_tracking_pageview')->execute();
|
||||
|
||||
if ($pageViews instanceof Statement) {
|
||||
while ($pageView = $pageViews->fetch()) {
|
||||
yield $this->factory->fromDbRow($pageView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Model $pageview): void
|
||||
{
|
||||
if ($pageview->getUid() === 0) {
|
||||
throw new \InvalidArgumentException('Can not update pageview if uid is 0.', 1585770573);
|
||||
}
|
||||
|
||||
$this->connection->update(
|
||||
'tx_tracking_pageview',
|
||||
$this->getFieldsFromModel($pageview),
|
||||
['uid' => $pageview->getUid()]
|
||||
);
|
||||
}
|
||||
|
||||
public function add(Model $pageview): void
|
||||
{
|
||||
$this->connection->insert(
|
||||
'tx_tracking_pageview',
|
||||
[
|
||||
$this->getFieldsFromModel($pageview)
|
||||
);
|
||||
}
|
||||
|
||||
private function getFieldsFromModel(Model $pageview): array
|
||||
{
|
||||
return [
|
||||
'pid' => $pageview->getPageUid(),
|
||||
'crdate' => $pageview->getCrdate()->format('U'),
|
||||
'tstamp' => $pageview->getCrdate()->format('U'),
|
||||
|
@ -48,7 +98,7 @@ class Pageview
|
|||
'sys_language_uid' => $pageview->getLanguage()->getLanguageId(),
|
||||
'url' => $pageview->getUrl(),
|
||||
'user_agent' => $pageview->getUserAgent(),
|
||||
]
|
||||
);
|
||||
'operating_system' => $pageview->getOperatingSystem(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
autowire: false
|
||||
autoconfigure: false
|
||||
public: false
|
||||
|
||||
DanielSiepmann\Tracking\Dashboard\:
|
||||
|
@ -11,7 +11,7 @@ services:
|
|||
arguments:
|
||||
$queryBuilder: '@querybuilder.tx_tracking_pageview'
|
||||
|
||||
dashboard.widget.danielsiepmann_tracking.pageViewsPerDay:
|
||||
dashboard.widget.danielsiepmann.tracking.pageViewsPerDay:
|
||||
class: 'TYPO3\CMS\Dashboard\Widgets\BarChartWidget'
|
||||
arguments:
|
||||
$view: '@dashboard.views.widget'
|
||||
|
@ -31,7 +31,7 @@ services:
|
|||
arguments:
|
||||
$queryBuilder: '@querybuilder.tx_tracking_pageview'
|
||||
|
||||
dashboard.widget.danielsiepmann_tracking.pageViewsPerPage:
|
||||
dashboard.widget.danielsiepmann.tracking.pageViewsPerPage:
|
||||
class: 'TYPO3\CMS\Dashboard\Widgets\DoughnutChartWidget'
|
||||
arguments:
|
||||
$view: '@dashboard.views.widget'
|
||||
|
@ -51,7 +51,7 @@ services:
|
|||
arguments:
|
||||
$queryBuilder: '@querybuilder.tx_tracking_pageview'
|
||||
|
||||
dashboard.widget.danielsiepmann_tracking.newestPageviews:
|
||||
dashboard.widget.danielsiepmann.tracking.newestPageviews:
|
||||
class: 'TYPO3\CMS\Dashboard\Widgets\ListWidget'
|
||||
arguments:
|
||||
$view: '@dashboard.views.widget'
|
||||
|
@ -65,3 +65,24 @@ services:
|
|||
description: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.newestPageviewsList.description'
|
||||
height: 'medium'
|
||||
width: 'small'
|
||||
|
||||
DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerOperatingSystem:
|
||||
class: 'DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerOperatingSystem'
|
||||
arguments:
|
||||
$queryBuilder: '@querybuilder.tx_tracking_pageview'
|
||||
|
||||
dashboard.widget.danielsiepmann.tracking.operatingSystems:
|
||||
class: 'TYPO3\CMS\Dashboard\Widgets\DoughnutChartWidget'
|
||||
arguments:
|
||||
$view: '@dashboard.views.widget'
|
||||
$dataProvider: '@DanielSiepmann\Tracking\Dashboard\Provider\PageviewsPerOperatingSystem'
|
||||
tags:
|
||||
- name: 'dashboard.widget'
|
||||
identifier: 'operatingSystemsDoughnut'
|
||||
groupNames: 'tracking'
|
||||
iconIdentifier: 'content-widget-chart-pie'
|
||||
title: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.operatingSystemsDoughnut.title'
|
||||
description: 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widgets.operatingSystemsDoughnut.description'
|
||||
additionalCssClasses: 'dashboard-item--chart'
|
||||
height: 'medium'
|
||||
width: 'small'
|
||||
|
|
|
@ -41,3 +41,8 @@ services:
|
|||
and not (request.getHeader("User-Agent")[0] matches "/Wget|curl|Go-http-client/")
|
||||
and not (request.getHeader("User-Agent")[0] matches "/Googlebot|Bingbot|bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Sogou|Exabot|NextCloud-News|Feedly|XING FeedReader|CCBot|SemrushBot|SEOkicks|Twitterbot|Seekport Crawler|SemanticScholarBot|ia_archiver|PaperLiBot|TrendsmapResolver|AhrefsBot|Nuzzel/")
|
||||
and not (request.getHeader("User-Agent")[0] matches "/mattermost|Slackbot|WhatsApp/")
|
||||
|
||||
DanielSiepmann\Tracking\Command\UpdateDataCommand:
|
||||
tags:
|
||||
- name: 'console.command'
|
||||
command: 'tracking:updatedata'
|
||||
|
|
|
@ -15,7 +15,7 @@ return [
|
|||
],
|
||||
'types' => [
|
||||
'0' => [
|
||||
'showitem' => 'sys_language_uid, pid, url, user_agent, type, crdate',
|
||||
'showitem' => 'sys_language_uid, pid, url, user_agent, operating_system, type, crdate',
|
||||
],
|
||||
],
|
||||
'columns' => [
|
||||
|
@ -54,6 +54,13 @@ return [
|
|||
'readOnly' => true,
|
||||
],
|
||||
],
|
||||
'operating_system' => [
|
||||
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.operating_system',
|
||||
'config' => [
|
||||
'type' => 'input',
|
||||
'readOnly' => true,
|
||||
],
|
||||
],
|
||||
'type' => [
|
||||
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.type',
|
||||
'config' => [
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
<trans-unit id="dashboard.widgets.pageViewsPerPageDoughnut.description">
|
||||
<source>Displays total page views per page.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="dashboard.widgets.operatingSystemsDoughnut.title">
|
||||
<source>Page Views / Operating System</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="dashboard.widgets.operatingSystemsDoughnut.description">
|
||||
<source>Displays total page views per operating system.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="dashboard.widgets.newestPageviewsList.title">
|
||||
<source>Newest Page Views</source>
|
||||
</trans-unit>
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
<trans-unit id="table.pageview.user_agent">
|
||||
<source>User agent</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="table.pageview.operating_system">
|
||||
<source>Operating System</source>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
|
@ -169,4 +169,119 @@ class PageviewTest extends TestCase
|
|||
$subject->getUserAgent()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function returnsZeroAsDefaultUid(): void
|
||||
{
|
||||
$language = $this->prophesize(SiteLanguage::class);
|
||||
|
||||
$subject = new Pageview(
|
||||
0,
|
||||
$language->reveal(),
|
||||
new \DateTimeImmutable(),
|
||||
0,
|
||||
'',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'
|
||||
);
|
||||
|
||||
static::assertSame(
|
||||
0,
|
||||
$subject->getUid()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function returnsSetAsUid(): void
|
||||
{
|
||||
$language = $this->prophesize(SiteLanguage::class);
|
||||
|
||||
$subject = new Pageview(
|
||||
0,
|
||||
$language->reveal(),
|
||||
new \DateTimeImmutable(),
|
||||
0,
|
||||
'',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0',
|
||||
10
|
||||
);
|
||||
|
||||
static::assertSame(
|
||||
10,
|
||||
$subject->getUid()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider possibleUserStringWithOperatingSystems
|
||||
* @testdox Operating system $expectedOperatingSystem is extracted from UserAgent string: $userAgent
|
||||
*/
|
||||
public function returnsOperatingSystem(string $userAgent, string $expectedOperatingSystem): void
|
||||
{
|
||||
$language = $this->prophesize(SiteLanguage::class);
|
||||
|
||||
$subject = new Pageview(
|
||||
0,
|
||||
$language->reveal(),
|
||||
new \DateTimeImmutable(),
|
||||
0,
|
||||
'',
|
||||
$userAgent
|
||||
);
|
||||
|
||||
static::assertSame(
|
||||
$expectedOperatingSystem,
|
||||
$subject->getOperatingSystem()
|
||||
);
|
||||
}
|
||||
|
||||
public function possibleUserStringWithOperatingSystems(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'userAgent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36',
|
||||
'expectedOperatingSystem' => 'Linux',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Dalvik/2.1.0 (Linux; U; Android 9; ONEPLUS A3003 Build/PKQ1.181203.001)',
|
||||
'expectedOperatingSystem' => 'Android',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Apache-HttpClient/4.5.2 (Java/1.8.0_151)',
|
||||
'expectedOperatingSystem' => '',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'AwarioSmartBot/1.0 (+https://awario.com/bots.html; bots@awario.com)',
|
||||
'expectedOperatingSystem' => '',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
|
||||
'expectedOperatingSystem' => 'Windows',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:73.0) Gecko/20100101 Firefox/73.0',
|
||||
'expectedOperatingSystem' => 'Macintosh',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Mozilla/5.0 (X11; CrOS x86_64 12607.82.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.123 Safari/537.36',
|
||||
'expectedOperatingSystem' => 'Google Chrome OS',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.4) Gecko/20070704 Firefox/52.0',
|
||||
'expectedOperatingSystem' => 'OpenBSD',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Mozilla/5.0 (iPad; CPU OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/80.0.3987.95 Mobile/15E148 Safari/604.1',
|
||||
'expectedOperatingSystem' => 'iOS',
|
||||
],
|
||||
[
|
||||
'userAgent' => 'Mozilla/5.0 (iPhone; CPU OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/22.0 Mobile/15E148 Safari/605.1.15',
|
||||
'expectedOperatingSystem' => 'iOS',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ use Prophecy\PhpUnit\ProphecyTrait;
|
|||
use Prophecy\Prophet;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Routing\PageArguments;
|
||||
use TYPO3\CMS\Core\Site\Entity\Site;
|
||||
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||
use TYPO3\CMS\Core\Site\SiteFinder;
|
||||
|
||||
/**
|
||||
* @covers DanielSiepmann\Tracking\Domain\Pageview\Factory
|
||||
|
@ -40,7 +42,7 @@ class FactoryTest extends TestCase
|
|||
/**
|
||||
* @test
|
||||
*/
|
||||
public function returnsPageview(): void
|
||||
public function returnsPageviewFromRequest(): void
|
||||
{
|
||||
$routing = $this->prophesize(PageArguments::class);
|
||||
$routing->getPageId()->willReturn(10);
|
||||
|
@ -197,4 +199,37 @@ class FactoryTest extends TestCase
|
|||
$result->getPageUid()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function returnsPageviewFromDbRow(): void
|
||||
{
|
||||
$siteLanguage = $this->prophesize(SiteLanguage::class);
|
||||
$site = $this->prophesize(Site::class);
|
||||
$site->getLanguageById(0)->willReturn($siteLanguage->reveal());
|
||||
$siteFinder = $this->prophesize(SiteFinder::class);
|
||||
$siteFinder->getSiteByPageId(2)->willReturn($site->reveal());
|
||||
|
||||
$subject = new Factory($siteFinder->reveal());
|
||||
|
||||
$result = $subject->fromDbRow([
|
||||
'uid' => 1,
|
||||
'pid' => 2,
|
||||
'sys_language_uid' => 0,
|
||||
'crdate' => 1533906435,
|
||||
'type' => 0,
|
||||
'url' => 'https://example.com/path',
|
||||
'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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,13 @@ namespace DanielSiepmann\Tracking\Tests\Unit\Domain\Repository;
|
|||
*/
|
||||
|
||||
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 PHPUnit\Framework\TestCase;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||
|
||||
/**
|
||||
|
@ -41,6 +44,7 @@ class PageviewTest extends TestCase
|
|||
public function modelCanBeAdded(): void
|
||||
{
|
||||
$connection = $this->prophesize(Connection::class);
|
||||
$factory = $this->prophesize(Factory::class);
|
||||
|
||||
$dateTime = $this->prophesize(\DateTimeImmutable::class);
|
||||
$dateTime->format('U')->willReturn(1582660189);
|
||||
|
@ -55,6 +59,7 @@ class PageviewTest extends TestCase
|
|||
$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',
|
||||
|
@ -66,10 +71,161 @@ class PageviewTest extends TestCase
|
|||
'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());
|
||||
$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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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,
|
||||
);
|
||||
|
|
|
@ -45,9 +45,9 @@ Todos
|
|||
|
||||
#. Add referrer if available.
|
||||
|
||||
#. Add operating System
|
||||
#. Add device type phone, tablet, desktop?
|
||||
|
||||
#. Another Symfony Expression which returns the OS ("Ubuntu", "Macintosh", "Android", "iPhone", "Windows")
|
||||
#. Add operating system version?
|
||||
|
||||
#. Add further widgets.
|
||||
|
||||
|
@ -62,6 +62,7 @@ Todos
|
|||
#. Provide an overview of crawls as widgets. E.g. to allow fine grained robots.txt.
|
||||
|
||||
#. Add information to Admin Panel.
|
||||
|
||||
#. Add command that will iterate over all DB entries and remove ones matching the black list rule.
|
||||
E.g. if rule is adjusted in meanwhile.
|
||||
|
||||
|
|
Loading…
Reference in a new issue