* @link https://www.zentao.net */ class todoTao extends todoModel { /** * 获取单条待办。 * Get a todo. * * @param int $todoID * @access protected * @return object */ protected function fetch($todoID) { return $this->dao->select('*')->from(TABLE_TODO)->where('id')->eq($todoID)->fetch(); } /** * 获取一个或多个待办。 * Get a or more todo. * * @param array $todoIdList * @access protected * @return array */ protected function fetchRows($todoIdList) { return $this->dao->select('*')->from(TABLE_TODO)->where('id')->in(array_keys($todoIdList))->fetchAll('id'); } /** * 获取待办数量。 * Get todo count. * * @param string $account * @param string $vision * @access protected * @return int */ protected function getCountByAccount($account, $vision = 'rnd') { return $this->dao->select('COUNT(1) AS count')->from(TABLE_TODO) ->where('cycle')->eq('0') ->andWhere('deleted')->eq('0') ->andWhere('vision')->eq($vision) ->andWhere('account', true)->eq($account) ->orWhere('assignedTo')->eq($account) ->orWhere('finishedBy')->eq($account) ->markRight(1) ->fetch('count'); } /** * 获取各模块project列表。 * Get project list. * * @param string $table * @param array $idList * @access protected * @return array */ protected function getProjectList($table, $idList) { return $this->dao->select('id,project')->from($table)->where('id')->in($idList)->fetchPairs('id', 'project'); } /** * 插入待办数据。 * Insert todo data. * * @param object $todo * @access protected * @return int */ protected function insert($todo) { $isModuleType = isset($todo->type) && in_array($todo->type, $this->config->todo->moduleList); $this->dao->insert(TABLE_TODO)->data($todo) ->autoCheck() ->check($this->config->todo->create->requiredFields, 'notempty') ->checkIF($isModuleType, 'objectID', 'notempty') ->exec(); if(dao::isError() && $isModuleType) { $errors = dao::getError(); if(isset($errors['name']) && isset($errors['objectID'])) { dao::$errors[$todo->type] = $errors['name']; } else { dao::$errors = $errors; } } return (int)$this->dao->lastInsertID(); } /** * 更新待办数据。 * Update todo data. * * @param int $todoID * @param object $todo * @access protected * @return bool */ protected function updateRow($todoID, $todo) { $requiredFields = isset($todo->type) && in_array($todo->type, $this->config->todo->moduleList) ? str_replace(',name,', ',objectID,', ",{$this->config->todo->edit->requiredFields},") : $this->config->todo->edit->requiredFields; $this->dao->update(TABLE_TODO)->data($todo) ->autoCheck() ->checkIF($requiredFields, $requiredFields, 'notempty') ->where('id')->eq($todoID) ->exec(); return !dao::isError(); } /** * 关闭一个待办。 * Close one todo. * * @param int $todoID * @access protected * @return bool */ protected function closeTodo($todoID) { $now = helper::now(); $this->dao->update(TABLE_TODO) ->set('status')->eq('closed') ->set('closedBy')->eq($this->app->user->account) ->set('closedDate')->eq($now) ->set('assignedTo')->eq('closed') ->set('assignedDate')->eq($now) ->where('id')->eq($todoID) ->exec(); return !dao::isError(); } /** * 获取周期待办列表。 * Get cycle list. * * @param array $todoList * @param string $orderBy * @access protected * @return array */ protected function getCycleList($todoList, $orderBy = 'date_asc') { if(empty($todoList)) return []; return $this->dao->select('*')->from(TABLE_TODO) ->where('type')->eq('custom') ->andWhere('deleted')->eq('0') ->andWhere('objectID')->in(array_keys($todoList)) ->orderBy($orderBy) ->fetchAll('objectID'); } /** * 通过待办构建周期待办数据。 * Build cycle todo. * * @param object $todo * @access protected * @return object */ protected function buildCycleTodo($todo) { $newTodo = new stdclass(); $newTodo->account = $todo->account; $newTodo->begin = $todo->begin; $newTodo->end = $todo->end; $newTodo->type = 'custom'; $newTodo->objectID = $todo->id; $newTodo->pri = $todo->pri; $newTodo->name = $todo->name; $newTodo->desc = $todo->desc; $newTodo->status = 'wait'; $newTodo->private = $todo->private; $newTodo->assignedTo = $todo->assignedTo; $newTodo->assignedBy = $todo->assignedBy ; return $newTodo; } /** * 通过周期待办,获取要生成待办的日期。 * Gets the date by the cycle todo. * * @param object $todo * @param object|string $lastCycle * @param string $today * @access protected * @return false|string */ protected function getCycleTodoDate($todo, $lastCycle, $today) { $date = ''; if($todo->config->type == 'day') { return $this->getCycleDailyTodoDate($todo, $lastCycle, $today); } elseif($todo->config->type == 'week') { $week = date('w', strtotime($today)); if(strpos(",{$todo->config->week},", ",{$week},") !== false) { if(empty($lastCycle)) $date = $today; if($lastCycle && $lastCycle->date < $today) $date = $today; } } elseif($todo->config->type == 'month') { $day = date('j', strtotime($today)); if(strpos(",{$todo->config->month},", ",{$day},") !== false) { if(empty($lastCycle)) $date = $today; if($lastCycle && $lastCycle->date < $today) $date = $today; } } return $date; } /** * 获取批量创建待办的有效数据。 * Get valid todos of batch create. * * @param object $todos * @param int $loop * @param string $assignedTo * @access protected * @return object */ protected function getValidsOfBatchCreate($todos, $loop , $assignedTo) { $todo = new stdclass(); $todo->account = $this->app->user->account; $todo->date = $todos->date[$loop]; $todo->type = $todos->type[$loop]; $todo->pri = $todos->pri[$loop]; $todo->name = isset($todos->name[$loop]) ? $todos->name[$loop] : ''; $todo->desc = $todos->desc[$loop]; $todo->begin = !empty($todos->begin[$loop]) ? $todos->begin[$loop] : 2400; $todo->end = !empty($todos->end[$loop]) ? $todos->end[$loop] : 2400; $todo->status = 'wait'; $todo->private = 0; $todo->objectID = 0; $todo->assignedTo = $assignedTo; $todo->assignedBy = $this->app->user->account; $todo->assignedDate = helper::now(); $todo->vision = $this->config->vision; if(in_array($todo->type, $this->config->todo->moduleList)) { $todo->objectID = isset($todos->{$this->config->todo->objectList[$todo->type]}[$loop + 1]) ? $todos->{$this->config->todo->objectList[$todo->type]}[$loop + 1] : 0; } if($todo->type != 'custom' && $todo->objectID) { $type = $todo->type; $object = $this->loadModel($type)->getByID($todo->objectID); if(isset($object->name)) $todo->name = $object->name; if(isset($object->title)) $todo->name = $object->title; } if($todo->end < $todo->begin) dao::$errors["end[$loop]"] = sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin); return $todo; } /** * 通过周期待办,获取要生成每日待办的日期。 * Gets the daily todo date by the cycle todo. * * @param object $todo * @param object|string $lastCycle * @param string $today * @access protected * @return false|string */ private function getCycleDailyTodoDate($todo, $lastCycle, $today) { $date = ''; if(isset($todo->config->day)) { $day = (int)$todo->config->day; if($day <= 0) return false; /* If no data, judge the interval from the beginning time. */ if(empty($lastCycle)) { $todayTime = new DateTime($today); $beginTime = new DateTime($todo->config->begin); $interval = $todayTime->diff($beginTime)->days; if($interval != $day) return false; $date = $today; } /* If data is available, determine the interval of time since the previous cycle. */ if(!empty($lastCycle->date)) { $todayTime = new DateTime($today); $lastCycleTime = new DateTime($lastCycle->date); $interval = $todayTime->diff($lastCycleTime)->days; if($interval != $day) return false; $date = date('Y-m-d', strtotime("{$lastCycle->date} +{$day} days")); } } if(isset($todo->config->specifiedDate)) { $date = $today; $specifiedDate = $todo->config->specify->month + 1 . '-' . $todo->config->specify->day; /* If not set cycle every year and have data, continue. */ if(!empty($lastCycle) and !isset($todo->config->cycleYear)) { /* Delete a one-time todo. */ $this->todo->delete(TABLE_TODO, $todo->id); return false; } /* If set specified date, only judge month and day. */ if(date('m-d', strtotime($date)) != $specifiedDate) return false; } return $date; } /** * 修改待办事项的时间。 * Update the date of todo. * * @param array $todoIdList * @param string $date * @return bool */ protected function updateDate($todoIdList, $date) { $this->dao->update(TABLE_TODO)->set('date')->eq($date)->where('id')->in($todoIdList)->exec(); return !dao::isError(); } /** * 获取用户的待办事项数量。 * Get todo count on the account. * * @param string $account * @access protected * @return int */ protected function getTodoCountByAccount($account) { return $this->dao->select('COUNT(1) AS count')->from(TABLE_TODO) ->where('cycle')->eq('0') ->andWhere('deleted')->eq('0') ->andWhere('vision')->eq($this->config->vision) ->andWhere('account', true)->eq($account) ->orWhere('assignedTo')->eq($account) ->orWhere('finishedBy')->eq($account) ->markRight(1) ->fetch('count'); } /** * 根据待办类型设置待办名称。 * Set todo name by its type. * * @param object $todo * @access protected * @return object */ protected function setTodoNameByType($todo) { $savedTodoName = $todo->name; if(in_array($todo->type, array('story', 'epic', 'requirement'))) { $story = $this->dao->findByID($todo->objectID)->from(TABLE_STORY)->fetch(); $todo->object = $story; $todo->name = zget($story, 'title', ''); } if($todo->type == 'task') { $task = $this->dao->findByID($todo->objectID)->from(TABLE_TASK)->fetch(); $todo->object = $task; $todo->name = zget($task, 'name', ''); } if($todo->type == 'bug') { $bug = $this->dao->findByID($todo->objectID)->from(TABLE_BUG)->fetch(); $todo->object = $bug; $todo->name = zget($bug, 'title', ''); } /* if($todo->type == 'story') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_STORY)->fetch('title'); if($todo->type == 'task') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_TASK)->fetch('name'); if($todo->type == 'bug') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_BUG)->fetch('title'); */ if($todo->type == 'testtask') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_TESTTASK)->fetch('name'); if($this->config->edition == 'max') { if($todo->type == 'risk' ) $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_RISK)->fetch('name'); if($todo->type == 'issue') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_ISSUE)->fetch('title'); if($todo->type == 'review') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_REVIEW)->fetch('title'); if($todo->type == 'opportunity') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_OPPORTUNITY)->fetch('name'); } if($this->config->edition != 'open' && $todo->type == 'feedback') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title'); if(empty($todo->name)) $todo->name = $savedTodoName; return $todo; } /** * 获取待办列表数据。 * Get the todo list data. * * @param string $type * @param string $account * @param string|array $status * @param string $begin * @param string $end * @param int $limit * @param string $orderBy * @param object $pager * @access protected * @return array */ protected function getListBy($type, $account, $status, $begin, $end, $limit, $orderBy, $pager = null) { return $this->dao->select('*')->from(TABLE_TODO) ->where('deleted')->eq('0') ->andWhere('vision')->eq($this->config->vision) ->beginIF($type == 'assignedtoother')->andWhere('account', true)->eq($account)->fi() ->beginIF($type != 'assignedtoother')->andWhere('assignedTo', true)->eq($account)->fi() ->orWhere('finishedBy')->eq($account) ->orWhere('closedBy')->eq($account) ->markRight(1) ->beginIF($begin && $type != 'future')->andWhere('date')->ge($begin)->fi() ->beginIF($end && $type != 'future')->andWhere('date')->le($end)->fi() ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() ->beginIF($status == 'undone')->andWhere('status')->notin('done,closed')->fi() ->beginIF($type == 'cycle')->andWhere('cycle')->eq('1')->fi() ->beginIF($type != 'cycle')->andWhere('cycle')->eq('0')->fi() ->beginIF($type == 'assignedtoother')->andWhere('assignedTo')->notin(array($account, ''))->fi() ->beginIF($type == 'future') ->andWhere('(date')->eq(FUTURE_TIME) ->orWhere('(begin')->eq('2400') ->andWhere('end')->eq('2400') ->markRight(2) ->fi() ->orderBy($orderBy) ->beginIF($limit > 0)->limit($limit)->fi() ->page($pager) ->fetchAll(); } }