简体   繁体   中英

Call to undefined method Illuminate\Database\Eloquent\Builder::search() using laravel scout and tntsearch

in my larave-vue app I want to be able to filter by a search term using laravel scout tntsearch, along with this I also perform additional filtering, sorting or where clauses in my controller. I can't get both to work correctly in my app.

In my controller I have this:

$posts = Post::filter($filters)->search($request->input('query'))->paginate(0);
            $posts->load(['postcategory.section','author']);

            if($posts->isEmpty())
            {
                return response()->json([
                    'message' => 'No results found',
                ],500);    
            }

            return response()->json([
                'message' => 'Results found',
                'posts' => $posts,
            ]);

It gives me the following error:

Call to undefined method Illuminate\Database\Eloquent\Builder::search()

For some reason It's not working, I have tried changing the order of the filter, search and paginate but I still get errors.

In case you are wondering how does my filter method works it's basically a scope

You can read an indepth write up about it here:

https://medium.com/@mykeels/writing-clean-composable-eloquent-filters-edd242c82cc8

See my QueryFilters and Filterable trait bellow just in case

<?php
namespace App\Filters;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

class QueryFilters
{
    protected $request;
    protected $builder;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function title($term)
    {
        $lowerCaseTerm = strtolower($term);
        return $this->builder->where('title', 'LIKE', "%$lowerCaseTerm%");
    }

    public function postCategory($term)
    {

        return $this->builder->whereHas('postcategory', function ($query) use ($term){
            $query->where('id', $term);
        });
    }

    public function sort($term)
    {
        $sortArray = explode(",", $term);

        for($i = 0; $i <= $sortArray.length; $i++)
        {
            $sortBy = substr_replace($sortArray[i], "", -1);

            $sortChar = substr($sortArray[i], -1);

            $sortOrder = $sortChar == '+' ? 'ASC' : 'DESC';  

            $this->bulider->orderBy($sortBy, $sortOrder);
        }

        return $this->builder;
    }

    public function apply(Builder $builder)
    {
        $this->builder = $builder;
        foreach ($this->filters() as $name => $value)
        {
            //if method doesn't exists continue out of the loop 
            if ( ! method_exists($this, $name))
            {
                continue;
            }
            //method exists so check if it has a value payload so call the method with arguments
            if (strlen($value)) 
            {
                $this->$name($value);
            } 
            //it doesn't have a payload so call the method without arguments
            else 
            {
                $this->$name();
            }
        }
        return $this->builder;
    }

    public function filters()
    {
        //returns associative array of request body key value pairs
        return $this->request->all();
    }

}

And Filterable Trait

<?php
namespace App\Filters;

use Illuminate\Database\Eloquent\Builder;

trait Filterable
{
    public function scopeFilter($query, QueryFilters $filters)
    {
        return $filters->apply($query);
    }
}

The search() method is not made to be added to an existing query, here is the method that gets added to your model by the searchable trait

public static function search($query = '', $callback = null)
{
    return app(Builder::class, [
        'model' => new static,
        'query' => $query,
        'callback' => $callback,
        'softDelete'=> static::usesSoftDelete() && config('scout.soft_delete', false),
    ]);
}

The function is static, it doesn't take a query builder as a paramater, and returns a new builder no matter what. So you can't chain Search onto a query but you can START with the search and then apply your filters

So instead of this

$posts = Post::filter($filters)->search($request->input('query'))->paginate(0);

Try this

$posts = Post::search($request->input('query'))->filter($filters)->paginate(0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM