Skip to content

Commit

Permalink
Merge pull request #2276 from acelaya-forks/feature/visits-list-dupli…
Browse files Browse the repository at this point in the history
…cation

Reduce duplication in actions listing visits
  • Loading branch information
acelaya authored Nov 20, 2024
2 parents 0c75202 + d7e300e commit b2bfe97
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 91 deletions.
3 changes: 1 addition & 2 deletions module/Core/src/Visit/Model/OrphanVisitsParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ public function __construct(
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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
44 changes: 44 additions & 0 deletions module/Rest/src/Action/Visit/AbstractListVisitsAction.php
Original file line number Diff line number Diff line change
@@ -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;
}
21 changes: 7 additions & 14 deletions module/Rest/src/Action/Visit/DomainVisitsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,29 @@

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
Expand Down
28 changes: 9 additions & 19 deletions module/Rest/src/Action/Visit/NonOrphanVisitsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,20 @@

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);
}
}
30 changes: 11 additions & 19 deletions module/Rest/src/Action/Visit/OrphanVisitsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,22 @@

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);
}
}
23 changes: 5 additions & 18 deletions module/Rest/src/Action/Visit/ShortUrlVisitsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +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\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);
}
}
23 changes: 5 additions & 18 deletions module/Rest/src/Action/Visit/TagVisitsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,18 @@

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);
}
}

0 comments on commit b2bfe97

Please sign in to comment.