2020-08-09 11:58:18 -05:00
< ? php
/*
2020-08-22 06:01:37 -05:00
* OperatorQuerySearch . php
2020-08-09 11:58:18 -05:00
* Copyright ( c ) 2020 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 />.
*/
namespace FireflyIII\Support\Search ;
use Carbon\Carbon ;
use FireflyIII\Exceptions\FireflyException ;
use FireflyIII\Helpers\Collector\GroupCollectorInterface ;
2020-08-18 10:48:27 -05:00
use FireflyIII\Models\Account ;
2020-08-22 05:24:01 -05:00
use FireflyIII\Models\AccountMeta ;
2020-08-09 11:58:18 -05:00
use FireflyIII\Models\AccountType ;
2020-08-22 05:24:01 -05:00
use FireflyIII\Models\TransactionCurrency ;
2020-08-09 11:58:18 -05:00
use FireflyIII\Repositories\Account\AccountRepositoryInterface ;
use FireflyIII\Repositories\Bill\BillRepositoryInterface ;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface ;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface ;
2020-08-22 05:24:01 -05:00
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface ;
2020-08-09 11:58:18 -05:00
use FireflyIII\Repositories\Tag\TagRepositoryInterface ;
2020-08-22 05:24:01 -05:00
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface ;
2020-08-22 06:01:37 -05:00
use FireflyIII\Support\ParseDateString ;
2020-08-09 11:58:18 -05:00
use FireflyIII\User ;
use Gdbots\QueryParser\Node\Field ;
use Gdbots\QueryParser\Node\Node ;
2020-08-18 10:48:27 -05:00
use Gdbots\QueryParser\Node\Phrase ;
2020-08-09 11:58:18 -05:00
use Gdbots\QueryParser\Node\Word ;
use Gdbots\QueryParser\ParsedQuery ;
use Gdbots\QueryParser\QueryParser ;
use Illuminate\Pagination\LengthAwarePaginator ;
use Illuminate\Support\Collection ;
use Log ;
/**
2020-08-22 06:01:37 -05:00
* Class OperatorQuerySearch
2020-08-09 11:58:18 -05:00
*/
2020-08-22 06:01:37 -05:00
class OperatorQuerySearch implements SearchInterface
2020-08-09 11:58:18 -05:00
{
2020-08-22 05:24:01 -05:00
private AccountRepositoryInterface $accountRepository ;
private BillRepositoryInterface $billRepository ;
private BudgetRepositoryInterface $budgetRepository ;
private CategoryRepositoryInterface $categoryRepository ;
private TagRepositoryInterface $tagRepository ;
private CurrencyRepositoryInterface $currencyRepository ;
private TransactionTypeRepositoryInterface $typeRepository ;
private User $user ;
private ParsedQuery $query ;
private int $page ;
2020-08-22 09:55:54 -05:00
private int $limit ;
2020-08-22 05:24:01 -05:00
private array $words ;
private array $validOperators ;
private GroupCollectorInterface $collector ;
private float $startTime ;
private Collection $modifiers ; // obsolete
private Collection $operators ;
2020-08-09 11:58:18 -05:00
2020-08-18 10:48:27 -05:00
/**
2020-08-22 06:01:37 -05:00
* OperatorQuerySearch constructor .
2020-08-18 10:48:27 -05:00
* @ codeCoverageIgnore
*/
2020-08-09 11:58:18 -05:00
public function __construct ()
{
2020-08-22 06:01:37 -05:00
Log :: debug ( 'Constructed OperatorQuerySearch' );
2020-08-22 05:24:01 -05:00
$this -> modifiers = new Collection ; // obsolete
$this -> operators = new Collection ;
2020-08-09 11:58:18 -05:00
$this -> page = 1 ;
$this -> words = [];
2020-08-22 09:55:54 -05:00
$this -> limit = 25 ;
2020-08-18 10:48:27 -05:00
$this -> validOperators = array_keys ( config ( 'firefly.search.operators' ));
2020-08-09 11:58:18 -05:00
$this -> startTime = microtime ( true );
$this -> accountRepository = app ( AccountRepositoryInterface :: class );
$this -> categoryRepository = app ( CategoryRepositoryInterface :: class );
$this -> budgetRepository = app ( BudgetRepositoryInterface :: class );
$this -> billRepository = app ( BillRepositoryInterface :: class );
$this -> tagRepository = app ( TagRepositoryInterface :: class );
2020-08-22 05:24:01 -05:00
$this -> currencyRepository = app ( CurrencyRepositoryInterface :: class );
$this -> typeRepository = app ( TransactionTypeRepositoryInterface :: class );
2020-08-09 11:58:18 -05:00
}
/**
* @ inheritDoc
2020-08-18 10:48:27 -05:00
* @ codeCoverageIgnore
2020-08-09 11:58:18 -05:00
*/
public function getModifiers () : Collection
{
2020-08-22 05:25:00 -05:00
return $this -> getOperators ();
2020-08-22 05:24:01 -05:00
}
/**
* @ inheritDoc
* @ codeCoverageIgnore
*/
public function getOperators () : Collection
{
return $this -> operators ;
2020-08-09 11:58:18 -05:00
}
/**
* @ inheritDoc
2020-08-18 10:48:27 -05:00
* @ codeCoverageIgnore
2020-08-09 11:58:18 -05:00
*/
public function getWordsAsString () : string
{
return implode ( ' ' , $this -> words );
}
2020-08-22 05:24:01 -05:00
/**
* @ return array
*/
public function getWords () : array
{
return $this -> words ;
}
2020-08-09 11:58:18 -05:00
/**
* @ inheritDoc
2020-08-18 10:48:27 -05:00
* @ codeCoverageIgnore
2020-08-09 11:58:18 -05:00
*/
public function setPage ( int $page ) : void
{
$this -> page = $page ;
}
/**
* @ inheritDoc
2020-08-18 10:48:27 -05:00
* @ codeCoverageIgnore
2020-08-09 11:58:18 -05:00
*/
public function hasModifiers () : bool
{
die ( __METHOD__ );
}
/**
* @ inheritDoc
2020-08-18 10:48:27 -05:00
* @ throws FireflyException
2020-08-09 11:58:18 -05:00
*/
public function parseQuery ( string $query )
{
2020-08-18 10:48:27 -05:00
Log :: debug ( sprintf ( 'Now in parseQuery(%s)' , $query ));
2020-08-09 11:58:18 -05:00
$parser = new QueryParser ();
$this -> query = $parser -> parse ( $query );
$this -> collector = app ( GroupCollectorInterface :: class );
2020-08-18 10:48:27 -05:00
$this -> collector -> setUser ( $this -> user );
2020-08-22 09:55:54 -05:00
$this -> collector -> setLimit ( $this -> limit ) -> setPage ( $this -> page );
2020-08-18 10:48:27 -05:00
$this -> collector -> withAccountInformation () -> withCategoryInformation () -> withBudgetInformation ();
Log :: debug ( sprintf ( 'Found %d node(s)' , count ( $this -> query -> getNodes ())));
2020-08-09 11:58:18 -05:00
foreach ( $this -> query -> getNodes () as $searchNode ) {
$this -> handleSearchNode ( $searchNode );
}
$this -> collector -> setSearchWords ( $this -> words );
}
/**
* @ inheritDoc
2020-08-18 10:48:27 -05:00
* @ codeCoverageIgnore
2020-08-09 11:58:18 -05:00
*/
public function searchTime () : float
{
return microtime ( true ) - $this -> startTime ;
}
/**
* @ inheritDoc
2020-08-22 05:24:01 -05:00
* @ throws FireflyException
2020-08-09 11:58:18 -05:00
*/
public function searchTransactions () : LengthAwarePaginator
{
2020-08-22 05:24:01 -05:00
if ( 0 === count ( $this -> getWords ()) && 0 === count ( $this -> getOperators ())) {
throw new FireflyException ( 'Search query is empty.' );
}
2020-08-09 11:58:18 -05:00
return $this -> collector -> getPaginatedGroups ();
}
/**
* @ inheritDoc
2020-08-18 10:48:27 -05:00
* @ codeCoverageIgnore
2020-08-09 11:58:18 -05:00
*/
public function setUser ( User $user ) : void
{
$this -> user = $user ;
$this -> accountRepository -> setUser ( $user );
$this -> billRepository -> setUser ( $user );
$this -> categoryRepository -> setUser ( $user );
$this -> budgetRepository -> setUser ( $user );
2020-08-22 09:55:54 -05:00
$this -> setLimit (( int ) app ( 'preferences' ) -> getForUser ( $user , 'listPageSize' , 50 ) -> data );
2020-08-09 11:58:18 -05:00
}
/**
* @ param Node $searchNode
* @ throws FireflyException
*/
private function handleSearchNode ( Node $searchNode ) : void
{
$class = get_class ( $searchNode );
switch ( $class ) {
default :
2020-08-18 10:48:27 -05:00
Log :: error ( sprintf ( 'Cannot handle node %s' , $class ));
2020-08-09 11:58:18 -05:00
throw new FireflyException ( sprintf ( 'Firefly III search cant handle "%s"-nodes' , $class ));
case Word :: class :
2020-08-18 10:48:27 -05:00
case Phrase :: class :
Log :: debug ( sprintf ( 'Now handle %s' , $class ));
2020-08-09 11:58:18 -05:00
$this -> words [] = $searchNode -> getValue ();
break ;
case Field :: class :
2020-08-18 10:48:27 -05:00
Log :: debug ( sprintf ( 'Now handle %s' , $class ));
2020-08-09 11:58:18 -05:00
/** @var Field $searchNode */
// used to search for x:y
$operator = $searchNode -> getValue ();
$value = $searchNode -> getNode () -> getValue ();
// must be valid operator:
if ( in_array ( $operator , $this -> validOperators , true )) {
2020-08-22 05:24:01 -05:00
if ( $this -> updateCollector ( $operator , $value )) {
$this -> operators -> push (
[
2020-08-26 23:19:16 -05:00
'type' => self :: getRootOperator ( $operator ),
2020-08-22 05:24:01 -05:00
'value' => $value ,
]
);
}
2020-08-09 11:58:18 -05:00
}
break ;
}
}
/**
* @ param string $operator
* @ param string $value
2020-08-22 05:24:01 -05:00
* @ return bool
2020-08-18 10:48:27 -05:00
* @ throws FireflyException
2020-08-09 11:58:18 -05:00
*/
2020-08-22 05:24:01 -05:00
private function updateCollector ( string $operator , string $value ) : bool
2020-08-09 11:58:18 -05:00
{
2020-08-18 10:48:27 -05:00
Log :: debug ( sprintf ( 'updateCollector(%s, %s)' , $operator , $value ));
2020-08-22 05:24:01 -05:00
// check if alias, replace if necessary:
2020-08-26 23:19:16 -05:00
$operator = self :: getRootOperator ( $operator );
2020-08-22 05:24:01 -05:00
2020-08-09 11:58:18 -05:00
switch ( $operator ) {
default :
2020-08-18 10:48:27 -05:00
Log :: error ( sprintf ( 'No such operator: %s' , $operator ));
throw new FireflyException ( sprintf ( 'Unsupported search operator: "%s"' , $operator ));
// some search operators are ignored, basically:
case 'user_action' :
Log :: info ( sprintf ( 'Ignore search operator "%s"' , $operator ));
2020-08-22 05:24:01 -05:00
return false ;
//
// all account related searches:
//
case 'source_account_starts' :
$this -> searchAccount ( $value , 1 , 1 );
break ;
case 'source_account_ends' :
$this -> searchAccount ( $value , 1 , 2 );
break ;
case 'source_account_is' :
$this -> searchAccount ( $value , 1 , 4 );
break ;
case 'source_account_nr_starts' :
$this -> searchAccountNr ( $value , 1 , 1 );
2020-08-18 10:48:27 -05:00
break ;
2020-08-22 05:24:01 -05:00
case 'source_account_nr_ends' :
$this -> searchAccountNr ( $value , 1 , 2 );
2020-08-18 10:48:27 -05:00
break ;
2020-08-22 05:24:01 -05:00
case 'source_account_nr_is' :
$this -> searchAccountNr ( $value , 1 , 4 );
2020-08-18 10:48:27 -05:00
break ;
2020-08-22 05:24:01 -05:00
case 'source_account_nr_contains' :
$this -> searchAccountNr ( $value , 1 , 3 );
break ;
case 'source_account_contains' :
$this -> searchAccount ( $value , 1 , 3 );
break ;
case 'source_account_id' :
2020-08-22 06:01:37 -05:00
$account = $this -> accountRepository -> findNull (( int ) $value );
if ( null !== $account ) {
2020-08-22 05:24:01 -05:00
$this -> collector -> setSourceAccounts ( new Collection ([ $account ]));
2020-08-09 11:58:18 -05:00
}
2020-08-22 05:24:01 -05:00
break ;
2020-08-24 00:03:17 -05:00
case 'journal_id' :
$parts = explode ( ',' , $value );
$this -> collector -> setJournalIds ( $parts );
break ;
2020-08-22 05:24:01 -05:00
case 'destination_account_starts' :
$this -> searchAccount ( $value , 2 , 1 );
break ;
case 'destination_account_ends' :
$this -> searchAccount ( $value , 2 , 2 );
break ;
case 'destination_account_nr_starts' :
$this -> searchAccountNr ( $value , 2 , 1 );
break ;
case 'destination_account_nr_ends' :
$this -> searchAccountNr ( $value , 2 , 2 );
break ;
case 'destination_account_nr_is' :
$this -> searchAccountNr ( $value , 2 , 4 );
break ;
case 'destination_account_is' :
$this -> searchAccount ( $value , 2 , 4 );
break ;
case 'destination_account_nr_contains' :
$this -> searchAccountNr ( $value , 2 , 3 );
break ;
case 'destination_account_contains' :
$this -> searchAccount ( $value , 2 , 3 );
break ;
case 'destination_account_id' :
2020-08-22 06:01:37 -05:00
$account = $this -> accountRepository -> findNull (( int ) $value );
if ( null !== $account ) {
2020-08-22 05:24:01 -05:00
$this -> collector -> setDestinationAccounts ( new Collection ([ $account ]));
}
break ;
case 'account_id' :
2020-08-22 09:55:54 -05:00
$parts = explode ( ',' , $value );
$collection = new Collection ;
foreach ( $parts as $accountId ) {
2020-08-28 04:24:55 -05:00
$account = $this -> accountRepository -> findNull (( int ) $accountId );
2020-08-22 09:55:54 -05:00
if ( null !== $account ) {
$collection -> push ( $account );
}
}
if ( $collection -> count () > 0 ) {
$this -> collector -> setAccounts ( $collection );
2020-08-09 11:58:18 -05:00
}
break ;
2020-08-22 05:24:01 -05:00
//
2020-08-26 13:18:27 -05:00
// cash account
//
case 'source_is_cash' :
$account = $this -> getCashAccount ();
$this -> collector -> setSourceAccounts ( new Collection ([ $account ]));
break ;
case 'destination_is_cash' :
$account = $this -> getCashAccount ();
$this -> collector -> setDestinationAccounts ( new Collection ([ $account ]));
break ;
case 'account_is_cash' :
$account = $this -> getCashAccount ();
$this -> collector -> setAccounts ( new Collection ([ $account ]));
break ;
//
2020-08-22 05:24:01 -05:00
// description
//
case 'description_starts' :
$this -> collector -> descriptionStarts ([ $value ]);
break ;
case 'description_ends' :
$this -> collector -> descriptionEnds ([ $value ]);
break ;
case 'description_contains' :
$this -> words [] = $value ;
return false ;
case 'description_is' :
$this -> collector -> descriptionIs ( $value );
break ;
//
// currency
//
case 'currency_is' :
$currency = $this -> findCurrency ( $value );
if ( null !== $currency ) {
$this -> collector -> setCurrency ( $currency );
}
break ;
case 'foreign_currency_is' :
$currency = $this -> findCurrency ( $value );
if ( null !== $currency ) {
$this -> collector -> setForeignCurrency ( $currency );
}
break ;
//
// attachments
//
case 'has_attachments' :
Log :: debug ( 'Set collector to filter on attachments.' );
$this -> collector -> hasAttachments ();
break ;
//
// categories
case 'has_no_category' :
$this -> collector -> withoutCategory ();
break ;
case 'has_any_category' :
$this -> collector -> withCategory ();
break ;
case 'category_is' :
2020-08-09 11:58:18 -05:00
$result = $this -> categoryRepository -> searchCategory ( $value , 25 );
if ( $result -> count () > 0 ) {
$this -> collector -> setCategories ( $result );
}
break ;
2020-08-22 05:24:01 -05:00
//
// budgets
//
case 'has_no_budget' :
$this -> collector -> withoutBudget ();
break ;
case 'has_any_budget' :
$this -> collector -> withBudget ();
break ;
case 'budget_is' :
$result = $this -> budgetRepository -> searchBudget ( $value , 25 );
if ( $result -> count () > 0 ) {
$this -> collector -> setBudgets ( $result );
}
break ;
//
// bill
//
case 'bill_is' :
2020-08-09 11:58:18 -05:00
$result = $this -> billRepository -> searchBill ( $value , 25 );
if ( $result -> count () > 0 ) {
$this -> collector -> setBills ( $result );
}
break ;
2020-08-22 05:24:01 -05:00
//
// tags
//
case 'has_no_tag' :
$this -> collector -> withoutTags ();
break ;
case 'has_any_tag' :
$this -> collector -> hasAnyTag ();
break ;
2020-08-23 11:48:40 -05:00
case 'tag_is' :
2020-08-09 11:58:18 -05:00
$result = $this -> tagRepository -> searchTag ( $value );
if ( $result -> count () > 0 ) {
$this -> collector -> setTags ( $result );
}
break ;
2020-08-22 05:24:01 -05:00
//
// notes
//
case 'notes_contain' :
$this -> collector -> notesContain ( $value );
2020-08-09 11:58:18 -05:00
break ;
2020-08-22 05:24:01 -05:00
case 'notes_start' :
$this -> collector -> notesStartWith ( $value );
break ;
case 'notes_end' :
$this -> collector -> notesEndWith ( $value );
break ;
case 'notes_are' :
$this -> collector -> notesExactly ( $value );
break ;
case 'no_notes' :
$this -> collector -> withoutNotes ();
break ;
case 'any_notes' :
$this -> collector -> withAnyNotes ();
break ;
//
// amount
//
case 'amount_exactly' :
2020-08-09 11:58:18 -05:00
$amount = app ( 'steam' ) -> positive (( string ) $value );
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s"' , $operator , $amount ));
$this -> collector -> amountIs ( $amount );
break ;
case 'amount_less' :
$amount = app ( 'steam' ) -> positive (( string ) $value );
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s"' , $operator , $amount ));
$this -> collector -> amountLess ( $amount );
break ;
case 'amount_more' :
$amount = app ( 'steam' ) -> positive (( string ) $value );
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s"' , $operator , $amount ));
$this -> collector -> amountMore ( $amount );
break ;
2020-08-22 05:24:01 -05:00
//
// transaction type
//
case 'transaction_type' :
2020-08-09 11:58:18 -05:00
$this -> collector -> setTypes ([ ucfirst ( $value )]);
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s"' , $operator , $value ));
break ;
2020-08-22 05:24:01 -05:00
//
// dates
//
case 'date_is' :
2020-08-22 06:01:37 -05:00
$range = $this -> parseDateRange ( $value );
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s" (%s - %s)' , $operator , $value , $range [ 'start' ] -> format ( 'Y-m-d' ), $range [ 'end' ] -> format ( 'Y-m-d' )));
$this -> collector -> setRange ( $range [ 'start' ], $range [ 'end' ]);
// add to operators manually:
$this -> operators -> push ([ 'type' => 'date_before' , 'value' => $range [ 'start' ] -> format ( 'Y-m-d' ),]);
$this -> operators -> push ([ 'type' => 'date_after' , 'value' => $range [ 'end' ] -> format ( 'Y-m-d' ),]);
return false ;
2020-08-09 11:58:18 -05:00
case 'date_before' :
2020-08-22 06:01:37 -05:00
$range = $this -> parseDateRange ( $value );
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s" (%s - %s)' , $operator , $value , $range [ 'start' ] -> format ( 'Y-m-d' ), $range [ 'end' ] -> format ( 'Y-m-d' )));
// add to operators manually:
$this -> operators -> push ([ 'type' => 'date_before' , 'value' => $range [ 'start' ] -> format ( 'Y-m-d' ),]);
$this -> collector -> setBefore ( $range [ 'start' ]);
return false ;
2020-08-09 11:58:18 -05:00
case 'date_after' :
2020-08-22 06:01:37 -05:00
$range = $this -> parseDateRange ( $value );
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s" (%s - %s)' , $operator , $value , $range [ 'start' ] -> format ( 'Y-m-d' ), $range [ 'end' ] -> format ( 'Y-m-d' )));
// add to operators manually:
2020-08-22 06:02:33 -05:00
$this -> operators -> push ([ 'type' => 'date_after' , 'value' => $range [ 'end' ] -> format ( 'Y-m-d' ),]);
2020-08-22 06:01:37 -05:00
$this -> collector -> setAfter ( $range [ 'end' ]);
return false ;
2020-08-09 11:58:18 -05:00
case 'created_on' :
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s"' , $operator , $value ));
$createdAt = new Carbon ( $value );
$this -> collector -> setCreatedAt ( $createdAt );
break ;
case 'updated_on' :
Log :: debug ( sprintf ( 'Set "%s" using collector with value "%s"' , $operator , $value ));
$updatedAt = new Carbon ( $value );
$this -> collector -> setUpdatedAt ( $updatedAt );
break ;
2020-08-22 05:24:01 -05:00
//
// other fields
//
2020-08-09 11:58:18 -05:00
case 'external_id' :
$this -> collector -> setExternalId ( $value );
break ;
case 'internal_reference' :
$this -> collector -> setInternalReference ( $value );
break ;
}
2020-08-22 05:24:01 -05:00
return true ;
2020-08-09 11:58:18 -05:00
}
2020-08-18 10:48:27 -05:00
/**
2020-08-22 05:24:01 -05:00
* searchDirection : 1 = source ( default ), 2 = destination
* stringPosition : 1 = start ( default ), 2 = end , 3 = contains , 4 = is
2020-08-18 10:48:27 -05:00
* @ param string $value
2020-08-22 05:24:01 -05:00
* @ param int $searchDirection
* @ param int $stringPosition
2020-08-18 10:48:27 -05:00
*/
2020-08-22 05:24:01 -05:00
private function searchAccount ( string $value , int $searchDirection , int $stringPosition ) : void
2020-08-18 10:48:27 -05:00
{
2020-08-22 05:24:01 -05:00
Log :: debug ( sprintf ( 'searchAccount(%s, %d, %d)' , $value , $stringPosition , $searchDirection ));
// search direction (default): for source accounts
$searchTypes = [ AccountType :: ASSET , AccountType :: MORTGAGE , AccountType :: LOAN , AccountType :: DEBT , AccountType :: REVENUE ];
$collectorMethod = 'setSourceAccounts' ;
// search direction: for destination accounts
if ( 2 === $searchDirection ) {
// destination can be
$searchTypes = [ AccountType :: ASSET , AccountType :: MORTGAGE , AccountType :: LOAN , AccountType :: DEBT , AccountType :: EXPENSE ];
$collectorMethod = 'setDestinationAccounts' ;
}
// string position (default): starts with:
$stringMethod = 'str_starts_with' ;
// string position: ends with:
if ( 2 === $stringPosition ) {
$stringMethod = 'str_ends_with' ;
}
if ( 3 === $stringPosition ) {
$stringMethod = 'str_contains' ;
}
if ( 4 === $stringPosition ) {
$stringMethod = 'str_is_equal' ;
}
// get accounts:
$accounts = $this -> accountRepository -> searchAccount ( $value , $searchTypes , 25 );
2020-08-18 10:48:27 -05:00
if ( 0 === $accounts -> count ()) {
2020-08-22 05:24:01 -05:00
Log :: debug ( 'Found zero accounts, do nothing.' );
2020-08-18 10:48:27 -05:00
return ;
}
2020-08-22 05:24:01 -05:00
Log :: debug ( sprintf ( 'Found %d accounts, will filter.' , $accounts -> count ()));
$filtered = $accounts -> filter ( function ( Account $account ) use ( $value , $stringMethod ) {
return $stringMethod ( strtolower ( $account -> name ), strtolower ( $value ));
2020-08-18 10:48:27 -05:00
});
2020-08-22 05:24:01 -05:00
2020-08-18 10:48:27 -05:00
if ( 0 === $filtered -> count ()) {
2020-08-22 05:24:01 -05:00
Log :: debug ( 'Left with zero accounts, return.' );
2020-08-18 10:48:27 -05:00
return ;
}
2020-08-22 05:24:01 -05:00
Log :: debug ( sprintf ( 'Left with %d, set as %s().' , $filtered -> count (), $collectorMethod ));
$this -> collector -> $collectorMethod ( $filtered );
2020-08-18 10:48:27 -05:00
}
2020-08-22 05:24:01 -05:00
2020-08-18 10:48:27 -05:00
/**
2020-08-22 05:24:01 -05:00
* searchDirection : 1 = source ( default ), 2 = destination
* stringPosition : 1 = start ( default ), 2 = end , 3 = contains , 4 = is
2020-08-18 10:48:27 -05:00
* @ param string $value
2020-08-22 05:24:01 -05:00
* @ param int $searchDirection
* @ param int $stringPosition
2020-08-18 10:48:27 -05:00
*/
2020-08-22 05:24:01 -05:00
private function searchAccountNr ( string $value , int $searchDirection , int $stringPosition ) : void
2020-08-18 10:48:27 -05:00
{
2020-08-22 05:24:01 -05:00
Log :: debug ( sprintf ( 'searchAccountNr(%s, %d, %d)' , $value , $searchDirection , $stringPosition ));
// search direction (default): for source accounts
$searchTypes = [ AccountType :: ASSET , AccountType :: MORTGAGE , AccountType :: LOAN , AccountType :: DEBT , AccountType :: REVENUE ];
$collectorMethod = 'setSourceAccounts' ;
// search direction: for destination accounts
if ( 2 === $searchDirection ) {
// destination can be
$searchTypes = [ AccountType :: ASSET , AccountType :: MORTGAGE , AccountType :: LOAN , AccountType :: DEBT , AccountType :: EXPENSE ];
$collectorMethod = 'setDestinationAccounts' ;
}
// string position (default): starts with:
$stringMethod = 'str_starts_with' ;
// string position: ends with:
if ( 2 === $stringPosition ) {
$stringMethod = 'str_ends_with' ;
}
if ( 3 === $stringPosition ) {
$stringMethod = 'str_contains' ;
}
if ( 4 === $stringPosition ) {
$stringMethod = 'str_is_equal' ;
}
// search for accounts:
$accounts = $this -> accountRepository -> searchAccountNr ( $value , $searchTypes , 25 );
2020-08-18 10:48:27 -05:00
if ( 0 === $accounts -> count ()) {
2020-08-22 05:24:01 -05:00
Log :: debug ( 'Found zero accounts, do nothing.' );
2020-08-18 10:48:27 -05:00
return ;
}
2020-08-22 05:24:01 -05:00
// if found, do filter
Log :: debug ( sprintf ( 'Found %d accounts, will filter.' , $accounts -> count ()));
$filtered = $accounts -> filter ( function ( Account $account ) use ( $value , $stringMethod ) {
// either IBAN or account number!
$ibanMatch = $stringMethod ( strtolower ( $account -> iban ), strtolower ( $value ));
$accountNrMatch = false ;
/** @var AccountMeta $meta */
foreach ( $account -> accountMeta as $meta ) {
if ( 'account_number' === $meta -> name && $stringMethod ( strtolower ( $meta -> data ), strtolower ( $value ))) {
$accountNrMatch = true ;
}
}
return $ibanMatch || $accountNrMatch ;
2020-08-18 10:48:27 -05:00
});
2020-08-22 05:24:01 -05:00
2020-08-18 10:48:27 -05:00
if ( 0 === $filtered -> count ()) {
Log :: debug ( 'Left with zero, return.' );
return ;
}
2020-08-22 05:24:01 -05:00
Log :: debug ( 'Left with zero accounts, return.' );
$this -> collector -> $collectorMethod ( $filtered );
2020-08-18 10:48:27 -05:00
}
2020-08-22 05:24:01 -05:00
/**
* @ param string $value
* @ return TransactionCurrency | null
*/
private function findCurrency ( string $value ) : ? TransactionCurrency
{
2020-08-27 23:09:04 -05:00
if ( str_contains ( $value , '(' ) && str_contains ( $value , ')' )) {
// bad method to split and get the currency code:
$parts = explode ( ' ' , $value );
$value = trim ( $parts [ count ( $parts ) - 1 ], " () \t \n \r \0 \x0B " );
}
2020-08-22 05:24:01 -05:00
$result = $this -> currencyRepository -> findByCodeNull ( $value );
if ( null === $result ) {
$result = $this -> currencyRepository -> findByNameNull ( $value );
}
return $result ;
}
/**
* @ param string $operator
* @ return string
2020-08-26 23:19:16 -05:00
* @ throws FireflyException
2020-08-22 05:24:01 -05:00
*/
2020-08-26 23:19:16 -05:00
public static function getRootOperator ( string $operator ) : string
2020-08-22 05:24:01 -05:00
{
$config = config ( sprintf ( 'firefly.search.operators.%s' , $operator ));
if ( null === $config ) {
throw new FireflyException ( sprintf ( 'No configuration for search operator "%s"' , $operator ));
}
if ( true === $config [ 'alias' ]) {
Log :: debug ( sprintf ( '"%s" is an alias for "%s", so return that instead.' , $operator , $config [ 'alias_for' ]));
return $config [ 'alias_for' ];
}
Log :: debug ( sprintf ( '"%s" is not an alias.' , $operator ));
return $operator ;
}
2020-08-22 06:01:37 -05:00
/**
* @ param string $value
* @ return array
* @ throws FireflyException
*/
private function parseDateRange ( string $value ) : array
{
$parser = new ParseDateString ;
if ( $parser -> isDateRange ( $value )) {
return $parser -> parseRange ( $value , today ( config ( 'app.timezone' )));
}
$date = $parser -> parseDate ( $value );
return [
'start' => $date ,
'end' => $date ,
];
}
2020-08-22 09:55:54 -05:00
/**
* @ param int $limit
*/
public function setLimit ( int $limit ) : void
{
$this -> limit = $limit ;
}
2020-08-26 13:18:27 -05:00
/**
* @ return Account
*/
private function getCashAccount () : Account
{
return $this -> accountRepository -> getCashAccount ();
}
2020-08-09 11:58:18 -05:00
}