mirror of
https://github.com/shlinkio/shlink.git
synced 2025-03-14 04:00:57 +03:00
Merge branch 'feature/58' into develop
This commit is contained in:
commit
850ce152cd
13 changed files with 96 additions and 36 deletions
|
@ -74,10 +74,22 @@
|
|||
{
|
||||
"name": "searchTerm",
|
||||
"in": "query",
|
||||
"description": "A query used to filter results by searching for it on the longUrl and shortCode fields. (From Shlink 1.3.0)",
|
||||
"description": "A query used to filter results by searching for it on the longUrl and shortCode fields. (Since v1.3.0)",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "tags",
|
||||
"in": "query",
|
||||
"description": "A list of tags used to filter the resultset. Only short URLs tagged with at least one of the provided tags will be returned. (Since v1.3.0)",
|
||||
"required": false,
|
||||
"type": "array",
|
||||
"schema": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"$ref": "#/parameters/Authorization"
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -1,8 +1,8 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Shlink 1.0\n"
|
||||
"POT-Creation-Date: 2016-08-21 18:16+0200\n"
|
||||
"PO-Revision-Date: 2016-08-21 18:16+0200\n"
|
||||
"POT-Creation-Date: 2016-10-22 13:14+0200\n"
|
||||
"PO-Revision-Date: 2016-10-22 13:15+0200\n"
|
||||
"Last-Translator: Alejandro Celaya <alejandro@alejandrocelaya.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: es_ES\n"
|
||||
|
@ -162,6 +162,16 @@ msgstr "Listar todas las URLs cortas"
|
|||
msgid "The first page to list (%s items per page)"
|
||||
msgstr "La primera página a listar (%s elementos por página)"
|
||||
|
||||
msgid ""
|
||||
"A query used to filter results by searching for it on the longUrl and "
|
||||
"shortCode fields"
|
||||
msgstr ""
|
||||
"Una consulta usada para filtrar el resultado buscándola en los campos "
|
||||
"longUrl y shortCode"
|
||||
|
||||
msgid "A comma-separated list of tags to filter results"
|
||||
msgstr "Una lista de etiquetas separadas por coma para filtrar el resultado"
|
||||
|
||||
msgid "Whether to display the tags or not"
|
||||
msgstr "Si se desea mostrar las etiquetas o no"
|
||||
|
||||
|
|
|
@ -67,6 +67,12 @@ class ListShortcodesCommand extends Command
|
|||
->addOption(
|
||||
'tags',
|
||||
't',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
$this->translator->translate('A comma-separated list of tags to filter results')
|
||||
)
|
||||
->addOption(
|
||||
'showTags',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
$this->translator->translate('Whether to display the tags or not')
|
||||
);
|
||||
|
@ -76,13 +82,15 @@ class ListShortcodesCommand extends Command
|
|||
{
|
||||
$page = intval($input->getOption('page'));
|
||||
$searchTerm = $input->getOption('searchTerm');
|
||||
$showTags = $input->getOption('tags');
|
||||
$tags = $input->getOption('tags');
|
||||
$tags = ! empty($tags) ? explode(',', $tags) : [];
|
||||
$showTags = $input->getOption('showTags');
|
||||
|
||||
/** @var QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
do {
|
||||
$result = $this->shortUrlService->listShortUrls($page, $searchTerm);
|
||||
$result = $this->shortUrlService->listShortUrls($page, $searchTerm, $tags);
|
||||
$page++;
|
||||
$table = new Table($output);
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ class ListShortcodesCommandTest extends TestCase
|
|||
public function noInputCallsListJustOnce()
|
||||
{
|
||||
$this->questionHelper->setInputStream($this->getInputStream('\n'));
|
||||
$this->shortUrlService->listShortUrls(1, null)->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
$this->shortUrlService->listShortUrls(1, null, [])->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
|
||||
$this->commandTester->execute(['command' => 'shortcode:list']);
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ class ListShortcodesCommandTest extends TestCase
|
|||
{
|
||||
$page = 5;
|
||||
$this->questionHelper->setInputStream($this->getInputStream('\n'));
|
||||
$this->shortUrlService->listShortUrls($page, null)->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
$this->shortUrlService->listShortUrls($page, null, [])->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
|
||||
$this->commandTester->execute([
|
||||
'command' => 'shortcode:list',
|
||||
|
@ -118,12 +118,12 @@ class ListShortcodesCommandTest extends TestCase
|
|||
public function ifTagsFlagIsProvidedTagsColumnIsIncluded()
|
||||
{
|
||||
$this->questionHelper->setInputStream($this->getInputStream('\n'));
|
||||
$this->shortUrlService->listShortUrls(1, null)->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
$this->shortUrlService->listShortUrls(1, null, [])->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
|
||||
$this->commandTester->execute([
|
||||
'command' => 'shortcode:list',
|
||||
'--tags' => true,
|
||||
'--showTags' => true,
|
||||
]);
|
||||
$output = $this->commandTester->getDisplay();
|
||||
$this->assertTrue(strpos($output, 'Tags') > 0);
|
||||
|
|
|
@ -20,12 +20,21 @@ class PaginableRepositoryAdapter implements AdapterInterface
|
|||
* @var null|array|string
|
||||
*/
|
||||
private $orderBy;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $tags;
|
||||
|
||||
public function __construct(PaginableRepositoryInterface $paginableRepository, $searchQuery = null, $orderBy = null)
|
||||
{
|
||||
public function __construct(
|
||||
PaginableRepositoryInterface $paginableRepository,
|
||||
$searchTerm = null,
|
||||
array $tags = [],
|
||||
$orderBy = null
|
||||
) {
|
||||
$this->paginableRepository = $paginableRepository;
|
||||
$this->searchTerm = trim(strip_tags($searchQuery));
|
||||
$this->searchTerm = trim(strip_tags($searchTerm));
|
||||
$this->orderBy = $orderBy;
|
||||
$this->tags = $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,7 +46,13 @@ class PaginableRepositoryAdapter implements AdapterInterface
|
|||
*/
|
||||
public function getItems($offset, $itemCountPerPage)
|
||||
{
|
||||
return $this->paginableRepository->findList($itemCountPerPage, $offset, $this->searchTerm, $this->orderBy);
|
||||
return $this->paginableRepository->findList(
|
||||
$itemCountPerPage,
|
||||
$offset,
|
||||
$this->searchTerm,
|
||||
$this->tags,
|
||||
$this->orderBy
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,6 +66,6 @@ class PaginableRepositoryAdapter implements AdapterInterface
|
|||
*/
|
||||
public function count()
|
||||
{
|
||||
return $this->paginableRepository->countList($this->searchTerm);
|
||||
return $this->paginableRepository->countList($this->searchTerm, $this->tags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,18 @@ interface PaginableRepositoryInterface
|
|||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @param string|null $searchTerm
|
||||
* @param array $tags
|
||||
* @param string|array|null $orderBy
|
||||
* @return array
|
||||
*/
|
||||
public function findList($limit = null, $offset = null, $searchTerm = null, $orderBy = null);
|
||||
public function findList($limit = null, $offset = null, $searchTerm = null, array $tags = [], $orderBy = null);
|
||||
|
||||
/**
|
||||
* Counts the number of elements in a list using provided filtering data
|
||||
*
|
||||
* @param null $searchTerm
|
||||
* @param array $tags
|
||||
* @return int
|
||||
*/
|
||||
public function countList($searchTerm = null);
|
||||
public function countList($searchTerm = null, array $tags = []);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class PaginableRepositoryAdapterTest extends TestCase
|
|||
public function setUp()
|
||||
{
|
||||
$this->repo = $this->prophesize(PaginableRepositoryInterface::class);
|
||||
$this->adapter = new PaginableRepositoryAdapter($this->repo->reveal(), 'search', 'order');
|
||||
$this->adapter = new PaginableRepositoryAdapter($this->repo->reveal(), 'search', ['foo', 'bar'], 'order');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,7 +28,7 @@ class PaginableRepositoryAdapterTest extends TestCase
|
|||
*/
|
||||
public function getItemsFallbacksToFindList()
|
||||
{
|
||||
$this->repo->findList(10, 5, 'search', 'order')->shouldBeCalledTimes(1);
|
||||
$this->repo->findList(10, 5, 'search', ['foo', 'bar'], 'order')->shouldBeCalledTimes(1);
|
||||
$this->adapter->getItems(5, 10);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ class PaginableRepositoryAdapterTest extends TestCase
|
|||
*/
|
||||
public function countFallbacksToCountList()
|
||||
{
|
||||
$this->repo->countList('search')->shouldBeCalledTimes(1);
|
||||
$this->repo->countList('search', ['foo', 'bar'])->shouldBeCalledTimes(1);
|
||||
$this->adapter->count();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,13 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
|||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @param string|null $searchTerm
|
||||
* @param array $tags
|
||||
* @param string|array|null $orderBy
|
||||
* @return ShortUrl[]
|
||||
* @return \Shlinkio\Shlink\Core\Entity\ShortUrl[]
|
||||
*/
|
||||
public function findList($limit = null, $offset = null, $searchTerm = null, $orderBy = null)
|
||||
public function findList($limit = null, $offset = null, $searchTerm = null, array $tags = [], $orderBy = null)
|
||||
{
|
||||
$qb = $this->createListQueryBuilder($searchTerm);
|
||||
$qb = $this->createListQueryBuilder($searchTerm, $tags);
|
||||
$qb->select('s');
|
||||
|
||||
if (isset($limit)) {
|
||||
|
@ -43,11 +44,12 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
|||
* Counts the number of elements in a list using provided filtering data
|
||||
*
|
||||
* @param null|string $searchTerm
|
||||
* @param array $tags
|
||||
* @return int
|
||||
*/
|
||||
public function countList($searchTerm = null)
|
||||
public function countList($searchTerm = null, array $tags = [])
|
||||
{
|
||||
$qb = $this->createListQueryBuilder($searchTerm);
|
||||
$qb = $this->createListQueryBuilder($searchTerm, $tags);
|
||||
$qb->select('COUNT(s)');
|
||||
|
||||
return (int) $qb->getQuery()->getSingleScalarResult();
|
||||
|
@ -55,12 +57,14 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
|||
|
||||
/**
|
||||
* @param null|string $searchTerm
|
||||
* @param array $tags
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
protected function createListQueryBuilder($searchTerm = null)
|
||||
protected function createListQueryBuilder($searchTerm = null, array $tags = [])
|
||||
{
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
$qb->from(ShortUrl::class, 's');
|
||||
$qb->where('1=1');
|
||||
|
||||
// Apply search term to every searchable field if not empty
|
||||
if (! empty($searchTerm)) {
|
||||
|
@ -70,11 +74,17 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
|||
];
|
||||
|
||||
// Unpack and apply search conditions
|
||||
$qb->where($qb->expr()->orX(...$conditions));
|
||||
$qb->andWhere($qb->expr()->orX(...$conditions));
|
||||
$searchTerm = '%' . $searchTerm . '%';
|
||||
$qb->setParameter('searchPattern', $searchTerm);
|
||||
}
|
||||
|
||||
// Filter by tags if provided
|
||||
if (! empty($tags)) {
|
||||
$qb->join('s.tags', 't')
|
||||
->andWhere($qb->expr()->in('t.name', $tags));
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,13 +33,14 @@ class ShortUrlService implements ShortUrlServiceInterface
|
|||
/**
|
||||
* @param int $page
|
||||
* @param string $searchQuery
|
||||
* @param array $tags
|
||||
* @return ShortUrl[]|Paginator
|
||||
*/
|
||||
public function listShortUrls($page = 1, $searchQuery = null)
|
||||
public function listShortUrls($page = 1, $searchQuery = null, array $tags = [])
|
||||
{
|
||||
/** @var ShortUrlRepository $repo */
|
||||
$repo = $this->em->getRepository(ShortUrl::class);
|
||||
$paginator = new Paginator(new PaginableRepositoryAdapter($repo, $searchQuery));
|
||||
$paginator = new Paginator(new PaginableRepositoryAdapter($repo, $searchQuery, $tags));
|
||||
$paginator->setItemCountPerPage(PaginableRepositoryAdapter::ITEMS_PER_PAGE)
|
||||
->setCurrentPageNumber($page);
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ interface ShortUrlServiceInterface
|
|||
/**
|
||||
* @param int $page
|
||||
* @param string $searchQuery
|
||||
* @param array $tags
|
||||
* @return ShortUrl[]|Paginator
|
||||
*/
|
||||
public function listShortUrls($page = 1, $searchQuery = null);
|
||||
public function listShortUrls($page = 1, $searchQuery = null, array $tags = []);
|
||||
|
||||
/**
|
||||
* @param string $shortCode
|
||||
|
|
|
@ -74,6 +74,7 @@ class ListShortcodesAction extends AbstractRestAction
|
|||
return [
|
||||
isset($query['page']) ? $query['page'] : 1,
|
||||
isset($query['searchTerm']) ? $query['searchTerm'] : null,
|
||||
isset($query['tags']) ? $query['tags'] : [],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ class ListShortcodesActionTest extends TestCase
|
|||
public function properListReturnsSuccessResponse()
|
||||
{
|
||||
$page = 3;
|
||||
$this->service->listShortUrls($page, null)->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
$this->service->listShortUrls($page, null, [])->willReturn(new Paginator(new ArrayAdapter()))
|
||||
->shouldBeCalledTimes(1);
|
||||
|
||||
$response = $this->action->__invoke(
|
||||
ServerRequestFactory::fromGlobals()->withQueryParams([
|
||||
|
@ -52,8 +52,8 @@ class ListShortcodesActionTest extends TestCase
|
|||
public function anExceptionsReturnsErrorResponse()
|
||||
{
|
||||
$page = 3;
|
||||
$this->service->listShortUrls($page, null)->willThrow(\Exception::class)
|
||||
->shouldBeCalledTimes(1);
|
||||
$this->service->listShortUrls($page, null, [])->willThrow(\Exception::class)
|
||||
->shouldBeCalledTimes(1);
|
||||
|
||||
$response = $this->action->__invoke(
|
||||
ServerRequestFactory::fromGlobals()->withQueryParams([
|
||||
|
|
Loading…
Add table
Reference in a new issue