From e67966df4518e2271badbb1f6ef16fa63d5a96c6 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Sun, 20 Feb 2022 21:05:46 +0100 Subject: [PATCH] add analytic chart and table --- core/Analytic/RangeAnalytic.php | 133 ++++++++++++++++++ .../Analytic/AnalyticController.php | 37 +++++ core/Entity/Analytic/Referer.php | 10 +- core/Entity/Analytic/View.php | 10 +- core/Entity/Site/Node.php | 10 +- core/EventListener/AnalyticListener.php | 2 +- core/Form/Site/NodeType.php | 4 +- core/Resources/translations/messages.fr.yaml | 3 +- core/Resources/views/analytic/stats.html.twig | 111 +++++++++++++++ .../site/tree_admin/navigation.html.twig | 5 + 10 files changed, 306 insertions(+), 19 deletions(-) create mode 100644 core/Analytic/RangeAnalytic.php create mode 100644 core/Controller/Analytic/AnalyticController.php create mode 100644 core/Resources/views/analytic/stats.html.twig diff --git a/core/Analytic/RangeAnalytic.php b/core/Analytic/RangeAnalytic.php new file mode 100644 index 0000000..a4d5ef6 --- /dev/null +++ b/core/Analytic/RangeAnalytic.php @@ -0,0 +1,133 @@ + + */ +class RangeAnalytic +{ + protected ViewRepositoryQuery $viewQuery; + protected RefererRepositoryQuery $refererQuery; + + public function __construct(ViewRepositoryQuery $viewQuery, RefererRepositoryQuery $refererQuery) + { + $this->viewQuery = $viewQuery; + $this->refererQuery = $refererQuery; + } + + public function getViews(\DateTime $from, \DateTime $to, Node $node): array + { + $entities = $this->viewQuery->create() + ->andWhere('.date >= :from') + ->andWhere('.date <= :to') + ->andWhere('.node = :node') + ->orderBy('.date') + ->setParameters([ + ':from' => $from, + ':to' => $to, + ':node' => $node->getId(), + ]) + ->find() + ; + + $diff = $from->diff($to); + + if ($diff->days >= 365) { + $format = 'Y-m'; + } else { + $format = 'Y-m-d'; + } + + $datas = []; + + foreach ($entities as $entity) { + $index = $entity->getDate()->format($format); + + if (!isset($datas[$index])) { + $datas[$index] = 0; + } + + $datas[$index] += $entity->getViews(); + } + + return $datas; + } + + public function getPathViews(\DateTime $from, \DateTime $to, Node $node): array + { + $entities = $this->viewQuery->create() + ->andWhere('.date >= :from') + ->andWhere('.date <= :to') + ->andWhere('.node = :node') + ->orderBy('.date') + ->setParameters([ + ':from' => $from, + ':to' => $to, + ':node' => $node->getId(), + ]) + ->find() + ; + + $datas = []; + + foreach ($entities as $entity) { + $index = $entity->getPath(); + + if (!isset($datas[$index])) { + $datas[$index] = 0; + } + + $datas[$index] += $entity->getViews(); + } + + return $datas; + } + + public function getReferers(\DateTime $from, \DateTime $to, Node $node): array + { + $entities = $this->refererQuery->create() + ->andWhere('.date >= :from') + ->andWhere('.date <= :to') + ->andWhere('.node = :node') + ->orderBy('.date') + ->setParameters([ + ':from' => $from, + ':to' => $to, + ':node' => $node->getId(), + ]) + ->find() + ; + + $datas = []; + + foreach ($entities as $entity) { + $index = parse_url($entity->getUri(), PHP_URL_HOST); + + if (!isset($datas[$index])) { + $datas[$index] = [ + 'views' => 0, + 'uris' => [], + ]; + } + + $datas[$index]['views'] += $entity->getViews(); + + $path = parse_url($entity->getUri(), PHP_URL_PATH); + + if (!isset($datas[$index]['uris'][$path])) { + $datas[$index]['uris'][$path] = 0; + } + + $datas[$index]['uris'][$path] += $entity->getViews(); + } + + return $datas; + } +} diff --git a/core/Controller/Analytic/AnalyticController.php b/core/Controller/Analytic/AnalyticController.php new file mode 100644 index 0000000..83b9640 --- /dev/null +++ b/core/Controller/Analytic/AnalyticController.php @@ -0,0 +1,37 @@ +createNotFoundException(); + } + + $views = $rangeAnalytic->getViews(new \DateTime('now - '.$range), new \DateTime(), $node); + $pathViews = $rangeAnalytic->getPathViews(new \DateTime('now - '.$range), new \DateTime(), $node); + $referers = $rangeAnalytic->getReferers(new \DateTime('now - '.$range), new \DateTime(), $node); + + return $this->render('@Core/analytic/stats.html.twig', [ + 'range' => $range, + 'views' => $views, + 'pathViews' => $pathViews, + 'referers' => $referers, + 'node' => $node, + ]); + } +} diff --git a/core/Entity/Analytic/Referer.php b/core/Entity/Analytic/Referer.php index 0281d3c..1c8b94d 100644 --- a/core/Entity/Analytic/Referer.php +++ b/core/Entity/Analytic/Referer.php @@ -18,28 +18,28 @@ class Referer implements EntityInterface * @ORM\GeneratedValue * @ORM\Column(type="integer") */ - private $id; + protected $id; /** * @ORM\ManyToOne(targetEntity=Node::class, inversedBy="nodeViews") * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ - private $node; + protected $node; /** * @ORM\Column(type="string", length=255) */ - private $uri; + protected $uri; /** * @ORM\Column(type="integer", options={"default"=0}) */ - private $views = 0; + protected $views = 0; /** * @ORM\Column(type="date") */ - private $date; + protected $date; public function getId(): ?int { diff --git a/core/Entity/Analytic/View.php b/core/Entity/Analytic/View.php index a5db1b9..0bd3338 100644 --- a/core/Entity/Analytic/View.php +++ b/core/Entity/Analytic/View.php @@ -18,28 +18,28 @@ class View implements EntityInterface * @ORM\GeneratedValue * @ORM\Column(type="integer") */ - private $id; + protected $id; /** * @ORM\ManyToOne(targetEntity=Node::class, inversedBy="nodeViews") * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ - private $node; + protected $node; /** * @ORM\Column(type="string", length=255) */ - private $path; + protected $path; /** * @ORM\Column(type="integer", options={"default"=0}) */ - private $views = 0; + protected $views = 0; /** * @ORM\Column(type="date") */ - private $date; + protected $date; public function getId(): ?int { diff --git a/core/Entity/Site/Node.php b/core/Entity/Site/Node.php index 35a684e..4196966 100644 --- a/core/Entity/Site/Node.php +++ b/core/Entity/Site/Node.php @@ -145,7 +145,7 @@ class Node implements EntityInterface /** * @ORM\Column(type="boolean", options={"default"=0}) */ - protected $enableAnalytic = false; + protected $enableAnalytics = false; /** * @ORM\OneToMany(targetEntity=View::class, mappedBy="node") @@ -569,14 +569,14 @@ class Node implements EntityInterface return $this; } - public function getEnableAnalytic(): ?bool + public function getEnableAnalytics(): ?bool { - return $this->enableAnalytic; + return $this->enableAnalytics; } - public function setEnableAnalytic(bool $enableAnalytic): self + public function setEnableAnalytics(bool $enableAnalytics): self { - $this->enableAnalytic = $enableAnalytic; + $this->enableAnalytics = $enableAnalytics; return $this; } diff --git a/core/EventListener/AnalyticListener.php b/core/EventListener/AnalyticListener.php index eb6b983..6154378 100644 --- a/core/EventListener/AnalyticListener.php +++ b/core/EventListener/AnalyticListener.php @@ -63,7 +63,7 @@ class AnalyticListener $node = $this->nodeRepository->findOneBy([ 'id' => $request->attributes->get('_node'), - 'enableViewCounter' => true, + 'enableAnalytics' => true, ]); if (!$node) { diff --git a/core/Form/Site/NodeType.php b/core/Form/Site/NodeType.php index 4f41c1d..284d0f9 100644 --- a/core/Form/Site/NodeType.php +++ b/core/Form/Site/NodeType.php @@ -61,10 +61,10 @@ class NodeType extends AbstractType ); $builder->add( - 'enableAnalytic', + 'enableAnalytics', CheckboxType::class, [ - 'label' => 'Enable analytic', + 'label' => 'Enable analytics', 'required' => false, 'attr' => [ ], diff --git a/core/Resources/translations/messages.fr.yaml b/core/Resources/translations/messages.fr.yaml index 7f02595..039b2cc 100644 --- a/core/Resources/translations/messages.fr.yaml +++ b/core/Resources/translations/messages.fr.yaml @@ -39,7 +39,8 @@ "Never": "Jamais" "URL": "URL" "Disable URL": "Désactiver l'URL" -"Enable analytic": "Activer l'analyse" +"Enable analytics": "Activer les analyses" +"Analytics": "Analyses" "Controller": "Contrôleur" "Leave blank for automatic generation": "Laisser vide pour une génération automatique" "Leave blank to use the default one. Example: App\\Controller\\FooController::barAction": "Laisser vide pour utiliser celui par défaut. Exemple : App\\Controller\\FooController::barAction" diff --git a/core/Resources/views/analytic/stats.html.twig b/core/Resources/views/analytic/stats.html.twig new file mode 100644 index 0000000..b1bf18d --- /dev/null +++ b/core/Resources/views/analytic/stats.html.twig @@ -0,0 +1,111 @@ + diff --git a/core/Resources/views/site/tree_admin/navigation.html.twig b/core/Resources/views/site/tree_admin/navigation.html.twig index b077da6..f49a211 100644 --- a/core/Resources/views/site/tree_admin/navigation.html.twig +++ b/core/Resources/views/site/tree_admin/navigation.html.twig @@ -72,6 +72,7 @@ {% set move = path('admin_site_node_move', {entity: node.id}) %} {% set edit = path('admin_site_node_edit', {entity: node.id}) %} {% set new = path('admin_site_node_new', {node: node.id}) %} + {% set analytics = path('admin_analytic_stats', {node: node.id}) %}
@@ -147,6 +148,10 @@ {% endif %} + +