single-value path, so the predicates below are grouped in a scoped * beginOr/closeOr and the whole group still ANDs with any other search attribute. */ class TaskRecurringFilter extends BaseFilter implements FilterInterface { private $db; public function setDatabase(Database $db) { $this->db = $db; return $this; } public function getAttributes() { return array('recurring'); } public function apply() { $value = strtolower(trim((string) $this->value)); $system = substr($value, 0, 3); // evt | cal | any $role = substr($value, 3, 3); // ori | dup | all if (! in_array($system, array('evt', 'cal', 'any'), true) || ! in_array($role, array('ori', 'dup', 'all'), true)) { return $this; // unknown/typo value -> no-op } $wantEvt = $system === 'evt' || $system === 'any'; $wantCal = $system === 'cal' || $system === 'any'; $wantOri = $role === 'ori' || $role === 'all'; $wantDup = $role === 'dup' || $role === 'all'; $this->query->beginOr(); if ($wantEvt && $wantOri) { $this->query->eq(TaskModel::TABLE.'.recurrence_status', TaskModel::RECURRING_STATUS_PENDING); } if ($wantEvt && $wantDup) { $this->query->eq(TaskModel::TABLE.'.recurrence_status', TaskModel::RECURRING_STATUS_PROCESSED); } if ($wantCal && $wantOri) { $this->query->in(TaskModel::TABLE.'.id', $this->metaIds('recoreco_enabled')); } if ($wantCal && $wantDup) { $this->query->in(TaskModel::TABLE.'.id', $this->metaIds('recoreco_clone')); } $this->query->closeOr(); return $this; } /** * Task ids carrying a RecoReco metadata flag set to 1. Returns a non-matching sentinel when the * set is empty so the IN clause matches nothing (RecoReco absent -> event-only degrade). * * @param string $name * @return array */ private function metaIds($name) { $ids = $this->db->table('task_has_metadata') ->eq('name', $name) ->eq('value', '1') ->findAllByColumn('task_id'); return ! empty($ids) ? $ids : array(-1); } }