Added support to print all short URLs at once from CLI

This commit is contained in:
Alejandro Celaya
2020-07-14 13:00:56 +02:00
parent 71570af7db
commit 3ff9e101a8
5 changed files with 50 additions and 21 deletions

View File

@@ -11,7 +11,6 @@ use Shlinkio\Shlink\CLI\Util\ShlinkTable;
use Shlinkio\Shlink\Common\Paginator\Util\PaginatorUtilsTrait; use Shlinkio\Shlink\Common\Paginator\Util\PaginatorUtilsTrait;
use Shlinkio\Shlink\Core\Model\ShortUrlsOrdering; use Shlinkio\Shlink\Core\Model\ShortUrlsOrdering;
use Shlinkio\Shlink\Core\Model\ShortUrlsParams; use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
use Shlinkio\Shlink\Core\Paginator\Adapter\ShortUrlRepositoryAdapter;
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface; use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer; use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer;
use Shlinkio\Shlink\Core\Validation\ShortUrlsParamsInputFilter; use Shlinkio\Shlink\Core\Validation\ShortUrlsParamsInputFilter;
@@ -61,7 +60,7 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
'page', 'page',
'p', 'p',
InputOption::VALUE_REQUIRED, InputOption::VALUE_REQUIRED,
sprintf('The first page to list (%s items per page)', ShortUrlRepositoryAdapter::ITEMS_PER_PAGE), 'The first page to list (10 items per page unless "--all" is provided)',
'1', '1',
) )
->addOption( ->addOption(
@@ -82,7 +81,8 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
InputOption::VALUE_REQUIRED, InputOption::VALUE_REQUIRED,
'The field from which we want to order by. Pass ASC or DESC separated by a comma', 'The field from which we want to order by. Pass ASC or DESC separated by a comma',
) )
->addOption('showTags', null, InputOption::VALUE_NONE, 'Whether to display the tags or not'); ->addOption('showTags', null, InputOption::VALUE_NONE, 'Whether to display the tags or not')
->addOption('all', 'a', InputOption::VALUE_NONE, 'Disables pagination and just displays all existing URLs');
} }
protected function getStartDateDesc(): string protected function getStartDateDesc(): string
@@ -104,24 +104,32 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
$tags = $input->getOption('tags'); $tags = $input->getOption('tags');
$tags = ! empty($tags) ? explode(',', $tags) : []; $tags = ! empty($tags) ? explode(',', $tags) : [];
$showTags = (bool) $input->getOption('showTags'); $showTags = (bool) $input->getOption('showTags');
$all = (bool) $input->getOption('all');
$startDate = $this->getDateOption($input, $output, 'startDate'); $startDate = $this->getDateOption($input, $output, 'startDate');
$endDate = $this->getDateOption($input, $output, 'endDate'); $endDate = $this->getDateOption($input, $output, 'endDate');
$orderBy = $this->processOrderBy($input); $orderBy = $this->processOrderBy($input);
$data = [
ShortUrlsParamsInputFilter::PAGE => $page,
ShortUrlsParamsInputFilter::SEARCH_TERM => $searchTerm,
ShortUrlsParamsInputFilter::TAGS => $tags,
ShortUrlsOrdering::ORDER_BY => $orderBy,
ShortUrlsParamsInputFilter::START_DATE => $startDate !== null ? $startDate->toAtomString() : null,
ShortUrlsParamsInputFilter::END_DATE => $endDate !== null ? $endDate->toAtomString() : null,
];
if ($all) {
$data[ShortUrlsParamsInputFilter::ITEMS_PER_PAGE] = -1;
}
do { do {
$result = $this->renderPage($output, $showTags, ShortUrlsParams::fromRawData([ $result = $this->renderPage($output, $showTags, ShortUrlsParams::fromRawData($data));
ShortUrlsParamsInputFilter::PAGE => $page,
ShortUrlsParamsInputFilter::SEARCH_TERM => $searchTerm,
ShortUrlsParamsInputFilter::TAGS => $tags,
ShortUrlsOrdering::ORDER_BY => $orderBy,
ShortUrlsParamsInputFilter::START_DATE => $startDate !== null ? $startDate->toAtomString() : null,
ShortUrlsParamsInputFilter::END_DATE => $endDate !== null ? $endDate->toAtomString() : null,
]));
$page++; $page++;
$continue = $this->isLastPage($result) $continue = ! $this->isLastPage($result) && $io->confirm(
? false sprintf('Continue with page <options=bold>%s</>?', $page),
: $io->confirm(sprintf('Continue with page <options=bold>%s</>?', $page), false); false,
);
} while ($continue); } while ($continue);
$io->newLine(); $io->newLine();

View File

@@ -12,11 +12,14 @@ use function Shlinkio\Shlink\Core\parseDateField;
final class ShortUrlsParams final class ShortUrlsParams
{ {
public const DEFAULT_ITEMS_PER_PAGE = 10;
private int $page; private int $page;
private ?string $searchTerm; private ?string $searchTerm;
private array $tags; private array $tags;
private ShortUrlsOrdering $orderBy; private ShortUrlsOrdering $orderBy;
private ?DateRange $dateRange; private ?DateRange $dateRange;
private ?int $itemsPerPage = null;
private function __construct() private function __construct()
{ {
@@ -56,6 +59,9 @@ final class ShortUrlsParams
parseDateField($inputFilter->getValue(ShortUrlsParamsInputFilter::END_DATE)), parseDateField($inputFilter->getValue(ShortUrlsParamsInputFilter::END_DATE)),
); );
$this->orderBy = ShortUrlsOrdering::fromRawData($query); $this->orderBy = ShortUrlsOrdering::fromRawData($query);
$this->itemsPerPage = (int) (
$inputFilter->getValue(ShortUrlsParamsInputFilter::ITEMS_PER_PAGE) ?? self::DEFAULT_ITEMS_PER_PAGE
);
} }
public function page(): int public function page(): int
@@ -63,6 +69,11 @@ final class ShortUrlsParams
return $this->page; return $this->page;
} }
public function itemsPerPage(): int
{
return $this->itemsPerPage;
}
public function searchTerm(): ?string public function searchTerm(): ?string
{ {
return $this->searchTerm; return $this->searchTerm;

View File

@@ -10,8 +10,6 @@ use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
class ShortUrlRepositoryAdapter implements AdapterInterface class ShortUrlRepositoryAdapter implements AdapterInterface
{ {
public const ITEMS_PER_PAGE = 10;
private ShortUrlRepositoryInterface $repository; private ShortUrlRepositoryInterface $repository;
private ShortUrlsParams $params; private ShortUrlsParams $params;

View File

@@ -44,7 +44,7 @@ class ShortUrlService implements ShortUrlServiceInterface
/** @var ShortUrlRepository $repo */ /** @var ShortUrlRepository $repo */
$repo = $this->em->getRepository(ShortUrl::class); $repo = $this->em->getRepository(ShortUrl::class);
$paginator = new Paginator(new ShortUrlRepositoryAdapter($repo, $params)); $paginator = new Paginator(new ShortUrlRepositoryAdapter($repo, $params));
$paginator->setItemCountPerPage(ShortUrlRepositoryAdapter::ITEMS_PER_PAGE) $paginator->setItemCountPerPage($params->itemsPerPage())
->setCurrentPageNumber($params->page()); ->setCurrentPageNumber($params->page());
return $paginator; return $paginator;

View File

@@ -5,10 +5,13 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Validation; namespace Shlinkio\Shlink\Core\Validation;
use Laminas\Filter; use Laminas\Filter;
use Laminas\InputFilter\Input;
use Laminas\InputFilter\InputFilter; use Laminas\InputFilter\InputFilter;
use Laminas\Validator; use Laminas\Validator;
use Shlinkio\Shlink\Common\Validation; use Shlinkio\Shlink\Common\Validation;
use function is_numeric;
class ShortUrlsParamsInputFilter extends InputFilter class ShortUrlsParamsInputFilter extends InputFilter
{ {
use Validation\InputFactoryTrait; use Validation\InputFactoryTrait;
@@ -18,6 +21,7 @@ class ShortUrlsParamsInputFilter extends InputFilter
public const TAGS = 'tags'; public const TAGS = 'tags';
public const START_DATE = 'startDate'; public const START_DATE = 'startDate';
public const END_DATE = 'endDate'; public const END_DATE = 'endDate';
public const ITEMS_PER_PAGE = 'itemsPerPage';
public function __construct(array $data) public function __construct(array $data)
{ {
@@ -32,14 +36,22 @@ class ShortUrlsParamsInputFilter extends InputFilter
$this->add($this->createInput(self::SEARCH_TERM, false)); $this->add($this->createInput(self::SEARCH_TERM, false));
$page = $this->createInput(self::PAGE, false); $this->add($this->createNumericInput(self::PAGE, 1));
$page->getValidatorChain()->attach(new Validator\Digits())
->attach(new Validator\GreaterThan(['min' => 1, 'inclusive' => true]));
$this->add($page);
$tags = $this->createArrayInput(self::TAGS, false); $tags = $this->createArrayInput(self::TAGS, false);
$tags->getFilterChain()->attach(new Filter\StringToLower()) $tags->getFilterChain()->attach(new Filter\StringToLower())
->attach(new Filter\PregReplace(['pattern' => '/ /', 'replacement' => '-'])); ->attach(new Filter\PregReplace(['pattern' => '/ /', 'replacement' => '-']));
$this->add($tags); $this->add($tags);
$this->add($this->createNumericInput(self::ITEMS_PER_PAGE, -1));
}
private function createNumericInput(string $name, int $min): Input
{
$input = $this->createInput($name, false);
$input->getValidatorChain()->attach(new Validator\Callback(fn ($value) => is_numeric($value)))
->attach(new Validator\GreaterThan(['min' => $min, 'inclusive' => true]));
return $input;
} }
} }