Make fully configurable livewire searching componentLaravel
October 22, 20201 minuteuserVishal Ribdiya
Make fully configurable livewire searching component
Nowdays, laravel livewire is becoming more trendy for geeks. as most of developers are using it, more and more issues they are facing while developing the products. one of them is searching the records. 

Recently we have developed the livewire common searchable component which makes your searching easier, as you can specify which fields you want to search by just giving the field name into the component.

What you have to do is just create SearchableComponent a class into your App\Http\Livewire directory.  just copy the following class on the given namespace.

<?php

namespace App\Http\Livewire;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Livewire\Component;
use Livewire\WithPagination;
use Str;

abstract class SearchableComponent extends Component
{
    use WithPagination;

    /**
     * @var string
     */
    public $search = '';

    /**
     * @var int
     */
    protected $paginate = 12;

    /** @var Builder */
    private $query;

    /**
     * SearchableComponent constructor.
     *
     * @param $id
     */
    public function __construct($id)
    {
        parent::__construct($id);

        $this->prepareModelQuery();
    }

    /**
     *  Prepare query
     */
    private function prepareModelQuery()
    {
        /** @var Model $model */
        $model = app($this->model());

        $this->query = $model->newQuery();
    }

    /**
     * @return mixed
     */
    abstract function model();

    /**
     * Reset model query
     */
    protected function resetQuery()
    {
        $this->prepareModelQuery();
    }

    /**
     * @return Builder
     */
    protected function getQuery()
    {
        return $this->query;
    }

    /**
     * @param  Builder  $query
     */
    protected function setQuery(Builder $query)
    {
        $this->query = $query;
    }

    /**
     * @param  bool  $search
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    protected function paginate($search = true)
    {
        if ($search) {
            $this->filterResults();
        }

        $all = $this->query->paginate($this->paginate);
        $currentPage = $all->currentPage();
        $lastPage = $all->lastPage();
        if ($currentPage > $lastPage) {
            $this->page = $lastPage;
        }

        return $this->query->paginate($this->paginate);
    }

    /**
     * @return Builder
     */
    protected function filterResults()
    {
        $searchableFields = $this->searchableFields();
        $search = $this->search;

        $this->query->when(! empty($search), function (Builder $q) use ($search, $searchableFields) {
            $searchString = '%'.$search.'%';
            foreach ($searchableFields as $field) {
                if (Str::contains($field, '.')) {
                    $field = explode('.', $field);
                    $q->orWhereHas($field[0], function (Builder $query) use ($field, $searchString) {
                        $query->whereRaw("lower($field[1]) like ?", $searchString);
                    });
                } else {
                    $q->orWhereRaw("lower($field) like ?", $searchString);
                }
            }
        });

        return $this->query;
    }

    /**
     * @return mixed
     */
    abstract function searchableFields();
}
Now you have to extend your existing laravel component by SearchableComponent. let's say we already have Tags livewire component. and its looks like following.

<?php

namespace App\Http\Livewire;

use App\Models\Tag;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;

class Tags extends SearchableComponent
{
    public function render()
    {
        $tags = $this->searchTags();

        return view('livewire.tags', [
            'tags' => $tags,
        ])->with("search");
    }

    /**
     * @return LengthAwarePaginator
     */
    public function searchTags()
    {
        $this->setQuery($this->getQuery());

        return $this->paginate();
    }

    function model()
    {
        return Tag::class;
    }

    function searchableFields()
    {
        return [
            'name',
        ];
    }
}
So here we have extended our existing Tags component by SearchingComponent.  

In searchable fields you can specify the field name that you want to search. and replace the Model with your records Model.

That it. Now you don't need to write search queries again and again. just extend your livewire component by searchable component.

Here are some Interesting livewire tutorials that you need to check :