From dbe9287314d615edba8aff6cf5e28fc62f473df2 Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Sat, 19 Feb 2022 23:41:25 +0100 Subject: [PATCH] backports murph-skeleton --- config/services.yaml | 4 + core/Entity/NodeView.php | 102 ++++++++++++++++++ core/Entity/Site/Node.php | 54 ++++++++++ core/EventListener/NodeViewListener.php | 68 ++++++++++++ core/Factory/NodeViewFactory.php | 21 ++++ core/Form/Site/NodeType.php | 13 +++ core/Repository/NodeViewRepository.php | 21 ++++ core/Repository/NodeViewRepositoryQuery.php | 27 +++++ core/Resources/translations/messages.fr.yaml | 2 + .../views/site/node_admin/_form.html.twig | 1 + 10 files changed, 313 insertions(+) create mode 100644 core/Entity/NodeView.php create mode 100644 core/EventListener/NodeViewListener.php create mode 100644 core/Factory/NodeViewFactory.php create mode 100644 core/Repository/NodeViewRepository.php create mode 100644 core/Repository/NodeViewRepositoryQuery.php diff --git a/config/services.yaml b/config/services.yaml index 1145401..4fc9a31 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -23,6 +23,10 @@ services: tags: - { name: kernel.event_listener, event: kernel.exception } + App\Core\EventListener\NodeViewListener: + tags: + - { name: kernel.event_listener, event: kernel.request } + App\: resource: '../src/' exclude: diff --git a/core/Entity/NodeView.php b/core/Entity/NodeView.php new file mode 100644 index 0000000..506dbb5 --- /dev/null +++ b/core/Entity/NodeView.php @@ -0,0 +1,102 @@ +id; + } + + public function getNode(): ?Node + { + return $this->node; + } + + public function setNode(?Node $node): self + { + $this->node = $node; + + return $this; + } + + public function getPath(): ?string + { + return $this->path; + } + + public function setPath(string $path): self + { + $this->path = $path; + + return $this; + } + + public function getViews(): ?int + { + return $this->views; + } + + public function setViews(int $views): self + { + $this->views = $views; + + return $this; + } + + public function addView(): self + { + ++$this->views; + + return $this; + } + + public function getDate(): ?\DateTimeInterface + { + return $this->date; + } + + public function setDate(\DateTimeInterface $date): self + { + $this->date = $date; + + return $this; + } +} diff --git a/core/Entity/Site/Node.php b/core/Entity/Site/Node.php index ab7d6ef..0c71538 100644 --- a/core/Entity/Site/Node.php +++ b/core/Entity/Site/Node.php @@ -4,6 +4,7 @@ namespace App\Core\Entity\Site; use App\Core\Doctrine\Timestampable; use App\Core\Entity\EntityInterface; +use App\Core\Entity\NodeView; use App\Core\Entity\Site\Page\Page; use App\Core\Repository\Site\NodeRepository; use Doctrine\Common\Collections\ArrayCollection; @@ -139,10 +140,21 @@ class Node implements EntityInterface */ protected $contentType; + /** + * @ORM\Column(type="boolean", options={"default"=0}) + */ + private $enableViewCounter = false; + + /** + * @ORM\OneToMany(targetEntity=NodeView::class, mappedBy="node", orphanRemoval=true) + */ + private $nodeViews; + public function __construct() { $this->children = new ArrayCollection(); $this->aliasNodes = new ArrayCollection(); + $this->nodeViews = new ArrayCollection(); } public function getId(): ?int @@ -548,4 +560,46 @@ class Node implements EntityInterface return $this; } + + public function getEnableViewCounter(): ?bool + { + return $this->enableViewCounter; + } + + public function setEnableViewCounter(bool $enableViewCounter): self + { + $this->enableViewCounter = $enableViewCounter; + + return $this; + } + + /** + * @return Collection|NodeView[] + */ + public function getNodeViews(): Collection + { + return $this->nodeViews; + } + + public function addNodeView(NodeView $nodeView): self + { + if (!$this->nodeViews->contains($nodeView)) { + $this->nodeViews[] = $nodeView; + $nodeView->setNode($this); + } + + return $this; + } + + public function removeNodeView(NodeView $nodeView): self + { + if ($this->nodeViews->removeElement($nodeView)) { + // set the owning side to null (unless already changed) + if ($nodeView->getNode() === $this) { + $nodeView->setNode(null); + } + } + + return $this; + } } diff --git a/core/EventListener/NodeViewListener.php b/core/EventListener/NodeViewListener.php new file mode 100644 index 0000000..52b3880 --- /dev/null +++ b/core/EventListener/NodeViewListener.php @@ -0,0 +1,68 @@ + + */ +class NodeViewListener +{ + protected NodeRepository $nodeRepository; + protected NodeViewRepositoryQuery $nodeViewRepositoryQuery; + protected NodeViewFactory $nodeViewFactory; + protected EntityManager $manager; + + public function __construct( + NodeRepository $nodeRepository, + NodeViewRepositoryQuery $nodeViewRepositoryQuery, + NodeViewFactory $nodeViewFactory, + EntityManager $manager + ) { + $this->nodeRepository = $nodeRepository; + $this->nodeViewRepositoryQuery = $nodeViewRepositoryQuery; + $this->nodeViewFactory = $nodeViewFactory; + $this->manager = $manager; + } + + public function onKernelRequest(RequestEvent $event) + { + $request = $event->getRequest(); + + if (!$request->attributes->has('_node')) { + return; + } + + $node = $this->nodeRepository->findOneById($request->attributes->get('_node')); + + if (!$node || !$node->getEnableViewCounter()) { + return; + } + + $nodeView = $this->nodeViewRepositoryQuery->create() + ->filterByRequest($request) + ->andWhere('.date=CURRENT_DATE()') + ->findOne() + ; + + if (!$nodeView) { + $nodeView = $this->nodeViewFactory->create($node, $request->getPathInfo()); + } + + $nodeView->addView(); + + if ($nodeView->getId()) { + $this->manager->update($nodeView); + } else { + $this->manager->create($nodeView); + } + } +} diff --git a/core/Factory/NodeViewFactory.php b/core/Factory/NodeViewFactory.php new file mode 100644 index 0000000..ecc3862 --- /dev/null +++ b/core/Factory/NodeViewFactory.php @@ -0,0 +1,21 @@ +setNode($node) + ->setPath($path) + ->setDate(new \DateTime()) + ; + + return $entity; + } +} diff --git a/core/Form/Site/NodeType.php b/core/Form/Site/NodeType.php index 5c9b314..184cf55 100644 --- a/core/Form/Site/NodeType.php +++ b/core/Form/Site/NodeType.php @@ -60,6 +60,19 @@ class NodeType extends AbstractType ] ); + $builder->add( + 'enableViewCounter', + CheckboxType::class, + [ + 'label' => 'Enable view counter', + 'required' => false, + 'attr' => [ + ], + 'constraints' => [ + ], + ] + ); + $builder->add( 'code', TextType::class, diff --git a/core/Repository/NodeViewRepository.php b/core/Repository/NodeViewRepository.php new file mode 100644 index 0000000..5175e58 --- /dev/null +++ b/core/Repository/NodeViewRepository.php @@ -0,0 +1,21 @@ +andWhere('.node = :node') + ->andWhere('.path = :path') + ->setParameters([ + ':node' => $request->attributes->get('_node'), + ':path' => $request->getPathInfo(), + ]) + ; + } +} diff --git a/core/Resources/translations/messages.fr.yaml b/core/Resources/translations/messages.fr.yaml index 0204b3e..26a9430 100644 --- a/core/Resources/translations/messages.fr.yaml +++ b/core/Resources/translations/messages.fr.yaml @@ -39,6 +39,8 @@ "Never": "Jamais" "URL": "URL" "Disable URL": "Désactiver l'URL" +"Enable view counter": "Activer le compteur de vues" +"Stats": "Statistiques" "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/site/node_admin/_form.html.twig b/core/Resources/views/site/node_admin/_form.html.twig index 9fb460f..b1d7d78 100644 --- a/core/Resources/views/site/node_admin/_form.html.twig +++ b/core/Resources/views/site/node_admin/_form.html.twig @@ -205,6 +205,7 @@ {{ form_row(form.disableUrl) }} + {{ form_row(form.enableViewCounter) }} {{ form_row(form.code) }} {{ form_row(form.contentType) }} {{ form_row(form.controller) }}