From 11858be4e8d5aba983700c6cba1c4d0a33ea8e9d Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sat, 9 Apr 2016 22:42:17 -0400 Subject: Filter refactoring --- app/Filter/BaseFilter.php | 119 ++++++++++++++++++++++ app/Filter/ProjectGroupRoleProjectFilter.php | 38 +++++++ app/Filter/ProjectGroupRoleUsernameFilter.php | 44 ++++++++ app/Filter/ProjectIdsFilter.php | 43 ++++++++ app/Filter/ProjectStatusFilter.php | 45 +++++++++ app/Filter/ProjectTypeFilter.php | 45 +++++++++ app/Filter/ProjectUserRoleProjectFilter.php | 38 +++++++ app/Filter/ProjectUserRoleUsernameFilter.php | 41 ++++++++ app/Filter/TaskAssigneeFilter.php | 75 ++++++++++++++ app/Filter/TaskCategoryFilter.php | 46 +++++++++ app/Filter/TaskColorFilter.php | 60 +++++++++++ app/Filter/TaskColumnFilter.php | 44 ++++++++ app/Filter/TaskCompletionDateFilter.php | 38 +++++++ app/Filter/TaskCreationDateFilter.php | 38 +++++++ app/Filter/TaskDescriptionFilter.php | 38 +++++++ app/Filter/TaskDueDateFilter.php | 41 ++++++++ app/Filter/TaskDueDateRangeFilter.php | 39 +++++++ app/Filter/TaskIdExclusionFilter.php | 38 +++++++ app/Filter/TaskIdFilter.php | 38 +++++++ app/Filter/TaskLinkFilter.php | 85 ++++++++++++++++ app/Filter/TaskModificationDateFilter.php | 38 +++++++ app/Filter/TaskProjectFilter.php | 44 ++++++++ app/Filter/TaskProjectsFilter.php | 38 +++++++ app/Filter/TaskReferenceFilter.php | 38 +++++++ app/Filter/TaskStartDateFilter.php | 38 +++++++ app/Filter/TaskStatusFilter.php | 43 ++++++++ app/Filter/TaskSubtaskAssigneeFilter.php | 140 ++++++++++++++++++++++++++ app/Filter/TaskSwimlaneFilter.php | 50 +++++++++ app/Filter/TaskTitleFilter.php | 46 +++++++++ app/Filter/UserNameFilter.php | 35 +++++++ 30 files changed, 1503 insertions(+) create mode 100644 app/Filter/BaseFilter.php create mode 100644 app/Filter/ProjectGroupRoleProjectFilter.php create mode 100644 app/Filter/ProjectGroupRoleUsernameFilter.php create mode 100644 app/Filter/ProjectIdsFilter.php create mode 100644 app/Filter/ProjectStatusFilter.php create mode 100644 app/Filter/ProjectTypeFilter.php create mode 100644 app/Filter/ProjectUserRoleProjectFilter.php create mode 100644 app/Filter/ProjectUserRoleUsernameFilter.php create mode 100644 app/Filter/TaskAssigneeFilter.php create mode 100644 app/Filter/TaskCategoryFilter.php create mode 100644 app/Filter/TaskColorFilter.php create mode 100644 app/Filter/TaskColumnFilter.php create mode 100644 app/Filter/TaskCompletionDateFilter.php create mode 100644 app/Filter/TaskCreationDateFilter.php create mode 100644 app/Filter/TaskDescriptionFilter.php create mode 100644 app/Filter/TaskDueDateFilter.php create mode 100644 app/Filter/TaskDueDateRangeFilter.php create mode 100644 app/Filter/TaskIdExclusionFilter.php create mode 100644 app/Filter/TaskIdFilter.php create mode 100644 app/Filter/TaskLinkFilter.php create mode 100644 app/Filter/TaskModificationDateFilter.php create mode 100644 app/Filter/TaskProjectFilter.php create mode 100644 app/Filter/TaskProjectsFilter.php create mode 100644 app/Filter/TaskReferenceFilter.php create mode 100644 app/Filter/TaskStartDateFilter.php create mode 100644 app/Filter/TaskStatusFilter.php create mode 100644 app/Filter/TaskSubtaskAssigneeFilter.php create mode 100644 app/Filter/TaskSwimlaneFilter.php create mode 100644 app/Filter/TaskTitleFilter.php create mode 100644 app/Filter/UserNameFilter.php (limited to 'app/Filter') diff --git a/app/Filter/BaseFilter.php b/app/Filter/BaseFilter.php new file mode 100644 index 00000000..a7e6a61a --- /dev/null +++ b/app/Filter/BaseFilter.php @@ -0,0 +1,119 @@ +value = $value; + } + + /** + * Get object instance + * + * @static + * @access public + * @param mixed $value + * @return static + */ + public static function getInstance($value = null) + { + $self = new static($value); + return $self; + } + + /** + * Set query + * + * @access public + * @param Table $query + * @return \Kanboard\Core\Filter\FilterInterface + */ + public function withQuery(Table $query) + { + $this->query = $query; + return $this; + } + + /** + * Set the value + * + * @access public + * @param string $value + * @return \Kanboard\Core\Filter\FilterInterface + */ + public function withValue($value) + { + $this->value = $value; + return $this; + } + + /** + * Parse operator in the input string + * + * @access protected + * @return string + */ + protected function parseOperator() + { + $operators = array( + '<=' => 'lte', + '>=' => 'gte', + '<' => 'lt', + '>' => 'gt', + ); + + foreach ($operators as $operator => $method) { + if (strpos($this->value, $operator) === 0) { + $this->value = substr($this->value, strlen($operator)); + return $method; + } + } + + return ''; + } + + /** + * Apply a date filter + * + * @access protected + * @param string $field + */ + protected function applyDateFilter($field) + { + $timestamp = strtotime($this->value); + $method = $this->parseOperator(); + + if ($method !== '') { + $this->query->$method($field, $timestamp); + } else { + $this->query->gte($field, $timestamp); + $this->query->lte($field, $timestamp + 86399); + } + } +} diff --git a/app/Filter/ProjectGroupRoleProjectFilter.php b/app/Filter/ProjectGroupRoleProjectFilter.php new file mode 100644 index 00000000..b0950868 --- /dev/null +++ b/app/Filter/ProjectGroupRoleProjectFilter.php @@ -0,0 +1,38 @@ +query->eq(ProjectGroupRole::TABLE.'.project_id', $this->value); + return $this; + } +} diff --git a/app/Filter/ProjectGroupRoleUsernameFilter.php b/app/Filter/ProjectGroupRoleUsernameFilter.php new file mode 100644 index 00000000..c10855bc --- /dev/null +++ b/app/Filter/ProjectGroupRoleUsernameFilter.php @@ -0,0 +1,44 @@ +query + ->join(GroupMember::TABLE, 'group_id', 'group_id', ProjectGroupRole::TABLE) + ->join(User::TABLE, 'id', 'user_id', GroupMember::TABLE) + ->ilike(User::TABLE.'.username', $this->value.'%'); + + return $this; + } +} diff --git a/app/Filter/ProjectIdsFilter.php b/app/Filter/ProjectIdsFilter.php new file mode 100644 index 00000000..641f7f18 --- /dev/null +++ b/app/Filter/ProjectIdsFilter.php @@ -0,0 +1,43 @@ +value)) { + $this->query->eq(Project::TABLE.'.id', 0); + } else { + $this->query->in(Project::TABLE.'.id', $this->value); + } + + return $this; + } +} diff --git a/app/Filter/ProjectStatusFilter.php b/app/Filter/ProjectStatusFilter.php new file mode 100644 index 00000000..a994600c --- /dev/null +++ b/app/Filter/ProjectStatusFilter.php @@ -0,0 +1,45 @@ +value) || ctype_digit($this->value)) { + $this->query->eq(Project::TABLE.'.is_active', $this->value); + } elseif ($this->value === 'inactive' || $this->value === 'closed' || $this->value === 'disabled') { + $this->query->eq(Project::TABLE.'.is_active', 0); + } else { + $this->query->eq(Project::TABLE.'.is_active', 1); + } + + return $this; + } +} diff --git a/app/Filter/ProjectTypeFilter.php b/app/Filter/ProjectTypeFilter.php new file mode 100644 index 00000000..e085e2f6 --- /dev/null +++ b/app/Filter/ProjectTypeFilter.php @@ -0,0 +1,45 @@ +value) || ctype_digit($this->value)) { + $this->query->eq(Project::TABLE.'.is_private', $this->value); + } elseif ($this->value === 'private') { + $this->query->eq(Project::TABLE.'.is_private', Project::TYPE_PRIVATE); + } else { + $this->query->eq(Project::TABLE.'.is_private', Project::TYPE_TEAM); + } + + return $this; + } +} diff --git a/app/Filter/ProjectUserRoleProjectFilter.php b/app/Filter/ProjectUserRoleProjectFilter.php new file mode 100644 index 00000000..3b880df5 --- /dev/null +++ b/app/Filter/ProjectUserRoleProjectFilter.php @@ -0,0 +1,38 @@ +query->eq(ProjectUserRole::TABLE.'.project_id', $this->value); + return $this; + } +} diff --git a/app/Filter/ProjectUserRoleUsernameFilter.php b/app/Filter/ProjectUserRoleUsernameFilter.php new file mode 100644 index 00000000..c00493a3 --- /dev/null +++ b/app/Filter/ProjectUserRoleUsernameFilter.php @@ -0,0 +1,41 @@ +query + ->join(User::TABLE, 'id', 'user_id') + ->ilike(User::TABLE.'.username', $this->value.'%'); + + return $this; + } +} diff --git a/app/Filter/TaskAssigneeFilter.php b/app/Filter/TaskAssigneeFilter.php new file mode 100644 index 00000000..783d6a12 --- /dev/null +++ b/app/Filter/TaskAssigneeFilter.php @@ -0,0 +1,75 @@ +currentUserId = $userId; + return $this; + } + + /** + * Get search attribute + * + * @access public + * @return string[] + */ + public function getAttributes() + { + return array('assignee'); + } + + /** + * Apply filter + * + * @access public + * @return string + */ + public function apply() + { + if (is_int($this->value) || ctype_digit($this->value)) { + $this->query->eq(Task::TABLE.'.owner_id', $this->value); + } else { + switch ($this->value) { + case 'me': + $this->query->eq(Task::TABLE.'.owner_id', $this->currentUserId); + break; + case 'nobody': + $this->query->eq(Task::TABLE.'.owner_id', 0); + break; + default: + $this->query->beginOr(); + $this->query->ilike(User::TABLE.'.username', '%'.$this->value.'%'); + $this->query->ilike(User::TABLE.'.name', '%'.$this->value.'%'); + $this->query->closeOr(); + } + } + } +} diff --git a/app/Filter/TaskCategoryFilter.php b/app/Filter/TaskCategoryFilter.php new file mode 100644 index 00000000..517f24d9 --- /dev/null +++ b/app/Filter/TaskCategoryFilter.php @@ -0,0 +1,46 @@ +value) || ctype_digit($this->value)) { + $this->query->eq(Task::TABLE.'.category_id', $this->value); + } elseif ($this->value === 'none') { + $this->query->eq(Task::TABLE.'.category_id', 0); + } else { + $this->query->eq(Category::TABLE.'.name', $this->value); + } + + return $this; + } +} diff --git a/app/Filter/TaskColorFilter.php b/app/Filter/TaskColorFilter.php new file mode 100644 index 00000000..784162d4 --- /dev/null +++ b/app/Filter/TaskColorFilter.php @@ -0,0 +1,60 @@ +colorModel = $colorModel; + return $this; + } + + /** + * Get search attribute + * + * @access public + * @return string[] + */ + public function getAttributes() + { + return array('color', 'colour'); + } + + /** + * Apply filter + * + * @access public + * @return FilterInterface + */ + public function apply() + { + $this->query->eq(Task::TABLE.'.color_id', $this->colorModel->find($this->value)); + return $this; + } +} diff --git a/app/Filter/TaskColumnFilter.php b/app/Filter/TaskColumnFilter.php new file mode 100644 index 00000000..9a4d4253 --- /dev/null +++ b/app/Filter/TaskColumnFilter.php @@ -0,0 +1,44 @@ +value) || ctype_digit($this->value)) { + $this->query->eq(Task::TABLE.'.column_id', $this->value); + } else { + $this->query->eq(Column::TABLE.'.title', $this->value); + } + + return $this; + } +} diff --git a/app/Filter/TaskCompletionDateFilter.php b/app/Filter/TaskCompletionDateFilter.php new file mode 100644 index 00000000..5166bebf --- /dev/null +++ b/app/Filter/TaskCompletionDateFilter.php @@ -0,0 +1,38 @@ +applyDateFilter(Task::TABLE.'.date_completed'); + return $this; + } +} diff --git a/app/Filter/TaskCreationDateFilter.php b/app/Filter/TaskCreationDateFilter.php new file mode 100644 index 00000000..26318b3e --- /dev/null +++ b/app/Filter/TaskCreationDateFilter.php @@ -0,0 +1,38 @@ +applyDateFilter(Task::TABLE.'.date_creation'); + return $this; + } +} diff --git a/app/Filter/TaskDescriptionFilter.php b/app/Filter/TaskDescriptionFilter.php new file mode 100644 index 00000000..6dda58ae --- /dev/null +++ b/app/Filter/TaskDescriptionFilter.php @@ -0,0 +1,38 @@ +query->ilike(Task::TABLE.'.description', '%'.$this->value.'%'); + return $this; + } +} diff --git a/app/Filter/TaskDueDateFilter.php b/app/Filter/TaskDueDateFilter.php new file mode 100644 index 00000000..6ba55eb9 --- /dev/null +++ b/app/Filter/TaskDueDateFilter.php @@ -0,0 +1,41 @@ +query->neq(Task::TABLE.'.date_due', 0); + $this->query->notNull(Task::TABLE.'.date_due'); + $this->applyDateFilter(Task::TABLE.'.date_due'); + + return $this; + } +} diff --git a/app/Filter/TaskDueDateRangeFilter.php b/app/Filter/TaskDueDateRangeFilter.php new file mode 100644 index 00000000..10deb0d3 --- /dev/null +++ b/app/Filter/TaskDueDateRangeFilter.php @@ -0,0 +1,39 @@ +query->gte(Task::TABLE.'.date_due', is_numeric($this->value[0]) ? $this->value[0] : strtotime($this->value[0])); + $this->query->lte(Task::TABLE.'.date_due', is_numeric($this->value[1]) ? $this->value[1] : strtotime($this->value[1])); + return $this; + } +} diff --git a/app/Filter/TaskIdExclusionFilter.php b/app/Filter/TaskIdExclusionFilter.php new file mode 100644 index 00000000..8bfefb2b --- /dev/null +++ b/app/Filter/TaskIdExclusionFilter.php @@ -0,0 +1,38 @@ +query->notin(Task::TABLE.'.id', $this->value); + return $this; + } +} diff --git a/app/Filter/TaskIdFilter.php b/app/Filter/TaskIdFilter.php new file mode 100644 index 00000000..87bac794 --- /dev/null +++ b/app/Filter/TaskIdFilter.php @@ -0,0 +1,38 @@ +query->eq(Task::TABLE.'.id', $this->value); + return $this; + } +} diff --git a/app/Filter/TaskLinkFilter.php b/app/Filter/TaskLinkFilter.php new file mode 100644 index 00000000..18a13a09 --- /dev/null +++ b/app/Filter/TaskLinkFilter.php @@ -0,0 +1,85 @@ +db = $db; + return $this; + } + + /** + * Get search attribute + * + * @access public + * @return string[] + */ + public function getAttributes() + { + return array('link'); + } + + /** + * Apply filter + * + * @access public + * @return string + */ + public function apply() + { + $task_ids = $this->getSubQuery()->findAllByColumn('task_id'); + + if (! empty($task_ids)) { + $this->query->in(Task::TABLE.'.id', $task_ids); + } else { + $this->query->eq(Task::TABLE.'.id', 0); // No match + } + } + + /** + * Get subquery + * + * @access protected + * @return Table + */ + protected function getSubQuery() + { + return $this->db->table(TaskLink::TABLE) + ->columns( + TaskLink::TABLE.'.task_id', + Link::TABLE.'.label' + ) + ->join(Link::TABLE, 'id', 'link_id', TaskLink::TABLE) + ->ilike(Link::TABLE.'.label', $this->value); + } +} diff --git a/app/Filter/TaskModificationDateFilter.php b/app/Filter/TaskModificationDateFilter.php new file mode 100644 index 00000000..d8838bce --- /dev/null +++ b/app/Filter/TaskModificationDateFilter.php @@ -0,0 +1,38 @@ +applyDateFilter(Task::TABLE.'.date_modification'); + return $this; + } +} diff --git a/app/Filter/TaskProjectFilter.php b/app/Filter/TaskProjectFilter.php new file mode 100644 index 00000000..e432efee --- /dev/null +++ b/app/Filter/TaskProjectFilter.php @@ -0,0 +1,44 @@ +value) || ctype_digit($this->value)) { + $this->query->eq(Task::TABLE.'.project_id', $this->value); + } else { + $this->query->ilike(Project::TABLE.'.name', $this->value); + } + + return $this; + } +} diff --git a/app/Filter/TaskProjectsFilter.php b/app/Filter/TaskProjectsFilter.php new file mode 100644 index 00000000..e0fc09cf --- /dev/null +++ b/app/Filter/TaskProjectsFilter.php @@ -0,0 +1,38 @@ +query->in(Task::TABLE.'.project_id', $this->value); + return $this; + } +} diff --git a/app/Filter/TaskReferenceFilter.php b/app/Filter/TaskReferenceFilter.php new file mode 100644 index 00000000..4ad47dd5 --- /dev/null +++ b/app/Filter/TaskReferenceFilter.php @@ -0,0 +1,38 @@ +query->eq(Task::TABLE.'.reference', $this->value); + return $this; + } +} diff --git a/app/Filter/TaskStartDateFilter.php b/app/Filter/TaskStartDateFilter.php new file mode 100644 index 00000000..d45bc0d4 --- /dev/null +++ b/app/Filter/TaskStartDateFilter.php @@ -0,0 +1,38 @@ +applyDateFilter(Task::TABLE.'.date_started'); + return $this; + } +} diff --git a/app/Filter/TaskStatusFilter.php b/app/Filter/TaskStatusFilter.php new file mode 100644 index 00000000..0ba4361e --- /dev/null +++ b/app/Filter/TaskStatusFilter.php @@ -0,0 +1,43 @@ +value === 'open' || $this->value === 'closed') { + $this->query->eq(Task::TABLE.'.is_active', $this->value === 'open' ? Task::STATUS_OPEN : Task::STATUS_CLOSED); + } else { + $this->query->eq(Task::TABLE.'.is_active', $this->value); + } + + return $this; + } +} diff --git a/app/Filter/TaskSubtaskAssigneeFilter.php b/app/Filter/TaskSubtaskAssigneeFilter.php new file mode 100644 index 00000000..4c757315 --- /dev/null +++ b/app/Filter/TaskSubtaskAssigneeFilter.php @@ -0,0 +1,140 @@ +currentUserId = $userId; + return $this; + } + + /** + * Set database object + * + * @access public + * @param Database $db + * @return TaskSubtaskAssigneeFilter + */ + public function setDatabase(Database $db) + { + $this->db = $db; + return $this; + } + + /** + * Get search attribute + * + * @access public + * @return string[] + */ + public function getAttributes() + { + return array('subtask:assignee'); + } + + /** + * Apply filter + * + * @access public + * @return string + */ + public function apply() + { + $task_ids = $this->getSubQuery()->findAllByColumn('task_id'); + + if (! empty($task_ids)) { + $this->query->in(Task::TABLE.'.id', $task_ids); + } else { + $this->query->eq(Task::TABLE.'.id', 0); // No match + } + } + + /** + * Get subquery + * + * @access protected + * @return Table + */ + protected function getSubQuery() + { + $subquery = $this->db->table(Subtask::TABLE) + ->columns( + Subtask::TABLE.'.user_id', + Subtask::TABLE.'.task_id', + User::TABLE.'.name', + User::TABLE.'.username' + ) + ->join(User::TABLE, 'id', 'user_id', Subtask::TABLE) + ->neq(Subtask::TABLE.'.status', Subtask::STATUS_DONE); + + return $this->applySubQueryFilter($subquery); + } + + /** + * Apply subquery filter + * + * @access protected + * @param Table $subquery + * @return Table + */ + protected function applySubQueryFilter(Table $subquery) + { + if (is_int($this->value) || ctype_digit($this->value)) { + $subquery->eq(Subtask::TABLE.'.user_id', $this->value); + } else { + switch ($this->value) { + case 'me': + $subquery->eq(Subtask::TABLE.'.user_id', $this->currentUserId); + break; + case 'nobody': + $subquery->eq(Subtask::TABLE.'.user_id', 0); + break; + default: + $subquery->beginOr(); + $subquery->ilike(User::TABLE.'.username', $this->value.'%'); + $subquery->ilike(User::TABLE.'.name', '%'.$this->value.'%'); + $subquery->closeOr(); + } + } + + return $subquery; + } +} diff --git a/app/Filter/TaskSwimlaneFilter.php b/app/Filter/TaskSwimlaneFilter.php new file mode 100644 index 00000000..4e030244 --- /dev/null +++ b/app/Filter/TaskSwimlaneFilter.php @@ -0,0 +1,50 @@ +value) || ctype_digit($this->value)) { + $this->query->eq(Task::TABLE.'.swimlane_id', $this->value); + } elseif ($this->value === 'default') { + $this->query->eq(Task::TABLE.'.swimlane_id', 0); + } else { + $this->query->beginOr(); + $this->query->ilike(Swimlane::TABLE.'.name', $this->value); + $this->query->ilike(Project::TABLE.'.default_swimlane', $this->value); + $this->query->closeOr(); + } + + return $this; + } +} diff --git a/app/Filter/TaskTitleFilter.php b/app/Filter/TaskTitleFilter.php new file mode 100644 index 00000000..9853369c --- /dev/null +++ b/app/Filter/TaskTitleFilter.php @@ -0,0 +1,46 @@ +value) || (strlen($this->value) > 1 && $this->value{0} === '#' && ctype_digit(substr($this->value, 1)))) { + $this->query->beginOr(); + $this->query->eq(Task::TABLE.'.id', str_replace('#', '', $this->value)); + $this->query->ilike(Task::TABLE.'.title', '%'.$this->value.'%'); + $this->query->closeOr(); + } else { + $this->query->ilike(Task::TABLE.'.title', '%'.$this->value.'%'); + } + + return $this; + } +} diff --git a/app/Filter/UserNameFilter.php b/app/Filter/UserNameFilter.php new file mode 100644 index 00000000..dfb07fdd --- /dev/null +++ b/app/Filter/UserNameFilter.php @@ -0,0 +1,35 @@ +query->beginOr() + ->ilike('username', '%'.$this->value.'%') + ->ilike('name', '%'.$this->value.'%') + ->closeOr(); + + return $this; + } +} -- cgit v1.2.3