diff --git a/module/Core/src/Visit/Model/OrphanVisitsParams.php b/module/Core/src/Visit/Model/OrphanVisitsParams.php index 0e6afedc8..c161ee541 100644 --- a/module/Core/src/Visit/Model/OrphanVisitsParams.php +++ b/module/Core/src/Visit/Model/OrphanVisitsParams.php @@ -21,9 +21,13 @@ public function __construct( parent::__construct($dateRange, $page, $itemsPerPage, $excludeBots); } - public static function fromRawData(array $query): self + public static function empty(): self + { + return new self(); + } + + public static function fromVisitsParamsAndRawData(VisitsParams $visitsParams, array $query): self { - $visitsParams = parent::fromRawData($query); $type = $query['type'] ?? null; return new self( diff --git a/module/Core/test/Visit/Paginator/Adapter/OrphanVisitsPaginatorAdapterTest.php b/module/Core/test/Visit/Paginator/Adapter/OrphanVisitsPaginatorAdapterTest.php index abad2fc03..977de28ca 100644 --- a/module/Core/test/Visit/Paginator/Adapter/OrphanVisitsPaginatorAdapterTest.php +++ b/module/Core/test/Visit/Paginator/Adapter/OrphanVisitsPaginatorAdapterTest.php @@ -27,7 +27,7 @@ class OrphanVisitsPaginatorAdapterTest extends TestCase protected function setUp(): void { $this->repo = $this->createMock(VisitRepositoryInterface::class); - $this->params = OrphanVisitsParams::fromRawData([]); + $this->params = OrphanVisitsParams::empty(); $this->apiKey = ApiKey::create(); $this->adapter = new OrphanVisitsPaginatorAdapter($this->repo, $this->params, $this->apiKey); diff --git a/module/Core/test/Visit/VisitsStatsHelperTest.php b/module/Core/test/Visit/VisitsStatsHelperTest.php index d6762c009..44c0513db 100644 --- a/module/Core/test/Visit/VisitsStatsHelperTest.php +++ b/module/Core/test/Visit/VisitsStatsHelperTest.php @@ -271,7 +271,7 @@ public function orphanVisitsAreReturnedAsExpected(): void )->willReturn($list); $this->em->expects($this->once())->method('getRepository')->with(Visit::class)->willReturn($repo); - $paginator = $this->helper->orphanVisits(new OrphanVisitsParams()); + $paginator = $this->helper->orphanVisits(OrphanVisitsParams::empty()); self::assertEquals($list, ArrayUtils::iteratorToArray($paginator->getCurrentPageResults())); } diff --git a/module/Rest/src/Action/Visit/AbstractListVisitsAction.php b/module/Rest/src/Action/Visit/AbstractListVisitsAction.php new file mode 100644 index 000000000..08ee10b2f --- /dev/null +++ b/module/Rest/src/Action/Visit/AbstractListVisitsAction.php @@ -0,0 +1,42 @@ +getQueryParams()); + $apiKey = AuthenticationMiddleware::apiKeyFromRequest($request); + $visits = $this->getVisitsPaginator($request, $params, $apiKey); + + return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]); + } + + /** + * @return Pagerfanta + */ + abstract protected function getVisitsPaginator( + ServerRequestInterface $request, + VisitsParams $params, + ApiKey $apiKey, + ): Pagerfanta; +} diff --git a/module/Rest/src/Action/Visit/DomainVisitsAction.php b/module/Rest/src/Action/Visit/DomainVisitsAction.php index fc9cf20c5..4a65a9142 100644 --- a/module/Rest/src/Action/Visit/DomainVisitsAction.php +++ b/module/Rest/src/Action/Visit/DomainVisitsAction.php @@ -4,36 +4,30 @@ 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 diff --git a/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php b/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php index 1fffdb8b5..5fb60015b 100644 --- a/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php +++ b/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php @@ -4,30 +4,21 @@ 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); } } diff --git a/module/Rest/src/Action/Visit/OrphanVisitsAction.php b/module/Rest/src/Action/Visit/OrphanVisitsAction.php index 7906fdaec..cef824b66 100644 --- a/module/Rest/src/Action/Visit/OrphanVisitsAction.php +++ b/module/Rest/src/Action/Visit/OrphanVisitsAction.php @@ -4,30 +4,23 @@ 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); } } diff --git a/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php b/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php index fe5099a2e..391bef249 100644 --- a/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php +++ b/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php @@ -4,32 +4,20 @@ 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); } } diff --git a/module/Rest/src/Action/Visit/TagVisitsAction.php b/module/Rest/src/Action/Visit/TagVisitsAction.php index 1739264fc..2f917f511 100644 --- a/module/Rest/src/Action/Visit/TagVisitsAction.php +++ b/module/Rest/src/Action/Visit/TagVisitsAction.php @@ -4,31 +4,19 @@ 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); } }