Skip to content

Commit f1017f3

Browse files
committed
re-index re-worked
1 parent 80a01b5 commit f1017f3

10 files changed

Lines changed: 59 additions & 32 deletions

resources/stubs/ElasticModel.php.stub

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace {{ namespace }};
44

55
use Carbon\Carbon;
6-
use PDPhilip\Elasticsearch\Eloquent\HasMappingDefinition;
76
use PDPhilip\Elasticsearch\Eloquent\Model as Eloquent;
87
use PDPhilip\Elasticsearch\Schema\Blueprint;
98

@@ -15,7 +14,7 @@ use PDPhilip\Elasticsearch\Schema\Blueprint;
1514
* @property Carbon $updated_at
1615
* @property Carbon $created_at
1716
*/
18-
class {{ class }} extends Eloquent implements HasMappingDefinition
17+
class {{ class }} extends Eloquent
1918
{
2019
protected $connection = 'elasticsearch';
2120

src/Commands/ReIndexCommand.php

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use Illuminate\Support\Facades\DB;
1111
use OmniTerm\HasOmniTerm;
1212
use PDPhilip\Elasticsearch\Connection;
13-
use PDPhilip\Elasticsearch\Eloquent\HasMappingDefinition;
1413
use PDPhilip\Elasticsearch\Eloquent\Model;
1514
use PDPhilip\Elasticsearch\Schema\Blueprint;
1615
use PDPhilip\Elasticsearch\Schema\Builder as SchemaBuilder;
@@ -174,21 +173,17 @@ private function resolveModel(): ?Model
174173
return null;
175174
}
176175

177-
if (! is_subclass_of($class, HasMappingDefinition::class)) {
176+
if (! $class::hasMappingDefinition()) {
178177
$this->newLine();
179178
$this->omni->statusError('Missing mapping definition', $class, [
180-
'Your model must implement HasMappingDefinition:',
179+
'Your model must override mappingDefinition():',
181180
'',
182-
'use PDPhilip\Elasticsearch\Eloquent\HasMappingDefinition;',
183181
'use PDPhilip\Elasticsearch\Schema\Blueprint;',
184182
'',
185-
'class YourModel extends Eloquent implements HasMappingDefinition',
183+
'public static function mappingDefinition(Blueprint $index): void',
186184
'{',
187-
' public static function mappingDefinition(Blueprint $index): void',
188-
' {',
189-
' $index->keyword(\'status\');',
190-
' $index->geoPoint(\'location\');',
191-
' }',
185+
' $index->keyword(\'status\');',
186+
' $index->geoPoint(\'location\');',
192187
'}',
193188
]);
194189
$this->newLine();
@@ -250,7 +245,6 @@ private function setupFromModel(Model $model): void
250245
$this->tempIndexName = $this->indexName.'_temp';
251246
$this->connectionName = $model->getConnectionName();
252247

253-
/** @var Connection $connection */
254248
$this->connection = DB::connection($this->connectionName);
255249
$this->schema = $this->connection->getSchemaBuilder();
256250

@@ -603,14 +597,14 @@ private function summary(): void
603597
{
604598
$duration = round(microtime(true) - $this->startTime, 2);
605599

606-
$this->omni->hr();
607-
$this->omni->titleBar('Re-Index Complete', 'emerald');
608-
$this->omni->tableHeader('Metric', 'Value');
609-
$this->omni->tableRow('Index', $this->indexName);
610-
$this->omni->tableRow('Original count', number_format($this->originalCount));
611-
$this->omni->tableRow('Final count', number_format($this->finalCount));
612-
$this->omni->tableRow('Duration', $duration.'s');
613-
$this->omni->hr();
600+
$data = [
601+
'Index' => $this->indexName,
602+
'Original count' => number_format($this->originalCount),
603+
'Final count' => number_format($this->finalCount),
604+
'Duration' => $duration.'s',
605+
606+
];
607+
$this->omni->dataList($data, 'Re-Index Complete', 'text-emerald-500');
614608
$this->newLine();
615609
}
616610

@@ -671,7 +665,7 @@ private function mappingMismatches(): array
671665

672666
$blueprint = Helpers::getLaravelCompatabilityVersion() >= 12
673667
? new Blueprint($this->connection, $this->indexName)
674-
: new Blueprint($this->indexName);
668+
: new Blueprint($this->indexName); // @phpstan-ignore arguments.count
675669
($this->mappingDefinition)($blueprint);
676670

677671
$mismatches = [];

src/Eloquent/ElasticsearchModel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ protected function newBaseQueryBuilder()
130130
Model::OPTION_STORE_IDS => $this->storeIdInDocument,
131131
]);
132132

133-
if ($this instanceof HasMappingDefinition) {
133+
if (static::hasMappingDefinition()) {
134134
$connection->registerMappingDefinition(
135135
$connection->getTablePrefix().$this->getTable(),
136136
fn ($index) => static::mappingDefinition($index)

src/Eloquent/HasMappingDefinition.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
use PDPhilip\Elasticsearch\Schema\Blueprint;
88

9+
/**
10+
* @deprecated Override Model::mappingDefinition() directly instead.
11+
*/
912
interface HasMappingDefinition
1013
{
1114
public static function mappingDefinition(Blueprint $index): void;

src/Eloquent/Model.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use Illuminate\Database\Eloquent\Model as BaseModel;
88
use PDPhilip\Elasticsearch\Data\ModelMeta;
9+
use PDPhilip\Elasticsearch\Schema\Blueprint;
10+
use ReflectionMethod;
911

1012
/**
1113
* @property object $searchHighlights
@@ -82,4 +84,23 @@ final public static function isElasticsearchModel(string|object $class): bool
8284
// Document models must use the DocumentModel trait.
8385
return self::$documentModelClasses[$class] = array_key_exists(ElasticsearchModel::class, class_uses_recursive($class));
8486
}
87+
88+
/**
89+
* Define the index mapping for this model.
90+
* Override this method to specify field types for your Elasticsearch index.
91+
*/
92+
public static function mappingDefinition(Blueprint $index): void
93+
{
94+
//
95+
}
96+
97+
/**
98+
* Check if this model has a mapping definition (i.e. overrides the base method).
99+
*/
100+
final public static function hasMappingDefinition(): bool
101+
{
102+
$ref = new ReflectionMethod(static::class, 'mappingDefinition');
103+
104+
return $ref->getDeclaringClass()->getName() !== self::class;
105+
}
85106
}

src/Query/Concerns/BuildsNestedQueries.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ public function whereNestedObject($column, $query, $filterInnerHits = false, $op
2828
}
2929
$options = $options->toArray();
3030

31-
$this->options()->add('parentField', $column);
3231
if (! is_string($query) && is_callable($query)) {
33-
call_user_func($query, $query = $this->newQuery($from));
32+
$callback = $query;
33+
$query = $this->newQuery($from);
34+
$query->options()->add('parentField', $column);
35+
call_user_func($callback, $query);
3436
}
3537

3638
$this->wheres[] = compact('column', 'query', 'type', 'boolean', 'not', 'options');
@@ -72,9 +74,11 @@ public function filterNested($column, $query, $options = [])
7274
$options = $this->setOptions($options, 'nested');
7375
$options = $options->toArray();
7476

75-
$this->options()->add('parentField', $column);
7677
if (! is_string($query) && is_callable($query)) {
77-
call_user_func($query, $query = $this->newQuery($from));
78+
$callback = $query;
79+
$query = $this->newQuery($from);
80+
$query->options()->add('parentField', $column);
81+
call_user_func($callback, $query);
7882
}
7983

8084
$this->wheres[] = compact('column', 'query', 'type', 'boolean', 'not', 'options');

tests/MakeCommandTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868

6969
$content = File::get(app_path('Models/Event.php'));
7070
expect($content)
71-
->toContain('implements HasMappingDefinition')
71+
->not->toContain('implements HasMappingDefinition')
7272
->toContain('public static function mappingDefinition(Blueprint $index): void')
7373
->toContain("\$index->date('created_at');")
7474
->toContain("\$index->date('updated_at');");

tests/Models/ReIndexTarget.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44

55
namespace PDPhilip\Elasticsearch\Tests\Models;
66

7-
use PDPhilip\Elasticsearch\Eloquent\HasMappingDefinition;
87
use PDPhilip\Elasticsearch\Eloquent\Model;
98
use PDPhilip\Elasticsearch\Schema\Blueprint;
109
use PDPhilip\Elasticsearch\Tests\Concerns\TestsWithIdStrategies;
1110

12-
class ReIndexTarget extends Model implements HasMappingDefinition
11+
class ReIndexTarget extends Model
1312
{
1413
use TestsWithIdStrategies;
1514

tests/QueryElasticsearchSpecificTest.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,14 @@
128128
});
129129

130130
it('counts nested queries', function () {
131-
$count = Post::where('status',2)->whereNestedObject('comments', function (Builder $query) {
131+
// Only "Getting Started with Laravel" has status=2 AND a USA comment
132+
$count = Post::where('status', 2)->whereNestedObject('comments', function (Builder $query) {
133+
$query->where('country', 'USA');
134+
})->count();
135+
expect($count)->toBe(1);
136+
137+
// Both USA-comment posts (status 1 and 2)
138+
$count = Post::whereNestedObject('comments', function (Builder $query) {
132139
$query->where('country', 'USA');
133140
})->count();
134141
expect($count)->toBe(2);

tests/ReIndexCommandTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
])->assertFailed();
5656
});
5757

58-
it('fails when model lacks HasMappingDefinition', function () {
58+
it('fails when model lacks mappingDefinition override', function () {
5959
$this->artisan('elastic:re-index', [
6060
'model' => \PDPhilip\Elasticsearch\Tests\Models\Product::class,
6161
'--force' => true,

0 commit comments

Comments
 (0)