Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.2] Optional query builder calls via a when() method #12878

Merged
merged 4 commits into from
Mar 28, 2016

Conversation

tomschlick
Copy link
Contributor

I keep finding myself in situations where I need to break a chained query builder to add in optional calls. For instance, recently when working on an api, I needed to add optional sorting / filtering for the query. If the sort parameters existed in the url, then they should be added but if not it should follow its default sort.

To do this in the current QB you have to break the chain...

$query = $model->where('customer_id', 1234)
    ->where('created_at', '>=' '2016-01-04 20:34:56');

if (! empty($sortParams)) {
    $query->orderBy($sortParams);
}

return $query->get();

with this new when() method, we apply the new commands via a closure if the first parameter evaluates as true...

return $model->where('customer_id', 1234)
    ->where('created_at', '>=' '2016-01-04 20:34:56')
    ->when(! empty($sortParams), function($builder) use($sortParams) {
        return $builder->orderBy($sortParams);
    })
    ->get():

This is a simple example but if you were trying to add many things based on conditional arguments you could see how the top would get unruly pretty quickly. The lower example alleviates that a bit, at least in my mind.

@tomschlick tomschlick changed the title Optional query builder calls via a when() method [5.2] Optional query builder calls via a when() method Mar 27, 2016
@dvlpp
Copy link

dvlpp commented Mar 27, 2016

IMO, maybe because of the PHP closure "use" complexity, your proposal makes it more difficult to read than conditionnals. But I'm not saying that the PR should be rejected: in some cases, it could be useful.

@eddiewebb
Copy link

Leaning with @dvlpp, extending the chain with conditional logic is less readable, and does not seem to shave any verbosity.

@robclancy
Copy link
Contributor

PHP already has an if statement why are you trying to make a new ultra specific one?

@@ -436,6 +436,25 @@ public function rightJoinWhere($table, $one, $operator, $two)
}

/**
* Apply the callback's query changes if the value is trueish.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"truthy" is the correct word here

@tomschlick
Copy link
Contributor Author

@dvlpp yeah i put the use() to be syntactically correct but in real life you may just use the request()->input('whatever') call directly within the closure instead of passing it through

@eddiewebb exactly, not perfect for every situation, and shouldn't be abused, but in some cases I think it makes total sense when you're trying to keep the "flow" of a longer query going instead of breaking it out into 5 or 6 chunks for each conditional

@robclancy of course PHP has ifs, which I'm utilizing here, problem is that we don't have that ability within the chain for a query.

@vlakoff
Copy link
Contributor

vlakoff commented Mar 27, 2016

Agree with the others, I often "break the chain" as such and I think it is the lesser evil.

Still, you may add this method to your codebase like so:

use Illuminate\Database\Query\Builder;

Builder::macro('when', function ($value, $callback) {

    if ($value) {
        return call_user_func($callback, $this);
    }

    return $this;
});

@tomschlick
Copy link
Contributor Author

Of course. I already do that. Just thought it would be useful to some others. 

Tom Schlick

On Sun, Mar 27, 2016 at 12:02 PM -0700, "vlakoff" notifications@github.com wrote:

Agree with the others, I often "break the chain" as such and I think it is the lesser evil.

Still, you may add this method to your codebase like so:

use Illuminate\Database\Query\Builder;

Builder::macro('when', function ($value, $callback) {

if ($value) {
    return call_user_func($callback, $this);
}

return $this;

});


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub

@drbyte
Copy link
Contributor

drbyte commented Mar 27, 2016

@tomschlick I feel your pain. I have a project where I've had to break the chain frequently to handle a number of "orWhere" clauses, which have various dependencies. I'm doing similarly to what you and @vlakoff have posted.

I'm torn as to whether it helps with readability, or just makes me feel better that I can keep the chain together. I think "not breaking the chain" helps with readability, even with the closures in the middle.

I'm not casting a vote here, just raising my hand to wave and say "I hear you".

@taylorotwell taylorotwell merged commit 42ee94e into laravel:5.2 Mar 28, 2016
@tomschlick tomschlick deleted the patch-2 branch March 28, 2016 02:24
@tomschlick
Copy link
Contributor Author

Wooohooo!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants