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:
Daniel Siepmann 2020-04-01 21:04:32 +02:00
parent 8e2cadef08
commit 44ca6a2d3c
16 changed files with 665 additions and 24 deletions

View 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;
}
}

View 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,
];
}
}

View file

@ -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'];
}

View file

@ -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 '';
}
}

View file

@ -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');

View file

@ -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(),
];
}
}

View file

@ -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'

View file

@ -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'

View file

@ -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' => [

View file

@ -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>

View file

@ -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>

View file

@ -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',
],
];
}
}

View file

@ -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());
}
}

View file

@ -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;
}
}
}

View file

@ -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,
);

View file

@ -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.