Optimize array.

This commit is contained in:
James Cole
2025-08-08 20:59:24 +02:00
parent deca4fed56
commit 76e91be4dc
4 changed files with 186 additions and 158 deletions

View File

@@ -117,7 +117,6 @@ class ShowController extends Controller
Log::debug('Start period overview'); Log::debug('Start period overview');
Timer::start('period-overview'); Timer::start('period-overview');
$periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end); $periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end);
Log::debug('End period overview'); Log::debug('End period overview');

View File

@@ -416,6 +416,7 @@ class AccountController extends Controller
$cache = new CacheProperties(); $cache = new CacheProperties();
$cache->addProperty($account->id); $cache->addProperty($account->id);
$cache->addProperty($start); $cache->addProperty($start);
$cache->addProperty($this->convertToPrimary);
$cache->addProperty($end); $cache->addProperty($end);
$cache->addProperty('chart.account.income-category'); $cache->addProperty('chart.account.income-category');
if ($cache->has()) { if ($cache->has()) {
@@ -435,15 +436,32 @@ class AccountController extends Controller
foreach ($journals as $journal) { foreach ($journals as $journal) {
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']); $key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
if (!array_key_exists($key, $result)) { if (!array_key_exists($key, $result)) {
// currency info:
$currencyId = (int)$journal['currency_id'];
$currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol'];
$currencyCode = $journal['currency_code'];
$currencyDecimalPlaces = $journal['currency_decimal_places'];
$field = 'amount';
if ($this->convertToPrimary && $this->primaryCurrency->id !== $currencyId) {
$field = 'pc_amount';
$currencyName = $this->primaryCurrency->name;
$currencySymbol = $this->primaryCurrency->symbol;
$currencyCode = $this->primaryCurrency->code;
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
}
$result[$key] = [ $result[$key] = [
'total' => '0', 'total' => '0',
'category_id' => $journal['category_id'], 'category_id' => $journal['category_id'],
'currency_name' => $journal['currency_name'], 'currency_name' => $currencyName,
'currency_symbol' => $journal['currency_symbol'], 'currency_code' => $currencyCode,
'currency_code' => $journal['currency_code'], 'currency_symbol' => $currencySymbol,
'currency_decimal_places' => $currencyDecimalPlaces,
]; ];
} }
$result[$key]['total'] = bcadd((string)$journal['amount'], $result[$key]['total']); $result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
} }
$names = $this->getCategoryNames(array_keys($result)); $names = $this->getCategoryNames(array_keys($result));

View File

@@ -562,7 +562,13 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
'foreign_currencies.decimal_places as foreign_currency_decimal_places', 'foreign_currencies.decimal_places as foreign_currency_decimal_places',
// fields // fields
'transaction_journals.date', 'transaction_types.type', 'transaction_journals.transaction_currency_id', 'transactions.amount']) 'transaction_journals.date',
'transaction_types.type',
'transaction_journals.transaction_currency_id',
'transactions.amount',
'transactions.native_amount',
'transactions.foreign_amount'
])
->toArray() ->toArray()
; ;

View File

@@ -35,6 +35,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Debug\Timer; use FireflyIII\Support\Debug\Timer;
use FireflyIII\Support\Facades\Navigation;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
/** /**
@@ -81,7 +82,7 @@ trait PeriodOverview
Log::debug('Now in getAccountPeriodOverview()'); Log::debug('Now in getAccountPeriodOverview()');
Timer::start('account-period-total'); Timer::start('account-period-total');
$this->accountRepository = app(AccountRepositoryInterface::class); $this->accountRepository = app(AccountRepositoryInterface::class);
$range = app('navigation')->getViewRange(true); $range = Navigation::getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for cache // properties for cache
@@ -91,11 +92,11 @@ trait PeriodOverview
$cache->addProperty('account-show-period-entries'); $cache->addProperty('account-show-period-entries');
$cache->addProperty($account->id); $cache->addProperty($account->id);
if ($cache->has()) { if ($cache->has()) {
return $cache->get(); // return $cache->get();
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = Navigation::blockPeriods($start, $end, $range);
$entries = []; $entries = [];
$spent = []; $spent = [];
$earned = []; $earned = [];
@@ -104,19 +105,16 @@ trait PeriodOverview
// run a custom query because doing this with the collector is MEGA slow. // run a custom query because doing this with the collector is MEGA slow.
$transactions = $this->accountRepository->periodCollection($account, $start, $end); $transactions = $this->accountRepository->periodCollection($account, $start, $end);
// loop dates // loop dates
Log::debug(sprintf('Count of loops: %d', count($dates))); Log::debug(sprintf('Count of loops: %d', count($dates)));
$loops = 0; $loops = 0;
// stop after 10 loops for memory reasons. // stop after 10 loops for memory reasons.
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']); $title = Navigation::periodShow($currentDate['start'], $currentDate['period']);
if ($loops < 10) {
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
[$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']);
[$transactions, $transferredAway] = $this->filterTransfers('away', $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $transferredAway] = $this->filterTransfers('away', $transactions, $currentDate['start'], $currentDate['end']);
[$transactions, $transferredIn] = $this->filterTransfers('in', $transactions, $currentDate['start'], $currentDate['end']); [$transactions, $transferredIn] = $this->filterTransfers('in', $transactions, $currentDate['start'], $currentDate['end']);
}
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
@@ -139,6 +137,7 @@ trait PeriodOverview
private function filterTransactionsByType(TransactionTypeEnum $type, array $transactions, Carbon $start, Carbon $end): array private function filterTransactionsByType(TransactionTypeEnum $type, array $transactions, Carbon $start, Carbon $end): array
{ {
$result = []; $result = [];
$filtered = [];
/** /**
* @var int $index * @var int $index
@@ -146,18 +145,23 @@ trait PeriodOverview
*/ */
foreach ($transactions as $index => $item) { foreach ($transactions as $index => $item) {
$date = Carbon::parse($item['date']); $date = Carbon::parse($item['date']);
if ($item['type'] === $type->value && $date >= $start && $date <= $end) { $fits = $item['type'] === $type->value && $date >= $start && $date <= $end;
if ($fits) {
$result[] = $item; $result[] = $item;
unset($transactions[$index]); unset($transactions[$index]);
} }
if(!$fits) {
$filtered[] = $item;
}
} }
return [$transactions, $result]; return [$filtered, $result];
} }
private function filterTransfers(string $direction, array $transactions, Carbon $start, Carbon $end): array private function filterTransfers(string $direction, array $transactions, Carbon $start, Carbon $end): array
{ {
$result = []; $result = [];
$filtered = [];
/** /**
* @var int $index * @var int $index
@@ -166,18 +170,19 @@ trait PeriodOverview
foreach ($transactions as $index => $item) { foreach ($transactions as $index => $item) {
$date = Carbon::parse($item['date']); $date = Carbon::parse($item['date']);
if ($date >= $start && $date <= $end) { if ($date >= $start && $date <= $end) {
if ('away' === $direction && -1 === bccomp((string) $item['amount'], '0')) { if ('away' === $direction && -1 === bccomp((string)$item['amount'], '0')) {
$result[] = $item; $result[] = $item;
unset($transactions[$index]); continue;
} }
if ('in' === $direction && 1 === bccomp((string) $item['amount'], '0')) { if ('in' === $direction && 1 === bccomp((string)$item['amount'], '0')) {
$result[] = $item; $result[] = $item;
unset($transactions[$index]); continue;
} }
$filtered[] = $item;
} }
} }
return [$transactions, $result]; return [$filtered, $result];
} }
private function groupByCurrency(array $journals): array private function groupByCurrency(array $journals): array
@@ -186,7 +191,7 @@ trait PeriodOverview
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
$currencyId = (int) $journal['currency_id']; $currencyId = (int)$journal['currency_id'];
$currencyCode = $journal['currency_code']; $currencyCode = $journal['currency_code'];
$currencyName = $journal['currency_name']; $currencyName = $journal['currency_name'];
$currencySymbol = $journal['currency_symbol']; $currencySymbol = $journal['currency_symbol'];
@@ -203,7 +208,7 @@ trait PeriodOverview
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places; $currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
} }
if ($this->convertToPrimary && $currencyId !== $this->primaryCurrency->id && $foreignCurrencyId === $this->primaryCurrency->id) { if ($this->convertToPrimary && $currencyId !== $this->primaryCurrency->id && $foreignCurrencyId === $this->primaryCurrency->id) {
$currencyId = (int) $foreignCurrencyId; $currencyId = (int)$foreignCurrencyId;
$currencyCode = $journal['foreign_currency_code']; $currencyCode = $journal['foreign_currency_code'];
$currencyName = $journal['foreign_currency_name']; $currencyName = $journal['foreign_currency_name'];
$currencySymbol = $journal['foreign_currency_symbol']; $currencySymbol = $journal['foreign_currency_symbol'];
@@ -235,7 +240,7 @@ trait PeriodOverview
*/ */
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
{ {
$range = app('navigation')->getViewRange(true); $range = Navigation::getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for entries with their amounts. // properties for entries with their amounts.
@@ -251,7 +256,7 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = Navigation::blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all expenses in this period: // collect all expenses in this period:
@@ -281,7 +286,7 @@ trait PeriodOverview
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'transactions' => 0, 'transactions' => 0,
@@ -327,7 +332,7 @@ trait PeriodOverview
*/ */
protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array
{ {
$range = app('navigation')->getViewRange(true); $range = Navigation::getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
@@ -342,7 +347,7 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = Navigation::blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// get all expenses without a budget. // get all expenses without a budget.
@@ -353,7 +358,7 @@ trait PeriodOverview
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']); $set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
@@ -380,17 +385,17 @@ trait PeriodOverview
protected function getNoCategoryPeriodOverview(Carbon $theDate): array protected function getNoCategoryPeriodOverview(Carbon $theDate): array
{ {
app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d'))); app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
$range = app('navigation')->getViewRange(true); $range = Navigation::getViewRange(true);
$first = $this->journalRepos->firstNull(); $first = $this->journalRepos->firstNull();
$start = null === $first ? new Carbon() : $first->date; $start = null === $first ? new Carbon() : $first->date;
$end = clone $theDate; $end = clone $theDate;
$end = app('navigation')->endOfPeriod($end, $range); $end = Navigation::endOfPeriod($end, $range);
app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d'))); app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d')));
app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d'))); app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d')));
// properties for cache // properties for cache
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = Navigation::blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all expenses in this period: // collect all expenses in this period:
@@ -422,7 +427,7 @@ trait PeriodOverview
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'title' => $title, 'title' => $title,
@@ -445,7 +450,7 @@ trait PeriodOverview
*/ */
protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags. protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags.
{ {
$range = app('navigation')->getViewRange(true); $range = Navigation::getViewRange(true);
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
// properties for cache // properties for cache
@@ -459,7 +464,7 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = Navigation::blockPeriods($start, $end, $range);
$entries = []; $entries = [];
// collect all expenses in this period: // collect all expenses in this period:
@@ -495,7 +500,7 @@ trait PeriodOverview
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']); $spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']); $earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']); $transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
$entries[] $entries[]
= [ = [
'transactions' => 0, 'transactions' => 0,
@@ -540,7 +545,7 @@ trait PeriodOverview
*/ */
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
{ {
$range = app('navigation')->getViewRange(true); $range = Navigation::getViewRange(true);
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType)); $types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end]; [$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
@@ -555,7 +560,7 @@ trait PeriodOverview
} }
/** @var array $dates */ /** @var array $dates */
$dates = app('navigation')->blockPeriods($start, $end, $range); $dates = Navigation::blockPeriods($start, $end, $range);
$entries = []; $entries = [];
$spent = []; $spent = [];
$earned = []; $earned = [];
@@ -567,7 +572,7 @@ trait PeriodOverview
$loops = 0; $loops = 0;
foreach ($dates as $currentDate) { foreach ($dates as $currentDate) {
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']); $title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
if ($loops < 10) { if ($loops < 10) {
// set to correct array // set to correct array
@@ -605,7 +610,7 @@ trait PeriodOverview
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
if ($account->id === (int) $journal['source_account_id']) { if ($account->id === (int)$journal['source_account_id']) {
$return[] = $journal; $return[] = $journal;
} }
} }
@@ -622,7 +627,7 @@ trait PeriodOverview
/** @var array $journal */ /** @var array $journal */
foreach ($journals as $journal) { foreach ($journals as $journal) {
if ($account->id === (int) $journal['destination_account_id']) { if ($account->id === (int)$journal['destination_account_id']) {
$return[] = $journal; $return[] = $journal;
} }
} }