From accbdea942b73cc7af4382f72e1117cf0229e704 Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 15 Jul 2017 17:19:12 +0200 Subject: [PATCH] Improve search and display of results. --- app/Http/Controllers/SearchController.php | 25 ++- app/Http/breadcrumbs.php | 2 +- app/Support/Search/Modifier.php | 6 +- app/Support/Search/Search.php | 107 +--------- app/Support/Search/SearchInterface.php | 19 -- public/js/ff/search/index.js | 35 +++ resources/lang/en_US/breadcrumbs.php | 2 +- resources/lang/en_US/firefly.php | 19 +- resources/lang/nl_NL/firefly.php | 5 +- resources/views/search/index.twig | 200 +++++++----------- resources/views/search/partials/accounts.twig | 36 ---- resources/views/search/partials/budgets.twig | 24 --- .../views/search/partials/categories.twig | 24 --- resources/views/search/partials/tags.twig | 26 --- .../search/partials/transactions-large.twig | 130 ------------ .../views/search/partials/transactions.twig | 78 ------- resources/views/search/search.twig | 72 +++++++ routes/web.php | 2 +- 18 files changed, 225 insertions(+), 587 deletions(-) create mode 100644 public/js/ff/search/index.js delete mode 100644 resources/views/search/partials/accounts.twig delete mode 100644 resources/views/search/partials/budgets.twig delete mode 100644 resources/views/search/partials/categories.twig delete mode 100644 resources/views/search/partials/tags.twig delete mode 100644 resources/views/search/partials/transactions-large.twig delete mode 100644 resources/views/search/partials/transactions.twig create mode 100644 resources/views/search/search.twig diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 44f880045a..a0acba5a7e 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -16,6 +16,7 @@ namespace FireflyIII\Http\Controllers; use FireflyIII\Support\Search\SearchInterface; use Illuminate\Http\Request; use Illuminate\Support\Collection; +use Response; use View; /** @@ -51,9 +52,14 @@ class SearchController extends Controller */ public function index(Request $request, SearchInterface $searcher) { - $query = $request->get('q'); + $fullQuery = $request->get('q'); - return view('search.index',compact('query')); + // parse search terms: + $searcher->parseQuery($fullQuery); + $query = $searcher->getWordsAsString(); + $subTitle = trans('breadcrumbs.search_result', ['query' => $query]); + + return view('search.index', compact('query', 'fullQuery', 'subTitle')); // yes, hard coded values: $minSearchLen = 1; @@ -98,4 +104,19 @@ class SearchController extends Controller return view('search.index', compact('rawQuery', 'hasModifiers', 'modifiers', 'subTitle', 'limit', 'query', 'result')); } + public function search(Request $request, SearchInterface $searcher) + { + $fullQuery = $request->get('query'); + + // parse search terms: + $searcher->parseQuery($fullQuery); + $searcher->setLimit(20); + $transactions = $searcher->searchTransactions(); + $html = view('search.search', compact('transactions'))->render(); + + return Response::json(['count' => $transactions->count(), 'html' => $html]); + + + } + } diff --git a/app/Http/breadcrumbs.php b/app/Http/breadcrumbs.php index aec8c16581..df835e940a 100644 --- a/app/Http/breadcrumbs.php +++ b/app/Http/breadcrumbs.php @@ -680,7 +680,7 @@ Breadcrumbs::register( Breadcrumbs::register( 'search.index', function (BreadCrumbGenerator $breadcrumbs, $query) { $breadcrumbs->parent('home'); - $breadcrumbs->push(trans('breadcrumbs.searchResult', ['query' => e($query)]), route('search.index')); + $breadcrumbs->push(trans('breadcrumbs.search_result', ['query' => e($query)]), route('search.index')); } ); diff --git a/app/Support/Search/Modifier.php b/app/Support/Search/Modifier.php index 4422cf2e56..acfae12cf6 100644 --- a/app/Support/Search/Modifier.php +++ b/app/Support/Search/Modifier.php @@ -86,17 +86,17 @@ class Modifier case 'date': case 'on': $res = self::sameDate($transaction->date, $modifier['value']); - Log::debug(sprintf('Date is %s? %s', $modifier['value'], var_export($res, true))); + Log::debug(sprintf('Date same as %s? %s', $modifier['value'], var_export($res, true))); break; case 'date_before': case 'before': $res = self::dateBefore($transaction->date, $modifier['value']); - Log::debug(sprintf('Date is %s? %s', $modifier['value'], var_export($res, true))); + Log::debug(sprintf('Date before %s? %s', $modifier['value'], var_export($res, true))); break; case 'date_after': case 'after': $res = self::dateAfter($transaction->date, $modifier['value']); - Log::debug(sprintf('Date is %s? %s', $modifier['value'], var_export($res, true))); + Log::debug(sprintf('Date before %s? %s', $modifier['value'], var_export($res, true))); break; } diff --git a/app/Support/Search/Search.php b/app/Support/Search/Search.php index 490e24708a..ce7b271973 100644 --- a/app/Support/Search/Search.php +++ b/app/Support/Search/Search.php @@ -17,11 +17,6 @@ namespace FireflyIII\Support\Search; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Helpers\Collector\JournalCollectorInterface; use FireflyIII\Helpers\Filter\InternalTransferFilter; -use FireflyIII\Models\Account; -use FireflyIII\Models\AccountType; -use FireflyIII\Models\Budget; -use FireflyIII\Models\Category; -use FireflyIII\Models\Tag; use FireflyIII\Models\Transaction; use FireflyIII\User; use Illuminate\Support\Collection; @@ -98,112 +93,20 @@ class Search implements SearchInterface } } - /** - * @return Collection - */ - public function searchAccounts(): Collection - { - $words = $this->words; - $accounts = $this->user->accounts() - ->accountTypeIn([AccountType::DEFAULT, AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE, AccountType::BENEFICIARY]) - ->get(['accounts.*']); - /** @var Collection $result */ - $result = $accounts->filter( - function (Account $account) use ($words) { - if ($this->strpos_arr(strtolower($account->name), $words)) { - return $account; - } - - return false; - } - ); - - $result = $result->slice(0, $this->limit); - - return $result; - } - - /** - * @return Collection - */ - public function searchBudgets(): Collection - { - /** @var Collection $set */ - $set = auth()->user()->budgets()->get(); - $words = $this->words; - /** @var Collection $result */ - $result = $set->filter( - function (Budget $budget) use ($words) { - if ($this->strpos_arr(strtolower($budget->name), $words)) { - return $budget; - } - - return false; - } - ); - - $result = $result->slice(0, $this->limit); - - return $result; - } - - /** - * @return Collection - */ - public function searchCategories(): Collection - { - $words = $this->words; - $categories = $this->user->categories()->get(); - /** @var Collection $result */ - $result = $categories->filter( - function (Category $category) use ($words) { - if ($this->strpos_arr(strtolower($category->name), $words)) { - return $category; - } - - return false; - } - ); - $result = $result->slice(0, $this->limit); - - return $result; - } - - /** - * @return Collection - */ - public function searchTags(): Collection - { - $words = $this->words; - $tags = $this->user->tags()->get(); - /** @var Collection $result */ - $result = $tags->filter( - function (Tag $tag) use ($words) { - if ($this->strpos_arr(strtolower($tag->tag), $words)) { - return $tag; - } - - return false; - } - ); - $result = $result->slice(0, $this->limit); - - return $result; - } - /** * @return Collection */ public function searchTransactions(): Collection { + Log::debug('Start of searchTransactions()'); $pageSize = 100; $processed = 0; $page = 1; $result = new Collection(); + $startTime = microtime(true); do { /** @var JournalCollectorInterface $collector */ $collector = app(JournalCollectorInterface::class); - $collector->setUser($this->user); $collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page); if ($this->hasModifiers()) { $collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation(); @@ -247,7 +150,11 @@ class Search implements SearchInterface Log::debug(sprintf('reachedEndOfList: %s', var_export($reachedEndOfList, true))); Log::debug(sprintf('foundEnough: %s', var_export($foundEnough, true))); - } while (!$reachedEndOfList && !$foundEnough); + // break at some point so the script does not crash: + $currentTime = microtime(true) - $startTime; + Log::debug(sprintf('Have been running for %f seconds.', $currentTime)); + + } while (!$reachedEndOfList && !$foundEnough && $currentTime <= 30); $result = $result->slice(0, $this->limit); diff --git a/app/Support/Search/SearchInterface.php b/app/Support/Search/SearchInterface.php index a06ea95d27..d709d02b67 100644 --- a/app/Support/Search/SearchInterface.php +++ b/app/Support/Search/SearchInterface.php @@ -38,25 +38,6 @@ interface SearchInterface */ public function parseQuery(string $query); - /** - * @return Collection - */ - public function searchAccounts(): Collection; - - /** - * @return Collection - */ - public function searchBudgets(): Collection; - - /** - * @return Collection - */ - public function searchCategories(): Collection; - - /** - * @return Collection - */ - public function searchTags(): Collection; /** * @return Collection diff --git a/public/js/ff/search/index.js b/public/js/ff/search/index.js new file mode 100644 index 0000000000..06a8f26697 --- /dev/null +++ b/public/js/ff/search/index.js @@ -0,0 +1,35 @@ +/* + * index.js + * Copyright (c) 2017 thegrumpydictator@gmail.com + * This software may be modified and distributed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International License. + * + * See the LICENSE file for details. + */ + +/** global: searchQuery,searchUri */ + + + +$(function () { + "use strict"; + startSearch(searchQuery); + +}); + +function startSearch(query) { + + $.post(searchUri, {query: query}).done(presentSearchResults).fail(searchFailure); +} + +function searchFailure() { + $('.result_row').hide(); + $('.error_row').show(); +} + +function presentSearchResults(data) { + $('.search_ongoing').hide(); + $('p.search_count').show(); + $('span.search_count').text(data.count); + $('.search_box').find('.overlay').remove(); + $('.search_results').html(data.html).show(); +} \ No newline at end of file diff --git a/resources/lang/en_US/breadcrumbs.php b/resources/lang/en_US/breadcrumbs.php index 54cb260179..28c31b9787 100644 --- a/resources/lang/en_US/breadcrumbs.php +++ b/resources/lang/en_US/breadcrumbs.php @@ -24,7 +24,7 @@ return [ 'edit_bill' => 'Edit bill ":name"', 'delete_bill' => 'Delete bill ":name"', 'reports' => 'Reports', - 'searchResult' => 'Search for ":query"', + 'search_result' => 'Search results for ":query"', 'withdrawal_list' => 'Expenses', 'deposit_list' => 'Revenue, income and deposits', 'transfer_list' => 'Transfers', diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 888f5a70d3..db7c42e92b 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -27,8 +27,7 @@ return [ 'showEverything' => 'Show everything', 'never' => 'Never', 'search_results_for' => 'Search results for ":query"', - 'advanced_search' => 'Advanced search', - 'advanced_search_intro' => 'There are several modifiers that you can use in your search to narrow down the results. If you use any of these, the search will only return transactions. Please click the -icon for more information.', + 'no_results_for_empty_search' => 'Your search was empty, so nothing was found.', 'bounced_error' => 'The message sent to :email bounced, so no access for you.', 'deleted_error' => 'These credentials do not match our records.', 'general_blocked_error' => 'Your account has been disabled, so you cannot login.', @@ -69,13 +68,6 @@ return [ 'two_factor_lost_fix_owner' => 'Otherwise, email the site owner, :site_owner and ask them to reset your two factor authentication.', 'warning_much_data' => ':days days of data may take a while to load.', 'registered' => 'You have registered successfully!', - 'search' => 'Search', - 'search_found_accounts' => 'Found :count account(s) for your query.', - 'search_found_categories' => 'Found :count category(ies) for your query.', - 'search_found_budgets' => 'Found :count budget(s) for your query.', - 'search_found_tags' => 'Found :count tag(s) for your query.', - 'search_found_transactions' => 'Found :count transaction(s) for your query.', - 'results_limited' => 'The results are limited to :count entries.', 'tagbalancingAct' => 'Balancing act', 'tagadvancePayment' => 'Advance payment', 'tagnothing' => '', @@ -152,6 +144,15 @@ return [ 'transfer_exchange_rate_instructions' => 'Source asset account "@source_name" only accepts transactions in @source_currency. Destination asset account "@dest_name" only accepts transactions in @dest_currency. You must provide the transferred amount correctly in both currencies.', 'transaction_data' => 'Transaction data', + // search + 'search' => 'Search', + 'search_found_transactions' => 'Number of transactions found:', + 'general_search_error' => 'An error occured while searching. Please check the log files for more information.', + 'search_box' => 'Search', + 'search_box_intro' => 'Welcome to the search function of Firefly III. Enter your search query in the box. Make sure you check out the help file because the search is pretty advanced.', + 'search_error' => 'Error while searching', + 'search_searching' => 'Searching ...', + // repeat frequencies: 'repeat_freq_yearly' => 'yearly', 'repeat_freq_monthly' => 'monthly', diff --git a/resources/lang/nl_NL/firefly.php b/resources/lang/nl_NL/firefly.php index 5dbff94299..a0a6ea7fcd 100644 --- a/resources/lang/nl_NL/firefly.php +++ b/resources/lang/nl_NL/firefly.php @@ -70,11 +70,8 @@ return [ 'warning_much_data' => 'Het kan even duren voor :days dagen aan gegevens geladen zijn.', 'registered' => 'Je bent geregistreerd!', 'search' => 'Zoeken', - 'search_found_accounts' => ':count rekening(en) gevonden bij je zoekopdracht.', - 'search_found_categories' => ':count categorie(en) gevonden bij je zoekopdracht.', - 'search_found_budgets' => ':count budget(ten) gevonden bij je zoekopdracht.', - 'search_found_tags' => ':count tag(s) gevonden bij je zoekopdracht.', 'search_found_transactions' => ':count transactie(s) gevonden bij je zoekopdracht.', + 'results_limited' => 'Er worden maximaal :count resultaten getoond.', 'tagbalancingAct' => 'Balancerende tag', 'tagadvancePayment' => 'Vooruitbetaalde tag', diff --git a/resources/views/search/index.twig b/resources/views/search/index.twig index 5bfb623b9a..9f2dfd1d62 100644 --- a/resources/views/search/index.twig +++ b/resources/views/search/index.twig @@ -5,151 +5,93 @@ {% endblock %} {% block content %} - {% if query == "" %} -
-
-

{{ 'no_results_for_empty_search'|_ }}

+
+
+
+
+

{{ 'search_box'|_ }}

+
+
+

+ {{ 'search_box_intro'|_ }} +

+ {# search form #} +
+
+ +
+ +
+
+
+
+ +
+
+
+
- {% endif %} +
{% if query %} - -
-
-
+
+
+ -

{{ trans('firefly.results_limited', {count: limit}) }}

- {% if hasModifiers %} -
-
-
-
-

{{ 'transactions'|_ }}

-
-
-

- {{ trans('firefly.search_found_transactions', {count: result.transactions|length}) }} -

- {% include 'search.partials.transactions-large' with {'journals' : result.transactions} %} -
+ + + {% endif %} + {% if query == "" %} +
+
+
+
+

{{ 'search_results'|_ }}

+
+
+

{{ 'no_results_for_empty_search'|_ }}

+
+
+
+
{% endif %} - - - {% endblock %} {% block scripts %} - -{% endblock %} - -{% block styles %} - -{% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/resources/views/search/partials/accounts.twig b/resources/views/search/partials/accounts.twig deleted file mode 100644 index ea071125ff..0000000000 --- a/resources/views/search/partials/accounts.twig +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - {% for account in result.accounts %} - - - - - - - - {% endfor %} - - -
{{ trans('list.name') }}
- {{ account.name }} - {{ trans('firefly.'~account.accountType.type) }}
diff --git a/resources/views/search/partials/budgets.twig b/resources/views/search/partials/budgets.twig deleted file mode 100644 index 5d6c4008d4..0000000000 --- a/resources/views/search/partials/budgets.twig +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - {% for budget in result.budgets %} - - - - - {% endfor %} - - -
{{ trans('list.name') }}
- {{ budget.name }} -
diff --git a/resources/views/search/partials/categories.twig b/resources/views/search/partials/categories.twig deleted file mode 100644 index 7dfef5da15..0000000000 --- a/resources/views/search/partials/categories.twig +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - {% for category in result.categories %} - - - - - {% endfor %} - - -
{{ trans('list.name') }}
- {{ category.name }} -
diff --git a/resources/views/search/partials/tags.twig b/resources/views/search/partials/tags.twig deleted file mode 100644 index fd4342c67b..0000000000 --- a/resources/views/search/partials/tags.twig +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - {% for tag in result.tags %} - - - - - - {% endfor %} - - -
{{ trans('list.name') }}{{ trans('list.type') }}
- {{ tag.tag }} - {{ ('tag'~tag.tagMode)|_ }}
diff --git a/resources/views/search/partials/transactions-large.twig b/resources/views/search/partials/transactions-large.twig deleted file mode 100644 index ca8c06ac92..0000000000 --- a/resources/views/search/partials/transactions-large.twig +++ /dev/null @@ -1,130 +0,0 @@ -{{ journals.render|raw }} - - - - - - - - - - - - - {% if not hideBudgets %} - - {% endif %} - - - {% if not hideCategories %} - - {% endif %} - - - {% if not hideBills %} - - {% endif %} - - - - {% for transaction in journals %} - - - - - - - - - - - - {% if not hideBudgets %} - - {% endif %} - - - {% if not hideCategories %} - - {% endif %} - - - {% if not hideBills %} - - {% endif %} - - {% endfor %} - -
{{ trans('list.description') }}{{ trans('list.amount') }}
- - - {% if transaction.transaction_description|length > 0 %} - {{ transaction.transaction_description }} ({{ transaction.description }}) - {% else %} - {{ transaction.description }} - {% endif %} - - {{ splitJournalIndicator(transaction.journal_id) }} - - {% if transaction.transactionJournal.attachments|length > 0 %} - - {% endif %} - - - - {# TODO replace with new format code #} - XX.XX - - -
- -
-
- {{ journals.render|raw }} -
-
- diff --git a/resources/views/search/partials/transactions.twig b/resources/views/search/partials/transactions.twig deleted file mode 100644 index 387b5ec07b..0000000000 --- a/resources/views/search/partials/transactions.twig +++ /dev/null @@ -1,78 +0,0 @@ -{{ journals.render|raw }} - - - - - - - - - - - - {% for transaction in transactions %} - - - - - - - - {% endfor %} - -
{{ trans('list.description') }}{{ trans('list.amount') }}
- - - {% if transaction.transaction_description|length > 0 %} - {{ transaction.transaction_description }} ({{ transaction.description }}) - {% else %} - {{ transaction.description }} - {% endif %} - - {{ splitJournalIndicator(transaction.journal_id) }} - - {% if transaction.transactionJournal.attachments|length > 0 %} - - {% endif %} - - - {# TODO replace with new format code #} - XX.XX - - -
- -
-
- {{ journals.render|raw }} -
-
- diff --git a/resources/views/search/search.twig b/resources/views/search/search.twig new file mode 100644 index 0000000000..61e89915b4 --- /dev/null +++ b/resources/views/search/search.twig @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + {% for transaction in transactions %} + + + + + + + + + + + + + {% endfor %} + +
{{ trans('list.description') }}{{ trans('list.amount') }}
+ + + {% if transaction.transaction_description|length > 0 %} + {{ transaction.transaction_description }} ({{ transaction.description }}) + {% else %} + {{ transaction.description }} + {% endif %} + + {{ splitJournalIndicator(transaction.journal_id) }} + + {% if transaction.transactionJournal.attachments|length > 0 %} + + {% endif %} + + + {{ transactionAmount(transaction) }} + +
\ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 27724470df..709e58bbe3 100755 --- a/routes/web.php +++ b/routes/web.php @@ -641,7 +641,7 @@ Route::group( Route::group( ['middleware' => 'user-full-auth', 'prefix' => 'search', 'as' => 'search.'], function () { Route::get('', ['uses' => 'SearchController@index', 'as' => 'index']); - + Route::any('search', ['uses' => 'SearchController@search', 'as' => 'search']); } );