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

Asked

Viewed 431 times

0

I am working with Laravel and created the following method to research 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 take the return and create other filters as for example:

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

So far so good, so I created another method to help me in 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 very similar way to the search:

$this->clientMain->realActive();

It returns me a Builder too, and in the same way it returns me what I want, just as with the 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 take the search result and filter the "Real Active", but when I do this I get the following error:

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

Because he returned me a Builder and Builder does not have the realActive method.

I did a 'gambiarra' that worked, in my realActive method I did 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 when it comes to using I do the following:

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

It works, but I was wondering if there’s a way to do it:

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

Besides being more practical, it’s easier to read, and I believe it’s possible since I can do in Laravel something like:

$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?

1 answer

1


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

The function search() has the following return:

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

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

Okay, how to fix this?

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

Changing its 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:

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

Or, judging your class to be called Client, thus:

$clients = Client::search('teste')->realActive();
  • Very good, worked perfectly!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.