Laravel Scout和TNTSearch搜索withTrashed

时间:2016-12-14 15:37:48

标签: laravel laravel-scout

我已经配置了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的错误。

2 个答案:

答案 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();
相关问题