2020-08-22 06:01:37 -05:00
< ? php
2021-01-29 11:50:35 -06:00
/*
* SearchRuleEngine . php
* Copyright ( c ) 2021 james @ firefly - iii . org
*
* This file is part of Firefly III ( https :// github . com / firefly - iii ) .
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*/
2020-09-18 05:16:47 -05:00
declare ( strict_types = 1 );
2020-08-22 06:01:37 -05:00
namespace FireflyIII\TransactionRules\Engine ;
2021-02-03 03:41:41 -06:00
use Carbon\Carbon ;
2020-08-22 09:55:54 -05:00
use FireflyIII\Exceptions\FireflyException ;
use FireflyIII\Models\Rule ;
use FireflyIII\Models\RuleAction ;
2020-12-18 12:16:56 -06:00
use FireflyIII\Models\RuleGroup ;
2020-08-22 09:55:54 -05:00
use FireflyIII\Models\RuleTrigger ;
2021-02-03 03:41:41 -06:00
use FireflyIII\Repositories\Journal\JournalRepositoryInterface ;
2020-08-22 09:55:54 -05:00
use FireflyIII\Support\Search\SearchInterface ;
use FireflyIII\TransactionRules\Factory\ActionFactory ;
use FireflyIII\User ;
use Illuminate\Support\Collection ;
2020-08-22 06:01:37 -05:00
/**
* Class SearchRuleEngine
*/
class SearchRuleEngine implements RuleEngineInterface
{
2020-12-18 12:16:56 -06:00
private Collection $groups ;
2021-03-21 03:15:40 -05:00
private array $operators ;
2023-05-29 06:56:55 -05:00
private bool $refreshTriggers ;
2021-02-08 08:12:04 -06:00
private array $resultCount ;
2021-03-21 03:15:40 -05:00
private Collection $rules ;
private User $user ;
2020-08-22 09:55:54 -05:00
public function __construct ()
{
2024-01-01 07:43:56 -06:00
$this -> rules = new Collection ();
$this -> groups = new Collection ();
$this -> operators = [];
$this -> resultCount = [];
2023-03-14 12:09:44 -05:00
// always collect the triggers from the database, unless indicated otherwise.
$this -> refreshTriggers = true ;
2020-08-22 09:55:54 -05:00
}
2021-03-21 03:15:40 -05:00
public function addOperator ( array $operator ) : void
2020-08-22 09:55:54 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( 'Add extra operator: ' , $operator );
2021-03-21 03:15:40 -05:00
$this -> operators [] = $operator ;
2020-08-22 09:55:54 -05:00
}
2021-03-21 03:15:40 -05:00
public function find () : Collection
2020-08-22 09:55:54 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( 'SearchRuleEngine::find()' );
2022-10-30 08:24:37 -05:00
$collection = new Collection ();
2021-03-21 03:15:40 -05:00
foreach ( $this -> rules as $rule ) {
2024-01-01 07:43:56 -06:00
$found = new Collection ();
2021-03-21 03:15:40 -05:00
if ( true === $rule -> strict ) {
$found = $this -> findStrictRule ( $rule );
2020-08-22 09:55:54 -05:00
}
2021-03-21 03:15:40 -05:00
if ( false === $rule -> strict ) {
$found = $this -> findNonStrictRule ( $rule );
2020-12-18 12:16:56 -06:00
}
2021-03-21 03:15:40 -05:00
$collection = $collection -> merge ( $found );
2020-12-18 12:16:56 -06:00
}
2020-08-22 09:55:54 -05:00
2021-03-21 03:15:40 -05:00
return $collection -> unique ();
2020-08-22 09:55:54 -05:00
}
2023-12-20 12:35:52 -06:00
public function setUser ( User $user ) : void
{
$this -> user = $user ;
$this -> operators = [];
}
/**
* @ throws FireflyException
*/
public function fire () : void
{
$this -> resultCount = [];
app ( 'log' ) -> debug ( 'SearchRuleEngine::fire()!' );
// if rules and no rule groups, file each rule separately.
if ( 0 !== $this -> rules -> count ()) {
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: found %d rule(s) to fire.' , $this -> rules -> count ()));
2023-12-24 23:32:43 -06:00
/** @var Rule $rule */
2023-12-20 12:35:52 -06:00
foreach ( $this -> rules as $rule ) {
2023-12-24 23:32:43 -06:00
$result = $this -> fireRule ( $rule );
if ( true === $result && $rule -> stop_processing ) {
app ( 'log' ) -> debug ( sprintf ( 'Rule #%d has triggered and executed, but calls to stop processing. Since not in the context of a group, do not stop.' , $rule -> id ));
}
if ( false === $result && $rule -> stop_processing ) {
app ( 'log' ) -> debug ( sprintf ( 'Rule #%d has triggered and changed nothing, but calls to stop processing. Do not stop.' , $rule -> id ));
}
2023-12-20 12:35:52 -06:00
}
app ( 'log' ) -> debug ( 'SearchRuleEngine:: done processing all rules!' );
return ;
}
if ( 0 !== $this -> groups -> count ()) {
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: found %d rule group(s) to fire.' , $this -> groups -> count ()));
// fire each group:
/** @var RuleGroup $group */
foreach ( $this -> groups as $group ) {
$this -> fireGroup ( $group );
}
}
app ( 'log' ) -> debug ( 'SearchRuleEngine:: done processing all rules!' );
}
/**
* Return the number of changed transactions from the previous " fire " action .
*/
public function getResults () : int
{
return count ( $this -> resultCount );
}
public function setRefreshTriggers ( bool $refreshTriggers ) : void
{
$this -> refreshTriggers = $refreshTriggers ;
}
public function setRuleGroups ( Collection $ruleGroups ) : void
{
app ( 'log' ) -> debug ( __METHOD__ );
foreach ( $ruleGroups as $group ) {
if ( $group instanceof RuleGroup ) {
app ( 'log' ) -> debug ( sprintf ( 'Adding a rule group to the SearchRuleEngine: #%d ("%s")' , $group -> id , $group -> title ));
$this -> groups -> push ( $group );
}
}
}
public function setRules ( Collection $rules ) : void
{
app ( 'log' ) -> debug ( __METHOD__ );
foreach ( $rules as $rule ) {
if ( $rule instanceof Rule ) {
app ( 'log' ) -> debug ( sprintf ( 'Adding a rule to the SearchRuleEngine: #%d ("%s")' , $rule -> id , $rule -> title ));
$this -> rules -> push ( $rule );
}
}
}
2021-03-21 03:15:40 -05:00
/**
2023-06-21 05:34:58 -05:00
* Finds the transactions a strict rule will execute on .
2021-03-21 03:15:40 -05:00
*/
2023-06-21 05:34:58 -05:00
private function findStrictRule ( Rule $rule ) : Collection
2021-03-21 03:15:40 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Now in findStrictRule(#%d)' , $rule -> id ? ? 0 ));
2024-01-01 07:43:56 -06:00
$searchArray = [];
$triggers = [];
2023-06-21 05:34:58 -05:00
if ( $this -> refreshTriggers ) {
$triggers = $rule -> ruleTriggers () -> orderBy ( 'order' , 'ASC' ) -> get ();
}
if ( ! $this -> refreshTriggers ) {
$triggers = $rule -> ruleTriggers ;
}
2021-05-01 11:54:11 -05:00
2023-06-21 05:34:58 -05:00
/** @var RuleTrigger $ruleTrigger */
foreach ( $triggers as $ruleTrigger ) {
if ( false === $ruleTrigger -> active ) {
continue ;
2021-03-21 03:15:40 -05:00
}
2021-05-01 11:54:11 -05:00
2024-01-01 04:31:14 -06:00
// if the trigger needs no context, value is different:
2023-12-24 23:32:43 -06:00
$needsContext = ( bool ) ( config ( sprintf ( 'search.operators.%s.needs_context' , $ruleTrigger -> trigger_type )) ? ? true );
2023-06-21 05:34:58 -05:00
if ( false === $needsContext ) {
2023-11-25 12:03:51 -06:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: add a rule trigger (no context): %s:true' , $ruleTrigger -> trigger_type ));
2023-06-21 05:34:58 -05:00
$searchArray [ $ruleTrigger -> trigger_type ][] = 'true' ;
}
if ( true === $needsContext ) {
2023-11-25 12:03:51 -06:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: add a rule trigger (context): %s:"%s"' , $ruleTrigger -> trigger_type , $ruleTrigger -> trigger_value ));
2023-06-21 05:34:58 -05:00
$searchArray [ $ruleTrigger -> trigger_type ][] = sprintf ( '"%s"' , $ruleTrigger -> trigger_value );
}
2021-03-21 03:15:40 -05:00
}
2023-06-21 05:34:58 -05:00
// add local operators:
foreach ( $this -> operators as $operator ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: add local added operator: %s:"%s"' , $operator [ 'type' ], $operator [ 'value' ]));
2023-06-21 05:34:58 -05:00
$searchArray [ $operator [ 'type' ]][] = sprintf ( '"%s"' , $operator [ 'value' ]);
}
2024-01-01 07:43:56 -06:00
$date = today ( config ( 'app.timezone' ));
2023-06-21 05:34:58 -05:00
if ( $this -> hasSpecificJournalTrigger ( $searchArray )) {
$date = $this -> setDateFromJournalTrigger ( $searchArray );
}
2023-11-25 12:03:51 -06:00
2023-06-21 05:34:58 -05:00
// build and run the search engine.
$searchEngine = app ( SearchInterface :: class );
$searchEngine -> setUser ( $this -> user );
$searchEngine -> setPage ( 1 );
$searchEngine -> setLimit ( 31337 );
$searchEngine -> setDate ( $date );
2024-01-01 04:31:14 -06:00
app ( 'log' ) -> debug ( 'Search array' , $searchArray );
2023-06-21 05:34:58 -05:00
foreach ( $searchArray as $type => $searches ) {
foreach ( $searches as $value ) {
2023-11-25 12:03:51 -06:00
$query = sprintf ( '%s:%s' , $type , $value );
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: add query "%s"' , $query ));
$searchEngine -> parseQuery ( $query );
2021-03-21 03:15:40 -05:00
}
}
2023-06-21 05:34:58 -05:00
2024-01-01 07:43:56 -06:00
$result = $searchEngine -> searchTransactions ();
2023-06-21 05:34:58 -05:00
return $result -> getCollection ();
2021-03-21 03:15:40 -05:00
}
/**
2023-06-21 05:34:58 -05:00
* Search in the triggers of this particular search and if it contains
* one search operator for " journal_id " it means the date ranges
* in the search may need to be updated .
2021-03-21 03:15:40 -05:00
*/
2023-06-21 05:34:58 -05:00
private function hasSpecificJournalTrigger ( array $array ) : bool
2021-03-21 03:15:40 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( 'Now in hasSpecificJournalTrigger.' );
2023-06-21 05:34:58 -05:00
$journalTrigger = false ;
$dateTrigger = false ;
foreach ( $array as $triggerName => $values ) {
if ( 'journal_id' === $triggerName && is_array ( $values ) && 1 === count ( $values )) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( 'Found a journal_id trigger with 1 journal, true.' );
2023-06-21 05:34:58 -05:00
$journalTrigger = true ;
}
if ( in_array ( $triggerName , [ 'date_is' , 'date' , 'on' , 'date_before' , 'before' , 'date_after' , 'after' ], true )) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( 'Found a date related trigger, set to true.' );
2023-06-21 05:34:58 -05:00
$dateTrigger = true ;
}
}
2024-01-01 07:43:56 -06:00
$result = $journalTrigger && $dateTrigger ;
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Result of hasSpecificJournalTrigger is %s.' , var_export ( $result , true )));
2021-03-21 03:15:40 -05:00
2023-06-21 05:34:58 -05:00
return $result ;
2021-03-21 03:15:40 -05:00
}
2023-06-21 05:34:58 -05:00
private function setDateFromJournalTrigger ( array $array ) : Carbon
2021-03-21 03:15:40 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( 'Now in setDateFromJournalTrigger()' );
2023-06-21 05:34:58 -05:00
$journalId = 0 ;
foreach ( $array as $triggerName => $values ) {
if ( 'journal_id' === $triggerName && is_array ( $values ) && 1 === count ( $values )) {
2023-12-24 23:32:43 -06:00
$journalId = ( int ) trim ( $values [ 0 ] ? ? '"0"' , '"' ); // follows format "123".
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Found journal ID #%d' , $journalId ));
2021-03-21 03:15:40 -05:00
}
}
2023-06-21 05:34:58 -05:00
if ( 0 !== $journalId ) {
$repository = app ( JournalRepositoryInterface :: class );
$repository -> setUser ( $this -> user );
2024-01-01 07:43:56 -06:00
$journal = $repository -> find ( $journalId );
2023-06-21 05:34:58 -05:00
if ( null !== $journal ) {
$date = $journal -> date ;
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Found journal #%d with date %s.' , $journal -> id , $journal -> date -> format ( 'Y-m-d' )));
2021-03-21 03:15:40 -05:00
2023-06-21 05:34:58 -05:00
return $date ;
2021-03-21 03:15:40 -05:00
}
}
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( 'Found no journal, return default date.' );
2023-06-21 05:34:58 -05:00
return today ( config ( 'app.timezone' ));
2021-03-21 03:15:40 -05:00
}
2021-09-18 03:26:12 -05:00
private function findNonStrictRule ( Rule $rule ) : Collection
{
2024-01-19 23:53:43 -06:00
app ( 'log' ) -> debug ( sprintf ( 'findNonStrictRule(#%d)' , $rule -> id ));
2021-09-18 03:26:12 -05:00
// start a search query for individual each trigger:
2023-03-14 12:09:44 -05:00
$total = new Collection ();
$count = 0 ;
$triggers = [];
if ( $this -> refreshTriggers ) {
2024-01-19 23:53:43 -06:00
app ( 'log' ) -> debug ( 'Will refresh triggers.' );
2023-03-14 12:09:44 -05:00
$triggers = $rule -> ruleTriggers () -> orderBy ( 'order' , 'ASC' ) -> get ();
}
if ( ! $this -> refreshTriggers ) {
2024-01-19 23:53:43 -06:00
app ( 'log' ) -> debug ( 'Will not refresh triggers.' );
2023-03-14 12:09:44 -05:00
$triggers = $rule -> ruleTriggers ;
}
2024-01-19 23:53:43 -06:00
app ( 'log' ) -> debug ( sprintf ( 'Will run %d trigger(s).' , count ( $triggers )));
2021-09-18 03:26:12 -05:00
/** @var RuleTrigger $ruleTrigger */
foreach ( $triggers as $ruleTrigger ) {
2024-01-19 23:53:43 -06:00
app ( 'log' ) -> debug ( sprintf ( 'Now at rule trigger #%d: %s:"%s" (%s).' , $ruleTrigger -> id , $ruleTrigger -> trigger_type , $ruleTrigger -> trigger_value , var_export ( $ruleTrigger -> stop_processing , true )));
2021-09-18 03:26:12 -05:00
if ( false === $ruleTrigger -> active ) {
2024-01-19 23:53:43 -06:00
app ( 'log' ) -> debug ( 'Trigger is not active, continue.' );
2024-01-20 00:04:19 -06:00
2021-09-18 03:26:12 -05:00
continue ;
}
if ( 'user_action' === $ruleTrigger -> trigger_type ) {
2024-01-19 23:53:43 -06:00
app ( 'log' ) -> debug ( 'Skip trigger type. continue.' );
2023-12-20 12:35:52 -06:00
2021-09-18 03:26:12 -05:00
continue ;
}
$searchArray = [];
2022-03-20 11:11:33 -05:00
$needsContext = config ( sprintf ( 'search.operators.%s.needs_context' , $ruleTrigger -> trigger_type )) ? ? true ;
2021-09-18 03:26:12 -05:00
if ( false === $needsContext ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: non strict, will search for: %s:true' , $ruleTrigger -> trigger_type ));
2021-09-18 03:26:12 -05:00
$searchArray [ $ruleTrigger -> trigger_type ] = 'true' ;
}
if ( true === $needsContext ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: non strict, will search for: %s:"%s"' , $ruleTrigger -> trigger_type , $ruleTrigger -> trigger_value ));
2021-09-18 03:26:12 -05:00
$searchArray [ $ruleTrigger -> trigger_type ] = sprintf ( '"%s"' , $ruleTrigger -> trigger_value );
}
// then, add local operators as well:
foreach ( $this -> operators as $operator ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: add local added operator: %s:"%s"' , $operator [ 'type' ], $operator [ 'value' ]));
2021-09-18 03:26:12 -05:00
$searchArray [ $operator [ 'type' ]] = sprintf ( '"%s"' , $operator [ 'value' ]);
}
// build and run the search engine.
$searchEngine = app ( SearchInterface :: class );
$searchEngine -> setUser ( $this -> user );
$searchEngine -> setPage ( 1 );
$searchEngine -> setLimit ( 31337 );
foreach ( $searchArray as $type => $value ) {
$searchEngine -> parseQuery ( sprintf ( '%s:%s' , $type , $value ));
}
2024-01-01 07:43:56 -06:00
$result = $searchEngine -> searchTransactions ();
$collection = $result -> getCollection ();
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Found in this run, %d transactions' , $collection -> count ()));
2024-01-01 07:43:56 -06:00
$total = $total -> merge ( $collection );
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Total collection is now %d transactions' , $total -> count ()));
2023-12-20 12:35:52 -06:00
++ $count ;
2023-12-24 23:03:56 -06:00
// if trigger says stop processing, do so.
2024-01-19 23:53:43 -06:00
if ( $ruleTrigger -> stop_processing && $result -> count () > 0 ) {
2023-12-24 23:03:56 -06:00
app ( 'log' ) -> debug ( 'The trigger says to stop processing, so stop processing other triggers.' );
break ;
}
2021-09-18 03:26:12 -05:00
}
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Total collection is now %d transactions' , $total -> count ()));
app ( 'log' ) -> debug ( sprintf ( 'Done running %d trigger(s)' , $count ));
2021-09-18 03:26:12 -05:00
// make collection unique
2024-01-01 07:43:56 -06:00
$unique = $total -> unique (
2023-11-04 08:18:49 -05:00
static function ( array $group ) {
2021-09-18 03:26:12 -05:00
$str = '' ;
foreach ( $group [ 'transactions' ] as $transaction ) {
$str = sprintf ( '%s%d' , $str , $transaction [ 'transaction_journal_id' ]);
}
2023-12-20 12:35:52 -06:00
return sprintf ( '%d%s' , $group [ 'id' ], $str );
// app('log')->debug(sprintf('Return key: %s ', $key));
2021-09-18 03:26:12 -05:00
}
);
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: Found %d transactions using search engine.' , $unique -> count ()));
2021-09-18 03:26:12 -05:00
return $unique ;
}
/**
* Returns true if the rule has been triggered .
*
* @ throws FireflyException
*/
private function fireRule ( Rule $rule ) : bool
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Now going to fire rule #%d' , $rule -> id ));
2021-09-18 03:26:12 -05:00
if ( false === $rule -> active ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Rule #%d is not active!' , $rule -> id ));
2021-09-18 03:26:12 -05:00
return false ;
}
if ( true === $rule -> strict ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Rule #%d is a strict rule.' , $rule -> id ));
2021-09-18 03:26:12 -05:00
return $this -> fireStrictRule ( $rule );
}
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Rule #%d is not strict rule.' , $rule -> id ));
2021-09-18 03:26:12 -05:00
return $this -> fireNonStrictRule ( $rule );
}
/**
* Return true if the rule is fired ( the collection is larger than zero ) .
*
* @ throws FireflyException
*/
private function fireStrictRule ( Rule $rule ) : bool
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine::fireStrictRule(%d)!' , $rule -> id ));
2021-09-18 03:26:12 -05:00
$collection = $this -> findStrictRule ( $rule );
$this -> processResults ( $rule , $collection );
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: done processing strict rule #%d' , $rule -> id ));
2021-09-18 03:26:12 -05:00
2024-01-01 07:43:56 -06:00
$result = $collection -> count () > 0 ;
2021-09-18 03:26:12 -05:00
if ( true === $result ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: rule #%d was triggered (on %d transaction(s)).' , $rule -> id , $collection -> count ()));
2021-09-18 03:26:12 -05:00
return true ;
}
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: rule #%d was not triggered (on %d transaction(s)).' , $rule -> id , $collection -> count ()));
2021-09-18 03:26:12 -05:00
return false ;
}
2020-08-22 09:55:54 -05:00
/**
2023-06-21 05:34:58 -05:00
* @ throws FireflyException
2020-08-22 09:55:54 -05:00
*/
2023-06-21 05:34:58 -05:00
private function processResults ( Rule $rule , Collection $collection ) : void
2020-08-22 09:55:54 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: Going to process %d results.' , $collection -> count ()));
2023-12-20 12:35:52 -06:00
2023-06-21 05:34:58 -05:00
/** @var array $group */
foreach ( $collection as $group ) {
$this -> processTransactionGroup ( $rule , $group );
2020-08-22 09:55:54 -05:00
}
2023-06-21 05:34:58 -05:00
}
2023-05-29 06:56:55 -05:00
2023-06-21 05:34:58 -05:00
/**
* @ throws FireflyException
*/
private function processTransactionGroup ( Rule $rule , array $group ) : void
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: Will now execute actions on transaction group #%d' , $group [ 'id' ]));
2023-12-20 12:35:52 -06:00
2023-06-21 05:34:58 -05:00
/** @var array $transaction */
foreach ( $group [ 'transactions' ] as $transaction ) {
$this -> processTransactionJournal ( $rule , $transaction );
}
2020-08-22 09:55:54 -05:00
}
/**
* @ throws FireflyException
*/
2023-06-21 05:34:58 -05:00
private function processTransactionJournal ( Rule $rule , array $transaction ) : void
2020-08-22 09:55:54 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: Will now execute actions on transaction journal #%d' , $transaction [ 'transaction_journal_id' ]));
2023-06-21 05:34:58 -05:00
$actions = $rule -> ruleActions () -> orderBy ( 'order' , 'ASC' ) -> get ();
2023-12-20 12:35:52 -06:00
2023-06-21 05:34:58 -05:00
/** @var RuleAction $ruleAction */
foreach ( $actions as $ruleAction ) {
if ( false === $ruleAction -> active ) {
continue ;
}
$break = $this -> processRuleAction ( $ruleAction , $transaction );
if ( true === $break ) {
break ;
}
2020-08-22 09:55:54 -05:00
}
}
2020-08-22 06:01:37 -05:00
2020-08-22 09:55:54 -05:00
/**
* @ throws FireflyException
*/
private function processRuleAction ( RuleAction $ruleAction , array $transaction ) : bool
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Executing rule action "%s" with value "%s"' , $ruleAction -> action_type , $ruleAction -> action_value ));
2020-08-22 09:55:54 -05:00
$actionClass = ActionFactory :: getAction ( $ruleAction );
2021-02-08 08:12:04 -06:00
$result = $actionClass -> actOnArray ( $transaction );
$journalId = $transaction [ 'transaction_journal_id' ] ? ? 0 ;
if ( true === $result ) {
2021-04-06 06:30:09 -05:00
$this -> resultCount [ $journalId ] = array_key_exists ( $journalId , $this -> resultCount ) ? $this -> resultCount [ $journalId ] ++ : 1 ;
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug (
2021-02-08 08:12:04 -06:00
sprintf (
'Action "%s" on journal #%d was executed, so count a result. Updated transaction journal count is now %d.' ,
$ruleAction -> action_type ,
$transaction [ 'transaction_journal_id' ] ? ? 0 ,
count ( $this -> resultCount ),
)
);
}
if ( false === $result ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Action "%s" reports NO changes were made.' , $ruleAction -> action_type ));
2021-02-08 08:12:04 -06:00
}
// pick up from the action if it actually acted or not:
2023-12-24 23:03:56 -06:00
if ( $ruleAction -> stop_processing && true === $result ) {
app ( 'log' ) -> debug ( sprintf ( 'Rule action "%s" reports changes AND asks to break, so break!' , $ruleAction -> action_type ));
2020-12-18 12:16:56 -06:00
2020-08-22 09:55:54 -05:00
return true ;
}
2023-12-24 23:03:56 -06:00
if ( $ruleAction -> stop_processing && false === $result ) {
app ( 'log' ) -> debug ( sprintf ( 'Rule action "%s" reports NO changes AND asks to break, but we wont break!' , $ruleAction -> action_type ));
}
2020-12-18 12:16:56 -06:00
2020-08-22 09:55:54 -05:00
return false ;
}
2020-08-24 00:03:17 -05:00
2020-08-24 00:31:50 -05:00
/**
2023-06-21 05:34:58 -05:00
* Return true if the rule is fired ( the collection is larger than zero ) .
*
2020-08-24 00:31:50 -05:00
* @ throws FireflyException
*/
2023-06-21 05:34:58 -05:00
private function fireNonStrictRule ( Rule $rule ) : bool
2020-08-24 00:31:50 -05:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine::fireNonStrictRule(%d)!' , $rule -> id ));
2023-06-21 05:34:58 -05:00
$collection = $this -> findNonStrictRule ( $rule );
$this -> processResults ( $rule , $collection );
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'SearchRuleEngine:: done processing non-strict rule #%d' , $rule -> id ));
2023-06-21 05:34:58 -05:00
return $collection -> count () > 0 ;
2020-08-24 00:31:50 -05:00
}
2020-12-18 12:16:56 -06:00
/**
2021-09-18 03:21:29 -05:00
* @ throws FireflyException
2020-12-18 12:16:56 -06:00
*/
2023-06-21 05:34:58 -05:00
private function fireGroup ( RuleGroup $group ) : void
2020-12-18 12:16:56 -06:00
{
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Going to fire group #%d with %d rule(s)' , $group -> id , $group -> rules -> count ()));
2023-12-20 12:35:52 -06:00
2023-06-21 05:34:58 -05:00
/** @var Rule $rule */
foreach ( $group -> rules as $rule ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'Going to fire rule #%d from group #%d' , $rule -> id , $group -> id ));
2023-06-21 05:34:58 -05:00
$result = $this -> fireRule ( $rule );
if ( true === $result && true === $rule -> stop_processing ) {
2023-10-29 00:33:43 -05:00
app ( 'log' ) -> debug ( sprintf ( 'The rule was triggered and rule->stop_processing = true, so group #%d will stop processing further rules.' , $group -> id ));
2023-06-21 05:34:58 -05:00
return ;
2020-12-18 12:16:56 -06:00
}
}
}
2020-12-21 22:35:06 -06:00
}