From 1100+ queries to a steady 6.

This commit is contained in:
James Cole 2015-12-30 09:17:29 +01:00
parent f99e46bf75
commit 2904baf44e
3 changed files with 100 additions and 25 deletions

View File

@ -141,8 +141,6 @@ class CategoryController extends Controller
{
/** @var CRI $repository */
$repository = app('FireflyIII\Repositories\Category\CategoryRepositoryInterface');
/** @var SCRI $singleRepository */
$singleRepository = app('FireflyIII\Repositories\Category\SingleCategoryRepositoryInterface');
// chart properties for cache:
$cache = new CacheProperties();
@ -167,7 +165,14 @@ class CategoryController extends Controller
* earned: x
*/
$entries = new Collection;
// go by budget, not by year.
// go by category, not by year.
// given a set of categories and accounts, it should not be difficult to get
// the exact array of data we need.
// then get the data for "no category".
$set = $repository->listMultiYear($categories, $accounts, $start, $end);
/** @var Category $category */
foreach ($categories as $category) {
$entry = ['name' => '', 'spent' => [], 'earned' => []];
@ -175,22 +180,35 @@ class CategoryController extends Controller
$currentStart = clone $start;
while ($currentStart < $end) {
// fix the date:
$year = $currentStart->year;
$currentEnd = clone $currentStart;
$currentEnd->endOfYear();
// get data:
if (is_null($category->id)) {
$name = trans('firefly.noCategory');
$spent = $repository->sumSpentNoCategory($accounts, $currentStart, $currentEnd);
$earned = $repository->sumEarnedNoCategory($accounts, $currentStart, $currentEnd);
} else {
// get from set:
$entrySpent = $set->filter(
function (Category $cat) use ($year, $category) {
return ($cat->type == 'Withdrawal' && $cat->dateFormatted == $year && $cat->id == $category->id);
}
)->first();
$entryEarned = $set->filter(
function (Category $cat) use ($year, $category) {
return ($cat->type == 'Deposit' && $cat->dateFormatted == $year && $cat->id == $category->id);
}
)->first();
$name = $category->name;
$spent = $singleRepository->spentInPeriodForAccounts($category, $accounts, $currentStart, $currentEnd);
$earned = $singleRepository->earnedInPeriodForAccounts($category, $accounts, $currentStart, $currentEnd);
$spent = !is_null($entrySpent) ? $entrySpent->sum : 0;
$earned = !is_null($entryEarned) ? $entryEarned->sum : 0;
}
// save to array:
$year = $currentStart->year;
$entry['name'] = $name;
$entry['spent'][$year] = ($spent * -1);
$entry['earned'][$year] = $earned;
@ -205,7 +223,6 @@ class CategoryController extends Controller
$data = $this->generator->multiYear($entries);
$cache->store($data);
return Response::json($data);
}

View File

@ -122,6 +122,62 @@ class CategoryRepository implements CategoryRepositoryInterface
->get(['transaction_journals.*']);
}
/**
* This method returns a very special collection for each category:
*
* category, year, expense/earned, amount
*
* categories can be duplicated.
*
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function listMultiYear(Collection $categories, Collection $accounts, Carbon $start, Carbon $end)
{
/*
* select categories.id, DATE_FORMAT(transaction_journals.date,"%Y") as dateFormatted, transaction_types.type, SUM(amount) as sum from categories
left join category_transaction_journal ON category_transaction_journal.category_id = categories.id
left join transaction_journals ON transaction_journals.id = category_transaction_journal.transaction_journal_id
left join transaction_types ON transaction_types.id = transaction_journals.transaction_type_id
left join transactions ON transactions.transaction_journal_id = transaction_journals.id
where
categories.user_id =1
and transaction_types.type in ("Withdrawal","Deposit")
and transactions.account_id IN (2,4,6,10,11,610,725,879,1248)
group by categories.id, transaction_types.type, dateFormatted
*/
$set = Auth::user()->categories()
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'category_transaction_journal.transaction_journal_id')
->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id')
->leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->whereIn('transaction_types.type', [TransactionType::DEPOSIT, TransactionType::WITHDRAWAL])
->whereIn('transactions.account_id', $accounts->pluck('id')->toArray())
->whereIn('categories.id', $categories->pluck('id')->toArray())
->groupBy('categories.id')
->groupBy('transaction_types.type')
->groupBy('dateFormatted')
->get(
[
'categories.*',
DB::Raw('DATE_FORMAT(`transaction_journals`.`date`,"%Y") as `dateFormatted`'),
'transaction_types.type',
DB::Raw('SUM(`amount`) as `sum`')
]
);
return $set;
}
/**
* Returns a collection of Categories appended with the amount of money that has been earned
@ -136,11 +192,6 @@ class CategoryRepository implements CategoryRepositoryInterface
*/
public function earnedForAccountsPerMonth(Collection $accounts, Carbon $start, Carbon $end)
{
$accountIds = [];
foreach ($accounts as $account) {
$accountIds[] = $account->id;
}
$collection = Auth::user()->categories()
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
@ -156,8 +207,8 @@ class CategoryRepository implements CategoryRepositoryInterface
$join->on('t_dest.transaction_journal_id', '=', 'transaction_journals.id')->where('t_dest.amount', '>', 0);
}
)
->whereIn('t_dest.account_id', $accountIds)// to these accounts (earned)
->whereNotIn('t_src.account_id', $accountIds)//-- but not from these accounts
->whereIn('t_dest.account_id', $accounts->pluck('id')->toArray())// to these accounts (earned)
->whereNotIn('t_src.account_id', $accounts->pluck('id')->toArray())//-- but not from these accounts
->whereIn(
'transaction_types.type', [TransactionType::DEPOSIT, TransactionType::TRANSFER, TransactionType::OPENING_BALANCE]
)
@ -191,12 +242,7 @@ class CategoryRepository implements CategoryRepositoryInterface
*/
public function spentForAccountsPerMonth(Collection $accounts, Carbon $start, Carbon $end)
{
$accountIds = [];
foreach ($accounts as $account) {
$accountIds[] = $account->id;
}
$accountIds = $accounts->pluck('id')->toArray();
$collection = Auth::user()->categories()
->leftJoin('category_transaction_journal', 'category_transaction_journal.category_id', '=', 'categories.id')
->leftJoin('transaction_journals', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id')
@ -275,10 +321,7 @@ class CategoryRepository implements CategoryRepositoryInterface
*/
protected function sumNoCategory(Collection $accounts, Carbon $start, Carbon $end, $group = Query::EARNED)
{
$accountIds = [];
foreach ($accounts as $account) {
$accountIds[] = $account->id;
}
$accountIds = $accounts->pluck('id')->toArray();
if ($group == Query::EARNED) {
$types = [TransactionType::DEPOSIT];
} else {

View File

@ -3,7 +3,6 @@
namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\Sql\Query;
use Illuminate\Support\Collection;
/**
@ -45,6 +44,22 @@ interface CategoryRepositoryInterface
*/
public function listCategories();
/**
* This method returns a very special collection for each category:
*
* category, year, expense/earned, amount
*
* categories can be duplicated.
*
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function listMultiYear(Collection $categories, Collection $accounts, Carbon $start, Carbon $end);
/**
* Returns a list of transaction journals in the range (all types, all accounts) that have no category
* associated to them.