PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/app/Model/TaskFilter.php

https://gitlab.com/x33n/kanboard
PHP | 949 lines | 513 code | 121 blank | 315 comment | 42 complexity | cc9a393e9ed1cafad43d8c2a02ca1502 MD5 | raw file
  1. <?php
  2. namespace Model;
  3. use DateTime;
  4. use Eluceo\iCal\Component\Calendar;
  5. use Eluceo\iCal\Component\Event;
  6. use Eluceo\iCal\Property\Event\Attendees;
  7. /**
  8. * Task Filter
  9. *
  10. * @package model
  11. * @author Frederic Guillot
  12. */
  13. class TaskFilter extends Base
  14. {
  15. /**
  16. * Query
  17. *
  18. * @access public
  19. * @var \PicoDb\Table
  20. */
  21. public $query;
  22. /**
  23. * Apply filters according to the search input
  24. *
  25. * @access public
  26. * @param string $input
  27. * @return TaskFilter
  28. */
  29. public function search($input)
  30. {
  31. $tree = $this->lexer->map($this->lexer->tokenize($input));
  32. $this->query = $this->taskFinder->getExtendedQuery();
  33. if (empty($tree)) {
  34. $this->filterByTitle($input);
  35. }
  36. foreach ($tree as $filter => $value) {
  37. switch ($filter) {
  38. case 'T_ASSIGNEE':
  39. $this->filterByAssignee($value);
  40. break;
  41. case 'T_COLOR':
  42. $this->filterByColors($value);
  43. break;
  44. case 'T_DUE':
  45. $this->filterByDueDate($value);
  46. break;
  47. case 'T_UPDATED':
  48. $this->filterByModificationDate($value);
  49. break;
  50. case 'T_CREATED':
  51. $this->filterByCreationDate($value);
  52. break;
  53. case 'T_TITLE':
  54. $this->filterByTitle($value);
  55. break;
  56. case 'T_STATUS':
  57. $this->filterByStatusName($value);
  58. break;
  59. case 'T_DESCRIPTION':
  60. $this->filterByDescription($value);
  61. break;
  62. case 'T_CATEGORY':
  63. $this->filterByCategoryName($value);
  64. break;
  65. case 'T_PROJECT':
  66. $this->filterByProjectName($value);
  67. break;
  68. case 'T_COLUMN':
  69. $this->filterByColumnName($value);
  70. break;
  71. case 'T_REFERENCE':
  72. $this->filterByReference($value);
  73. break;
  74. case 'T_SWIMLANE':
  75. $this->filterBySwimlaneName($value);
  76. break;
  77. }
  78. }
  79. return $this;
  80. }
  81. /**
  82. * Create a new query
  83. *
  84. * @access public
  85. * @return TaskFilter
  86. */
  87. public function create()
  88. {
  89. $this->query = $this->db->table(Task::TABLE);
  90. $this->query->left(User::TABLE, 'ua', 'id', Task::TABLE, 'owner_id');
  91. $this->query->left(User::TABLE, 'uc', 'id', Task::TABLE, 'creator_id');
  92. $this->query->columns(
  93. Task::TABLE.'.*',
  94. 'ua.email AS assignee_email',
  95. 'ua.name AS assignee_name',
  96. 'ua.username AS assignee_username',
  97. 'uc.email AS creator_email',
  98. 'uc.username AS creator_username'
  99. );
  100. return $this;
  101. }
  102. /**
  103. * Create a new subtask query
  104. *
  105. * @access public
  106. * @return \PicoDb\Table
  107. */
  108. public function createSubtaskQuery()
  109. {
  110. return $this->db->table(Subtask::TABLE)
  111. ->columns(
  112. Subtask::TABLE.'.user_id',
  113. Subtask::TABLE.'.task_id',
  114. User::TABLE.'.name',
  115. User::TABLE.'.username'
  116. )
  117. ->join(User::TABLE, 'id', 'user_id', Subtask::TABLE)
  118. ->neq(Subtask::TABLE.'.status', Subtask::STATUS_DONE);
  119. }
  120. /**
  121. * Clone the filter
  122. *
  123. * @access public
  124. * @return TaskFilter
  125. */
  126. public function copy()
  127. {
  128. $filter = clone($this);
  129. $filter->query = clone($this->query);
  130. $filter->query->condition = clone($this->query->condition);
  131. return $filter;
  132. }
  133. /**
  134. * Exclude a list of task_id
  135. *
  136. * @access public
  137. * @param integer[] $task_ids
  138. * @return TaskFilter
  139. */
  140. public function excludeTasks(array $task_ids)
  141. {
  142. $this->query->notin(Task::TABLE.'.id', $task_ids);
  143. return $this;
  144. }
  145. /**
  146. * Filter by id
  147. *
  148. * @access public
  149. * @param integer $task_id
  150. * @return TaskFilter
  151. */
  152. public function filterById($task_id)
  153. {
  154. if ($task_id > 0) {
  155. $this->query->eq(Task::TABLE.'.id', $task_id);
  156. }
  157. return $this;
  158. }
  159. /**
  160. * Filter by reference
  161. *
  162. * @access public
  163. * @param string $reference
  164. * @return TaskFilter
  165. */
  166. public function filterByReference($reference)
  167. {
  168. if (! empty($reference)) {
  169. $this->query->eq(Task::TABLE.'.reference', $reference);
  170. }
  171. return $this;
  172. }
  173. /**
  174. * Filter by title
  175. *
  176. * @access public
  177. * @param string $title
  178. * @return TaskFilter
  179. */
  180. public function filterByDescription($title)
  181. {
  182. $this->query->ilike(Task::TABLE.'.description', '%'.$title.'%');
  183. return $this;
  184. }
  185. /**
  186. * Filter by title or id if the string is like #123 or an integer
  187. *
  188. * @access public
  189. * @param string $title
  190. * @return TaskFilter
  191. */
  192. public function filterByTitle($title)
  193. {
  194. if (ctype_digit($title) || (strlen($title) > 1 && $title{0} === '#' && ctype_digit(substr($title, 1)))) {
  195. $this->query->beginOr();
  196. $this->query->eq(Task::TABLE.'.id', str_replace('#', '', $title));
  197. $this->query->ilike(Task::TABLE.'.title', '%'.$title.'%');
  198. $this->query->closeOr();
  199. }
  200. else {
  201. $this->query->ilike(Task::TABLE.'.title', '%'.$title.'%');
  202. }
  203. return $this;
  204. }
  205. /**
  206. * Filter by a list of project id
  207. *
  208. * @access public
  209. * @param array $project_ids
  210. * @return TaskFilter
  211. */
  212. public function filterByProjects(array $project_ids)
  213. {
  214. $this->query->in(Task::TABLE.'.project_id', $project_ids);
  215. return $this;
  216. }
  217. /**
  218. * Filter by project id
  219. *
  220. * @access public
  221. * @param integer $project_id
  222. * @return TaskFilter
  223. */
  224. public function filterByProject($project_id)
  225. {
  226. if ($project_id > 0) {
  227. $this->query->eq(Task::TABLE.'.project_id', $project_id);
  228. }
  229. return $this;
  230. }
  231. /**
  232. * Filter by project name
  233. *
  234. * @access public
  235. * @param array $values List of project name
  236. * @return TaskFilter
  237. */
  238. public function filterByProjectName(array $values)
  239. {
  240. $this->query->beginOr();
  241. foreach ($values as $project) {
  242. if (ctype_digit($project)) {
  243. $this->query->eq(Task::TABLE.'.project_id', $project);
  244. }
  245. else {
  246. $this->query->ilike(Project::TABLE.'.name', $project);
  247. }
  248. }
  249. $this->query->closeOr();
  250. }
  251. /**
  252. * Filter by swimlane name
  253. *
  254. * @access public
  255. * @param array $values List of swimlane name
  256. * @return TaskFilter
  257. */
  258. public function filterBySwimlaneName(array $values)
  259. {
  260. $this->query->beginOr();
  261. foreach ($values as $swimlane) {
  262. if ($swimlane === 'default') {
  263. $this->query->eq(Task::TABLE.'.swimlane_id', 0);
  264. }
  265. else {
  266. $this->query->ilike(Swimlane::TABLE.'.name', $swimlane);
  267. $this->query->addCondition(Task::TABLE.'.swimlane_id=0 AND '.Project::TABLE.'.default_swimlane '.$this->db->getDriver()->getOperator('ILIKE')." '$swimlane'");
  268. }
  269. }
  270. $this->query->closeOr();
  271. }
  272. /**
  273. * Filter by category id
  274. *
  275. * @access public
  276. * @param integer $category_id
  277. * @return TaskFilter
  278. */
  279. public function filterByCategory($category_id)
  280. {
  281. if ($category_id >= 0) {
  282. $this->query->eq(Task::TABLE.'.category_id', $category_id);
  283. }
  284. return $this;
  285. }
  286. /**
  287. * Filter by category
  288. *
  289. * @access public
  290. * @param array $values List of assignees
  291. * @return TaskFilter
  292. */
  293. public function filterByCategoryName(array $values)
  294. {
  295. $this->query->beginOr();
  296. foreach ($values as $category) {
  297. if ($category === 'none') {
  298. $this->query->eq(Task::TABLE.'.category_id', 0);
  299. }
  300. else {
  301. $this->query->eq(Category::TABLE.'.name', $category);
  302. }
  303. }
  304. $this->query->closeOr();
  305. }
  306. /**
  307. * Filter by assignee
  308. *
  309. * @access public
  310. * @param integer $owner_id
  311. * @return TaskFilter
  312. */
  313. public function filterByOwner($owner_id)
  314. {
  315. if ($owner_id >= 0) {
  316. $this->query->eq(Task::TABLE.'.owner_id', $owner_id);
  317. }
  318. return $this;
  319. }
  320. /**
  321. * Filter by assignee names
  322. *
  323. * @access public
  324. * @param array $values List of assignees
  325. * @return TaskFilter
  326. */
  327. public function filterByAssignee(array $values)
  328. {
  329. $this->query->beginOr();
  330. foreach ($values as $assignee) {
  331. switch ($assignee) {
  332. case 'me':
  333. $this->query->eq(Task::TABLE.'.owner_id', $this->userSession->getId());
  334. break;
  335. case 'nobody':
  336. $this->query->eq(Task::TABLE.'.owner_id', 0);
  337. break;
  338. default:
  339. $this->query->ilike(User::TABLE.'.username', '%'.$assignee.'%');
  340. $this->query->ilike(User::TABLE.'.name', '%'.$assignee.'%');
  341. }
  342. }
  343. $this->filterBySubtaskAssignee($values);
  344. $this->query->closeOr();
  345. return $this;
  346. }
  347. /**
  348. * Filter by subtask assignee names
  349. *
  350. * @access public
  351. * @param array $values List of assignees
  352. * @return TaskFilter
  353. */
  354. public function filterBySubtaskAssignee(array $values)
  355. {
  356. $subtaskQuery = $this->createSubtaskQuery();
  357. $subtaskQuery->beginOr();
  358. foreach ($values as $assignee) {
  359. if ($assignee === 'me') {
  360. $subtaskQuery->eq(Subtask::TABLE.'.user_id', $this->userSession->getId());
  361. }
  362. else {
  363. $subtaskQuery->ilike(User::TABLE.'.username', '%'.$assignee.'%');
  364. $subtaskQuery->ilike(User::TABLE.'.name', '%'.$assignee.'%');
  365. }
  366. }
  367. $subtaskQuery->closeOr();
  368. $this->query->in(Task::TABLE.'.id', $subtaskQuery->findAllByColumn('task_id'));
  369. return $this;
  370. }
  371. /**
  372. * Filter by color
  373. *
  374. * @access public
  375. * @param string $color_id
  376. * @return TaskFilter
  377. */
  378. public function filterByColor($color_id)
  379. {
  380. if ($color_id !== '') {
  381. $this->query->eq(Task::TABLE.'.color_id', $color_id);
  382. }
  383. return $this;
  384. }
  385. /**
  386. * Filter by colors
  387. *
  388. * @access public
  389. * @param array $colors
  390. * @return TaskFilter
  391. */
  392. public function filterByColors(array $colors)
  393. {
  394. $this->query->beginOr();
  395. foreach ($colors as $color) {
  396. $this->filterByColor($this->color->find($color));
  397. }
  398. $this->query->closeOr();
  399. return $this;
  400. }
  401. /**
  402. * Filter by column
  403. *
  404. * @access public
  405. * @param integer $column_id
  406. * @return TaskFilter
  407. */
  408. public function filterByColumn($column_id)
  409. {
  410. if ($column_id >= 0) {
  411. $this->query->eq(Task::TABLE.'.column_id', $column_id);
  412. }
  413. return $this;
  414. }
  415. /**
  416. * Filter by column name
  417. *
  418. * @access public
  419. * @param array $values List of column name
  420. * @return TaskFilter
  421. */
  422. public function filterByColumnName(array $values)
  423. {
  424. $this->query->beginOr();
  425. foreach ($values as $project) {
  426. $this->query->ilike(Board::TABLE.'.title', $project);
  427. }
  428. $this->query->closeOr();
  429. }
  430. /**
  431. * Filter by swimlane
  432. *
  433. * @access public
  434. * @param integer $swimlane_id
  435. * @return TaskFilter
  436. */
  437. public function filterBySwimlane($swimlane_id)
  438. {
  439. if ($swimlane_id >= 0) {
  440. $this->query->eq(Task::TABLE.'.swimlane_id', $swimlane_id);
  441. }
  442. return $this;
  443. }
  444. /**
  445. * Filter by status name
  446. *
  447. * @access public
  448. * @param string $status
  449. * @return TaskFilter
  450. */
  451. public function filterByStatusName($status)
  452. {
  453. if ($status === 'open' || $status === 'closed') {
  454. $this->filterByStatus($status === 'open' ? Task::STATUS_OPEN : Task::STATUS_CLOSED);
  455. }
  456. return $this;
  457. }
  458. /**
  459. * Filter by status
  460. *
  461. * @access public
  462. * @param integer $is_active
  463. * @return TaskFilter
  464. */
  465. public function filterByStatus($is_active)
  466. {
  467. if ($is_active >= 0) {
  468. $this->query->eq(Task::TABLE.'.is_active', $is_active);
  469. }
  470. return $this;
  471. }
  472. /**
  473. * Filter by due date
  474. *
  475. * @access public
  476. * @param string $date ISO8601 date format
  477. * @return TaskFilter
  478. */
  479. public function filterByDueDate($date)
  480. {
  481. $this->query->neq(Task::TABLE.'.date_due', 0);
  482. $this->query->notNull(Task::TABLE.'.date_due');
  483. return $this->filterWithOperator(Task::TABLE.'.date_due', $date, true);
  484. }
  485. /**
  486. * Filter by due date (range)
  487. *
  488. * @access public
  489. * @param string $start
  490. * @param string $end
  491. * @return TaskFilter
  492. */
  493. public function filterByDueDateRange($start, $end)
  494. {
  495. $this->query->gte('date_due', $this->dateParser->getTimestampFromIsoFormat($start));
  496. $this->query->lte('date_due', $this->dateParser->getTimestampFromIsoFormat($end));
  497. return $this;
  498. }
  499. /**
  500. * Filter by start date (range)
  501. *
  502. * @access public
  503. * @param string $start
  504. * @param string $end
  505. * @return TaskFilter
  506. */
  507. public function filterByStartDateRange($start, $end)
  508. {
  509. $this->query->addCondition($this->getCalendarCondition(
  510. $this->dateParser->getTimestampFromIsoFormat($start),
  511. $this->dateParser->getTimestampFromIsoFormat($end),
  512. 'date_started',
  513. 'date_completed'
  514. ));
  515. return $this;
  516. }
  517. /**
  518. * Filter by creation date
  519. *
  520. * @access public
  521. * @param string $date ISO8601 date format
  522. * @return TaskFilter
  523. */
  524. public function filterByCreationDate($date)
  525. {
  526. if ($date === 'recently') {
  527. return $this->filterRecentlyDate(Task::TABLE.'.date_creation');
  528. }
  529. return $this->filterWithOperator(Task::TABLE.'.date_creation', $date, true);
  530. }
  531. /**
  532. * Filter by creation date
  533. *
  534. * @access public
  535. * @param string $start
  536. * @param string $end
  537. * @return TaskFilter
  538. */
  539. public function filterByCreationDateRange($start, $end)
  540. {
  541. $this->query->addCondition($this->getCalendarCondition(
  542. $this->dateParser->getTimestampFromIsoFormat($start),
  543. $this->dateParser->getTimestampFromIsoFormat($end),
  544. 'date_creation',
  545. 'date_completed'
  546. ));
  547. return $this;
  548. }
  549. /**
  550. * Filter by modification date
  551. *
  552. * @access public
  553. * @param string $date ISO8601 date format
  554. * @return TaskFilter
  555. */
  556. public function filterByModificationDate($date)
  557. {
  558. if ($date === 'recently') {
  559. return $this->filterRecentlyDate(Task::TABLE.'.date_modification');
  560. }
  561. return $this->filterWithOperator(Task::TABLE.'.date_modification', $date, true);
  562. }
  563. /**
  564. * Get all results of the filter
  565. *
  566. * @access public
  567. * @return array
  568. */
  569. public function findAll()
  570. {
  571. return $this->query->asc(Task::TABLE.'.id')->findAll();
  572. }
  573. /**
  574. * Get the PicoDb query
  575. *
  576. * @access public
  577. * @return \PicoDb\Table
  578. */
  579. public function getQuery()
  580. {
  581. return $this->query;
  582. }
  583. /**
  584. * Get swimlanes and tasks to display the board
  585. *
  586. * @access public
  587. * @return array
  588. */
  589. public function getBoard($project_id)
  590. {
  591. $tasks = $this->filterByProject($project_id)->query->asc(Task::TABLE.'.position')->findAll();
  592. return $this->board->getBoard($project_id, function ($project_id, $column_id, $swimlane_id) use ($tasks) {
  593. return array_filter($tasks, function(array $task) use ($column_id, $swimlane_id) {
  594. return $task['column_id'] == $column_id && $task['swimlane_id'] == $swimlane_id;
  595. });
  596. });
  597. }
  598. /**
  599. * Format tasks to be displayed in the Gantt chart
  600. *
  601. * @access public
  602. * @return array
  603. */
  604. public function toGanttBars()
  605. {
  606. $bars = array();
  607. $columns = array();
  608. foreach ($this->query->findAll() as $task) {
  609. if (! isset($column_count[$task['project_id']])) {
  610. $columns[$task['project_id']] = $this->board->getColumnsList($task['project_id']);
  611. }
  612. $start = $task['date_started'] ?: time();
  613. $end = $task['date_due'] ?: $start;
  614. $bars[] = array(
  615. 'type' => 'task',
  616. 'id' => $task['id'],
  617. 'title' => $task['title'],
  618. 'start' => array(
  619. (int) date('Y', $start),
  620. (int) date('n', $start),
  621. (int) date('j', $start),
  622. ),
  623. 'end' => array(
  624. (int) date('Y', $end),
  625. (int) date('n', $end),
  626. (int) date('j', $end),
  627. ),
  628. 'column_title' => $task['column_name'],
  629. 'assignee' => $task['assignee_name'] ?: $task['assignee_username'],
  630. 'progress' => $this->task->getProgress($task, $columns[$task['project_id']]).'%',
  631. 'link' => $this->helper->url->href('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])),
  632. 'color' => $this->color->getColorProperties($task['color_id']),
  633. 'not_defined' => empty($task['date_due']) || empty($task['date_started']),
  634. );
  635. }
  636. return $bars;
  637. }
  638. /**
  639. * Format the results to the ajax autocompletion
  640. *
  641. * @access public
  642. * @return array
  643. */
  644. public function toAutoCompletion()
  645. {
  646. return $this->query->columns(Task::TABLE.'.id', Task::TABLE.'.title')->callback(function(array $results) {
  647. foreach ($results as &$result) {
  648. $result['value'] = $result['title'];
  649. $result['label'] = '#'.$result['id'].' - '.$result['title'];
  650. }
  651. return $results;
  652. })->findAll();
  653. }
  654. /**
  655. * Transform results to calendar events
  656. *
  657. * @access public
  658. * @param string $start_column Column name for the start date
  659. * @param string $end_column Column name for the end date
  660. * @return array
  661. */
  662. public function toDateTimeCalendarEvents($start_column, $end_column)
  663. {
  664. $events = array();
  665. foreach ($this->query->findAll() as $task) {
  666. $events[] = array_merge(
  667. $this->getTaskCalendarProperties($task),
  668. array(
  669. 'start' => date('Y-m-d\TH:i:s', $task[$start_column]),
  670. 'end' => date('Y-m-d\TH:i:s', $task[$end_column] ?: time()),
  671. 'editable' => false,
  672. )
  673. );
  674. }
  675. return $events;
  676. }
  677. /**
  678. * Transform results to all day calendar events
  679. *
  680. * @access public
  681. * @param string $column Column name for the date
  682. * @return array
  683. */
  684. public function toAllDayCalendarEvents($column = 'date_due')
  685. {
  686. $events = array();
  687. foreach ($this->query->findAll() as $task) {
  688. $events[] = array_merge(
  689. $this->getTaskCalendarProperties($task),
  690. array(
  691. 'start' => date('Y-m-d', $task[$column]),
  692. 'end' => date('Y-m-d', $task[$column]),
  693. 'allday' => true,
  694. )
  695. );
  696. }
  697. return $events;
  698. }
  699. /**
  700. * Transform results to ical events
  701. *
  702. * @access public
  703. * @param string $start_column Column name for the start date
  704. * @param string $end_column Column name for the end date
  705. * @param Calendar $vCalendar Calendar object
  706. * @return Calendar
  707. */
  708. public function addDateTimeIcalEvents($start_column, $end_column, Calendar $vCalendar = null)
  709. {
  710. if ($vCalendar === null) {
  711. $vCalendar = new Calendar('Kanboard');
  712. }
  713. foreach ($this->query->findAll() as $task) {
  714. $start = new DateTime;
  715. $start->setTimestamp($task[$start_column]);
  716. $end = new DateTime;
  717. $end->setTimestamp($task[$end_column] ?: time());
  718. $vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$start_column.'-'.$end_column);
  719. $vEvent->setDtStart($start);
  720. $vEvent->setDtEnd($end);
  721. $vCalendar->addComponent($vEvent);
  722. }
  723. return $vCalendar;
  724. }
  725. /**
  726. * Transform results to all day ical events
  727. *
  728. * @access public
  729. * @param string $column Column name for the date
  730. * @param Calendar $vCalendar Calendar object
  731. * @return Calendar
  732. */
  733. public function addAllDayIcalEvents($column = 'date_due', Calendar $vCalendar = null)
  734. {
  735. if ($vCalendar === null) {
  736. $vCalendar = new Calendar('Kanboard');
  737. }
  738. foreach ($this->query->findAll() as $task) {
  739. $date = new DateTime;
  740. $date->setTimestamp($task[$column]);
  741. $vEvent = $this->getTaskIcalEvent($task, 'task-#'.$task['id'].'-'.$column);
  742. $vEvent->setDtStart($date);
  743. $vEvent->setDtEnd($date);
  744. $vEvent->setNoTime(true);
  745. $vCalendar->addComponent($vEvent);
  746. }
  747. return $vCalendar;
  748. }
  749. /**
  750. * Get common events for task ical events
  751. *
  752. * @access protected
  753. * @param array $task
  754. * @param string $uid
  755. * @return Event
  756. */
  757. protected function getTaskIcalEvent(array &$task, $uid)
  758. {
  759. $dateCreation = new DateTime;
  760. $dateCreation->setTimestamp($task['date_creation']);
  761. $dateModif = new DateTime;
  762. $dateModif->setTimestamp($task['date_modification']);
  763. $vEvent = new Event($uid);
  764. $vEvent->setCreated($dateCreation);
  765. $vEvent->setModified($dateModif);
  766. $vEvent->setUseTimezone(true);
  767. $vEvent->setSummary(t('#%d', $task['id']).' '.$task['title']);
  768. $vEvent->setUrl($this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
  769. if (! empty($task['owner_id'])) {
  770. $vEvent->setOrganizer($task['assignee_name'] ?: $task['assignee_username'], $task['assignee_email']);
  771. }
  772. if (! empty($task['creator_id'])) {
  773. $attendees = new Attendees;
  774. $attendees->add('MAILTO:'.($task['creator_email'] ?: $task['creator_username'].'@kanboard.local'));
  775. $vEvent->setAttendees($attendees);
  776. }
  777. return $vEvent;
  778. }
  779. /**
  780. * Filter with an operator
  781. *
  782. * @access public
  783. * @param string $field
  784. * @param string $value
  785. * @param boolean $is_date
  786. * @return TaskFilter
  787. */
  788. private function filterWithOperator($field, $value, $is_date)
  789. {
  790. $operators = array(
  791. '<=' => 'lte',
  792. '>=' => 'gte',
  793. '<' => 'lt',
  794. '>' => 'gt',
  795. );
  796. foreach ($operators as $operator => $method) {
  797. if (strpos($value, $operator) === 0) {
  798. $value = substr($value, strlen($operator));
  799. $this->query->$method($field, $is_date ? $this->dateParser->getTimestampFromIsoFormat($value) : $value);
  800. return $this;
  801. }
  802. }
  803. if ($is_date) {
  804. $timestamp = $this->dateParser->getTimestampFromIsoFormat($value);
  805. $this->query->gte($field, $timestamp);
  806. $this->query->lte($field, $timestamp + 86399);
  807. }
  808. else {
  809. $this->query->eq($field, $value);
  810. }
  811. return $this;
  812. }
  813. /**
  814. * Use the board_highlight_period for the "recently" keyword
  815. *
  816. * @access private
  817. * @param string $field
  818. * @return TaskFilter
  819. */
  820. private function filterRecentlyDate($field)
  821. {
  822. $duration = $this->config->get('board_highlight_period', 0);
  823. if ($duration > 0) {
  824. $this->query->gte($field, time() - $duration);
  825. }
  826. return $this;
  827. }
  828. }