mirror of
https://github.com/DanielSiepmann/tracking.git
synced 2024-11-25 06:36:12 +01:00
commit
64b0261694
28 changed files with 1609 additions and 0 deletions
19
.github/workflows/ci.yaml
vendored
Normal file
19
.github/workflows/ci.yaml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
name: CI
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Validate composer.json and composer.lock
|
||||||
|
run: composer validate
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: composer install --prefer-dist --no-progress --no-suggest
|
||||||
|
|
||||||
|
- name: Test CGL
|
||||||
|
run: ./vendor/bin/phpcs
|
||||||
|
|
||||||
|
- name: Execute PHPUnit Tests
|
||||||
|
run: ./vendor/bin/phpunit
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/.Build/
|
||||||
|
/composer.lock
|
||||||
|
/vendor/
|
125
Classes/Dashboard/Widgets/PageViewsBar.php
Normal file
125
Classes/Dashboard/Widgets/PageViewsBar.php
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Dashboard\Widgets;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Extension;
|
||||||
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||||
|
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||||
|
use TYPO3\CMS\Dashboard\Widgets\AbstractBarChartWidget;
|
||||||
|
|
||||||
|
class PageViewsBar extends AbstractBarChartWidget
|
||||||
|
{
|
||||||
|
protected $title = Extension::LANGUAGE_PATH . ':dashboard.widgets.pageViewsBar.title';
|
||||||
|
|
||||||
|
protected $description = Extension::LANGUAGE_PATH . ':trackingdashboard.widgets.pageViewsBar.description';
|
||||||
|
|
||||||
|
protected $width = 2;
|
||||||
|
|
||||||
|
protected $height = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var QueryBuilder
|
||||||
|
*/
|
||||||
|
protected $queryBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \ArrayObject
|
||||||
|
*/
|
||||||
|
private $settings;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $identifier,
|
||||||
|
QueryBuilder $queryBuilder,
|
||||||
|
\ArrayObject $settings
|
||||||
|
) {
|
||||||
|
parent::__construct($identifier);
|
||||||
|
|
||||||
|
$this->queryBuilder = $queryBuilder;
|
||||||
|
$this->settings = $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepareChartData(): void
|
||||||
|
{
|
||||||
|
list($labels, $data) = $this->calculateDataForLastDays((int) $this->settings['periodInDays']);
|
||||||
|
|
||||||
|
$this->chartData = [
|
||||||
|
'labels' => $labels,
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => $this->getLanguageService()->sL(
|
||||||
|
'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:widgets.pageViewsBar.chart.dataSet.0'
|
||||||
|
),
|
||||||
|
'backgroundColor' => $this->chartColors[0],
|
||||||
|
'border' => 0,
|
||||||
|
'data' => $data
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPageViewsInPeriod(int $start, int $end): int
|
||||||
|
{
|
||||||
|
$constraints = [
|
||||||
|
$this->queryBuilder->expr()->gte('crdate', $start),
|
||||||
|
$this->queryBuilder->expr()->lte('crdate', $end),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (count($this->settings['blackListedPages'])) {
|
||||||
|
$constraints[] = $this->queryBuilder->expr()->notIn(
|
||||||
|
'tx_tracking_pageview.pid',
|
||||||
|
$this->queryBuilder->createNamedParameter(
|
||||||
|
$this->settings['blackListedPages'],
|
||||||
|
Connection::PARAM_INT_ARRAY
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)$this->queryBuilder
|
||||||
|
->count('*')
|
||||||
|
->from('tx_tracking_pageview')
|
||||||
|
->where(... $constraints)
|
||||||
|
->execute()
|
||||||
|
->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function calculateDataForLastDays(int $days): array
|
||||||
|
{
|
||||||
|
$labels = [];
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$format = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] ?: 'Y-m-d';
|
||||||
|
|
||||||
|
for ($daysBefore = $days; $daysBefore >= 0; $daysBefore--) {
|
||||||
|
$labels[] = date($format, strtotime('-' . $daysBefore . ' day'));
|
||||||
|
$startPeriod = strtotime('-' . $daysBefore . ' day 0:00:00');
|
||||||
|
$endPeriod = strtotime('-' . $daysBefore . ' day 23:59:59');
|
||||||
|
|
||||||
|
$data[] = $this->getPageViewsInPeriod($startPeriod, $endPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
$labels,
|
||||||
|
$data,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
121
Classes/Dashboard/Widgets/PageViewsPerPageDoughnut.php
Normal file
121
Classes/Dashboard/Widgets/PageViewsPerPageDoughnut.php
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Dashboard\Widgets;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Extension;
|
||||||
|
use Doctrine\DBAL\ParameterType;
|
||||||
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||||
|
use TYPO3\CMS\Dashboard\Widgets\AbstractDoughnutChartWidget;
|
||||||
|
|
||||||
|
class PageViewsPerPageDoughnut extends AbstractDoughnutChartWidget
|
||||||
|
{
|
||||||
|
protected $title = Extension::LANGUAGE_PATH . ':dashboard.widgets.pageViewsPerPageDoughnut.title';
|
||||||
|
|
||||||
|
protected $description = Extension::LANGUAGE_PATH . ':dashboard.widgets.pageViewsPerPageDoughnut.description';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var QueryBuilder
|
||||||
|
*/
|
||||||
|
protected $queryBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \ArrayObject
|
||||||
|
*/
|
||||||
|
private $settings;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $identifier,
|
||||||
|
QueryBuilder $queryBuilder,
|
||||||
|
\ArrayObject $settings
|
||||||
|
) {
|
||||||
|
parent::__construct($identifier);
|
||||||
|
|
||||||
|
$this->queryBuilder = $queryBuilder;
|
||||||
|
$this->settings = $settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prepareChartData(): void
|
||||||
|
{
|
||||||
|
list($labels, $data) = $this->getPageViewsPerPage((int) $this->settings['periodInDays']);
|
||||||
|
|
||||||
|
$this->chartData = [
|
||||||
|
'labels' => $labels,
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'backgroundColor' => $this->chartColors,
|
||||||
|
'data' => $data,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPageViewsPerPage(int $days): array
|
||||||
|
{
|
||||||
|
$labels = [];
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$constraints = [
|
||||||
|
$this->queryBuilder->expr()->gte('tx_tracking_pageview.crdate', strtotime('-' . $days . ' day 0:00:00')),
|
||||||
|
$this->queryBuilder->expr()->lte('tx_tracking_pageview.crdate', time()),
|
||||||
|
];
|
||||||
|
if (count($this->settings['blackListedPages'])) {
|
||||||
|
$constraints[] = $this->queryBuilder->expr()->notIn(
|
||||||
|
'tx_tracking_pageview.pid',
|
||||||
|
$this->queryBuilder->createNamedParameter(
|
||||||
|
$this->settings['blackListedPages'],
|
||||||
|
Connection::PARAM_INT_ARRAY
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->queryBuilder
|
||||||
|
->selectLiteral('count(tx_tracking_pageview.pid) as total')
|
||||||
|
->addSelect('pages.title', 'pages.uid')
|
||||||
|
->from('tx_tracking_pageview')
|
||||||
|
->leftJoin(
|
||||||
|
'tx_tracking_pageview',
|
||||||
|
'pages',
|
||||||
|
'pages',
|
||||||
|
$this->queryBuilder->expr()->eq(
|
||||||
|
'tx_tracking_pageview.pid',
|
||||||
|
$this->queryBuilder->quoteIdentifier('pages.uid')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->where(... $constraints)
|
||||||
|
->groupBy('tx_tracking_pageview.pid')
|
||||||
|
->orderBy('total', 'desc')
|
||||||
|
->setMaxResults(6) // Because 6 colors are defined
|
||||||
|
->execute()
|
||||||
|
->fetchAll();
|
||||||
|
|
||||||
|
foreach ($result as $row) {
|
||||||
|
$labels[] = $row['title'] . ' [' . $row['uid'] . ']';
|
||||||
|
$data[] = $row['total'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
$labels,
|
||||||
|
$data,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
48
Classes/Dashboard/Widgets/SettingsFactory.php
Normal file
48
Classes/Dashboard/Widgets/SettingsFactory.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Dashboard\Widgets;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SettingsFactory
|
||||||
|
{
|
||||||
|
private $defaults = [
|
||||||
|
'pageViewsBar' => [
|
||||||
|
'periodInDays' => 31,
|
||||||
|
'blackListedPages' => [],
|
||||||
|
],
|
||||||
|
'pageViewsPerPageDoughnut' => [
|
||||||
|
'periodInDays' => 31,
|
||||||
|
'blackListedPages' => [],
|
||||||
|
'maxResults' => 6,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
public function fromArray(string $widgetIdentifier, array $settings): \ArrayObject
|
||||||
|
{
|
||||||
|
$settingsToUse = $this->defaults[$widgetIdentifier] ?? [];
|
||||||
|
|
||||||
|
ArrayUtility::mergeRecursiveWithOverrule($settingsToUse, $settings);
|
||||||
|
|
||||||
|
return new \ArrayObject($settingsToUse);
|
||||||
|
}
|
||||||
|
}
|
103
Classes/Domain/Model/Pageview.php
Normal file
103
Classes/Domain/Model/Pageview.php
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Domain\Model;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Site\Entity\SiteLanguage;
|
||||||
|
|
||||||
|
class Pageview
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $pageUid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var SiteLanguage
|
||||||
|
*/
|
||||||
|
private $language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \DateTimeImmutable
|
||||||
|
*/
|
||||||
|
private $crdate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $pageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $userAgent;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
int $pageUid,
|
||||||
|
SiteLanguage $language,
|
||||||
|
\DateTimeImmutable $crdate,
|
||||||
|
int $pageType,
|
||||||
|
string $url,
|
||||||
|
string $userAgent
|
||||||
|
) {
|
||||||
|
$this->pageUid = $pageUid;
|
||||||
|
$this->language = $language;
|
||||||
|
$this->crdate = $crdate;
|
||||||
|
$this->pageType = $pageType;
|
||||||
|
$this->url = $url;
|
||||||
|
$this->userAgent = $userAgent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageUid(): int
|
||||||
|
{
|
||||||
|
return $this->pageUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLanguage(): SiteLanguage
|
||||||
|
{
|
||||||
|
return $this->language;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCrdate(): \DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->crdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageType(): int
|
||||||
|
{
|
||||||
|
return $this->pageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUrl(): string
|
||||||
|
{
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserAgent(): string
|
||||||
|
{
|
||||||
|
return $this->userAgent;
|
||||||
|
}
|
||||||
|
}
|
47
Classes/Domain/Pageview/Factory.php
Normal file
47
Classes/Domain/Pageview/Factory.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Domain\Pageview;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Model\Pageview;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use TYPO3\CMS\Core\Routing\PageArguments;
|
||||||
|
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||||
|
|
||||||
|
class Factory implements FromRequest
|
||||||
|
{
|
||||||
|
public static function fromRequest(ServerRequestInterface $request): Pageview
|
||||||
|
{
|
||||||
|
return new PageView(
|
||||||
|
static::getRouting($request)->getPageId(),
|
||||||
|
$request->getAttribute('language'),
|
||||||
|
new \DateTimeImmutable(),
|
||||||
|
static::getRouting($request)->getPageType(),
|
||||||
|
(string) $request->getUri(),
|
||||||
|
$request->getHeader('User-Agent')[0] ?? ''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getRouting(ServerRequestInterface $request): PageArguments
|
||||||
|
{
|
||||||
|
return $request->getAttribute('routing');
|
||||||
|
}
|
||||||
|
}
|
30
Classes/Domain/Pageview/FromRequest.php
Normal file
30
Classes/Domain/Pageview/FromRequest.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Domain\Pageview;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Model\Pageview;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
|
||||||
|
interface FromRequest
|
||||||
|
{
|
||||||
|
public static function fromRequest(ServerRequestInterface $request): Pageview;
|
||||||
|
}
|
54
Classes/Domain/Repository/Pageview.php
Normal file
54
Classes/Domain/Repository/Pageview.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Domain\Repository;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Model\Pageview as Model;
|
||||||
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
|
||||||
|
class Pageview
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Connection
|
||||||
|
*/
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
public function __construct(Connection $connection)
|
||||||
|
{
|
||||||
|
$this->connection = $connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(Model $pageview)
|
||||||
|
{
|
||||||
|
$this->connection->insert(
|
||||||
|
'tx_tracking_pageview',
|
||||||
|
[
|
||||||
|
'pid' => $pageview->getPageUid(),
|
||||||
|
'crdate' => $pageview->getCrdate()->format('U'),
|
||||||
|
'tstamp' => $pageview->getCrdate()->format('U'),
|
||||||
|
'type' => $pageview->getPageType(),
|
||||||
|
'sys_language_uid' => $pageview->getLanguage()->getLanguageId(),
|
||||||
|
'url' => $pageview->getUrl(),
|
||||||
|
'user_agent' => $pageview->getUserAgent(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
29
Classes/Extension.php
Normal file
29
Classes/Extension.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class Extension
|
||||||
|
{
|
||||||
|
public const EXT_KEY = 'tracking';
|
||||||
|
|
||||||
|
public const LANGUAGE_PATH = 'LLL:EXT:' . self::EXT_KEY . '/Resources/Private/Language/locallang.xlf';
|
||||||
|
}
|
77
Classes/Middleware/Pageview.php
Normal file
77
Classes/Middleware/Pageview.php
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Middleware;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Pageview\Factory;
|
||||||
|
use DanielSiepmann\Tracking\Domain\Repository\Pageview as Repository;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
|
||||||
|
use TYPO3\CMS\Core\Context\Context;
|
||||||
|
|
||||||
|
class Pageview implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Repository
|
||||||
|
*/
|
||||||
|
private $repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Context
|
||||||
|
*/
|
||||||
|
private $context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $rule = '';
|
||||||
|
|
||||||
|
public function __construct(Repository $repository, Context $context, string $rule)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
$this->context = $context;
|
||||||
|
$this->rule = $rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(
|
||||||
|
ServerRequestInterface $request,
|
||||||
|
RequestHandlerInterface $handler
|
||||||
|
): ResponseInterface {
|
||||||
|
if ($this->shouldTrack($request, $this->context)) {
|
||||||
|
$this->repository->add(Factory::fromRequest($request));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $handler->handle($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shouldTrack(
|
||||||
|
ServerRequestInterface $request,
|
||||||
|
Context $context
|
||||||
|
): bool {
|
||||||
|
return (bool) (new ExpressionLanguage())->evaluate($this->rule, [
|
||||||
|
'request' => $request,
|
||||||
|
'context' => $context,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
6
Configuration/Backend/DashboardWidgetGroups.php
Normal file
6
Configuration/Backend/DashboardWidgetGroups.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'tracking' => [
|
||||||
|
'title' => 'LLL:EXT:tracking/Resources/Private/Language/locallang.xlf:dashboard.widget.group.tracking',
|
||||||
|
],
|
||||||
|
];
|
15
Configuration/RequestMiddlewares.php
Normal file
15
Configuration/RequestMiddlewares.php
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'frontend' => [
|
||||||
|
'tracking-pageview' => [
|
||||||
|
'target' => \DanielSiepmann\Tracking\Middleware\Pageview::class,
|
||||||
|
'before' => [
|
||||||
|
'typo3/cms-frontend/content-length-headers',
|
||||||
|
],
|
||||||
|
'after' => [
|
||||||
|
'typo3/cms-frontend/shortcut-and-mountpoint-redirect',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
77
Configuration/Services.yaml
Normal file
77
Configuration/Services.yaml
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
public: false
|
||||||
|
|
||||||
|
DanielSiepmann\Tracking\:
|
||||||
|
resource: '../Classes/*'
|
||||||
|
|
||||||
|
# Virtual services
|
||||||
|
|
||||||
|
DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsBar:
|
||||||
|
factory:
|
||||||
|
- '@DanielSiepmann\Tracking\Dashboard\Widgets\SettingsFactory'
|
||||||
|
- 'fromArray'
|
||||||
|
arguments:
|
||||||
|
$widgetIdentifier: 'pageViewsBar'
|
||||||
|
$settings: []
|
||||||
|
DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsPerPageDoughnut:
|
||||||
|
factory:
|
||||||
|
- '@DanielSiepmann\Tracking\Dashboard\Widgets\SettingsFactory'
|
||||||
|
- 'fromArray'
|
||||||
|
arguments:
|
||||||
|
$widgetIdentifier: 'pageViewsPerPageDoughnut'
|
||||||
|
$settings: []
|
||||||
|
|
||||||
|
DanielSiepmann\Tracking\DI\DatabaseConnection\Pageview:
|
||||||
|
factory:
|
||||||
|
- '@TYPO3\CMS\Core\Database\ConnectionPool'
|
||||||
|
- 'getConnectionForTable'
|
||||||
|
arguments:
|
||||||
|
- 'tx_tracking_pageview'
|
||||||
|
DanielSiepmann\Tracking\DI\QueryBuilder\PageView:
|
||||||
|
factory:
|
||||||
|
- '@TYPO3\CMS\Core\Database\ConnectionPool'
|
||||||
|
- 'getQueryBuilderForTable'
|
||||||
|
arguments:
|
||||||
|
- 'tx_tracking_pageview'
|
||||||
|
|
||||||
|
# Existing classes
|
||||||
|
|
||||||
|
DanielSiepmann\Tracking\Domain\Repository\Pageview:
|
||||||
|
public: true
|
||||||
|
arguments:
|
||||||
|
- '@DanielSiepmann\Tracking\DI\DatabaseConnection\Pageview'
|
||||||
|
|
||||||
|
DanielSiepmann\Tracking\Middleware\Pageview:
|
||||||
|
public: true
|
||||||
|
arguments:
|
||||||
|
$rule: >
|
||||||
|
not (context.getAspect("backend.user").isLoggedIn())
|
||||||
|
and not (request.getHeader("User-Agent")[0] matches "/^Wget|TYPO3|TYPO3 linkvalidator/")
|
||||||
|
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|curl/")
|
||||||
|
|
||||||
|
# Dashboard Widgets
|
||||||
|
|
||||||
|
DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsBar:
|
||||||
|
class: 'DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsBar'
|
||||||
|
arguments:
|
||||||
|
$identifier: 'pageViewsBar'
|
||||||
|
$queryBuilder: '@DanielSiepmann\Tracking\DI\QueryBuilder\PageView'
|
||||||
|
$settings: '@DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsBar'
|
||||||
|
tags:
|
||||||
|
- name: 'dashboard.widget'
|
||||||
|
identifier: 'pageViewsBar'
|
||||||
|
widgetGroups: 'tracking'
|
||||||
|
|
||||||
|
DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsPerPageDoughnut:
|
||||||
|
class: 'DanielSiepmann\Tracking\Dashboard\Widgets\PageViewsPerPageDoughnut'
|
||||||
|
arguments:
|
||||||
|
$identifier: 'pageViewsPerPageDoughnut'
|
||||||
|
$queryBuilder: '@DanielSiepmann\Tracking\DI\QueryBuilder\PageView'
|
||||||
|
$settings: '@DanielSiepmann\Tracking\DI\Dashboard\Widgets\Settings\PageViewsPerPageDoughnut'
|
||||||
|
tags:
|
||||||
|
- name: 'dashboard.widget'
|
||||||
|
identifier: 'pageViewsPerPageDoughnut'
|
||||||
|
widgetGroups: 'tracking'
|
78
Configuration/TCA/tx_tracking_pageview.php
Normal file
78
Configuration/TCA/tx_tracking_pageview.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'ctrl' => [
|
||||||
|
'label' => 'url',
|
||||||
|
'label_alt' => 'crdate',
|
||||||
|
'label_alt_force' => true,
|
||||||
|
'sortby' => 'crdate DESC',
|
||||||
|
'tstamp' => 'tstamp',
|
||||||
|
'crdate' => 'crdate',
|
||||||
|
'cruser_id' => 'cruser_id',
|
||||||
|
'languageField' => 'sys_language_uid',
|
||||||
|
'title' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview',
|
||||||
|
'searchFields' => 'uid, url'
|
||||||
|
],
|
||||||
|
'interface' => [
|
||||||
|
'always_description' => 0,
|
||||||
|
'showRecordFieldList' => 'url, user_agent, type, sys_language_uid, crdate, tstamp, crdate, cruser_id'
|
||||||
|
],
|
||||||
|
'types' => [
|
||||||
|
'0' => [
|
||||||
|
'showitem' => 'sys_language_uid, pid, url, user_agent, type, crdate',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'columns' => [
|
||||||
|
'pid' => [
|
||||||
|
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.pid',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'readOnly' => true,
|
||||||
|
'renderType' => 'selectSingle',
|
||||||
|
'foreign_table' => 'pages',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'crdate' => [
|
||||||
|
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.crdate',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'eval' => 'datetime',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'sys_language_uid' => [
|
||||||
|
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.sys_language',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'select',
|
||||||
|
'renderType' => 'selectSingle',
|
||||||
|
'foreign_table' => 'sys_language',
|
||||||
|
'items' => [
|
||||||
|
['LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.sys_language.0', 0],
|
||||||
|
],
|
||||||
|
'readOnly' => true,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'user_agent' => [
|
||||||
|
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.user_agent',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'readOnly' => true,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'type' => [
|
||||||
|
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.type',
|
||||||
|
'config' => [
|
||||||
|
'type' => 'input',
|
||||||
|
'readOnly' => true,
|
||||||
|
'eval' => 'int',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'url' => [
|
||||||
|
'label' => 'LLL:EXT:tracking/Resources/Private/Language/locallang_tca.xlf:table.pageview.url',
|
||||||
|
'config' => [
|
||||||
|
'readOnly' => true,
|
||||||
|
'type' => 'input',
|
||||||
|
'size' => 50,
|
||||||
|
'max' => 255,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
26
Resources/Private/Language/locallang.xlf
Normal file
26
Resources/Private/Language/locallang.xlf
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
|
||||||
|
<file source-language="en" datatype="plaintext">
|
||||||
|
<header/>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="dashboard.widget.group.tracking">
|
||||||
|
<source>Tracking</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="dashboard.widgets.pageViewsBar.title">
|
||||||
|
<source>Page Views / Day</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="dashboard.widgets.pageViewsBar.description">
|
||||||
|
<source>Displays total page views per day.</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="dashboard.widgets.pageViewsBar.chart.dataSet.0">
|
||||||
|
<source>Total Page Views</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="dashboard.widgets.pageViewsPerPageDoughnut.title">
|
||||||
|
<source>Page Views / Page</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="dashboard.widgets.pageViewsPerPageDoughnut.description">
|
||||||
|
<source>Displays total page views per page.</source>
|
||||||
|
</trans-unit>
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
32
Resources/Private/Language/locallang_tca.xlf
Normal file
32
Resources/Private/Language/locallang_tca.xlf
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
|
||||||
|
<file source-language="en" datatype="plaintext">
|
||||||
|
<header/>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="table.pageview">
|
||||||
|
<source>Pageview</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="table.pageview.pid">
|
||||||
|
<source>Page</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="table.pageview.url">
|
||||||
|
<source>URL</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="table.pageview.sys_language">
|
||||||
|
<source>System language</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="table.pageview.sys_language.0">
|
||||||
|
<source>Default system language</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="table.pageview.crdate">
|
||||||
|
<source>Date + Time</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="table.pageview.type">
|
||||||
|
<source>Pagetype</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="table.pageview.user_agent">
|
||||||
|
<source>User agent</source>
|
||||||
|
</trans-unit>
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
169
Tests/Unit/Domain/Model/PageviewTest.php
Normal file
169
Tests/Unit/Domain/Model/PageviewTest.php
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Unit\Domain\Model;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Model\Pageview;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers DanielSiepmann\Tracking\Domain\Model\Pageview
|
||||||
|
*/
|
||||||
|
class PageviewTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function canBeCreated()
|
||||||
|
{
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$subject = new Pageview(
|
||||||
|
0,
|
||||||
|
$language->reveal(),
|
||||||
|
new \DateTimeImmutable(),
|
||||||
|
0,
|
||||||
|
'',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
static::assertInstanceOf(Pageview::class, $subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsPageUid()
|
||||||
|
{
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$subject = new Pageview(
|
||||||
|
500,
|
||||||
|
$language->reveal(),
|
||||||
|
new \DateTimeImmutable(),
|
||||||
|
0,
|
||||||
|
'',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
static::assertSame(500, $subject->getPageUid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsLanguage()
|
||||||
|
{
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$subject = new Pageview(
|
||||||
|
0,
|
||||||
|
$language->reveal(),
|
||||||
|
new \DateTimeImmutable(),
|
||||||
|
0,
|
||||||
|
'',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
static::assertSame($language->reveal(), $subject->getLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsCrdate()
|
||||||
|
{
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
$crdate = new \DateTimeImmutable();
|
||||||
|
|
||||||
|
$subject = new Pageview(
|
||||||
|
0,
|
||||||
|
$language->reveal(),
|
||||||
|
$crdate,
|
||||||
|
0,
|
||||||
|
'',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
static::assertSame($crdate, $subject->getCrdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsPageType()
|
||||||
|
{
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$subject = new Pageview(
|
||||||
|
0,
|
||||||
|
$language->reveal(),
|
||||||
|
new \DateTimeImmutable(),
|
||||||
|
999,
|
||||||
|
'',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
static::assertSame(999, $subject->getPageType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsUrl()
|
||||||
|
{
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$subject = new Pageview(
|
||||||
|
0,
|
||||||
|
$language->reveal(),
|
||||||
|
new \DateTimeImmutable(),
|
||||||
|
0,
|
||||||
|
'https://example.com/path.html',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
static::assertSame('https://example.com/path.html', $subject->getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsUserAgent()
|
||||||
|
{
|
||||||
|
$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(
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0',
|
||||||
|
$subject->getUserAgent()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
196
Tests/Unit/Domain/Pageview/FactoryTest.php
Normal file
196
Tests/Unit/Domain/Pageview/FactoryTest.php
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Unit\Domain\Pageview;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Model\Pageview;
|
||||||
|
use DanielSiepmann\Tracking\Domain\Pageview\Factory;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use TYPO3\CMS\Core\Routing\PageArguments;
|
||||||
|
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers DanielSiepmann\Tracking\Domain\Pageview\Factory
|
||||||
|
*/
|
||||||
|
class FactoryTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsPageview()
|
||||||
|
{
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(0);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([]);
|
||||||
|
|
||||||
|
$result = Factory::fromRequest($request->reveal());
|
||||||
|
static::assertInstanceOf(Pageview::class, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnedPageviewContainsUserAgent()
|
||||||
|
{
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(0);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$result = Factory::fromRequest($request->reveal());
|
||||||
|
static::assertSame(
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0',
|
||||||
|
$result->getUserAgent()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnedPageviewContainsUri()
|
||||||
|
{
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(0);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('https://example.com/path?query=params&some=more#anchor');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([]);
|
||||||
|
|
||||||
|
$result = Factory::fromRequest($request->reveal());
|
||||||
|
static::assertSame(
|
||||||
|
'https://example.com/path?query=params&some=more#anchor',
|
||||||
|
$result->getUrl()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnedPageviewContainsPageType()
|
||||||
|
{
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(50);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([]);
|
||||||
|
|
||||||
|
$result = Factory::fromRequest($request->reveal());
|
||||||
|
static::assertSame(
|
||||||
|
50,
|
||||||
|
$result->getPageType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnedPageviewContainsDateTime()
|
||||||
|
{
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(0);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([]);
|
||||||
|
|
||||||
|
$result = Factory::fromRequest($request->reveal());
|
||||||
|
static::assertInstanceOf(\DateTimeImmutable::class, $result->getCrdate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnedPageviewContainsLanguage()
|
||||||
|
{
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(0);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([]);
|
||||||
|
|
||||||
|
$result = Factory::fromRequest($request->reveal());
|
||||||
|
static::assertInstanceOf(SiteLanguage::class, $result->getLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnedPageviewContainsPageId()
|
||||||
|
{
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(0);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([]);
|
||||||
|
|
||||||
|
$result = Factory::fromRequest($request->reveal());
|
||||||
|
static::assertSame(
|
||||||
|
10,
|
||||||
|
$result->getPageUid()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
72
Tests/Unit/Domain/Repository/PageviewTest.php
Normal file
72
Tests/Unit/Domain/Repository/PageviewTest.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Unit\Domain\Repository;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Model\Pageview as Model;
|
||||||
|
use DanielSiepmann\Tracking\Domain\Repository\Pageview;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use TYPO3\CMS\Core\Database\Connection;
|
||||||
|
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers DanielSiepmann\Tracking\Domain\Repository\Pageview
|
||||||
|
*/
|
||||||
|
class PageviewTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function modelCanBeAdded()
|
||||||
|
{
|
||||||
|
$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->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');
|
||||||
|
|
||||||
|
$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',
|
||||||
|
]
|
||||||
|
)->willReturn(1)->shouldBeCalledTimes(1);
|
||||||
|
|
||||||
|
$subject = new Pageview($connection->reveal());
|
||||||
|
$subject->add($model->reveal());
|
||||||
|
}
|
||||||
|
}
|
95
Tests/Unit/Middleware/PageviewTest.php
Normal file
95
Tests/Unit/Middleware/PageviewTest.php
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DanielSiepmann\Tracking\Unit\Middleware;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\Model\Pageview as Model;
|
||||||
|
use DanielSiepmann\Tracking\Domain\Repository\Pageview as Repository;
|
||||||
|
use DanielSiepmann\Tracking\Middleware\Pageview;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Prophecy\Argument;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use TYPO3\CMS\Core\Context\Context;
|
||||||
|
use TYPO3\CMS\Core\Routing\PageArguments;
|
||||||
|
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers DanielSiepmann\Tracking\Middleware\Pageview
|
||||||
|
*/
|
||||||
|
class PageviewTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function doesNotAddBlacklistedRequest()
|
||||||
|
{
|
||||||
|
$repository = $this->prophesize(Repository::class);
|
||||||
|
$context = $this->prophesize(Context::class);
|
||||||
|
$rule = 'false';
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$response = $this->prophesize(ResponseInterface::class);
|
||||||
|
$handler = $this->prophesize(RequestHandlerInterface::class);
|
||||||
|
|
||||||
|
$handler->handle($request->reveal())->willReturn($response->reveal());
|
||||||
|
$repository->add()->shouldNotBeCalled();
|
||||||
|
|
||||||
|
$subject = new Pageview($repository->reveal(), $context->reveal(), $rule);
|
||||||
|
$result = $subject->process($request->reveal(), $handler->reveal());
|
||||||
|
|
||||||
|
static::assertInstanceOf(ResponseInterface::class, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function addsPageviewToRepository()
|
||||||
|
{
|
||||||
|
$repository = $this->prophesize(Repository::class);
|
||||||
|
$context = $this->prophesize(Context::class);
|
||||||
|
$rule = 'true';
|
||||||
|
|
||||||
|
$routing = $this->prophesize(PageArguments::class);
|
||||||
|
$routing->getPageId()->willReturn(10);
|
||||||
|
$routing->getPageType()->willReturn(0);
|
||||||
|
|
||||||
|
$language = $this->prophesize(SiteLanguage::class);
|
||||||
|
|
||||||
|
$request = $this->prophesize(ServerRequestInterface::class);
|
||||||
|
$request->getAttribute('routing')->willReturn($routing->reveal());
|
||||||
|
$request->getAttribute('language')->willReturn($language->reveal());
|
||||||
|
$request->getUri()->willReturn('');
|
||||||
|
$request->getHeader('User-Agent')->willReturn([]);
|
||||||
|
|
||||||
|
$response = $this->prophesize(ResponseInterface::class);
|
||||||
|
$handler = $this->prophesize(RequestHandlerInterface::class);
|
||||||
|
|
||||||
|
$handler->handle($request->reveal())->willReturn($response->reveal());
|
||||||
|
$repository->add(Argument::type(Model::class))->shouldBeCalledtimes(1);
|
||||||
|
|
||||||
|
$subject = new Pageview($repository->reveal(), $context->reveal(), $rule);
|
||||||
|
$result = $subject->process($request->reveal(), $handler->reveal());
|
||||||
|
|
||||||
|
static::assertInstanceOf(ResponseInterface::class, $result);
|
||||||
|
}
|
||||||
|
}
|
55
composer.json
Normal file
55
composer.json
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"name": "danielsiepmann/tracking",
|
||||||
|
"description": "Tracking for TYPO3",
|
||||||
|
"type": "typo3-cms-extension",
|
||||||
|
"license": "GPL-2.0-or-later",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Daniel Siepmann",
|
||||||
|
"email": "coding@daniel-siepmann.de"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"DanielSiepmann\\Tracking\\": "Classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"DanielSiepmann\\Tracking\\Tests\\": "Tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/dbal": "^2.10",
|
||||||
|
"php": "^7.3.0",
|
||||||
|
"psr/http-message": "^1.0",
|
||||||
|
"psr/http-server-handler": "^1.0",
|
||||||
|
"psr/http-server-middleware": "^1.0",
|
||||||
|
"symfony/expression-language": "^5.0",
|
||||||
|
"typo3/cms-core": "^10.3.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"typo3/cms-dashboard": "To make use of provided TYPO3 widgets"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"typo3/cms": {
|
||||||
|
"cms-package-dir": "{$vendor-dir}/typo3/cms",
|
||||||
|
"extension-key": "tracking",
|
||||||
|
"web-dir": ".Build/web"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-develop": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"post-autoload-dump": [
|
||||||
|
"mkdir -p .Build/web/typo3conf/ext/",
|
||||||
|
"[ -L .Build/web/typo3conf/ext/tracking ] || ln -snvf ../../../../. .Build/web/typo3conf/ext/tracking"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"phpunit/phpunit": "^9.0",
|
||||||
|
"typo3/cms-dashboard": "^10.3.0"
|
||||||
|
}
|
||||||
|
}
|
23
ext_emconf.php
Normal file
23
ext_emconf.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
$EM_CONF[$_EXTKEY] = [
|
||||||
|
'title' => 'Tracking',
|
||||||
|
'description' => 'Tracks page visits in TYPO3.',
|
||||||
|
'category' => 'fe',
|
||||||
|
'state' => 'alpha',
|
||||||
|
'uploadfolder' => 0,
|
||||||
|
'createDirs' => '',
|
||||||
|
'clearCacheOnLoad' => 0,
|
||||||
|
'author' => 'Daniel Siepmann',
|
||||||
|
'author_email' => 'coding@daniel-siepmann.de',
|
||||||
|
'author_company' => '',
|
||||||
|
'version' => '0.1.0',
|
||||||
|
'constraints' => [
|
||||||
|
'depends' => [
|
||||||
|
'core' => '',
|
||||||
|
],
|
||||||
|
'conflicts' => [],
|
||||||
|
'suggests' => [
|
||||||
|
'dashboard' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
3
ext_localconf.php
Normal file
3
ext_localconf.php
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::allowTableOnStandardPages('tx_tracking_pageview');
|
5
ext_tables.sql
Normal file
5
ext_tables.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
CREATE TABLE tx_tracking_pageview (
|
||||||
|
url text,
|
||||||
|
user_agent text,
|
||||||
|
type int(11) unsigned DEFAULT '0' NOT NULL,
|
||||||
|
);
|
16
phpcs.xml.dist
Normal file
16
phpcs.xml.dist
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="project">
|
||||||
|
<description>This project coding standard</description>
|
||||||
|
|
||||||
|
<file>Classes/</file>
|
||||||
|
<file>Tests/</file>
|
||||||
|
|
||||||
|
<!-- Set default settings -->
|
||||||
|
<arg value="sp"/>
|
||||||
|
<arg name="colors"/>
|
||||||
|
<arg name="encoding" value="utf-8" />
|
||||||
|
<arg name="extensions" value="php" />
|
||||||
|
|
||||||
|
<!-- Base rules -->
|
||||||
|
<rule ref="PSR12" />
|
||||||
|
</ruleset>
|
26
phpunit.xml.dist
Normal file
26
phpunit.xml.dist
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<phpunit
|
||||||
|
backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="false"
|
||||||
|
convertWarningsToExceptions="false"
|
||||||
|
forceCoversAnnotation="false"
|
||||||
|
processIsolation="false"
|
||||||
|
stopOnError="false"
|
||||||
|
stopOnFailure="false"
|
||||||
|
stopOnIncomplete="false"
|
||||||
|
stopOnSkipped="false"
|
||||||
|
verbose="false">
|
||||||
|
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="unit-tests">
|
||||||
|
<directory>Tests/Unit/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory suffix=".php">Classes</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
59
readme.rst
Normal file
59
readme.rst
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
About
|
||||||
|
=====
|
||||||
|
|
||||||
|
This extension should only demonstrate technical features of TYPO3.
|
||||||
|
It is not intended for use in production systems.
|
||||||
|
|
||||||
|
The following features should be demonstrated:
|
||||||
|
|
||||||
|
PSR-4 Autoloading Standard
|
||||||
|
Use `composer.json` to provide autoloading information.
|
||||||
|
Classes will be loaded when needed. No need for require statements.
|
||||||
|
|
||||||
|
PSR-12 Extended Coding Style Guide
|
||||||
|
Current stable Coding Style Guide, applied via Coding Sniffer.
|
||||||
|
|
||||||
|
PSR-7 HTTP Message Interface
|
||||||
|
Also known as Request Response, used to create tracking information from incoming
|
||||||
|
request.
|
||||||
|
|
||||||
|
PSR-11 Container Interface
|
||||||
|
Also known as Dependency Injection.
|
||||||
|
Used to resolve external dependencies, e.g. foreign classes.
|
||||||
|
Existing TYPO3 factories are used to build `QueryBuilder` instances.
|
||||||
|
Also DI is "misused" to provide configuration for dashboard widgets
|
||||||
|
and tracking blacklists.
|
||||||
|
|
||||||
|
PSR-15 HTTP Handlers
|
||||||
|
Also known as middlewares.
|
||||||
|
Used to hook into processing to create tracking information.
|
||||||
|
|
||||||
|
PSR-14 Event Dispatcher
|
||||||
|
Not in use yet.
|
||||||
|
|
||||||
|
EXT:dashboard
|
||||||
|
Used to visualize collected tracking information.
|
||||||
|
|
||||||
|
Todos
|
||||||
|
=====
|
||||||
|
|
||||||
|
#. 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.
|
||||||
|
|
||||||
|
#. Add further widgets.
|
||||||
|
|
||||||
|
#. Top 404 requests (Collect them to show them).
|
||||||
|
|
||||||
|
#. Grouped by user agents.
|
||||||
|
|
||||||
|
#. Move bot detection to another rule.
|
||||||
|
|
||||||
|
#. Keep indexing those requests, but mark them as bot and separate them in widgets.
|
||||||
|
|
||||||
|
#. Provide an overview of crawls as widgets. E.g. to allow fine grained robots.txt.
|
||||||
|
|
||||||
|
#. Add information to Admin Panel.
|
||||||
|
|
||||||
|
#. Add operating System
|
||||||
|
|
||||||
|
#. Another Symfony Expression which returns the OS ("Ubuntu", "Macintosh", "Android", "iPhone", "Windows")
|
Loading…
Reference in a new issue