diff --git a/app/Api/V1/Requests/Models/Rule/StoreRequest.php b/app/Api/V1/Requests/Models/Rule/StoreRequest.php index 51201b38f8..2177eadf34 100644 --- a/app/Api/V1/Requests/Models/Rule/StoreRequest.php +++ b/app/Api/V1/Requests/Models/Rule/StoreRequest.php @@ -105,8 +105,8 @@ class StoreRequest extends FormRequest */ public function rules(): array { - $validTriggers = $this->getTriggers(); - $validActions = array_keys(config('firefly.rule-actions')); + $validTriggers = $this->getTriggers(); + $validActions = array_keys(config('firefly.rule-actions')); // some triggers and actions require text: $contextTriggers = implode(',', $this->getTriggersWithContext()); @@ -118,11 +118,11 @@ class StoreRequest extends FormRequest 'rule_group_id' => 'belongsToUser:rule_groups|required_without:rule_group_title', 'rule_group_title' => 'nullable|min:1|max:255|required_without:rule_group_id|belongsToUser:rule_groups,title', 'trigger' => 'required|in:store-journal,update-journal', - 'triggers.*.type' => 'required|in:' . implode(',', $validTriggers), - 'triggers.*.value' => 'required_if:actions.*.type,' . $contextTriggers . '|min:1|ruleTriggerValue|max:1024', + 'triggers.*.type' => 'required|in:'.implode(',', $validTriggers), + 'triggers.*.value' => 'required_if:actions.*.type,'.$contextTriggers.'|min:1|ruleTriggerValue|max:1024', 'triggers.*.stop_processing' => [new IsBoolean()], 'triggers.*.active' => [new IsBoolean()], - 'actions.*.type' => 'required|in:' . implode(',', $validActions), + 'actions.*.type' => 'required|in:'.implode(',', $validActions), 'actions.*.value' => [sprintf('required_if:actions.*.type,%s', $contextActions), new IsValidActionExpression(), 'ruleActionValue'], 'actions.*.stop_processing' => [new IsBoolean()], 'actions.*.active' => [new IsBoolean()], @@ -181,10 +181,10 @@ class StoreRequest extends FormRequest */ protected function atLeastOneActiveTrigger(Validator $validator): void { - $data = $validator->getData(); + $data = $validator->getData(); /** @var null|array|int|string $triggers */ - $triggers = $data['triggers'] ?? []; + $triggers = $data['triggers'] ?? []; // need at least one trigger if (!is_countable($triggers) || 0 === count($triggers)) { return; @@ -210,10 +210,10 @@ class StoreRequest extends FormRequest */ protected function atLeastOneActiveAction(Validator $validator): void { - $data = $validator->getData(); + $data = $validator->getData(); /** @var null|array|int|string $actions */ - $actions = $data['actions'] ?? []; + $actions = $data['actions'] ?? []; // need at least one trigger if (!is_countable($actions) || 0 === count($actions)) { return; diff --git a/app/Api/V1/Requests/Models/Rule/UpdateRequest.php b/app/Api/V1/Requests/Models/Rule/UpdateRequest.php index 3cc27ba875..6f4be69a3d 100644 --- a/app/Api/V1/Requests/Models/Rule/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Rule/UpdateRequest.php @@ -141,7 +141,7 @@ class UpdateRequest extends FormRequest 'triggers.*.stop_processing' => [new IsBoolean()], 'triggers.*.active' => [new IsBoolean()], 'actions.*.type' => 'required|in:'.implode(',', $validActions), - 'actions.*.value' => [sprintf('required_if:actions.*.type,%s',$contextActions), new IsValidActionExpression(), 'ruleActionValue'], + 'actions.*.value' => [sprintf('required_if:actions.*.type,%s', $contextActions), new IsValidActionExpression(), 'ruleActionValue'], 'actions.*.stop_processing' => [new IsBoolean()], 'actions.*.active' => [new IsBoolean()], 'strict' => [new IsBoolean()], diff --git a/app/Api/V1/Requests/Models/Rule/ValidateExpressionRequest.php b/app/Api/V1/Requests/Models/Rule/ValidateExpressionRequest.php index b5523778f9..766826d3a2 100644 --- a/app/Api/V1/Requests/Models/Rule/ValidateExpressionRequest.php +++ b/app/Api/V1/Requests/Models/Rule/ValidateExpressionRequest.php @@ -26,9 +26,7 @@ namespace FireflyIII\Api\V1\Requests\Models\Rule; use FireflyIII\Rules\IsValidActionExpression; use FireflyIII\Support\Request\ChecksLogin; -use Illuminate\Contracts\Validation\Validator; use Illuminate\Foundation\Http\FormRequest; -use Illuminate\Validation\ValidationException; /** * Class ValidateExpressionRequest @@ -41,6 +39,4 @@ class ValidateExpressionRequest extends FormRequest { return ['expression' => ['required', new IsValidActionExpression()]]; } - - } diff --git a/app/Models/RuleAction.php b/app/Models/RuleAction.php index e4f9766468..eed2a1dc13 100644 --- a/app/Models/RuleAction.php +++ b/app/Models/RuleAction.php @@ -31,7 +31,6 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Log; /** * FireflyIII\Models\RuleAction @@ -67,7 +66,7 @@ class RuleAction extends Model use ReturnsIntegerIdTrait; protected $casts - = [ + = [ 'created_at' => 'datetime', 'updated_at' => 'datetime', 'active' => 'boolean', @@ -80,12 +79,14 @@ class RuleAction extends Model public function getValue(array $journal): string { if (false === config('firefly.feature_flags.expression_engine')) { - Log::debug('Expression engine is disabled, returning action value as string.'); + \Log::debug('Expression engine is disabled, returning action value as string.'); + return (string)$this->action_value; } $expr = new ActionExpression($this->action_value); $result = $expr->evaluate($journal); - Log::debug(sprintf('Expression engine is enabled, result of expression "%s" is "%s".', $this->action_value, $result)); + \Log::debug(sprintf('Expression engine is enabled, result of expression "%s" is "%s".', $this->action_value, $result)); + return $result; } @@ -97,14 +98,14 @@ class RuleAction extends Model protected function order(): Attribute { return Attribute::make( - get: static fn($value) => (int)$value, + get: static fn ($value) => (int)$value, ); } protected function ruleId(): Attribute { return Attribute::make( - get: static fn($value) => (int)$value, + get: static fn ($value) => (int)$value, ); } } diff --git a/app/Rules/IsValidActionExpression.php b/app/Rules/IsValidActionExpression.php index 372b16a275..dc79a129eb 100644 --- a/app/Rules/IsValidActionExpression.php +++ b/app/Rules/IsValidActionExpression.php @@ -44,7 +44,7 @@ class IsValidActionExpression implements ValidationRule return; } $value ??= ''; - $expr = new ActionExpression($value); + $expr = new ActionExpression($value); if (!$expr->isValid()) { $fail('validation.rule_action_expression')->translate( diff --git a/app/TransactionRules/Actions/AppendDescription.php b/app/TransactionRules/Actions/AppendDescription.php index b397233ea9..a46623efef 100644 --- a/app/TransactionRules/Actions/AppendDescription.php +++ b/app/TransactionRules/Actions/AppendDescription.php @@ -34,8 +34,8 @@ use FireflyIII\TransactionRules\Traits\RefreshNotesTrait; */ class AppendDescription implements ActionInterface { - private RuleAction $action; use RefreshNotesTrait; + private RuleAction $action; /** * TriggerInterface constructor. diff --git a/app/TransactionRules/Actions/AppendDescriptionToNotes.php b/app/TransactionRules/Actions/AppendDescriptionToNotes.php index 0be769263f..fb7b46f53f 100644 --- a/app/TransactionRules/Actions/AppendDescriptionToNotes.php +++ b/app/TransactionRules/Actions/AppendDescriptionToNotes.php @@ -51,6 +51,7 @@ class AppendDescriptionToNotes implements ActionInterface public function actOnArray(array $journal): bool { $this->refreshNotes($journal); + /** @var null|TransactionJournal $object */ $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); if (null === $object) { diff --git a/app/TransactionRules/Actions/AppendNotes.php b/app/TransactionRules/Actions/AppendNotes.php index 665e973bb5..3ec1a32c77 100644 --- a/app/TransactionRules/Actions/AppendNotes.php +++ b/app/TransactionRules/Actions/AppendNotes.php @@ -27,6 +27,7 @@ use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Models\Note; use FireflyIII\Models\RuleAction; use FireflyIII\Models\TransactionJournal; +use FireflyIII\TransactionRules\Traits\RefreshNotesTrait; /** * Class AppendNotes. @@ -34,6 +35,7 @@ use FireflyIII\Models\TransactionJournal; */ class AppendNotes implements ActionInterface { + use RefreshNotesTrait; private RuleAction $action; /** @@ -46,6 +48,7 @@ class AppendNotes implements ActionInterface public function actOnArray(array $journal): bool { + $this->refreshNotes($journal); $dbNote = Note::where('noteable_id', (int)$journal['transaction_journal_id']) ->where('noteable_type', TransactionJournal::class) ->first(['notes.*']) diff --git a/app/TransactionRules/Actions/AppendNotesToDescription.php b/app/TransactionRules/Actions/AppendNotesToDescription.php index fbd1ebfea6..6b36165551 100644 --- a/app/TransactionRules/Actions/AppendNotesToDescription.php +++ b/app/TransactionRules/Actions/AppendNotesToDescription.php @@ -30,6 +30,7 @@ use FireflyIII\Models\Note; use FireflyIII\Models\RuleAction; use FireflyIII\Models\TransactionJournal; use FireflyIII\Support\Request\ConvertsDataTypes; +use FireflyIII\TransactionRules\Traits\RefreshNotesTrait; /** * Class AppendNotesToDescription @@ -38,7 +39,7 @@ use FireflyIII\Support\Request\ConvertsDataTypes; class AppendNotesToDescription implements ActionInterface { use ConvertsDataTypes; - + use RefreshNotesTrait; private RuleAction $action; /** @@ -52,6 +53,7 @@ class AppendNotesToDescription implements ActionInterface public function actOnArray(array $journal): bool { app('log')->debug('Now in AppendNotesToDescription'); + $this->refreshNotes($journal); /** @var null|TransactionJournal $object */ $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); diff --git a/app/TransactionRules/Actions/SetDescription.php b/app/TransactionRules/Actions/SetDescription.php index f423806e5e..a1886ce24f 100644 --- a/app/TransactionRules/Actions/SetDescription.php +++ b/app/TransactionRules/Actions/SetDescription.php @@ -26,12 +26,14 @@ namespace FireflyIII\TransactionRules\Actions; use FireflyIII\Events\TriggeredAuditLog; use FireflyIII\Models\RuleAction; use FireflyIII\Models\TransactionJournal; +use FireflyIII\TransactionRules\Traits\RefreshNotesTrait; /** * Class SetDescription. */ class SetDescription implements ActionInterface { + use RefreshNotesTrait; private RuleAction $action; /** @@ -44,6 +46,8 @@ class SetDescription implements ActionInterface public function actOnArray(array $journal): bool { + $this->refreshNotes($journal); + /** @var TransactionJournal $object */ $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']); $before = $object->description; diff --git a/app/TransactionRules/Engine/SearchRuleEngine.php b/app/TransactionRules/Engine/SearchRuleEngine.php index 2ca5a186ea..79eed1d4da 100644 --- a/app/TransactionRules/Engine/SearchRuleEngine.php +++ b/app/TransactionRules/Engine/SearchRuleEngine.php @@ -53,10 +53,10 @@ class SearchRuleEngine implements RuleEngineInterface public function __construct() { - $this->rules = new Collection(); - $this->groups = new Collection(); - $this->operators = []; - $this->resultCount = []; + $this->rules = new Collection(); + $this->groups = new Collection(); + $this->operators = []; + $this->resultCount = []; // always collect the triggers from the database, unless indicated otherwise. $this->refreshTriggers = true; @@ -73,7 +73,7 @@ class SearchRuleEngine implements RuleEngineInterface app('log')->debug('SearchRuleEngine::find()'); $collection = new Collection(); foreach ($this->rules as $rule) { - $found = new Collection(); + $found = new Collection(); if (true === $rule->strict) { $found = $this->findStrictRule($rule); } @@ -82,8 +82,9 @@ class SearchRuleEngine implements RuleEngineInterface } $collection = $collection->merge($found); } - $result = $collection->unique(); + $result = $collection->unique(); app('log')->debug(sprintf('SearchRuleEngine::find() returns %d unique transactions.', $result->count())); + return $result; } @@ -93,8 +94,8 @@ class SearchRuleEngine implements RuleEngineInterface private function findStrictRule(Rule $rule): Collection { app('log')->debug(sprintf('Now in findStrictRule(#%d)', $rule->id ?? 0)); - $searchArray = []; - $triggers = []; + $searchArray = []; + $triggers = []; if ($this->refreshTriggers) { $triggers = $rule->ruleTriggers()->orderBy('order', 'ASC')->get(); } @@ -125,7 +126,7 @@ class SearchRuleEngine implements RuleEngineInterface app('log')->debug(sprintf('SearchRuleEngine:: add local added operator: %s:"%s"', $operator['type'], $operator['value'])); $searchArray[$operator['type']][] = sprintf('"%s"', $operator['value']); } - $date = today(config('app.timezone')); + $date = today(config('app.timezone')); if ($this->hasSpecificJournalTrigger($searchArray)) { $date = $this->setDateFromJournalTrigger($searchArray); } @@ -145,7 +146,7 @@ class SearchRuleEngine implements RuleEngineInterface } } - $result = $searchEngine->searchTransactions(); + $result = $searchEngine->searchTransactions(); return $result->getCollection(); } @@ -170,7 +171,7 @@ class SearchRuleEngine implements RuleEngineInterface $dateTrigger = true; } } - $result = $journalTrigger && $dateTrigger; + $result = $journalTrigger && $dateTrigger; app('log')->debug(sprintf('Result of hasSpecificJournalTrigger is %s.', var_export($result, true))); return $result; @@ -189,7 +190,7 @@ class SearchRuleEngine implements RuleEngineInterface if (0 !== $journalId) { $repository = app(JournalRepositoryInterface::class); $repository->setUser($this->user); - $journal = $repository->find($journalId); + $journal = $repository->find($journalId); if (null !== $journal) { $date = $journal->date; app('log')->debug(sprintf('Found journal #%d with date %s.', $journal->id, $journal->date->format('Y-m-d'))); @@ -265,10 +266,10 @@ class SearchRuleEngine implements RuleEngineInterface $searchEngine->parseQuery(sprintf('%s:%s', $type, $value)); } - $result = $searchEngine->searchTransactions(); - $collection = $result->getCollection(); + $result = $searchEngine->searchTransactions(); + $collection = $result->getCollection(); app('log')->debug(sprintf('Found in this run, %d transactions', $collection->count())); - $total = $total->merge($collection); + $total = $total->merge($collection); app('log')->debug(sprintf('Total collection is now %d transactions', $total->count())); ++$count; // if trigger says stop processing, do so. @@ -282,7 +283,7 @@ class SearchRuleEngine implements RuleEngineInterface app('log')->debug(sprintf('Done running %d trigger(s)', $count)); // make collection unique - $unique = $total->unique( + $unique = $total->unique( static function (array $group) { $str = ''; foreach ($group['transactions'] as $transaction) { @@ -373,7 +374,7 @@ class SearchRuleEngine implements RuleEngineInterface $this->processResults($rule, $collection); app('log')->debug(sprintf('SearchRuleEngine:: done processing strict rule #%d', $rule->id)); - $result = $collection->count() > 0; + $result = $collection->count() > 0; if (true === $result) { app('log')->debug(sprintf('SearchRuleEngine:: rule #%d was triggered (on %d transaction(s)).', $rule->id, $collection->count())); @@ -546,6 +547,7 @@ class SearchRuleEngine implements RuleEngineInterface $transaction['notes'] = $dbNote->text; } Log::debug(sprintf('Notes of journal #%d filled in.', $transaction['transaction_journal_id'])); + return $transaction; } } diff --git a/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php b/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php index 7fb6012dcd..03b3d69970 100644 --- a/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php +++ b/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php @@ -31,26 +31,24 @@ class ActionExpressionLanguageProvider implements ExpressionFunctionProviderInte { public function getFunctions(): array { - return [ - new ExpressionFunction('constant', function ($str): string { - return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str . '!'); + return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'!'); }, function ($arguments, $str): string { if (!is_string($str)) { return $str; } - return strtolower($str . '!'); + return strtolower($str.'!'); }), new ExpressionFunction('enum', function ($str): string { - return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str . '?'); + return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'?'); }, function ($arguments, $str): string { if (!is_string($str)) { return $str; } - return strtolower($str) . '?'; + return strtolower($str).'?'; }), ExpressionFunction::fromPhp('substr'), diff --git a/app/TransactionRules/Traits/RefreshNotesTrait.php b/app/TransactionRules/Traits/RefreshNotesTrait.php index 58d80d3a9b..30cc6f2aec 100644 --- a/app/TransactionRules/Traits/RefreshNotesTrait.php +++ b/app/TransactionRules/Traits/RefreshNotesTrait.php @@ -29,11 +29,6 @@ use Illuminate\Support\Facades\Log; trait RefreshNotesTrait { - /** - * @param array $transaction - * - * @return array - */ final protected function refreshNotes(array $transaction): array { $transaction['notes'] = ''; @@ -42,7 +37,7 @@ trait RefreshNotesTrait $transaction['notes'] = $dbNote->text; } Log::debug(sprintf('Notes of journal #%d refreshed.', $transaction['transaction_journal_id'])); + return $transaction; } - } diff --git a/routes/api.php b/routes/api.php index 3bf56fac07..d41fae7d9e 100644 --- a/routes/api.php +++ b/routes/api.php @@ -607,7 +607,6 @@ Route::group( Route::put('{rule}', ['uses' => 'UpdateController@update', 'as' => 'update']); Route::delete('{rule}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']); - Route::get('{rule}/test', ['uses' => 'TriggerController@testRule', 'as' => 'test']); // TODO give results back Route::post('{rule}/trigger', ['uses' => 'TriggerController@triggerRule', 'as' => 'trigger']);