<?php
declare(strict_types=1);
namespace Hitso\Bundle\CommonBundle\Repository;
use Hitso\Bundle\CommonBundle\Doctrine\Repository\EntityRepository;
use Hitso\Bundle\CommonBundle\Entity\VisitLog;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Webmozart\Assert\Assert;
class VisitLogRepository extends EntityRepository
{
public function __construct(RegistryInterface $registry, string $className = VisitLog::class)
{
parent::__construct($registry, $className);
}
public function logVisit(string $visitor): void
{
Assert::true(
in_array($visitor, [VisitLog::TYPE_GOOGLE, VisitLog::TYPE_MONITOR, VisitLog::TYPE_HITSO_MONITORING]),
'Invalid visitor'
);
$log = new VisitLog();
$log->setVisitor($visitor);
$this->_em->persist($log);
$this->_em->flush();
$this->deleteLogs(new \DateTime('-3 days'));
}
/**
* @param $visitor
*
* @return bool|\DateTime
*/
public function getLastTime($visitor)
{
/** @var VisitLog $entity */
$entity = $this->findOneBy(['visitor' => $visitor], ['createdAt' => 'DESC']);
return $entity ? $entity->getCreatedAt() : false;
}
/**
* @param $visitor
* @param int $days
* @param int $samples
*
* @return array
*/
public function getChartData($visitor, $days = 3, $samples = 4)
{
$sampleSize = 86400 / $samples;
$midnight = strtotime('midnight');
$todaySamples = (int) floor((time() - $midnight) / $sampleSize);
$endOfLast = $todaySamples * $sampleSize + $midnight;
$startOfFirst = $endOfLast - ($days * 86400);
$qb = $this->createQueryBuilder('v');
$qb->select()
->where($qb->expr()->eq('v.visitor', $qb->expr()->literal($visitor)))
->andWhere($qb->expr()->gte('v.createdAt', ':start'))
->andWhere($qb->expr()->lte('v.createdAt', ':end'))
->orderBy('v.createdAt', 'ASC');
$startDate = new \DateTime('@' . $startOfFirst);
$endDate = new \DateTime('@' . $endOfLast);
$tz = new \DateTimeZone(date_default_timezone_get());
$startDate->setTimezone($tz);
$endDate->setTimezone($tz);
/** @var VisitLog[] $logs */
$logs = $qb->getQuery()->execute(
[
'start' => $startDate,
'end' => $endDate,
]
);
$start = $startOfFirst;
$end = $startOfFirst + $sampleSize;
$keys = range($startOfFirst, $endOfLast - 1, $sampleSize);
$data = array_combine($keys, array_fill(0, count($keys), 0));
foreach ($logs as $log) {
$stamp = $log->getCreatedAt()->getTimestamp();
while ($stamp > $end) {
$start += $sampleSize;
$end += $sampleSize;
}
++$data[$start];
}
$results = [];
foreach ($data as $start => $count) {
$label = sprintf('%s-%s', date('Y-m-d H:i', $start), date('H:i', $start + $sampleSize - 1));
$results[$label] = $count;
}
return $results;
}
private function deleteLogs(\DateTime $before): void
{
if (random_int(1, 10) > 3) {
return;
}
$qb = $this->createQueryBuilder('v');
$qb->delete()
->andWhere('v.createdAt < :limit')
->setParameter('limit', $before)
->getQuery()
->execute();
}
}