|null $filterActions */ private ?array $filterActions = null; /** * @return list */ private function filterActions(): array { if (empty($this->filterActions)) { $this->filterActions = []; $filters = $this->attributeArray('filters') ?? []; foreach ($filters as $filter) { $filterAction = FreshRSS_FilterAction::fromJSON($filter); if ($filterAction != null) { $this->filterActions[] = $filterAction; } } } return $this->filterActions; } /** * @param array|null $filterActions */ private function _filterActions(?array $filterActions): void { $this->filterActions = is_array($filterActions) ? array_values($filterActions) : null; if ($this->filterActions !== null && !empty($this->filterActions)) { $this->_attribute('filters', array_map( static fn(?FreshRSS_FilterAction $af) => $af == null ? null : $af->toJSON(), $this->filterActions)); } else { $this->_attribute('filters', null); } } /** @return list */ public function filtersAction(string $action): array { $action = trim($action); if ($action == '') { return []; } $filters = []; $filterActions = $this->filterActions(); for ($i = count($filterActions) - 1; $i >= 0; $i--) { $filterAction = $filterActions[$i]; if (in_array($action, $filterAction->actions(), true)) { $filters[] = $filterAction->booleanSearch(); } } return $filters; } /** * @param array $filters */ public function _filtersAction(string $action, array $filters): void { $action = trim($action); if ($action === '') { return; } $filters = array_values(array_unique(array_map('trim', $filters), SORT_STRING)); $filterActions = $this->filterActions(); //Check existing filters for ($i = count($filterActions) - 1; $i >= 0; $i--) { $filterAction = $filterActions[$i]; if ($filterAction === null || !is_array($filterAction->actions()) || $filterAction->booleanSearch()->toString() === '') { array_splice($filterActions, $i, 1); continue; } $actions = $filterAction->actions(); //Remove existing rules with same action for ($j = count($actions) - 1; $j >= 0; $j--) { if ($actions[$j] === $action) { array_splice($actions, $j, 1); } } //Update existing filter with new action for ($k = count($filters) - 1; $k >= 0; $k--) { $filter = $filters[$k]; if ($filter === $filterAction->booleanSearch()->toString()) { $actions[] = $action; array_splice($filters, $k, 1); } } //Save result if (empty($actions)) { array_splice($filterActions, $i, 1); } else { $filterAction->_actions($actions); } } //Add new filters for ($k = count($filters) - 1; $k >= 0; $k--) { $filter = $filters[$k]; if ($filter != '') { $filterAction = FreshRSS_FilterAction::fromJSON([ 'search' => $filter, 'actions' => [$action], ]); if ($filterAction != null) { $filterActions[] = $filterAction; } } } if (empty($filterActions)) { $filterActions = null; } $this->_filterActions($filterActions); } /** * @param bool $applyLabel Parameter by reference, which will be set to true if the callers needs to apply a label to the article entry. * @param-out bool $applyLabel */ public function applyFilterActions(FreshRSS_Entry $entry, ?bool &$applyLabel = null): void { $applyLabel = false; foreach ($this->filterActions() as $filterAction) { if ($entry->matches($filterAction->booleanSearch())) { foreach ($filterAction->actions() as $action) { switch ($action) { case 'read': if (!$entry->isRead()) { $entry->_isRead(true); Minz_ExtensionManager::callHook(Minz_HookType::EntryAutoRead, $entry, 'filter'); } break; case 'star': if (!$entry->isUpdated()) { // Do not apply to updated articles, to avoid overruling a user manual action $entry->_isFavorite(true); } break; case 'label': if (!$entry->isUpdated()) { // Do not apply to updated articles, to avoid overruling a user manual action $applyLabel = true; } break; } } } } } }