diff --git a/module/Core/src/Visit/Model/OrphanVisitsParams.php b/module/Core/src/Visit/Model/OrphanVisitsParams.php index 0e6afedc..6991928d 100644 --- a/module/Core/src/Visit/Model/OrphanVisitsParams.php +++ b/module/Core/src/Visit/Model/OrphanVisitsParams.php @@ -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( diff --git a/module/Core/test/Visit/Paginator/Adapter/OrphanVisitsPaginatorAdapterTest.php b/module/Core/test/Visit/Paginator/Adapter/OrphanVisitsPaginatorAdapterTest.php index abad2fc0..b62fa0c6 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 = new OrphanVisitsParams(); $this->apiKey = ApiKey::create(); $this->adapter = new OrphanVisitsPaginatorAdapter($this->repo, $this->params, $this->apiKey); diff --git a/module/Rest/src/Action/Visit/AbstractListVisitsAction.php b/module/Rest/src/Action/Visit/AbstractListVisitsAction.php new file mode 100644 index 00000000..090d3078 --- /dev/null +++ b/module/Rest/src/Action/Visit/AbstractListVisitsAction.php @@ -0,0 +1,44 @@ +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 fc9cf20c..ee1625e0 100644 --- a/module/Rest/src/Action/Visit/DomainVisitsAction.php +++ b/module/Rest/src/Action/Visit/DomainVisitsAction.php @@ -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 diff --git a/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php b/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php index 1fffdb8b..8406b515 100644 --- a/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php +++ b/module/Rest/src/Action/Visit/NonOrphanVisitsAction.php @@ -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); } } diff --git a/module/Rest/src/Action/Visit/OrphanVisitsAction.php b/module/Rest/src/Action/Visit/OrphanVisitsAction.php index 7906fdae..341524c3 100644 --- a/module/Rest/src/Action/Visit/OrphanVisitsAction.php +++ b/module/Rest/src/Action/Visit/OrphanVisitsAction.php @@ -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); } } diff --git a/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php b/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php index fe5099a2..95ac42cc 100644 --- a/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php +++ b/module/Rest/src/Action/Visit/ShortUrlVisitsAction.php @@ -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); } } diff --git a/module/Rest/src/Action/Visit/TagVisitsAction.php b/module/Rest/src/Action/Visit/TagVisitsAction.php index 1739264f..08553ec5 100644 --- a/module/Rest/src/Action/Visit/TagVisitsAction.php +++ b/module/Rest/src/Action/Visit/TagVisitsAction.php @@ -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); } }