Laravel Scout 和 TNTSearch 搜索 Trashed
Laravel Scout and TNTSearch search withTrashed
我已经配置了 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();
});
}
这导致在搜索已删除项目时出现未定义的偏移量。顺便说一下,我正在为 Laravel Scout 使用 TNTSearch 驱动程序。我不知道这是 TNTSearch 还是 Laravel Scout 的错误。
我已经为您的问题制定了解决方案。我将为 Scout
提交一个 pull request
,希望它能与官方包合并。
这种方法允许您在搜索中包括 软删除模型:
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
方法似乎与 TNTSearch
.
相同
阿尔戈利亚Engine.php
在laravel\scout\src\Engines\AlgoliaEngine.php
中修改map
方法来匹配我们上面修改的abstract
class:
/**
* 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();
}
TNTSearchEngine.php
/**
* 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
方法手动暂停同步;否则搜索条件将更新为 unsearchable()
.
这是我的解决方案。
// will return matched ids of my model instance
$searchResultIds = MyModel::search($request->input('search'))->raw()['ids'];
MyModel::whereId('id', $searchResultIds)->onlyTrashed()->get();
我已经配置了 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();
});
}
这导致在搜索已删除项目时出现未定义的偏移量。顺便说一下,我正在为 Laravel Scout 使用 TNTSearch 驱动程序。我不知道这是 TNTSearch 还是 Laravel Scout 的错误。
我已经为您的问题制定了解决方案。我将为 Scout
提交一个 pull request
,希望它能与官方包合并。
这种方法允许您在搜索中包括 软删除模型:
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
方法似乎与 TNTSearch
.
阿尔戈利亚Engine.php
在laravel\scout\src\Engines\AlgoliaEngine.php
中修改map
方法来匹配我们上面修改的abstract
class:
/**
* 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();
}
TNTSearchEngine.php
/**
* 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
方法手动暂停同步;否则搜索条件将更新为 unsearchable()
.
这是我的解决方案。
// will return matched ids of my model instance
$searchResultIds = MyModel::search($request->input('search'))->raw()['ids'];
MyModel::whereId('id', $searchResultIds)->onlyTrashed()->get();