From 6cf3617ba8f1107f5f3f6f32f0d7153feb6652dd Mon Sep 17 00:00:00 2001 From: Mark Beech Date: Fri, 29 May 2020 09:59:13 +0100 Subject: [PATCH 1/5] Allow booting multiple aggregators without duplicating Model observers --- src/Searchable/AggregatorObserver.php | 17 +++++++++++ src/Searchable/Aggregators.php | 41 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/Searchable/Aggregators.php diff --git a/src/Searchable/AggregatorObserver.php b/src/Searchable/AggregatorObserver.php index 7b8a5904..7bd65653 100644 --- a/src/Searchable/AggregatorObserver.php +++ b/src/Searchable/AggregatorObserver.php @@ -47,6 +47,23 @@ public function setAggregator(string $aggregator, array $models): void } } + /** + * Set multiple aggregators. + * + * @param string[] $aggregators + * @param string $model + * + * @return void + */ + public function setAggregators(array $aggregators, string $model): void + { + if (! array_key_exists($model, $this->aggregators)) { + $this->aggregators[$model] = []; + } + + $this->aggregators[$model] = $aggregators; + } + /** * {@inheritdoc} */ diff --git a/src/Searchable/Aggregators.php b/src/Searchable/Aggregators.php new file mode 100644 index 00000000..d38a6013 --- /dev/null +++ b/src/Searchable/Aggregators.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Algolia\ScoutExtended\Searchable; + +class Aggregators extends Aggregator +{ + /** + * Boot multiple aggregators. + * + * @return void + */ + public static function bootSearchables(array $searchables): void + { + (new static)->registerSearchableMacros(); + + $models = []; + + foreach ($searchables as $searchable) { + foreach ((new $searchable)->getModels() as $model) { + $models[$model][] = $searchable; + } + } + + foreach ($models as $model => $searchables) { + $observer = tap(app(AggregatorObserver::class))->setAggregators($searchables, $model); + + $model::observe($observer); + } + } +} \ No newline at end of file From d7ae59dc5f2fce0436cf3710118d8e95a7ddc4c5 Mon Sep 17 00:00:00 2001 From: Mark Beech Date: Wed, 10 Mar 2021 13:08:08 +0000 Subject: [PATCH 2/5] Update src/Searchable/Aggregators.php Co-authored-by: Devin Beeuwkes <46448173+DevinCodes@users.noreply.github.com> --- src/Searchable/Aggregators.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Searchable/Aggregators.php b/src/Searchable/Aggregators.php index d38a6013..715e7131 100644 --- a/src/Searchable/Aggregators.php +++ b/src/Searchable/Aggregators.php @@ -28,7 +28,7 @@ public static function bootSearchables(array $searchables): void foreach ($searchables as $searchable) { foreach ((new $searchable)->getModels() as $model) { - $models[$model][] = $searchable; + $models[(string) $model][] = $searchable; } } @@ -38,4 +38,4 @@ public static function bootSearchables(array $searchables): void $model::observe($observer); } } -} \ No newline at end of file +} From 79aa9fb556140f8397d380c5aa39c91690de1cbd Mon Sep 17 00:00:00 2001 From: Devin Beeuwkes Date: Wed, 25 Aug 2021 14:15:54 +0200 Subject: [PATCH 3/5] feat: add tests for Aggregators::bootSearchables --- tests/Features/AggregatorTest.php | 48 +++++++++++++++++++++++++++++++ tests/laravel/app/All.php | 14 +++++++++ 2 files changed, 62 insertions(+) create mode 100644 tests/laravel/app/All.php diff --git a/tests/Features/AggregatorTest.php b/tests/Features/AggregatorTest.php index 1ac43de7..6816d4ed 100644 --- a/tests/Features/AggregatorTest.php +++ b/tests/Features/AggregatorTest.php @@ -5,6 +5,8 @@ namespace Tests\Features; use Algolia\ScoutExtended\Searchable\AggregatorCollection; +use Algolia\ScoutExtended\Searchable\Aggregators; +use App\All; use App\News; use App\Post; use App\Thread; @@ -219,4 +221,50 @@ public function testRelationLoad(): void $this->assertFalse(Wall::search()->get()->first()->relationLoaded('threads')); $this->assertTrue(News::search()->get()->first()->relationLoaded('threads')); } + + public function testAggregatorWithMultipleBoots(): void + { + Aggregators::bootSearchables([ + Wall::class, + All::class, + ]); + + $usersIndexMock = $this->mockIndex('users'); + $wallIndexMock = $this->mockIndex('wall'); + $allIndexMock = $this->mockIndex('all'); + + $usersIndexMock->shouldReceive('saveObjects')->once()->with(Mockery::on(function ($argument) { + return count($argument) === 1 && array_key_exists('email', $argument[0]) && + $argument[0]['objectID'] === 'App\User::1'; + })); + $wallIndexMock->shouldReceive('saveObjects')->once()->with(Mockery::on(function ($argument) { + return count($argument) === 1 && array_key_exists('email', $argument[0]) && + $argument[0]['objectID'] === 'App\User::1'; + })); + $allIndexMock->shouldReceive('saveObjects')->once()->with(Mockery::on(function ($argument) { + return count($argument) === 1 && array_key_exists('email', $argument[0]) && + $argument[0]['objectID'] === 'App\User::1'; + })); + $user = factory(User::class)->create(); + + $usersIndexMock->shouldReceive('deleteBy')->once()->with([ + 'tagFilters' => [ + ['App\User::1'], + ], + ]); + + $wallIndexMock->shouldReceive('deleteBy')->once()->with([ + 'tagFilters' => [ + ['App\User::1'], + ], + ]); + + $allIndexMock->shouldReceive('deleteBy')->once()->with([ + 'tagFilters' => [ + ['App\User::1'], + ], + ]); + + $user->delete(); + } } diff --git a/tests/laravel/app/All.php b/tests/laravel/app/All.php new file mode 100644 index 00000000..d7ba16d6 --- /dev/null +++ b/tests/laravel/app/All.php @@ -0,0 +1,14 @@ + Date: Wed, 25 Aug 2021 14:28:51 +0200 Subject: [PATCH 4/5] fix: tests --- tests/Features/FlushCommandTest.php | 2 ++ tests/Features/ImportCommandTest.php | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/tests/Features/FlushCommandTest.php b/tests/Features/FlushCommandTest.php index 8408f5a4..c88febb0 100644 --- a/tests/Features/FlushCommandTest.php +++ b/tests/Features/FlushCommandTest.php @@ -4,6 +4,7 @@ namespace Tests\Features; +use App\All; use App\EmptyItem; use App\News; use App\Thread; @@ -20,6 +21,7 @@ public function testClearsIndex(): void $this->mockIndex(User::class)->expects('clearObjects')->once(); $this->mockIndex(Thread::class)->expects('clearObjects')->once(); $this->mockIndex(Wall::class)->expects('clearObjects')->once(); + $this->mockIndex(All::class)->expects('clearObjects')->once(); $this->mockIndex(EmptyItem::class)->expects('clearObjects')->once(); $this->mockIndex(Term::class)->expects('clearObjects')->once(); diff --git a/tests/Features/ImportCommandTest.php b/tests/Features/ImportCommandTest.php index 33002e5e..c27a220f 100644 --- a/tests/Features/ImportCommandTest.php +++ b/tests/Features/ImportCommandTest.php @@ -4,6 +4,7 @@ namespace Tests\Features; +use App\All; use App\EmptyItem; use App\News; use App\Thread; @@ -20,6 +21,7 @@ final class ImportCommandTest extends TestCase public function testImport(): void { Wall::bootSearchable(); + All::bootSearchable(); News::bootSearchable(); $this->app['config']->set('scout.soft_delete', true); @@ -41,6 +43,12 @@ public function testImport(): void return count($argument) === 5 && $argument[0]['objectID'] === 'App\User::1'; })); + $allIndexMock = $this->mockIndex(All::class); + $allIndexMock->expects('clearObjects')->once(); + $allIndexMock->expects('saveObjects')->once()->with(Mockery::on(function ($argument) { + return count($argument) === 5 && $argument[0]['objectID'] === 'App\User::1'; + })); + $newsIndexMock = $this->mockIndex(News::class); $newsIndexMock->expects('clearObjects')->once(); $newsIndexMock->expects('saveObjects')->once()->with(Mockery::on(function ($argument) { From 9d17e75d45abe45b97f036c4812f33ae329b31c3 Mon Sep 17 00:00:00 2001 From: Devin Beeuwkes Date: Wed, 25 Aug 2021 14:57:43 +0200 Subject: [PATCH 5/5] chore: update annotations for PHPStan --- src/Searchable/ObjectIdEncrypter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Searchable/ObjectIdEncrypter.php b/src/Searchable/ObjectIdEncrypter.php index 15f3b93e..8a4f29b1 100644 --- a/src/Searchable/ObjectIdEncrypter.php +++ b/src/Searchable/ObjectIdEncrypter.php @@ -25,7 +25,7 @@ final class ObjectIdEncrypter /** * Holds the metadata separator. * - * @var string + * @var non-empty-string */ private static $separator = '::';