Reduce duplication in actions listing visits

This commit is contained in:
Alejandro Celaya 2024-11-20 09:45:18 +01:00
parent 0c75202936
commit d7e300e2d5
8 changed files with 83 additions and 91 deletions

View File

@ -21,9 +21,8 @@ final class OrphanVisitsParams extends VisitsParams
parent::__construct($dateRange, $page, $itemsPerPage, $excludeBots);
}
public static function fromRawData(array $query): self
public static function fromVisitsParamsAndRawData(VisitsParams $visitsParams, array $query): self
{
$visitsParams = parent::fromRawData($query);
$type = $query['type'] ?? null;
return new self(

View File

@ -27,7 +27,7 @@ class OrphanVisitsPaginatorAdapterTest extends TestCase
protected function setUp(): void
{
$this->repo = $this->createMock(VisitRepositoryInterface::class);
$this->params = OrphanVisitsParams::fromRawData([]);
$this->params = new OrphanVisitsParams();
$this->apiKey = ApiKey::create();
$this->adapter = new OrphanVisitsPaginatorAdapter($this->repo, $this->params, $this->apiKey);

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Laminas\Diactoros\Response\JsonResponse;
use Pagerfanta\Pagerfanta;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils;
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
abstract class AbstractListVisitsAction extends AbstractRestAction
{
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(protected readonly VisitsStatsHelperInterface $visitsHelper)
{
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$params = VisitsParams::fromRawData($request->getQueryParams());
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
$visits = $this->getVisitsPaginator($request, $params, $apiKey);
return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]);
}
/**
* @return Pagerfanta<Visit>
*/
abstract protected function getVisitsPaginator(
ServerRequestInterface $request,
VisitsParams $params,
ApiKey $apiKey,
): Pagerfanta;
}

View File

@ -4,36 +4,29 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface as Response;
use Pagerfanta\Pagerfanta;
use Psr\Http\Message\ServerRequestInterface as Request;
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils;
use Shlinkio\Shlink\Core\Config\Options\UrlShortenerOptions;
use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class DomainVisitsAction extends AbstractRestAction
class DomainVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/domains/{domain}/visits';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(
private readonly VisitsStatsHelperInterface $visitsHelper,
VisitsStatsHelperInterface $visitsHelper,
private readonly UrlShortenerOptions $urlShortenerOptions,
) {
parent::__construct($visitsHelper);
}
public function handle(Request $request): Response
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
{
$domain = $this->resolveDomainParam($request);
$params = VisitsParams::fromRawData($request->getQueryParams());
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
$visits = $this->visitsHelper->visitsForDomain($domain, $params, $apiKey);
return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]);
return $this->visitsHelper->visitsForDomain($domain, $params, $apiKey);
}
private function resolveDomainParam(Request $request): string

View File

@ -4,30 +4,20 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Pagerfanta\Pagerfanta;
use Psr\Http\Message\ServerRequestInterface;
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils;
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class NonOrphanVisitsAction extends AbstractRestAction
class NonOrphanVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/visits/non-orphan';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private readonly VisitsStatsHelperInterface $visitsHelper)
{
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$params = VisitsParams::fromRawData($request->getQueryParams());
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
$visits = $this->visitsHelper->nonOrphanVisits($params, $apiKey);
return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]);
protected function getVisitsPaginator(
ServerRequestInterface $request,
VisitsParams $params,
ApiKey $apiKey,
): Pagerfanta {
return $this->visitsHelper->nonOrphanVisits($params, $apiKey);
}
}

View File

@ -4,30 +4,22 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Pagerfanta\Pagerfanta;
use Psr\Http\Message\ServerRequestInterface;
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils;
use Shlinkio\Shlink\Core\Visit\Model\OrphanVisitsParams;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class OrphanVisitsAction extends AbstractRestAction
class OrphanVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/visits/orphan';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private readonly VisitsStatsHelperInterface $visitsHelper)
{
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$params = OrphanVisitsParams::fromRawData($request->getQueryParams());
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
$visits = $this->visitsHelper->orphanVisits($params, $apiKey);
return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]);
protected function getVisitsPaginator(
ServerRequestInterface $request,
VisitsParams $params,
ApiKey $apiKey,
): Pagerfanta {
$orphanParams = OrphanVisitsParams::fromVisitsParamsAndRawData($params, $request->getQueryParams());
return $this->visitsHelper->orphanVisits($orphanParams, $apiKey);
}
}

View File

@ -4,32 +4,19 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface as Response;
use Pagerfanta\Pagerfanta;
use Psr\Http\Message\ServerRequestInterface as Request;
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlVisitsAction extends AbstractRestAction
class ShortUrlVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}/visits';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private readonly VisitsStatsHelperInterface $visitsHelper)
{
}
public function handle(Request $request): Response
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
{
$identifier = ShortUrlIdentifier::fromApiRequest($request);
$params = VisitsParams::fromRawData($request->getQueryParams());
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
$visits = $this->visitsHelper->visitsForShortUrl($identifier, $params, $apiKey);
return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]);
return $this->visitsHelper->visitsForShortUrl($identifier, $params, $apiKey);
}
}

View File

@ -4,31 +4,18 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\Action\Visit;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface as Response;
use Pagerfanta\Pagerfanta;
use Psr\Http\Message\ServerRequestInterface as Request;
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils;
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class TagVisitsAction extends AbstractRestAction
class TagVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/tags/{tag}/visits';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private readonly VisitsStatsHelperInterface $visitsHelper)
{
}
public function handle(Request $request): Response
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
{
$tag = $request->getAttribute('tag', '');
$params = VisitsParams::fromRawData($request->getQueryParams());
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
$visits = $this->visitsHelper->visitsForTag($tag, $params, $apiKey);
return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]);
return $this->visitsHelper->visitsForTag($tag, $params, $apiKey);
}
}