Merge branch 'feature/58' into develop

This commit is contained in:
Alejandro Celaya
2016-10-22 13:16:13 +02:00
13 changed files with 96 additions and 36 deletions
+13 -1
View File
@@ -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.
+12 -2
View File
@@ -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;
}
}
+3 -2
View File
@@ -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([