- move NodeView to Analytic/View
- move NodeViewListener to AnalyticListener - add referer
This commit is contained in:
parent
58c8b6126e
commit
ec4b3341c8
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -27,3 +27,5 @@ yarn-error.log
|
|||
/public/uploads/
|
||||
!/public/uploads/.gitkeep
|
||||
/public/media/
|
||||
/migrations/
|
||||
!/migrations/.gitkeep
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"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-paginator-bundle": "^5.8",
|
||||
"liip/imagine-bundle": "^2.6",
|
||||
|
|
|
@ -23,7 +23,7 @@ services:
|
|||
tags:
|
||||
- { name: kernel.event_listener, event: kernel.exception }
|
||||
|
||||
App\Core\EventListener\NodeViewListener:
|
||||
App\Core\EventListener\AnalyticListener:
|
||||
tags:
|
||||
- { name: kernel.event_listener, event: kernel.request }
|
||||
|
||||
|
|
103
core/Entity/Analytic/Referer.php
Normal file
103
core/Entity/Analytic/Referer.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Entity\Analytic;
|
||||
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Repository\Entity\Analytic\NodeViewRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=ViewRepository::class)
|
||||
* @ORM\Table(name="analytic_referer")
|
||||
*/
|
||||
class Referer implements EntityInterface
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Node::class, inversedBy="nodeViews")
|
||||
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
|
||||
*/
|
||||
private $node;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $uri;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer", options={"default"=0})
|
||||
*/
|
||||
private $views = 0;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date")
|
||||
*/
|
||||
private $date;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getNode(): ?Node
|
||||
{
|
||||
return $this->node;
|
||||
}
|
||||
|
||||
public function setNode(?Node $node): self
|
||||
{
|
||||
$this->node = $node;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUri(): ?string
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
public function setUri(string $uri): self
|
||||
{
|
||||
$this->uri = $uri;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -1,16 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Entity;
|
||||
namespace App\Core\Entity\Analytic;
|
||||
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Repository\Entity\NodeViewRepository;
|
||||
use App\Repository\Entity\Analytic\NodeViewRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=NodeViewRepository::class)
|
||||
* @ORM\Entity(repositoryClass=ViewRepository::class)
|
||||
* @ORM\Table(name="analytic_view")
|
||||
*/
|
||||
class NodeView implements EntityInterface
|
||||
class View implements EntityInterface
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
|
@ -21,7 +22,7 @@ class NodeView implements EntityInterface
|
|||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Node::class, inversedBy="nodeViews")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
|
||||
*/
|
||||
private $node;
|
||||
|
|
@ -12,6 +12,8 @@ use Doctrine\Common\Collections\Collection;
|
|||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Gedmo\Mapping\Annotation as Gedmo;
|
||||
use function Symfony\Component\String\u;
|
||||
use App\Core\Entity\Analytic\View;
|
||||
use App\Core\Entity\Analytic\Referer;
|
||||
|
||||
/**
|
||||
* @Gedmo\Tree(type="nested")
|
||||
|
@ -143,18 +145,24 @@ class Node implements EntityInterface
|
|||
/**
|
||||
* @ORM\Column(type="boolean", options={"default"=0})
|
||||
*/
|
||||
private $enableViewCounter = false;
|
||||
protected $enableViewCounter = false;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=NodeView::class, mappedBy="node", orphanRemoval=true)
|
||||
* @ORM\OneToMany(targetEntity=View::class, mappedBy="node")
|
||||
*/
|
||||
private $nodeViews;
|
||||
protected $analyticViews;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=Referer::class, mappedBy="node")
|
||||
*/
|
||||
protected $analyticReferers;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = new ArrayCollection();
|
||||
$this->aliasNodes = new ArrayCollection();
|
||||
$this->nodeViews = new ArrayCollection();
|
||||
$this->analyticViews = new ArrayCollection();
|
||||
$this->analyticReferers = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
|
@ -574,29 +582,59 @@ class Node implements EntityInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Collection|NodeView[]
|
||||
* @return Collection|View[]
|
||||
*/
|
||||
public function getNodeViews(): Collection
|
||||
public function getAnalyticViews(): Collection
|
||||
{
|
||||
return $this->nodeViews;
|
||||
return $this->analyticViews;
|
||||
}
|
||||
|
||||
public function addNodeView(NodeView $nodeView): self
|
||||
public function addAnalyticView(View $view): self
|
||||
{
|
||||
if (!$this->nodeViews->contains($nodeView)) {
|
||||
$this->nodeViews[] = $nodeView;
|
||||
$nodeView->setNode($this);
|
||||
if (!$this->analyticViews->contains($view)) {
|
||||
$this->analyticViews[] = $view;
|
||||
$view->setNode($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeNodeView(NodeView $nodeView): self
|
||||
public function removeAnalyticView(View $view): self
|
||||
{
|
||||
if ($this->nodeViews->removeElement($nodeView)) {
|
||||
if ($this->analyticViews->removeElement($view)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($nodeView->getNode() === $this) {
|
||||
$nodeView->setNode(null);
|
||||
if ($view->getNode() === $this) {
|
||||
$view->setNode(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Referer[]
|
||||
*/
|
||||
public function getAnalyticReferers(): Collection
|
||||
{
|
||||
return $this->analyticReferers;
|
||||
}
|
||||
|
||||
public function addAnalyticReferer(Referer $referer): self
|
||||
{
|
||||
if (!$this->analyticReferers->contains($referer)) {
|
||||
$this->analyticReferers[] = $referer;
|
||||
$referer->setNode($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeAnalyticReferer(Referer $referer): self
|
||||
{
|
||||
if ($this->analyticReferers->removeElement($referer)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($referer->getNode() === $this) {
|
||||
$referer->setNode(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
124
core/EventListener/AnalyticListener.php
Normal file
124
core/EventListener/AnalyticListener.php
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* class AnalyticListener.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class AnalyticListener
|
||||
{
|
||||
protected NodeRepository $nodeRepository;
|
||||
protected ViewRepositoryQuery $viewRepositoryQuery;
|
||||
protected ViewFactory $viewFactory;
|
||||
protected RefererRepositoryQuery $refererRepositoryQuery;
|
||||
protected RefererFactory $refererFactory;
|
||||
protected EntityManager $manager;
|
||||
protected CrawlerDetect $crawlerDetect;
|
||||
protected Request $request;
|
||||
protected Node $node;
|
||||
|
||||
public function __construct(
|
||||
NodeRepository $nodeRepository,
|
||||
ViewRepositoryQuery $viewRepositoryQuery,
|
||||
ViewFactory $viewFactory,
|
||||
RefererRepositoryQuery $refererRepositoryQuery,
|
||||
RefererFactory $refererFactory,
|
||||
EntityManager $manager
|
||||
) {
|
||||
$this->nodeRepository = $nodeRepository;
|
||||
$this->viewRepositoryQuery = $viewRepositoryQuery;
|
||||
$this->viewFactory = $viewFactory;
|
||||
$this->refererRepositoryQuery = $refererRepositoryQuery;
|
||||
$this->refererFactory = $refererFactory;
|
||||
$this->manager = $manager;
|
||||
$this->crawlerDetect = new CrawlerDetect();
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (!$request->attributes->has('_node')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->crawlerDetect->isCrawler($request->headers->get('user-agent'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$node = $this->nodeRepository->findOneBy([
|
||||
'id' => $request->attributes->get('_node'),
|
||||
'enableViewCounter' => true,
|
||||
]);
|
||||
|
||||
if (!$node) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->node = $node;
|
||||
$this->request = $request;
|
||||
|
||||
$this->createView();
|
||||
$this->createReferer();
|
||||
}
|
||||
|
||||
protected function createView()
|
||||
{
|
||||
$entity = $this->viewRepositoryQuery->create()
|
||||
->filterByRequest($this->request)
|
||||
->andWhere('.date=CURRENT_DATE()')
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if (!$entity) {
|
||||
$entity = $this->viewFactory->create($this->node, $this->request->getPathInfo());
|
||||
}
|
||||
|
||||
$entity->addView();
|
||||
$this->save($entity);
|
||||
}
|
||||
|
||||
protected function createReferer()
|
||||
{
|
||||
if (!$this->request->headers->has('referer')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$entity = $this->refererRepositoryQuery->create()
|
||||
->filterByRequest($this->request)
|
||||
->andWhere('.date=CURRENT_DATE()')
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if (!$entity) {
|
||||
$entity = $this->refererFactory->create($this->node, $this->request->headers->get('referer'));
|
||||
}
|
||||
|
||||
$entity->addView();
|
||||
$this->save($entity);
|
||||
}
|
||||
|
||||
protected function save(EntityInterface $entity)
|
||||
{
|
||||
if ($entity->getId()) {
|
||||
$this->manager->update($entity);
|
||||
} else {
|
||||
$this->manager->create($entity);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\EventListener;
|
||||
|
||||
use App\Core\Factory\NodeViewFactory;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Repository\NodeViewRepositoryQuery;
|
||||
use App\Core\Repository\Site\NodeRepositoryQuery;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use App\Core\Repository\Site\NodeRepository;
|
||||
|
||||
/**
|
||||
* class NodeViewListener.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
22
core/Factory/Analytic/RefererFactory.php
Normal file
22
core/Factory/Analytic/RefererFactory.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Factory\Analytic;
|
||||
|
||||
use App\Core\Entity\Analytic\Referer as Entity;
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Core\Factory\FactoryInterface;
|
||||
|
||||
class RefererFactory implements FactoryInterface
|
||||
{
|
||||
public function create(Node $node, string $uri): Entity
|
||||
{
|
||||
$entity = new Entity();
|
||||
$entity
|
||||
->setNode($node)
|
||||
->setUri($uri)
|
||||
->setDate(new \DateTime())
|
||||
;
|
||||
|
||||
return $entity;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Factory;
|
||||
namespace App\Core\Factory\Analytic;
|
||||
|
||||
use App\Core\Entity\NodeView as Entity;
|
||||
use App\Core\Entity\Analytic\View as Entity;
|
||||
use App\Core\Entity\Site\Node;
|
||||
use App\Core\Factory\FactoryInterface;
|
||||
|
||||
class NodeViewFactory implements FactoryInterface
|
||||
class ViewFactory implements FactoryInterface
|
||||
{
|
||||
public function create(Node $node, string $path): Entity
|
||||
{
|
21
core/Repository/Analytic/RefererRepository.php
Normal file
21
core/Repository/Analytic/RefererRepository.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Repository\Analytic;
|
||||
|
||||
use App\Core\Entity\Analytic\Referer;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method Referer|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Referer|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Referer[] findAll()
|
||||
* @method Referer[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class RefererRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Referer::class);
|
||||
}
|
||||
}
|
28
core/Repository/Analytic/RefererRepositoryQuery.php
Normal file
28
core/Repository/Analytic/RefererRepositoryQuery.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Repository\Analytic;
|
||||
|
||||
use App\Core\Repository\Analytic\RefererRepository as Repository;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
|
||||
class RefererRepositoryQuery extends RepositoryQuery
|
||||
{
|
||||
public function __construct(Repository $repository, PaginatorInterface $paginator)
|
||||
{
|
||||
parent::__construct($repository, 'n', $paginator);
|
||||
}
|
||||
|
||||
public function filterByRequest(Request $request)
|
||||
{
|
||||
return $this
|
||||
->andWhere('.node = :node')
|
||||
->andWhere('.uri = :uri')
|
||||
->setParameters([
|
||||
':node' => $request->attributes->get('_node'),
|
||||
':uri' => $request->headers->get('referer'),
|
||||
])
|
||||
;
|
||||
}
|
||||
}
|
21
core/Repository/Analytic/ViewRepository.php
Normal file
21
core/Repository/Analytic/ViewRepository.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Repository\Analytic;
|
||||
|
||||
use App\Core\Entity\Analytic\View;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method View|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method View|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method View[] findAll()
|
||||
* @method View[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class ViewRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, View::class);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Repository;
|
||||
namespace App\Core\Repository\Analytic;
|
||||
|
||||
use App\Core\Repository\NodeViewRepository as Repository;
|
||||
use App\Core\Repository\Analytic\ViewRepository as Repository;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
|
||||
class NodeViewRepositoryQuery extends RepositoryQuery
|
||||
class ViewRepositoryQuery extends RepositoryQuery
|
||||
{
|
||||
public function __construct(Repository $repository, PaginatorInterface $paginator)
|
||||
{
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Repository;
|
||||
|
||||
use App\Core\Entity\NodeView;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method NodeView|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method NodeView|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method NodeView[] findAll()
|
||||
* @method NodeView[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class NodeViewRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, NodeView::class);
|
||||
}
|
||||
}
|
0
migrations/.gitignore
vendored
0
migrations/.gitignore
vendored
|
@ -129,6 +129,9 @@
|
|||
"imagine/imagine": {
|
||||
"version": "1.2.4"
|
||||
},
|
||||
"jaybizzle/crawler-detect": {
|
||||
"version": "v1.2.110"
|
||||
},
|
||||
"khanamiryan/qrcode-detector-decoder": {
|
||||
"version": "1.0.4"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue