| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2016-05-20 12:41:23 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Search.php | 
					
						
							|  |  |  |  * Copyright (C) 2016 thegrumpydictator@gmail.com | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-10-05 06:52:15 +02:00
										 |  |  |  * 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. | 
					
						
							| 
									
										
										
										
											2016-05-20 12:41:23 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-05 12:08:25 +01:00
										 |  |  | declare(strict_types = 1); | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace FireflyIII\Support\Search; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  | use FireflyIII\Helpers\Collector\JournalCollector; | 
					
						
							|  |  |  | use FireflyIII\Models\Account; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  | use FireflyIII\Models\Budget; | 
					
						
							|  |  |  | use FireflyIII\Models\Category; | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  | use FireflyIII\Models\Tag; | 
					
						
							|  |  |  | use FireflyIII\Models\Transaction; | 
					
						
							|  |  |  | use FireflyIII\User; | 
					
						
							| 
									
										
										
										
											2015-03-20 18:21:14 +01:00
										 |  |  | use Illuminate\Support\Collection; | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  | use Log; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Class Search | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @package FireflyIII\Search | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class Search implements SearchInterface | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |     /** @var int */ | 
					
						
							|  |  |  |     private $limit = 100; | 
					
						
							|  |  |  |     /** @var User */ | 
					
						
							|  |  |  |     private $user; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * AttachmentRepository constructor. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param User $user | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function __construct(User $user) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->user = $user; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |      * The search will assume that the user does not have so many accounts | 
					
						
							|  |  |  |      * that this search should be paginated. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |      * @param array $words | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Collection | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-06 10:15:07 +01:00
										 |  |  |     public function searchAccounts(array $words): Collection | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         $accounts = $this->user->accounts()->get(); | 
					
						
							|  |  |  |         /** @var Collection $result */ | 
					
						
							|  |  |  |         $result = $accounts->filter( | 
					
						
							|  |  |  |             function (Account $account) use ($words) { | 
					
						
							|  |  |  |                 if ($this->strpos_arr(strtolower($account->name), $words)) { | 
					
						
							|  |  |  |                     return $account; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return false; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $result = $result->slice(0, $this->limit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $result; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param array $words | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Collection | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-06 10:15:07 +01:00
										 |  |  |     public function searchBudgets(array $words): Collection | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         /** @var Collection $set */ | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         $set = auth()->user()->budgets()->get(); | 
					
						
							|  |  |  |         /** @var Collection $result */ | 
					
						
							|  |  |  |         $result = $set->filter( | 
					
						
							|  |  |  |             function (Budget $budget) use ($words) { | 
					
						
							|  |  |  |                 if ($this->strpos_arr(strtolower($budget->name), $words)) { | 
					
						
							|  |  |  |                     return $budget; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |                 return false; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         $result = $result->slice(0, $this->limit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $result; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |      * Search assumes the user does not have that many categories. So no paginated search. | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |      * @param array $words | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Collection | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-06 10:15:07 +01:00
										 |  |  |     public function searchCategories(array $words): Collection | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         $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; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |                 return false; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         $result     = $result->slice(0, $this->limit); | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         return $result; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param array $words | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Collection | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-06 10:15:07 +01:00
										 |  |  |     public function searchTags(array $words): Collection | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         $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; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param array $words | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return Collection | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-02-06 10:15:07 +01:00
										 |  |  |     public function searchTransactions(array $words): Collection | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         $pageSize  = 100; | 
					
						
							|  |  |  |         $processed = 0; | 
					
						
							|  |  |  |         $page      = 1; | 
					
						
							|  |  |  |         $result    = new Collection(); | 
					
						
							|  |  |  |         do { | 
					
						
							|  |  |  |             $collector = new JournalCollector($this->user); | 
					
						
							|  |  |  |             $collector->setAllAssetAccounts()->setLimit($pageSize)->setPage($page); | 
					
						
							|  |  |  |             $set = $collector->getPaginatedJournals(); | 
					
						
							|  |  |  |             Log::debug(sprintf('Found %d journals to check. ', $set->count())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Filter transactions that match the given triggers.
 | 
					
						
							|  |  |  |             $filtered = $set->filter( | 
					
						
							|  |  |  |                 function (Transaction $transaction) use ($words) { | 
					
						
							|  |  |  |                     // check descr of journal:
 | 
					
						
							|  |  |  |                     if ($this->strpos_arr(strtolower(strval($transaction->description)), $words)) { | 
					
						
							|  |  |  |                         return $transaction; | 
					
						
							| 
									
										
										
										
											2015-03-20 18:21:14 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     // check descr of transaction
 | 
					
						
							|  |  |  |                     if ($this->strpos_arr(strtolower(strval($transaction->transaction_description)), $words)) { | 
					
						
							|  |  |  |                         return $transaction; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     // return false:
 | 
					
						
							|  |  |  |                     return false; | 
					
						
							| 
									
										
										
										
											2015-03-20 18:21:14 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |             ); | 
					
						
							| 
									
										
										
										
											2015-05-05 12:57:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |             Log::debug(sprintf('Found %d journals that match.', $filtered->count())); | 
					
						
							| 
									
										
										
										
											2015-03-20 18:21:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |             // merge:
 | 
					
						
							|  |  |  |             /** @var Collection $result */ | 
					
						
							|  |  |  |             $result = $result->merge($filtered); | 
					
						
							|  |  |  |             Log::debug(sprintf('Total count is now %d', $result->count())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Update counters
 | 
					
						
							|  |  |  |             $page++; | 
					
						
							|  |  |  |             $processed += count($set); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Log::debug(sprintf('Page is now %d, processed is %d', $page, $processed)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Check for conditions to finish the loop
 | 
					
						
							|  |  |  |             $reachedEndOfList = $set->count() < 1; | 
					
						
							|  |  |  |             $foundEnough      = $result->count() >= $this->limit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Log::debug(sprintf('reachedEndOfList: %s', var_export($reachedEndOfList, true))); | 
					
						
							|  |  |  |             Log::debug(sprintf('foundEnough: %s', var_export($foundEnough, true))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         } while (!$reachedEndOfList && !$foundEnough); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $result = $result->slice(0, $this->limit); | 
					
						
							| 
									
										
										
										
											2015-03-20 18:30:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         return $result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param int $limit | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setLimit(int $limit) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->limit = $limit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param string $haystack | 
					
						
							|  |  |  |      * @param array  $needle | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return bool | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     private function strpos_arr(string $haystack, array $needle) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (strlen($haystack) === 0) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         foreach ($needle as $what) { | 
					
						
							|  |  |  |             if (($pos = strpos($haystack, $what)) !== false) { | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-03-20 18:30:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 14:52:31 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2015-02-27 11:09:23 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | }  |