我已经配置了Laravel Scout,可以在我的模型上使用::search()
。
相同的模型也使用SoftDeletes.
如何将::search()
与withTrashed()
合并?
以下代码不起作用。
MyModel::search($request->input('search'))->withTrashed()->paginate(10);
以下内容确实有效,但不包括已删除的项目。
MyModel::search($request->input('search'))->paginate(10);
更新1 我在scout/ModelObserver中发现删除的项目无法搜索。哪个是无聊的;我希望我的用户能够搜索他们的垃圾。
更新2
我尝试使用@camelCase建议的::withoutSyncingToSearch,
,我对此寄予厚望,但这也没有用。
$model = MyModel::withTrashed()->where('slug', $slug)->firstOrFail();
if ($model->deleted_at) {
$model->forceDelete();
} else {
MyModel::withoutSyncingToSearch(function () use ($model) {
$model->delete();
});
}
这会在搜索已删除的项目时导致未定义的偏移量。顺便说一下,我正在使用LaTSvel Scout的TNTSearch驱动程序。我不知道这是TNTSearch或Laravel Scout的错误。
答案 0 :(得分:1)
我已经找到了解决问题的方法。我将为pull request
提交Scout
,希望将其与官方套餐合并。
此方法允许您在搜索中包含软删除的模型:
App\User::search('search query string')->withTrashed()->get();
仅在搜索中显示软删除的模型:
App\User::search('search query string')->onlyTrashed()->get();
您需要修改3个文件:
<强> Builder.php 强>
在laravel\scout\src\Builder.php
中添加以下内容:
/**
* Whether the search should include soft deleted models.
*
* @var boolean
*/
public $withTrashed = false;
/**
* Whether the search should only include soft deleted models.
*
* @var boolean
*/
public $onlyTrashed = false;
/**
* Specify the search should include soft deletes
*
* @return $this
*/
public function withTrashed()
{
$this->withTrashed = true;
return $this;
}
/**
* Specify the search should only include soft deletes
*
* @return $this
*/
public function onlyTrashed()
{
$this->onlyTrashed = true;
return $this;
}
/**
* Paginate the given query into a simple paginator.
*
* @param int $perPage
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function paginate($perPage = null, $pageName = 'page', $page = null)
{
$engine = $this->engine();
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $this->model->getPerPage();
$results = Collection::make($engine->map(
$rawResults = $engine->paginate($this, $perPage, $page), $this->model, $this->withTrashed, $this->onlyTrashed
)); // $this->withTrashed, $this->onlyTrashed is new
$paginator = (new LengthAwarePaginator($results, $engine->getTotalCount($rawResults), $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]));
return $paginator->appends('query', $this->query);
}
<强> Engine.php 强>
在laravel\scout\src\Engines\Engine.php
中修改以下内容:
/**
* Map the given results to instances of the given model.
*
* @param mixed $results
* @param \Illuminate\Database\Eloquent\Model $model
* @param boolean $withTrashed // New
* @return \Illuminate\Database\Eloquent\Collection
*/
abstract public function map($results, $model, $withTrashed, $onlyTrashed); // $withTrashed, $onlyTrashed is new
/**
* Get the results of the given query mapped onto models.
*
* @param \Laravel\Scout\Builder $builder
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get(Builder $builder)
{
return Collection::make($this->map(
$this->search($builder), $builder->model, $builder->withTrashed, $builder->onlyTrashed // $builder->withTrashed, $builder->onlyTrashed is new
));
}
最后,您只需修改相对搜索引擎即可。我正在使用Algolia,但map
的{{1}}方法似乎相同。
<强> AlgoliaEngine.php 强>
在TNTSearch
中修改laravel\scout\src\Engines\AlgoliaEngine.php
方法以匹配我们上面修改的map
类:
abstract
<强> TNTSearchEngine.php 强>
/**
* Map the given results to instances of the given model.
*
* @param mixed $results
* @param \Illuminate\Database\Eloquent\Model $model
* @param boolean $withTrashed // New
* @return \Illuminate\Database\Eloquent\Collection
*/
public function map($results, $model, $withTrashed, $onlyTrashed) // $withTrashed, $onlyTrashed is new
{
if (count($results['hits']) === 0) {
return Collection::make();
}
$keys = collect($results['hits'])
->pluck('objectID')->values()->all();
$modelQuery = $model->whereIn(
$model->getQualifiedKeyName(), $keys
);
if ($withTrashed) $modelQuery->withTrashed(); // This is where the query will include deleted items, if specified
if ($onlyTrashed) $modelQuery->onlyTrashed(); // This is where the query will only include deleted items, if specified
$models = $modelQuery->get()->keyBy($model->getKeyName());
return Collection::make($results['hits'])->map(function ($hit) use ($model, $models) {
$key = $hit['objectID'];
if (isset($models[$key])) {
return $models[$key];
}
})->filter();
}
让我知道它是如何运作的。
注意:此方法仍需要您在删除模型时使用/**
* Map the given results to instances of the given model.
*
* @param mixed $results
* @param \Illuminate\Database\Eloquent\Model $model
*
* @return Collection
*/
public function map($results, $model, $withTrashed, $onlyTrashed)
{
if (count($results['ids']) === 0) {
return Collection::make();
}
$keys = collect($results['ids'])->values()->all();
$model_query = $model->whereIn(
$model->getQualifiedKeyName(), $keys
);
if ($withTrashed) $model_query->withTrashed();
if ($onlyTrashed) $model_query->onlyTrashed();
$models = $model_query->get()->keyBy($model->getKeyName());
return collect($results['ids'])->map(function ($hit) use ($models) {
if (isset($models[$hit])) {
return $models[$hit];
}
})->filter();
}
方法手动暂停同步;否则搜索条件将使用withoutSyncingToSearch
更新。
答案 1 :(得分:0)
这是我的解决方法。
// will return matched ids of my model instance
$searchResultIds = MyModel::search($request->input('search'))->raw()['ids'];
MyModel::whereId('id', $searchResultIds)->onlyTrashed()->get();