Created new action to get default visit stats

This commit is contained in:
Alejandro Celaya 2020-05-01 11:40:02 +02:00
parent 5beaab85ac
commit 1ef10f11cb
9 changed files with 129 additions and 1 deletions

View file

@ -27,6 +27,7 @@ return [
Service\VisitsTracker::class => ConfigAbstractFactory::class, Service\VisitsTracker::class => ConfigAbstractFactory::class,
Service\ShortUrlService::class => ConfigAbstractFactory::class, Service\ShortUrlService::class => ConfigAbstractFactory::class,
Visit\VisitLocator::class => ConfigAbstractFactory::class, Visit\VisitLocator::class => ConfigAbstractFactory::class,
Visit\VisitsStatsHelper::class => ConfigAbstractFactory::class,
Service\Tag\TagService::class => ConfigAbstractFactory::class, Service\Tag\TagService::class => ConfigAbstractFactory::class,
Service\ShortUrl\DeleteShortUrlService::class => ConfigAbstractFactory::class, Service\ShortUrl\DeleteShortUrlService::class => ConfigAbstractFactory::class,
Service\ShortUrl\ShortUrlResolver::class => ConfigAbstractFactory::class, Service\ShortUrl\ShortUrlResolver::class => ConfigAbstractFactory::class,
@ -56,6 +57,7 @@ return [
Service\VisitsTracker::class => ['em', EventDispatcherInterface::class], Service\VisitsTracker::class => ['em', EventDispatcherInterface::class],
Service\ShortUrlService::class => ['em', Service\ShortUrl\ShortUrlResolver::class, Util\UrlValidator::class], Service\ShortUrlService::class => ['em', Service\ShortUrl\ShortUrlResolver::class, Util\UrlValidator::class],
Visit\VisitLocator::class => ['em'], Visit\VisitLocator::class => ['em'],
Visit\VisitsStatsHelper::class => ['em'],
Service\Tag\TagService::class => ['em'], Service\Tag\TagService::class => ['em'],
Service\ShortUrl\DeleteShortUrlService::class => [ Service\ShortUrl\DeleteShortUrlService::class => [
'em', 'em',

View file

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Visit\Model;
use JsonSerializable;
final class VisitsStats implements JsonSerializable
{
private int $visitsCount;
public function __construct(int $visitsCount)
{
$this->visitsCount = $visitsCount;
}
public function jsonSerialize(): array
{
return [
'visitsCount' => $this->visitsCount,
];
}
}

View file

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Visit;
use Doctrine\ORM\EntityManagerInterface;
use Shlinkio\Shlink\Core\Entity\Visit;
use Shlinkio\Shlink\Core\Repository\VisitRepository;
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
class VisitsStatsHelper implements VisitsStatsHelperInterface
{
private EntityManagerInterface $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function getVisitsStats(): VisitsStats
{
return new VisitsStats($this->getVisitsCount());
}
private function getVisitsCount(): int
{
/** @var VisitRepository $visitsRepo */
$visitsRepo = $this->em->getRepository(Visit::class);
return $visitsRepo->count([]);
}
}

View file

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Visit;
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
interface VisitsStatsHelperInterface
{
public function getVisitsStats(): VisitsStats;
}

View file

@ -11,6 +11,7 @@ use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\Common\Mercure\LcobucciJwtProvider; use Shlinkio\Shlink\Common\Mercure\LcobucciJwtProvider;
use Shlinkio\Shlink\Core\Options\AppOptions; use Shlinkio\Shlink\Core\Options\AppOptions;
use Shlinkio\Shlink\Core\Service; use Shlinkio\Shlink\Core\Service;
use Shlinkio\Shlink\Core\Visit;
use Shlinkio\Shlink\Rest\Service\ApiKeyService; use Shlinkio\Shlink\Rest\Service\ApiKeyService;
return [ return [
@ -29,6 +30,7 @@ return [
Action\ShortUrl\ListShortUrlsAction::class => ConfigAbstractFactory::class, Action\ShortUrl\ListShortUrlsAction::class => ConfigAbstractFactory::class,
Action\ShortUrl\EditShortUrlTagsAction::class => ConfigAbstractFactory::class, Action\ShortUrl\EditShortUrlTagsAction::class => ConfigAbstractFactory::class,
Action\Visit\ShortUrlVisitsAction::class => ConfigAbstractFactory::class, Action\Visit\ShortUrlVisitsAction::class => ConfigAbstractFactory::class,
Action\Visit\GlobalVisitsAction::class => ConfigAbstractFactory::class,
Action\Tag\ListTagsAction::class => ConfigAbstractFactory::class, Action\Tag\ListTagsAction::class => ConfigAbstractFactory::class,
Action\Tag\DeleteTagsAction::class => ConfigAbstractFactory::class, Action\Tag\DeleteTagsAction::class => ConfigAbstractFactory::class,
Action\Tag\CreateTagsAction::class => ConfigAbstractFactory::class, Action\Tag\CreateTagsAction::class => ConfigAbstractFactory::class,
@ -66,6 +68,7 @@ return [
'config.url_shortener.domain', 'config.url_shortener.domain',
], ],
Action\Visit\ShortUrlVisitsAction::class => [Service\VisitsTracker::class, 'Logger_Shlink'], Action\Visit\ShortUrlVisitsAction::class => [Service\VisitsTracker::class, 'Logger_Shlink'],
Action\Visit\GlobalVisitsAction::class => [Visit\VisitsStatsHelper::class, 'Logger_Shlink'],
Action\ShortUrl\ListShortUrlsAction::class => [ Action\ShortUrl\ListShortUrlsAction::class => [
Service\ShortUrlService::class, Service\ShortUrlService::class,
'config.url_shortener.domain', 'config.url_shortener.domain',

View file

@ -27,6 +27,7 @@ return [
// Visits // Visits
Action\Visit\ShortUrlVisitsAction::getRouteDef([$dropDomainMiddleware]), Action\Visit\ShortUrlVisitsAction::getRouteDef([$dropDomainMiddleware]),
Action\Visit\GlobalVisitsAction::getRouteDef(),
// Tags // Tags
Action\Tag\ListTagsAction::getRouteDef(), Action\Tag\ListTagsAction::getRouteDef(),

View file

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
class GlobalVisitsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/visits';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
private VisitsStatsHelperInterface $statsHelper;
public function __construct(VisitsStatsHelperInterface $statsHelper, ?LoggerInterface $logger = null)
{
parent::__construct($logger);
$this->statsHelper = $statsHelper;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new JsonResponse([
'visits' => $this->statsHelper->getVisitsStats(),
]);
}
}

View file

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
class GlobalVisitsActionTest extends ApiTestCase
{
/** @test */
public function returnsExpectedVisitsStats(): void
{
$resp = $this->callApiWithKey(self::METHOD_GET, '/visits');
$payload = $this->getJsonResponsePayload($resp);
$this->assertArrayHasKey('visits', $payload);
$this->assertArrayHasKey('visitsCount', $payload['visits']);
$this->assertEquals(7, $payload['visits']['visitsCount']);
}
}

View file

@ -11,7 +11,7 @@ use ShlinkioApiTest\Shlink\Rest\Utils\NotFoundUrlHelpersTrait;
use function GuzzleHttp\Psr7\build_query; use function GuzzleHttp\Psr7\build_query;
use function sprintf; use function sprintf;
class GetVisitsActionTest extends ApiTestCase class ShortUrlVisitsActionTest extends ApiTestCase
{ {
use NotFoundUrlHelpersTrait; use NotFoundUrlHelpersTrait;