diff --git a/composer.json b/composer.json index 5b79981..1190101 100644 --- a/composer.json +++ b/composer.json @@ -16,12 +16,12 @@ "doctrine/doctrine-migrations-bundle": "^3.0", "doctrine/orm": "^2.8", "friendsofsymfony/jsrouting-bundle": "^2.7", - "jaybizzle/crawler-detect": "^1.2", "knplabs/doctrine-behaviors": "^2.2", "knplabs/knp-markdown-bundle": "^1.9", "knplabs/knp-menu-bundle": "^3.1", "knplabs/knp-paginator-bundle": "^5.8", "liip/imagine-bundle": "^2.6", + "matomo/device-detector": "^5.0", "phpdocumentor/reflection-docblock": "^5.2", "scheb/2fa-google-authenticator": "^5.7", "scheb/2fa-qr-code": "^5.7", diff --git a/core/Analytic/DateRangeAnalytic.php b/core/Analytic/DateRangeAnalytic.php index 36e818d..15f46ae 100644 --- a/core/Analytic/DateRangeAnalytic.php +++ b/core/Analytic/DateRangeAnalytic.php @@ -57,8 +57,6 @@ class DateRangeAnalytic $datas[$index] += $entity->getViews(); } - arsort($datas, SORT_NUMERIC); - return $datas; } @@ -73,13 +71,29 @@ class DateRangeAnalytic $index = $entity->getPath(); if (!isset($datas[$index])) { - $datas[$index] = 0; + $datas[$index] = [ + 'views' => 0, + 'desktopViews' => 0, + 'mobileViews' => 0, + ]; } - $datas[$index] += $entity->getViews(); + $datas[$index]['views'] += $entity->getViews(); + $datas[$index]['desktopViews'] += $entity->getDesktopViews(); + $datas[$index]['mobileViews'] += $entity->getMobileViews(); } - arsort($datas, SORT_NUMERIC); + uasort($datas, function($a, $b) { + if ($a['views'] > $b['views']) { + return -1; + } + + if ($a['views'] < $b['views']) { + return 1; + } + + return 0; + }); return $datas; } diff --git a/core/Entity/Analytic/Referer.php b/core/Entity/Analytic/Referer.php index 1c8b94d..0eeb73c 100644 --- a/core/Entity/Analytic/Referer.php +++ b/core/Entity/Analytic/Referer.php @@ -21,7 +21,7 @@ class Referer implements EntityInterface protected $id; /** - * @ORM\ManyToOne(targetEntity=Node::class, inversedBy="nodeViews") + * @ORM\ManyToOne(targetEntity=Node::class, inversedBy="analyticReferers") * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ protected $node; diff --git a/core/Entity/Analytic/View.php b/core/Entity/Analytic/View.php index 0bd3338..25dd681 100644 --- a/core/Entity/Analytic/View.php +++ b/core/Entity/Analytic/View.php @@ -21,7 +21,7 @@ class View implements EntityInterface protected $id; /** - * @ORM\ManyToOne(targetEntity=Node::class, inversedBy="nodeViews") + * @ORM\ManyToOne(targetEntity=Node::class, inversedBy="analyticViews") * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ protected $node; @@ -36,6 +36,16 @@ class View implements EntityInterface */ protected $views = 0; + /** + * @ORM\Column(type="integer", options={"default"=0}) + */ + protected $desktopViews = 0; + + /** + * @ORM\Column(type="integer", options={"default"=0}) + */ + protected $mobileViews = 0; + /** * @ORM\Column(type="date") */ @@ -89,6 +99,44 @@ class View implements EntityInterface return $this; } + public function getDesktopViews(): ?int + { + return $this->desktopViews; + } + + public function setDesktopViews(int $desktopViews): self + { + $this->desktopViews = $desktopViews; + + return $this; + } + + public function addDesktopView(): self + { + ++$this->desktopViews; + + return $this; + } + + public function getMobileViews(): ?int + { + return $this->mobileViews; + } + + public function setMobileViews(int $mobileViews): self + { + $this->mobileViews = $mobileViews; + + return $this; + } + + public function addMobileView(): self + { + ++$this->mobileViews; + + return $this; + } + public function getDate(): ?\DateTimeInterface { return $this->date; diff --git a/core/Entity/Redirect.php b/core/Entity/Redirect.php index 97cbf9b..0b1bcb4 100644 --- a/core/Entity/Redirect.php +++ b/core/Entity/Redirect.php @@ -65,12 +65,12 @@ class Redirect implements EntityInterface /** * @ORM\Column(type="boolean") */ - private $isEnabled; + protected $isEnabled; /** * @ORM\Column(type="boolean") */ - private $reuseQueryString; + protected $reuseQueryString; public function getId(): ?int { diff --git a/core/EventListener/AnalyticListener.php b/core/EventListener/AnalyticListener.php index fdec2f5..5fe1069 100644 --- a/core/EventListener/AnalyticListener.php +++ b/core/EventListener/AnalyticListener.php @@ -2,18 +2,19 @@ namespace App\Core\EventListener; -use App\Core\Manager\EntityManager; -use App\Core\Repository\Site\NodeRepositoryQuery; -use Symfony\Component\HttpKernel\Event\RequestEvent; -use App\Core\Repository\Site\NodeRepository; -use App\Core\Repository\Analytic\ViewRepositoryQuery; -use App\Core\Factory\Analytic\ViewFactory; -use App\Core\Entity\Site\Node; -use Symfony\Component\HttpFoundation\Request; -use App\Core\Repository\Analytic\RefererRepositoryQuery; -use App\Core\Factory\Analytic\RefererFactory; use App\Core\Entity\EntityInterface; -use Jaybizzle\CrawlerDetect\CrawlerDetect; +use App\Core\Entity\Site\Node; +use App\Core\Factory\Analytic\RefererFactory; +use App\Core\Factory\Analytic\ViewFactory; +use App\Core\Manager\EntityManager; +use App\Core\Repository\Analytic\RefererRepositoryQuery; +use App\Core\Repository\Analytic\ViewRepositoryQuery; +use App\Core\Repository\Site\NodeRepository; +use DeviceDetector\Cache\PSR6Bridge; +use DeviceDetector\DeviceDetector; +use Symfony\Component\Cache\Adapter\ApcuAdapter; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\RequestEvent; /** * class AnalyticListener. @@ -28,7 +29,7 @@ class AnalyticListener protected RefererRepositoryQuery $refererRepositoryQuery; protected RefererFactory $refererFactory; protected EntityManager $manager; - protected CrawlerDetect $crawlerDetect; + protected DeviceDetector $deviceDetector; protected Request $request; protected Node $node; @@ -46,7 +47,7 @@ class AnalyticListener $this->refererRepositoryQuery = $refererRepositoryQuery; $this->refererFactory = $refererFactory; $this->manager = $manager; - $this->crawlerDetect = new CrawlerDetect(); + $this->createDeviceDetector(); } public function onKernelRequest(RequestEvent $event) @@ -57,7 +58,10 @@ class AnalyticListener return; } - if ($this->crawlerDetect->isCrawler($request->headers->get('user-agent'))) { + $this->deviceDetector->setUserAgent($request->headers->get('user-agent')); + $this->deviceDetector->parse(); + + if ($this->deviceDetector->isBot()) { return; } @@ -77,6 +81,14 @@ class AnalyticListener $this->createReferer(); } + protected function createDeviceDetector() + { + $cache = new ApcuAdapter(); + + $this->deviceDetector = new DeviceDetector(); + $this->deviceDetector->setCache(new PSR6Bridge($cache)); + } + protected function createView() { $entity = $this->viewRepositoryQuery->create() @@ -90,6 +102,13 @@ class AnalyticListener } $entity->addView(); + + if ($this->deviceDetector->isDesktop()) { + $entity->addDesktopView(); + } elseif ($this->deviceDetector->isMobile()) { + $entity->addMobileView(); + } + $this->save($entity); } diff --git a/core/Resources/views/analytic/stats.html.twig b/core/Resources/views/analytic/stats.html.twig index 8190fa1..1d7e61d 100644 --- a/core/Resources/views/analytic/stats.html.twig +++ b/core/Resources/views/analytic/stats.html.twig @@ -47,18 +47,22 @@ {{ 'Path'|trans }} - {{ 'Views'|trans }} + {{ 'Views'|trans }} + + {% for path, views in pathViews %} {{ path }} - {{ views }} + {{ views.views }} + {{ views.desktopViews }} + {{ views.mobileViews }} {% else %} - +
diff --git a/core/Twig/Extension/RoutingExtension.php b/core/Twig/Extension/RoutingExtension.php index 287ea93..683153c 100644 --- a/core/Twig/Extension/RoutingExtension.php +++ b/core/Twig/Extension/RoutingExtension.php @@ -62,7 +62,7 @@ class RoutingExtension extends AbstractExtension public function getNodePath(Node $node, array $parameters = [], bool $relative = false): ?string { - if ($node->hasExternalUrl()) { + if ($node->hasExternalUrl() || $node->hasAppUrl()) { return $node->getUrl(); } @@ -75,7 +75,7 @@ class RoutingExtension extends AbstractExtension public function getNodeUrl(Node $node, array $parameters = [], bool $schemeRelative = false): ?string { - if ($node->hasExternalUrl()) { + if ($node->hasExternalUrl() || $node->hasAppUrl()) { return $node->getUrl(); } diff --git a/symfony.lock b/symfony.lock index 86b7c8f..a53d695 100644 --- a/symfony.lock +++ b/symfony.lock @@ -132,9 +132,6 @@ "imagine/imagine": { "version": "1.2.4" }, - "jaybizzle/crawler-detect": { - "version": "v1.2.110" - }, "khanamiryan/qrcode-detector-decoder": { "version": "1.0.4" }, @@ -172,12 +169,18 @@ "config/routes/liip_imagine.yaml" ] }, + "matomo/device-detector": { + "version": "5.0.4" + }, "michelf/php-markdown": { "version": "1.9.0" }, "monolog/monolog": { "version": "2.2.0" }, + "mustangostang/spyc": { + "version": "0.6.3" + }, "myclabs/php-enum": { "version": "1.8.0" },