How can I create a custom method in the Laravel model and match the result of another?

0

I'm working with Laravel and have created the following method to do research on a model:

public function search($string)
{
    return (strlen($string) > 0) ? $this->where('name', 'like', '%' . $string . '%') : $this;
}

I use it as follows:

$this->clientMain->search('teste');

So it returns me the result I want as a Builder or the object itself, so I can get the return and create other filters like:

$this->clientMain->search('teste')->where('status_id', 3);

So that's fine, so I've created another method to help me with filters:

public function realActive()
{
    return $this->where('status_id', 1)->where(function ($query) {
        $query->where(function ($query) {
            $query->whereHas('Responsible', function ($query){
                $query->where('active', 1);
            });
        })->orWhere(function ($query) {
            $fields = ['name', 'birthday', 'cpf', 'zip_code', 'neighborhood', 'street', 'number'];
            $entities = ['sex_id', 'city_id'];
            $query = $this->removeFilled($fields, $query);
            $query = $this->removeEmptyEntity($entities, $query);
            $query->where(function ($query){
                $contacts = ['telephone', 'cellphone', 'whatsapp'];
                $this->checkContact($contacts, $query);
            });
        });
    });
}

Where I use it in a way very similar to search:

$this->clientMain->realActive();

It returns me a Builder too, and likewise it returns me what I want, just as with search, I can also do something like:

$this->clientMain->realActive()->where('status_id', 3);

My problem is this, I wanted to combine the two in this way:

$clientsMain = $this->clientMain->search('teste')->realActive();

That is to get the search result and filter the "Real Assets", but when I do this I get the following error:

  

"Method Illuminate \ Database \ Query \ Builder :: realActive does not exist."

Because it returned me a Builder and Builder does not have the actualActive method.

I did a 'gambiarra' that worked, in my realActive method I did it this way:

public function realActive($builder = null)
{
    if(is_null($builder)){
        $builder = $this;
    }
    return $builder->where('status_id', 1)->where(function ($query) {
        $query->where(function ($query) {
            $query->whereHas('Responsible', function ($query){
                $query->where('active', 1);
            });
        })->orWhere(function ($query) {
            $fields = ['name', 'birthday', 'cpf', 'zip_code', 'neighborhood', 'street', 'number'];
            $entities = ['sex_id', 'city_id'];
            $query = $this->removeFilled($fields, $query);
            $query = $this->removeEmptyEntity($entities, $query);
            $query->where(function ($query){
                $contacts = ['telephone', 'cellphone', 'whatsapp'];
                $this->checkContact($contacts, $query);
            });
        });
    });
}

And at the time of using I do the following:

$clientsMain = $this->clientMain->search('teste');
$clientsMain = $this->clientMain->realActive($clientsMain);

It works, but I was wondering if there is a way to do this:

$clientsMain = $this->clientMain->search('teste')->realActive();

In addition to being more practical, it is easier to read, and I believe it is possible since I can do something like this in Laravel:

$clientsMain = $this->clientMain->where('name', 'teste')->where('last_name', 'outro teste');

How can I create a custom method in the Laravel model and match the result of another?

    
asked by anonymous 29.03.2018 / 14:39

1 answer

1

The problem is that the where() function does not return the class itself, returns an instance of QueryBuilder .

The function search() has the following return:

return $this->where(...);

Then you are no longer returning an instance of the clientMain class, but an instance of the QueryBuilder class.

Ok, how do I solve this?

Laravel has a feature called Local Scopes (read), which allows you to change to $query current and return it already filtered. There is also the possibility of using scopes with parameters, in which case the first parameter must always be $query , and then the others.

Changing your functions to use the scopes would look like this:

/**
 * Coloque uma descrição topzera desse escopo
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @param string $str
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeSearch($query, $str)
{
    return $query->where('name', 'like', '%' . $str . '%');
}


/**
 * Aqui também
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeRealActive($query)
{
    return $query->where('status_id', 1)->where(function ($query) {
        $query->where(function ($query) {
            $query->whereHas('Responsible', function ($query){
                $query->where('active', 1);
            });
        })->orWhere(function ($query) {
            $fields = ['name', 'birthday', 'cpf', 'zip_code', 'neighborhood', 'street', 'number'];
            $entities = ['sex_id', 'city_id'];
            $query = $this->removeFilled($fields, $query);
            $query = $this->removeEmptyEntity($entities, $query);
            $query->where(function ($query){
                $contacts = ['telephone', 'cellphone', 'whatsapp'];
                $this->checkContact($contacts, $query);
            });
        });
    });
}

Then, you'll be able to use it the way you wanted it to:

$clientsMain = $this->clientMain->search('teste')->realActive();

Or, judging your class to call Client , like this:

$clients = Client::search('teste')->realActive();
    
29.03.2018 / 15:14