Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cb3b32c

Browse files
authored
PHPORM-268 Add configuration for scout search indexes (#3281)
1 parent 11f3cc1 commit cb3b32c

File tree

4 files changed

+96
-6
lines changed

4 files changed

+96
-6
lines changed

‎src/MongoDBServiceProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,11 @@ private function registerScoutEngine(): void
167167
$connectionName = $app->get('config')->get('scout.mongodb.connection', 'mongodb');
168168
$connection = $app->get('db')->connection($connectionName);
169169
$softDelete = (bool) $app->get('config')->get('scout.soft_delete', false);
170+
$indexDefinitions = $app->get('config')->get('scout.mongodb.index-definitions', []);
170171

171172
assert($connection instanceof Connection, new InvalidArgumentException(sprintf('The connection "%s" is not a MongoDB connection.', $connectionName)));
172173

173-
return new ScoutEngine($connection->getMongoDB(), $softDelete);
174+
return new ScoutEngine($connection->getMongoDB(), $softDelete, $indexDefinitions);
174175
});
175176

176177
return $engineManager;

‎src/Scout/ScoutEngine.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Illuminate\Database\Eloquent\SoftDeletes;
1010
use Illuminate\Support\Collection;
1111
use Illuminate\Support\LazyCollection;
12+
use InvalidArgumentException;
1213
use Laravel\Scout\Builder;
1314
use Laravel\Scout\Engines\Engine;
1415
use Laravel\Scout\Searchable;
@@ -66,9 +67,11 @@ final class ScoutEngine extends Engine
6667

6768
private const TYPEMAP = ['root' => 'object', 'document' => 'bson', 'array' => 'bson'];
6869

70+
/** @param array<string, array> $indexDefinitions */
6971
public function __construct(
7072
private Database $database,
7173
private bool $softDelete,
74+
private array $indexDefinitions = [],
7275
) {
7376
}
7477

@@ -435,14 +438,16 @@ public function createIndex($name, array $options = []): void
435438
{
436439
assert(is_string($name), new TypeError(sprintf('Argument #1 ($name) must be of type string, %s given', get_debug_type($name))));
437440

441+
$definition = $this->indexDefinitions[$name] ?? self::DEFAULT_DEFINITION;
442+
if (! isset($definition['mappings'])) {
443+
throw new InvalidArgumentException(sprintf('Invalid search index definition for collection "%s", the "mappings" key is required. Find documentation at https://www.mongodb.com/docs/manual/reference/command/createSearchIndexes/#search-index-definition-syntax', $name));
444+
}
445+
438446
// Ensure the collection exists before creating the search index
439447
$this->database->createCollection($name);
440448

441449
$collection = $this->database->selectCollection($name);
442-
$collection->createSearchIndex(
443-
self::DEFAULT_DEFINITION,
444-
['name' => self::INDEX_NAME],
445-
);
450+
$collection->createSearchIndex($definition, ['name' => self::INDEX_NAME]);
446451

447452
if ($options['wait'] ?? true) {
448453
$this->wait(function () use ($collection) {

‎tests/Scout/ScoutEngineTest.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33
namespace MongoDB\Laravel\Tests\Scout;
44

5+
use ArrayIterator;
56
use Closure;
67
use DateTimeImmutable;
78
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
89
use Illuminate\Support\Collection as LaravelCollection;
910
use Illuminate\Support\LazyCollection;
1011
use Laravel\Scout\Builder;
1112
use Laravel\Scout\Jobs\RemoveFromSearch;
13+
use LogicException;
1214
use Mockery as m;
15+
use MongoDB\BSON\Document;
1316
use MongoDB\BSON\UTCDateTime;
1417
use MongoDB\Collection;
1518
use MongoDB\Database;
@@ -31,6 +34,82 @@ class ScoutEngineTest extends TestCase
3134
{
3235
private const EXPECTED_TYPEMAP = ['root' => 'object', 'document' => 'bson', 'array' => 'bson'];
3336

37+
public function testCreateIndexInvalidDefinition(): void
38+
{
39+
$database = m::mock(Database::class);
40+
$engine = new ScoutEngine($database, false, ['collection_invalid' => ['foo' => 'bar']]);
41+
42+
$this->expectException(LogicException::class);
43+
$this->expectExceptionMessage('Invalid search index definition for collection "collection_invalid", the "mappings" key is required.');
44+
$engine->createIndex('collection_invalid');
45+
}
46+
47+
public function testCreateIndex(): void
48+
{
49+
$collectionName = 'collection_custom';
50+
$expectedDefinition = [
51+
'mappings' => [
52+
'dynamic' => true,
53+
],
54+
];
55+
56+
$database = m::mock(Database::class);
57+
$collection = m::mock(Collection::class);
58+
$database->shouldReceive('createCollection')
59+
->once()
60+
->with($collectionName);
61+
$database->shouldReceive('selectCollection')
62+
->with($collectionName)
63+
->andReturn($collection);
64+
$collection->shouldReceive('createSearchIndex')
65+
->once()
66+
->with($expectedDefinition, ['name' => 'scout']);
67+
$collection->shouldReceive('listSearchIndexes')
68+
->once()
69+
->with(['name' => 'scout', 'typeMap' => ['root' => 'bson']])
70+
->andReturn(new ArrayIterator([Document::fromPHP(['name' => 'scout', 'status' => 'READY'])]));
71+
72+
$engine = new ScoutEngine($database, false, []);
73+
$engine->createIndex($collectionName);
74+
}
75+
76+
public function testCreateIndexCustomDefinition(): void
77+
{
78+
$collectionName = 'collection_custom';
79+
$expectedDefinition = [
80+
'mappings' => [
81+
[
82+
'analyzer' => 'lucene.standard',
83+
'fields' => [
84+
[
85+
'name' => 'wildcard',
86+
'type' => 'string',
87+
],
88+
],
89+
],
90+
],
91+
];
92+
93+
$database = m::mock(Database::class);
94+
$collection = m::mock(Collection::class);
95+
$database->shouldReceive('createCollection')
96+
->once()
97+
->with($collectionName);
98+
$database->shouldReceive('selectCollection')
99+
->with($collectionName)
100+
->andReturn($collection);
101+
$collection->shouldReceive('createSearchIndex')
102+
->once()
103+
->with($expectedDefinition, ['name' => 'scout']);
104+
$collection->shouldReceive('listSearchIndexes')
105+
->once()
106+
->with(['name' => 'scout', 'typeMap' => ['root' => 'bson']])
107+
->andReturn(new ArrayIterator([Document::fromPHP(['name' => 'scout', 'status' => 'READY'])]));
108+
109+
$engine = new ScoutEngine($database, false, [$collectionName => $expectedDefinition]);
110+
$engine->createIndex($collectionName);
111+
}
112+
34113
/** @param callable(): Builder $builder */
35114
#[DataProvider('provideSearchPipelines')]
36115
public function testSearch(Closure $builder, array $expectedPipeline): void

‎tests/Scout/ScoutIntegrationTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use function array_merge;
1818
use function count;
1919
use function env;
20+
use function iterator_to_array;
2021
use function Orchestra\Testbench\artisan;
2122
use function range;
2223
use function sprintf;
@@ -38,6 +39,9 @@ protected function getEnvironmentSetUp($app): void
3839

3940
$app['config']->set('scout.driver', 'mongodb');
4041
$app['config']->set('scout.prefix', 'prefix_');
42+
$app['config']->set('scout.mongodb.index-definitions', [
43+
'prefix_scout_users' => ['mappings' => ['dynamic' => true, 'fields' => ['bool_field' => ['type' => 'boolean']]]],
44+
]);
4145
}
4246

4347
public function setUp(): void
@@ -103,8 +107,9 @@ public function testItCanCreateTheCollection()
103107

104108
self::assertSame(44, $collection->countDocuments());
105109

106-
$searchIndexes = $collection->listSearchIndexes(['name' => 'scout']);
110+
$searchIndexes = $collection->listSearchIndexes(['name' => 'scout', 'typeMap' => ['root' => 'array', 'document' => 'array', 'array' => 'array']]);
107111
self::assertCount(1, $searchIndexes);
112+
self::assertSame(['mappings' => ['dynamic' => true, 'fields' => ['bool_field' => ['type' => 'boolean']]]], iterator_to_array($searchIndexes)[0]['latestDefinition']);
108113

109114
// Wait for all documents to be indexed asynchronously
110115
$i = 100;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /