Add category attribute for advanced search
This commit is contained in:
@@ -45,12 +45,8 @@ class Projectinfo extends Base
|
|||||||
->setDirection('DESC');
|
->setDirection('DESC');
|
||||||
|
|
||||||
if ($search !== '') {
|
if ($search !== '') {
|
||||||
|
$paginator->setQuery($this->taskFilter->search($search)->filterByProject($project['id'])->getQuery())
|
||||||
// $paginator
|
->calculate();
|
||||||
// ->setQuery($this->taskFinder->getSearchQuery($project['id'], $search))
|
|
||||||
// ->calculate();
|
|
||||||
|
|
||||||
$paginator->setQuery($this->taskFilter->search($search)->filterByProject($project['id'])->getQuery())->calculate();
|
|
||||||
|
|
||||||
$nb_tasks = $paginator->getTotal();
|
$nb_tasks = $paginator->getTotal();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class Lexer
|
|||||||
"/^(due:)/" => 'T_DUE',
|
"/^(due:)/" => 'T_DUE',
|
||||||
"/^(status:)/" => 'T_STATUS',
|
"/^(status:)/" => 'T_STATUS',
|
||||||
"/^(description:)/" => 'T_DESCRIPTION',
|
"/^(description:)/" => 'T_DESCRIPTION',
|
||||||
|
"/^(category:)/" => 'T_CATEGORY',
|
||||||
"/^(\s+)/" => 'T_WHITESPACE',
|
"/^(\s+)/" => 'T_WHITESPACE',
|
||||||
'/^([<=>]{0,2}[0-9]{4}-[0-9]{2}-[0-9]{2})/' => 'T_DATE',
|
'/^([<=>]{0,2}[0-9]{4}-[0-9]{2}-[0-9]{2})/' => 'T_DATE',
|
||||||
'/^(yesterday|tomorrow|today)/' => 'T_DATE',
|
'/^(yesterday|tomorrow|today)/' => 'T_DATE',
|
||||||
@@ -107,6 +108,7 @@ class Lexer
|
|||||||
switch ($token['token']) {
|
switch ($token['token']) {
|
||||||
case 'T_ASSIGNEE':
|
case 'T_ASSIGNEE':
|
||||||
case 'T_COLOR':
|
case 'T_COLOR':
|
||||||
|
case 'T_CATEGORY':
|
||||||
$next = next($tokens);
|
$next = next($tokens);
|
||||||
|
|
||||||
if ($next !== false && $next['token'] === 'T_STRING') {
|
if ($next !== false && $next['token'] === 'T_STRING') {
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ class TaskFilter extends Base
|
|||||||
case 'T_DESCRIPTION':
|
case 'T_DESCRIPTION':
|
||||||
$this->filterByDescription($value);
|
$this->filterByDescription($value);
|
||||||
break;
|
break;
|
||||||
|
case 'T_CATEGORY':
|
||||||
|
$this->filterByCategoryName($value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +205,30 @@ class TaskFilter extends Base
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter by category
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values List of assignees
|
||||||
|
* @return TaskFilter
|
||||||
|
*/
|
||||||
|
public function filterByCategoryName(array $values)
|
||||||
|
{
|
||||||
|
$this->query->join(Category::TABLE, 'id', 'category_id');
|
||||||
|
$this->query->beginOr();
|
||||||
|
|
||||||
|
foreach ($values as $category) {
|
||||||
|
if ($category === 'none') {
|
||||||
|
$this->query->eq(Task::TABLE.'.category_id', 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->query->eq(Category::TABLE.'.name', $category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->query->closeOr();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter by assignee
|
* Filter by assignee
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -26,21 +26,6 @@ class TaskFinder extends Base
|
|||||||
->eq('is_active', Task::STATUS_CLOSED);
|
->eq('is_active', Task::STATUS_CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get query for task search
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param string $search Search terms
|
|
||||||
* @return \PicoDb\Table
|
|
||||||
*/
|
|
||||||
public function getSearchQuery($project_id, $search)
|
|
||||||
{
|
|
||||||
return $this->getExtendedQuery()
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->ilike('title', '%'.$search.'%');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get query for assigned user tasks
|
* Get query for assigned user tasks
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -118,3 +118,12 @@ Search by description
|
|||||||
Attribute: **description**
|
Attribute: **description**
|
||||||
|
|
||||||
Example: `description:"text search"`
|
Example: `description:"text search"`
|
||||||
|
|
||||||
|
Search by category
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Attribute: **category**
|
||||||
|
|
||||||
|
- Find tasks with a specific category: `category:"Feature Request"`
|
||||||
|
- Find all tasks that have those category: `category:"Bug" category:"Improvements"`
|
||||||
|
- Find tasks with no category assigned: `category:none`
|
||||||
|
|||||||
@@ -66,6 +66,31 @@ class LexerTest extends Base
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCategoryQuery()
|
||||||
|
{
|
||||||
|
$lexer = new Lexer;
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array(array('match' => 'category:', 'token' => 'T_CATEGORY'), array('match' => 'Feature Request', 'token' => 'T_STRING')),
|
||||||
|
$lexer->tokenize('category:"Feature Request"')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array('T_CATEGORY' => array('Feature Request')),
|
||||||
|
$lexer->map($lexer->tokenize('category:"Feature Request"'))
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array('T_CATEGORY' => array('Feature Request', 'Bug')),
|
||||||
|
$lexer->map($lexer->tokenize('category:"Feature Request" category:Bug'))
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
array(),
|
||||||
|
$lexer->map($lexer->tokenize('category: '))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testStatusQuery()
|
public function testStatusQuery()
|
||||||
{
|
{
|
||||||
$lexer = new Lexer;
|
$lexer = new Lexer;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Model\User;
|
|||||||
use Model\TaskFilter;
|
use Model\TaskFilter;
|
||||||
use Model\TaskCreation;
|
use Model\TaskCreation;
|
||||||
use Model\DateParser;
|
use Model\DateParser;
|
||||||
|
use Model\Category;
|
||||||
|
|
||||||
class TaskFilterTest extends Base
|
class TaskFilterTest extends Base
|
||||||
{
|
{
|
||||||
@@ -74,6 +75,50 @@ class TaskFilterTest extends Base
|
|||||||
$this->assertEmpty($tasks);
|
$this->assertEmpty($tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSearchWithCategory()
|
||||||
|
{
|
||||||
|
$p = new Project($this->container);
|
||||||
|
$c = new Category($this->container);
|
||||||
|
$tc = new TaskCreation($this->container);
|
||||||
|
$tf = new TaskFilter($this->container);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||||
|
$this->assertEquals(1, $c->create(array('name' => 'Feature request', 'project_id' => 1)));
|
||||||
|
$this->assertEquals(2, $c->create(array('name' => 'hé hé', 'project_id' => 1)));
|
||||||
|
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task1')));
|
||||||
|
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task2', 'category_id' => 1)));
|
||||||
|
$this->assertNotFalse($tc->create(array('project_id' => 1, 'title' => 'task3', 'category_id' => 2)));
|
||||||
|
|
||||||
|
$tf->search('category:"Feature request"');
|
||||||
|
$tasks = $tf->findAll();
|
||||||
|
$this->assertNotEmpty($tasks);
|
||||||
|
$this->assertCount(1, $tasks);
|
||||||
|
$this->assertEquals('task2', $tasks[0]['title']);
|
||||||
|
|
||||||
|
$tf->search('category:"hé hé"');
|
||||||
|
$tasks = $tf->findAll();
|
||||||
|
$this->assertNotEmpty($tasks);
|
||||||
|
$this->assertCount(1, $tasks);
|
||||||
|
$this->assertEquals('task3', $tasks[0]['title']);
|
||||||
|
|
||||||
|
$tf->search('category:"Feature request" category:"hé hé"');
|
||||||
|
$tasks = $tf->findAll();
|
||||||
|
$this->assertNotEmpty($tasks);
|
||||||
|
$this->assertCount(2, $tasks);
|
||||||
|
$this->assertEquals('task2', $tasks[0]['title']);
|
||||||
|
$this->assertEquals('task3', $tasks[1]['title']);
|
||||||
|
|
||||||
|
$tf->search('category:none');
|
||||||
|
$tasks = $tf->findAll();
|
||||||
|
$this->assertNotEmpty($tasks);
|
||||||
|
$this->assertCount(1, $tasks);
|
||||||
|
$this->assertEquals('task1', $tasks[0]['title']);
|
||||||
|
|
||||||
|
$tf->search('category:"not found"');
|
||||||
|
$tasks = $tf->findAll();
|
||||||
|
$this->assertEmpty($tasks);
|
||||||
|
}
|
||||||
|
|
||||||
public function testSearchWithDueDate()
|
public function testSearchWithDueDate()
|
||||||
{
|
{
|
||||||
$dp = new DateParser($this->container);
|
$dp = new DateParser($this->container);
|
||||||
|
|||||||
Reference in New Issue
Block a user