mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2024-11-22 08:56:39 -06:00
Add new search options for https://github.com/firefly-iii/firefly-iii/issues/7571
This commit is contained in:
parent
a5c370c70e
commit
3136bccb24
@ -917,6 +917,7 @@ trait MetaCollection
|
||||
$list = $tags->pluck('tag')->toArray();
|
||||
$filter = static function (array $object) use ($list): bool {
|
||||
foreach ($object['transactions'] as $transaction) {
|
||||
app('log')->debug(sprintf('Transaction has %d tag(s)', count($transaction['tags'])));
|
||||
foreach ($transaction['tags'] as $tag) {
|
||||
if (in_array($tag['name'], $list, true)) {
|
||||
return false;
|
||||
|
@ -515,7 +515,6 @@ class GroupCollector implements GroupCollectorInterface
|
||||
// add to query:
|
||||
$this->query->orWhereIn('transaction_journals.transaction_group_id', $groupIds);
|
||||
}
|
||||
|
||||
$result = $this->query->get($this->fields);
|
||||
|
||||
// now to parse this into an array.
|
||||
@ -823,10 +822,15 @@ class GroupCollector implements GroupCollectorInterface
|
||||
private function postFilterCollection(Collection $collection): Collection
|
||||
{
|
||||
$currentCollection = $collection;
|
||||
|
||||
app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d filter(s) and %d transaction(s).', count($this->postFilters), count($currentCollection)));
|
||||
|
||||
|
||||
/**
|
||||
* @var Closure $function
|
||||
*/
|
||||
foreach ($this->postFilters as $function) {
|
||||
app('log')->debug('Applying filter...');
|
||||
$nextCollection = new Collection();
|
||||
// loop everything in the current collection
|
||||
// and save it (or not) in the new collection.
|
||||
@ -843,6 +847,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$nextCollection->push($item);
|
||||
}
|
||||
$currentCollection = $nextCollection;
|
||||
app('log')->debug(sprintf('GroupCollector: postFilterCollection has %d transaction(s) left.', count($currentCollection)));
|
||||
}
|
||||
return $currentCollection;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ class TagRepository implements TagRepositoryInterface
|
||||
*/
|
||||
public function get(): Collection
|
||||
{
|
||||
return $this->user->tags()->orderBy('tag', 'ASC')->get();
|
||||
return $this->user->tags()->orderBy('tag', 'ASC')->get(['tags.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -454,4 +454,24 @@ class TagRepository implements TagRepositoryInterface
|
||||
/** @var Location|null */
|
||||
return $tag->locations()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function tagStartsWith(string $query): Collection
|
||||
{
|
||||
$search = sprintf('%s%%', $query);
|
||||
|
||||
return $this->user->tags()->where('tag', 'LIKE', $search)->get(['tags.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function tagEndsWith(string $query): Collection
|
||||
{
|
||||
$search = sprintf('%%%s', $query);
|
||||
|
||||
return $this->user->tags()->where('tag', 'LIKE', $search)->get(['tags.*']);
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +153,24 @@ interface TagRepositoryInterface
|
||||
*/
|
||||
public function searchTag(string $query): Collection;
|
||||
|
||||
/**
|
||||
* Find one or more tags that start with the string in the query
|
||||
*
|
||||
* @param string $query
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function tagStartsWith(string $query): Collection;
|
||||
|
||||
/**
|
||||
* Find one or more tags that start with the string in the query
|
||||
*
|
||||
* @param string $query
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function tagEndsWith(string $query): Collection;
|
||||
|
||||
/**
|
||||
* Search the users tags.
|
||||
*
|
||||
|
@ -57,7 +57,6 @@ use Gdbots\QueryParser\QueryParser;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use LogicException;
|
||||
use PragmaRX\Random\Generators\StringGenerator;
|
||||
use TypeError;
|
||||
|
||||
/**
|
||||
@ -82,6 +81,9 @@ class OperatorQuerySearch implements SearchInterface
|
||||
private array $validOperators;
|
||||
private array $words;
|
||||
|
||||
private array $excludeTags;
|
||||
private array $includeTags;
|
||||
|
||||
/**
|
||||
* OperatorQuerySearch constructor.
|
||||
*
|
||||
@ -93,6 +95,8 @@ class OperatorQuerySearch implements SearchInterface
|
||||
$this->operators = new Collection();
|
||||
$this->page = 1;
|
||||
$this->words = [];
|
||||
$this->excludeTags = [];
|
||||
$this->includeTags = [];
|
||||
$this->prohibitedWords = [];
|
||||
$this->invalidOperators = [];
|
||||
$this->limit = 25;
|
||||
@ -167,6 +171,8 @@ class OperatorQuerySearch implements SearchInterface
|
||||
foreach ($query1->getNodes() as $searchNode) {
|
||||
$this->handleSearchNode($searchNode);
|
||||
}
|
||||
$this->parseTagInstructions();
|
||||
|
||||
|
||||
$this->collector->setSearchWords($this->words);
|
||||
$this->collector->excludeSearchWords($this->prohibitedWords);
|
||||
@ -868,7 +874,8 @@ class OperatorQuerySearch implements SearchInterface
|
||||
case 'tag_is':
|
||||
$result = $this->tagRepository->findByTag($value);
|
||||
if (null !== $result) {
|
||||
$this->collector->setTags(new Collection([$result]));
|
||||
$this->includeTags[] = $result->id;
|
||||
$this->includeTags = array_unique($this->includeTags);
|
||||
}
|
||||
// no tags found means search must result in nothing.
|
||||
if (null === $result) {
|
||||
@ -876,11 +883,79 @@ class OperatorQuerySearch implements SearchInterface
|
||||
$this->collector->findNothing();
|
||||
}
|
||||
break;
|
||||
case 'tag_contains':
|
||||
$tags = $this->tagRepository->searchTag($value);
|
||||
if (0 === $tags->count()) {
|
||||
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
|
||||
$this->collector->findNothing();
|
||||
}
|
||||
if ($tags->count() > 0) {
|
||||
$ids = array_values($tags->pluck('id')->toArray());
|
||||
$this->includeTags = array_unique(array_merge($this->includeTags, $ids));
|
||||
}
|
||||
break;
|
||||
case 'tag_starts':
|
||||
$tags = $this->tagRepository->tagStartsWith($value);
|
||||
if (0 === $tags->count()) {
|
||||
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
|
||||
$this->collector->findNothing();
|
||||
}
|
||||
if ($tags->count() > 0) {
|
||||
$ids = array_values($tags->pluck('id')->toArray());
|
||||
$this->includeTags = array_unique(array_merge($this->includeTags, $ids));
|
||||
}
|
||||
break;
|
||||
case '-tag_starts':
|
||||
$tags = $this->tagRepository->tagStartsWith($value);
|
||||
if (0 === $tags->count()) {
|
||||
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
|
||||
$this->collector->findNothing();
|
||||
}
|
||||
if ($tags->count() > 0) {
|
||||
$ids = array_values($tags->pluck('id')->toArray());
|
||||
$this->excludeTags = array_unique(array_merge($this->includeTags, $ids));
|
||||
}
|
||||
break;
|
||||
case 'tag_ends':
|
||||
$tags = $this->tagRepository->tagEndsWith($value);
|
||||
if (0 === $tags->count()) {
|
||||
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
|
||||
$this->collector->findNothing();
|
||||
}
|
||||
if ($tags->count() > 0) {
|
||||
$ids = array_values($tags->pluck('id')->toArray());
|
||||
$this->includeTags = array_unique(array_merge($this->includeTags, $ids));
|
||||
}
|
||||
break;
|
||||
case '-tag_ends':
|
||||
$tags = $this->tagRepository->tagEndsWith($value);
|
||||
if (0 === $tags->count()) {
|
||||
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
|
||||
$this->collector->findNothing();
|
||||
}
|
||||
if ($tags->count() > 0) {
|
||||
$ids = array_values($tags->pluck('id')->toArray());
|
||||
$this->excludeTags = array_unique(array_merge($this->includeTags, $ids));
|
||||
}
|
||||
break;
|
||||
case '-tag_contains':
|
||||
$tags = $this->tagRepository->searchTag($value)->keyBy('id');
|
||||
|
||||
if (0 === $tags->count()) {
|
||||
app('log')->info(sprintf('No valid tags in "%s"-operator, so search will not return ANY results.', $operator));
|
||||
$this->collector->findNothing();
|
||||
}
|
||||
if ($tags->count() > 0) {
|
||||
$ids = array_values($tags->pluck('id')->toArray());
|
||||
$this->excludeTags = array_unique(array_merge($this->excludeTags, $ids));
|
||||
}
|
||||
break;
|
||||
case '-tag_is':
|
||||
case 'tag_is_not':
|
||||
$result = $this->tagRepository->searchTag($value);
|
||||
if ($result->count() > 0) {
|
||||
$this->collector->setWithoutSpecificTags($result);
|
||||
$this->excludeTags[] = $result->id;
|
||||
$this->excludeTags = array_unique($this->excludeTags);
|
||||
}
|
||||
break;
|
||||
//
|
||||
@ -2160,4 +2235,42 @@ class OperatorQuerySearch implements SearchInterface
|
||||
$this->limit = $limit;
|
||||
$this->collector->setLimit($this->limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \Psr\Container\ContainerExceptionInterface
|
||||
* @throws \Psr\Container\NotFoundExceptionInterface
|
||||
*/
|
||||
private function parseTagInstructions(): void
|
||||
{
|
||||
app('log')->debug('Now in parseTagInstructions()');
|
||||
// if exclude tags, remove excluded tags.
|
||||
if (count($this->excludeTags) > 0) {
|
||||
app('log')->debug(sprintf('%d exclude tag(s)', count($this->excludeTags)));
|
||||
$collection = new Collection;
|
||||
foreach ($this->excludeTags as $tagId) {
|
||||
$tag = $this->tagRepository->find($tagId);
|
||||
if (null !== $tag) {
|
||||
app('log')->debug(sprintf('Exclude tag "%s"', $tag->tag));
|
||||
$collection->push($tag);
|
||||
}
|
||||
}
|
||||
app('log')->debug(sprintf('Selecting all tags except %d excluded tag(s).', $collection->count()));
|
||||
$this->collector->setWithoutSpecificTags($collection);
|
||||
}
|
||||
// if include tags, include them:
|
||||
if (count($this->includeTags) > 0) {
|
||||
app('log')->debug(sprintf('%d include tag(s)', count($this->includeTags)));
|
||||
$collection = new Collection;
|
||||
foreach ($this->includeTags as $tagId) {
|
||||
$tag = $this->tagRepository->find($tagId);
|
||||
if (null !== $tag) {
|
||||
app('log')->debug(sprintf('Include tag "%s"', $tag->tag));
|
||||
$collection->push($tag);
|
||||
}
|
||||
}
|
||||
$this->collector->setTags($collection);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ return [
|
||||
'tag_is' => ['alias' => false, 'needs_context' => true,],
|
||||
'tag_is_not' => ['alias' => false, 'needs_context' => true,],
|
||||
'tag' => ['alias' => true, 'alias_for' => 'tag_is', 'needs_context' => true,],
|
||||
'tag_contains' => ['alias' => false, 'needs_context' => true,],
|
||||
'tag_ends' => ['alias' => false, 'needs_context' => true,],
|
||||
'tag_starts' => ['alias' => false, 'needs_context' => true,],
|
||||
'description_is' => ['alias' => false, 'needs_context' => true,],
|
||||
'description' => ['alias' => true, 'alias_for' => 'description_is', 'needs_context' => true,],
|
||||
'description_contains' => ['alias' => false, 'needs_context' => true,],
|
||||
|
@ -449,6 +449,10 @@ return [
|
||||
'search_modifier_transaction_type' => 'Transaction type is ":value"',
|
||||
'search_modifier_not_transaction_type' => 'Transaction type is not ":value"',
|
||||
'search_modifier_tag_is' => 'Tag is ":value"',
|
||||
'search_modifier_tag_contains' => 'Tag contains ":value"',
|
||||
'search_modifier_not_tag_contains' => 'Tag does not contain ":value"',
|
||||
'search_modifier_tag_ends' => 'Tag ends with ":value"',
|
||||
'search_modifier_tag_starts' => 'Tag starts with ":value"',
|
||||
'search_modifier_not_tag_is' => 'No tag is ":value"',
|
||||
'search_modifier_date_on_year' => 'Transaction is in year ":value"',
|
||||
'search_modifier_not_date_on_year' => 'Transaction is not in year ":value"',
|
||||
|
Loading…
Reference in New Issue
Block a user