Skip to content

Commit

Permalink
[9.x] Fix removing queued models with custom Scout keys (#480)
Browse files Browse the repository at this point in the history
* Re-push remove from Scout queue fix

#479

* Fix test

* StyleCI fixes

* Update src/Jobs/RemoveFromSearch.php

Co-authored-by: Dries Vints <[email protected]>

* Update RemoveFromSearch.php

Co-authored-by: Dries Vints <[email protected]>
  • Loading branch information
stevebauman and driesvints authored Jun 10, 2021
1 parent ce621be commit c1e1e92
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 5 deletions.
20 changes: 18 additions & 2 deletions src/Jobs/RemoveFromSearch.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;

class RemoveFromSearch implements ShouldQueue
{
Expand All @@ -26,7 +27,7 @@ class RemoveFromSearch implements ShouldQueue
*/
public function __construct($models)
{
$this->models = $models;
$this->models = RemoveableScoutCollection::make($models);
}

/**
Expand Down Expand Up @@ -56,9 +57,24 @@ protected function restoreCollection($value)
return new EloquentCollection(
collect($value->id)->map(function ($id) use ($value) {
return tap(new $value->class, function ($model) use ($id) {
$model->forceFill([$model->getKeyName() => $id]);
$keyName = $this->getUnqualifiedScoutKeyName(
$model->getScoutKeyName()
);

$model->forceFill([$keyName => $id]);
});
})
);
}

/**
* Get the unqualified Scout key name.
*
* @param string $keyName
* @return string
*/
protected function getUnqualifiedScoutKeyName($keyName)
{
return Str::afterLast($keyName, '.');
}
}
25 changes: 25 additions & 0 deletions src/Jobs/RemoveableScoutCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Laravel\Scout\Jobs;

use Illuminate\Database\Eloquent\Collection;
use Laravel\Scout\Searchable;

class RemoveableScoutCollection extends Collection
{
/**
* Get the Scout identifiers for all of the entities.
*
* @return array
*/
public function getQueueableIds()
{
if ($this->isEmpty()) {
return [];
}

return in_array(Searchable::class, class_uses_recursive($this->first()))
? $this->map->getScoutKey()->all()
: parent::getQueueableIds();
}
}
28 changes: 28 additions & 0 deletions tests/Fixtures/SearchableModelWithCustomKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Laravel\Scout\Tests\Fixtures;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class SearchableModelWithCustomKey extends Model
{
use Searchable;

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['other_id'];

public function getScoutKey()
{
return $this->other_id;
}

public function getScoutKeyName()
{
return $this->qualifyColumn('other_id');
}
}
45 changes: 42 additions & 3 deletions tests/Unit/RemoveFromSearchTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Config;
use Laravel\Scout\Jobs\RemoveableScoutCollection;
use Laravel\Scout\Jobs\RemoveFromSearch;
use Laravel\Scout\Tests\Fixtures\SearchableModel;
use Laravel\Scout\Tests\Fixtures\SearchableModelWithCustomKey;
use Mockery as m;
use PHPUnit\Framework\TestCase;

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

public function test_handle_passes_the_collection_to_engine()
{
$job = new RemoveFromSearch($collection = Collection::make([
$job = new RemoveFromSearch(Collection::make([
$model = m::mock(),
]));

$model->shouldReceive('searchableUsing->delete')->with($collection);
$model->shouldReceive('searchableUsing->delete')->with(
m::on(function ($collection) use ($model) {
return $collection instanceof RemoveableScoutCollection && $collection->first() === $model;
})
);

$job->handle();
}

public function test_models_are_deserialized_without_the_database()
{
$job = new RemoveFromSearch($collection = Collection::make([
$job = new RemoveFromSearch(Collection::make([
$model = new SearchableModel(['id' => 1234]),
]));

Expand All @@ -46,4 +52,37 @@ public function test_models_are_deserialized_without_the_database()
$this->assertTrue($model->is($job->models->first()));
$this->assertEquals(1234, $job->models->first()->getScoutKey());
}

public function test_models_are_deserialized_without_the_database_using_custom_scout_key()
{
$job = new RemoveFromSearch(Collection::make([
$model = new SearchableModelWithCustomKey(['other_id' => 1234]),
]));

$job = unserialize(serialize($job));

$this->assertInstanceOf(Collection::class, $job->models);
$this->assertCount(1, $job->models);
$this->assertInstanceOf(SearchableModelWithCustomKey::class, $job->models->first());
$this->assertTrue($model->is($job->models->first()));
$this->assertEquals(1234, $job->models->first()->getScoutKey());
$this->assertEquals('searchable_model_with_custom_keys.other_id', $job->models->first()->getScoutKeyName());
}

public function test_removeable_scout_collection_returns_scout_keys()
{
$collection = RemoveableScoutCollection::make([
new SearchableModelWithCustomKey(['other_id' => 1234]),
new SearchableModelWithCustomKey(['other_id' => 2345]),
new SearchableModel(['id' => 3456]),
new SearchableModel(['id' => 7891]),
]);

$this->assertEquals([
1234,
2345,
3456,
7891,
], $collection->getQueueableIds());
}
}

0 comments on commit c1e1e92

Please sign in to comment.