I have a search query that needs to be done. However, a search doesn't always have all values set, like in this case.
$aEvents = DB::table('events')
->where('client_id', '=', $client_id);
The question is, how can I make this where statement depend on the value of $client_id. So if the value is empty I don't want the Where statement to occur.
Also, I do not want to write several complete queries with if statements in PHP. To many variables. Ideally I'd like something like this:
$aEvents = DB::table('events')
->(($client_id != "") ? where('client_id', '=', $client_id) : "");
Using eloquent is (really!) nice and save, but I'm not yet up to speed with if statements in std Class objects I guess. Any help is appreciated.
You may try something like this:
$query = DB::table('events');
if(!empty($client_id)) {
$query->where('client_id', $client_id);
}
$aEvents = $query->get(); // Call this at last to get the result
If you are passing client_id to the server via a form/query string(user input) then you may try something like this:
if($client_id = Input::get('client_id')) {
$query->where('client_id', $client_id);
}
Update: For pagination try this:
$aEvents = $query->paginate(10); // For 10 per page
So you may call links() method in your view if you pass it like this:
return View::make('viewName')->with('aEvents', $aEvents);
In the view for pagination links:
$aEvents->links()
You can also use query scopes in the model for this purpose. Scopes allow you to easily re-use query logic in your models. In the model Event, you can add the following query scope:
public function scopeClientID($query, $client_id)
{
if ($client_id != '') {
return $query->where('client_id', '=', $client_id);
} else {
return $query;
}
}
Then from your controller or wherever you're calling it from, you can do the following:
$aEvents = Event::clientID($client_id);
If you want to get all the results, then you can do:
$aEvents = Event::clientID($client_id)->get();
Or if you want pagination, you can do:
$aEvents = Event::clientID($client_id)->paginate();
You can also chain it with other methods like you'd do in a eloquent query.
You can read more about model query scopes at http://laravel.com/docs/eloquent#query-scopes
Related
Can someone help me out, I'm trying to do a where query on a Child Model. Everything seems fine when I have a value for the id but it returns nothing when no id is supplied.
My goal is to get all data when no id is supplied and get specific data when id supplied.
Here's my code
Report::with(['project'])
->whereHas('project' function($q) use($programId){
if($programId){
$q->where('program_id', $programId);
}
})->get();
Is there a better way to achieve my goal? or I just lack something on the query? Thank you in advance.
You can use when method for this.
The when method only executes the given closure when the first argument is true. If the first argument is false, the closure will not be executed.
Report::with('project')
->when($programId, function ($query) use ($programId) {
$query->whereHas('project' function($q) use($programId){
$q->where('project.program_id', $programId);
});
})->get();
So I have a little complex answer for this type of questions where you can create a query and do every logic to it.
// Initialise the model
$query = new Report;
// Start building the query
$query->with('project');
// Check if project Id exists
if ($projectId) {
return $query->whereHas('project', function ($subQuery) use ($projectId) {
$subQuery->where('program_id', $programId);
})->get();
} else {
return $query->get();
}
I have an Orders table that has relations to a Movements table, and im constantly doing things like this to calculate several common values for each order:
$warehouse = 7;
$order = Order::find(16111);
$entries = Movement::selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('order_id', $order->id)
->where('to_id', $warehouse)
->first();
$exits = Movement::selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('order_id', $order->id)
->where('from_id', $warehouse)
->first();
is it possible to create a custom function to just query the DB doing something like this:
$warehouse = 7;
$entries = Order::find(16111)->entries($warehouse);
$exits = Order::find(16111)->exits($warehouse);
If so how can it be done?
Thanks for your help...
Absolutely. What you are looking for is called local Query Scopes; it allows you to avoid repeating complexe queries in your code.
Local scopes allow you to define common sets of query constraints that you may easily re-use throughout your application.
Write your local query scope in your model and you'll never have to repeat this code again (DRY principle).
Here's an example to give you an idea, you'll need to tweak it to your needs.
In your Order model:
public function scopeEntries($query)
{
$warehouse = $this->warehouse; // Take advantage of Eloquent wherever you can
return $query->movements()->selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('to_id', $warehouse->id);
}
public function scopeExits($query)
{
$warehouse = $this->warehouse; // Take advantage of Eloquent wherever you can
return $query->movements()->selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('from_id', $warehouse->id)
->where('to_id', $warehouse->id);
}
Now in your code, you will be able to simply call $order->entries()->first() to retrieve the first entry but you can also call $order->exits()->get() to retrieve all exits.
I have a model in laravel and need to call it within itself to check if there already are entries. It's for a generic (polymorphic) case where I don't want to do it in the controller.
This works just fine:
$check = self
::where('foreign_id',$this->attributes['foreign_id'])
->where('foreign_type', $this->attributes['foreign_type'])
->where('category', $this->attributes['category'])
->orderBy('created_at','desc')
->first()
;
Now I can access the properties with $check->id for example.
But I can't do something like this:
$check = self
::where('foreign_id',$this->attributes['foreign_id'])
->where('foreign_type', $this->attributes['foreign_type'])
->where('category', $this->attributes['category'])
->orderBy('created_at','desc')
;
if($this->isUser()) $check->where('user_id',$this->attributes['user_id']);
else $check->where('guest_ip',$this->attributes['guest_ip']);
$check->first();
It's not adding the new wheres within the if statement to the query.
I thought self is the way to go according to this answer: https://stackoverflow.com/a/15282754/1233206
In my case however it seems to be not working. What am I doing wrong?
$check->first() will run a query and return the result. The $check variable itself will not be changed. So if you try this:
$check->first();
if($check->id == 'something'){}
It won't work because you're interacting with the query builder instance. You have to do this:
$check = $check->first();
if($check->id == 'something'){}
I have the following query:
$results = Product::where("active", "=", true)->leftJoin(/** something **/)->leftJoin(/** something **/);
The above array is then process in the view file:
foreach($results->get() as $item)
{
// do something
}
Now, this view is too generic and shared between almost 50 pages. I cannot change the view in any possible way. Now, I need a way to change the query result in the controller, I am unable to filter result since it is get() in the view. I need to know how to inject WHEN statement of MySQL into my Eloquent Query (above query using Product model).
How should I do that? I need something like this:
$results = Product::select("is_special WHEN price > 500 THEN 'true' ELSE 'false' ")->where("active", "=", true)->leftJoin(/** something **/)->leftJoin(/** something **/);
I you have any other way for filtering the result before get(), I welcome that!
Could you just pre-process some of the results before? Such as
$preSelected = Product::select(/** something **/)->where(/** x **/);
and in another Controller function
$preSelected = Product::select(/** something else **/)->where(/** y **/);
And then later it would be the same
$results = $preSelected->where("active", "=", true)
->leftJoin(/** something **/)->leftJoin(/** something **/);
Or another option would be to use DB::raw
$results = Product::select(DB::raw('is_special WHEN price > 500 THEN true ELSE false'))
->where("active", "=", true)->leftJoin(/** something **/)
->leftJoin(/** something **/);
though I try to avoid DB::raw whenever possible to increase security and reduce the possibility of e.g. SQL injection.
I have a model called "User", which "belongsToMany" Items.
This relationship works fine, so I can easily do something like this:
User::find(4)->items->find(1)->name
Now, I would like to do something like this:
User::find(4)->items->where('name', '=', 'stick')->get()
I would expect the code to return all the user's items with the name "stick", but unfortunately that is not what happens. I receive this error:
"Call to undefined method Illuminate\Database\Eloquent\Collection::where()"
I also tried to build a query scope:
public function scopeName($query, $name)
{
return $query->whereName($name);
}
The query scope works when I do something like this:
Item::name('SC')->get()
but
User::find(4)->items->name('SC')->get()
still does not work.
Can you help me returning all the user's items, which have the name 'stick'?
If you're looking to just get a single user's items named "stick", this is how you would do it:
$stickItems = Item::whereUserId(4)->whereName('stick')->get();
Here we are using Eloquent's dynamic where methods, but you could rewrite it like so:
$stickItems = Item::where('user_id', '=', 4)->where('name', '=', 'stick')->get();
That should get you what you want.
You have to call the items() method, not use the magic property:
User::find(4)->items()->where('name', 'stick')->get();
// ^^