Skip to content

Commit c1e1e92

Browse files
[9.x] Fix removing queued models with custom Scout keys (#480)
* Re-push remove from Scout queue fix #479 * Fix test * StyleCI fixes * Update src/Jobs/RemoveFromSearch.php Co-authored-by: Dries Vints <dries@vints.io> * Update RemoveFromSearch.php Co-authored-by: Dries Vints <dries@vints.io>
1 parent ce621be commit c1e1e92

File tree

4 files changed

+113
-5
lines changed

4 files changed

+113
-5
lines changed

src/Jobs/RemoveFromSearch.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Contracts\Queue\ShouldQueue;
77
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
88
use Illuminate\Queue\SerializesModels;
9+
use Illuminate\Support\Str;
910

1011
class RemoveFromSearch implements ShouldQueue
1112
{
@@ -26,7 +27,7 @@ class RemoveFromSearch implements ShouldQueue
2627
*/
2728
public function __construct($models)
2829
{
29-
$this->models = $models;
30+
$this->models = RemoveableScoutCollection::make($models);
3031
}
3132

3233
/**
@@ -56,9 +57,24 @@ protected function restoreCollection($value)
5657
return new EloquentCollection(
5758
collect($value->id)->map(function ($id) use ($value) {
5859
return tap(new $value->class, function ($model) use ($id) {
59-
$model->forceFill([$model->getKeyName() => $id]);
60+
$keyName = $this->getUnqualifiedScoutKeyName(
61+
$model->getScoutKeyName()
62+
);
63+
64+
$model->forceFill([$keyName => $id]);
6065
});
6166
})
6267
);
6368
}
69+
70+
/**
71+
* Get the unqualified Scout key name.
72+
*
73+
* @param string $keyName
74+
* @return string
75+
*/
76+
protected function getUnqualifiedScoutKeyName($keyName)
77+
{
78+
return Str::afterLast($keyName, '.');
79+
}
6480
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Laravel\Scout\Jobs;
4+
5+
use Illuminate\Database\Eloquent\Collection;
6+
use Laravel\Scout\Searchable;
7+
8+
class RemoveableScoutCollection extends Collection
9+
{
10+
/**
11+
* Get the Scout identifiers for all of the entities.
12+
*
13+
* @return array
14+
*/
15+
public function getQueueableIds()
16+
{
17+
if ($this->isEmpty()) {
18+
return [];
19+
}
20+
21+
return in_array(Searchable::class, class_uses_recursive($this->first()))
22+
? $this->map->getScoutKey()->all()
23+
: parent::getQueueableIds();
24+
}
25+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Laravel\Scout\Tests\Fixtures;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use Laravel\Scout\Searchable;
7+
8+
class SearchableModelWithCustomKey extends Model
9+
{
10+
use Searchable;
11+
12+
/**
13+
* The attributes that are mass assignable.
14+
*
15+
* @var array
16+
*/
17+
protected $fillable = ['other_id'];
18+
19+
public function getScoutKey()
20+
{
21+
return $this->other_id;
22+
}
23+
24+
public function getScoutKeyName()
25+
{
26+
return $this->qualifyColumn('other_id');
27+
}
28+
}

tests/Unit/RemoveFromSearchTest.php

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use Illuminate\Database\Eloquent\Collection;
66
use Illuminate\Support\Facades\Config;
7+
use Laravel\Scout\Jobs\RemoveableScoutCollection;
78
use Laravel\Scout\Jobs\RemoveFromSearch;
89
use Laravel\Scout\Tests\Fixtures\SearchableModel;
10+
use Laravel\Scout\Tests\Fixtures\SearchableModelWithCustomKey;
911
use Mockery as m;
1012
use PHPUnit\Framework\TestCase;
1113

@@ -23,18 +25,22 @@ protected function tearDown(): void
2325

2426
public function test_handle_passes_the_collection_to_engine()
2527
{
26-
$job = new RemoveFromSearch($collection = Collection::make([
28+
$job = new RemoveFromSearch(Collection::make([
2729
$model = m::mock(),
2830
]));
2931

30-
$model->shouldReceive('searchableUsing->delete')->with($collection);
32+
$model->shouldReceive('searchableUsing->delete')->with(
33+
m::on(function ($collection) use ($model) {
34+
return $collection instanceof RemoveableScoutCollection && $collection->first() === $model;
35+
})
36+
);
3137

3238
$job->handle();
3339
}
3440

3541
public function test_models_are_deserialized_without_the_database()
3642
{
37-
$job = new RemoveFromSearch($collection = Collection::make([
43+
$job = new RemoveFromSearch(Collection::make([
3844
$model = new SearchableModel(['id' => 1234]),
3945
]));
4046

@@ -46,4 +52,37 @@ public function test_models_are_deserialized_without_the_database()
4652
$this->assertTrue($model->is($job->models->first()));
4753
$this->assertEquals(1234, $job->models->first()->getScoutKey());
4854
}
55+
56+
public function test_models_are_deserialized_without_the_database_using_custom_scout_key()
57+
{
58+
$job = new RemoveFromSearch(Collection::make([
59+
$model = new SearchableModelWithCustomKey(['other_id' => 1234]),
60+
]));
61+
62+
$job = unserialize(serialize($job));
63+
64+
$this->assertInstanceOf(Collection::class, $job->models);
65+
$this->assertCount(1, $job->models);
66+
$this->assertInstanceOf(SearchableModelWithCustomKey::class, $job->models->first());
67+
$this->assertTrue($model->is($job->models->first()));
68+
$this->assertEquals(1234, $job->models->first()->getScoutKey());
69+
$this->assertEquals('searchable_model_with_custom_keys.other_id', $job->models->first()->getScoutKeyName());
70+
}
71+
72+
public function test_removeable_scout_collection_returns_scout_keys()
73+
{
74+
$collection = RemoveableScoutCollection::make([
75+
new SearchableModelWithCustomKey(['other_id' => 1234]),
76+
new SearchableModelWithCustomKey(['other_id' => 2345]),
77+
new SearchableModel(['id' => 3456]),
78+
new SearchableModel(['id' => 7891]),
79+
]);
80+
81+
$this->assertEquals([
82+
1234,
83+
2345,
84+
3456,
85+
7891,
86+
], $collection->getQueueableIds());
87+
}
4988
}

0 commit comments

Comments
 (0)