How can I build a condition based query in Laravel? - php

I can do this in Code Igniter:
$this->db->select();
$this->from->('node');
if ($published == true)
{
$this->db->where('published', 'true');
}
if (isset($year))
{
$this->db->where('year >', $year);
}
$this->db->get();
How can this code be translated so that it works in Laravel?

In Fluent you can do:
$query = DB::table('node');
if ($published == true)
$query->where('published', '=', 1);
if (isset($year))
$query->where('year', '>', $year);
$result = $query->get();

As of Laravel 5.2.27, you can avoid breaking the chain by writing your conditions as so:
$query = DB::table('node')
->when($published, function ($q) use ($published) {
return $q->where('published', 1);
})
->when($year, function($q) use ($year) {
return $q->where('year', '>', $year);
})
->get();
To use Eloquent,just swap $query = DB::table('node') with Node:: but realize if both conditions fail, you'll get everything in the table back unless you check for some other condition before querying the db/model or from within the query itself.
Note the that $published and $year must be in local scope to be used by the closure.
You can make it more concise and readable by creating a macro. See: Conditionally adding instructions to Laravel's query builder

Here is how you can accomplish your query:
$year = 2012;
$published = true;
DB::table('node')
->where(function($query) use ($published, $year)
{
if ($published) {
$query->where('published', 'true');
}
if (!empty($year) && is_numeric($year)) {
$query->where('year', '>', $year);
}
})
->get( array('column1','column2') );
To find more information, I recommend reading through Fluent and Eloquent in the Laravel docs.
http://laravel.com/docs/database/fluent

I have not seen it here. You can even start your query like
$modelQuery = Model::query();
and then chain other query command afterwards. Maybe it will be helpful for someone new.

You can use Model::when() in Condition or you can create Builder::micro()
For Example
$results = Model::where('user_id', Auth::id())
->when($request->customer_id, function($query) use ($request){
return $query->where('customer_id', $request->customer_id);
})
->get();
If You need to create micro for a condition then. follow below instruction.
Write thic code in your serverice provider
Builder::macro('if', function ($condition, $column, $operator, $value) {
if ($condition) {
return $this->where($column, $operator, $value);
}
return $this;
});
Use Like Below Example
$results = Model::where('user_id', Auth::id())
->if($request->customer_id, 'customer_id', '=', $request->customer_id)
->get();
Ref: themsaid

If you need to use Eloquent you can use it like, I'm not sure that whereNotNull is the best use but I couldn't find another method to return what we really want to be an empty query instance:
$query = Model::whereNotNull('someColumn');
if(x < y)
{
$query->where('column1', 'LIKE', '%'. $a .'%');
}else{
$query->where('column2', 'LIKE', '%'. $b .'%');
}
$results = $query->get();
This way any relationships still work, for example in your view you can still use
foreach($results as $result){
echo $result->someRelationship()->someValue;
}
There is a good amount of info on here http://daylerees.com/codebright/eloquent-queries about this sort of stuff.

In Laravel > 5.2 you can use when():
$results = DB::table('orders')
->where('branch_id', Auth::user()->branch_id)
->when($request->customer_id, function($query) use ($request){
return $query->where('customer_id', $request->customer_id);
})
->get();
Docs: https://laravel.com/api/5.8/Illuminate/Contracts/Container/Container.html#method_when
Blog post: https://themsaid.com/laravel-query-conditions-20160425/

for eloquent query i used following that executes only if where condition has value
->where(function($query) use ($value_id)
{
if ( ! is_null($value_id))
$query->where('vehicle_details.transport_type_id', $value_id);
})

We can write like this (More precise way):
$query = DB::table('node')->when($published, function ($q, $published) {
return $q->where('published', 1);
})->when($year, function($q, $year) {
return $q->where('year', '>', $year);
})->get()
Not mentioned in Laravel docs. Here is pull request.

Related

Laravel execute where condition based on variable null or not

I am new to laravel. I want to execute my where condition if my variable value is not null. I tried the below code exactly not getting an idea of what to do.
$search = $array['search'];
$id = $array['id'];
$Data = Model::where('id', '=', $id)
if($search != '') {
//I want to include where condition here
}
Use Conditional Clauses
Model::when($search !== null, function ($query) use ($search) {
return $query->where('column', $search);
})
Your $Data variable is an Eloquent Query Builder object so you can add conditions to it for the query you are building:
if ($search) {
$Data->where('field', $search);
}

How to use query result and query again using LIKE statement in Laravel

I am trying to use questions result and get question again if title has some char in it.
If I query in condition_question table, I get results as expected.
public function showQuestions($category)
{
$myArray = array($category);
$questions = Question::whereIn('question_id', function ($query) use ($myArray) {
$query->select('question_id')
->from('condition_question')
->whereIn('condition_id', $myArray);
})->orderBy('question_id', 'desc')->paginate(20);
return QuestionLiteResource::collection($questions);
}
Question: How can I use now $questions result and query again with LIKE statement. So far I tried many thing, for example like this, but something is missing as I am getting errors:
public function showQuestions($category, $queryQuestion)
{
$myArray = array($category);
$chary = $queryQuestion;
$questions = Question::whereIn('question_id', function ($query) use ($myArray) {
$query->select('question_id')
->from('condition_question')
->whereIn('condition_id', $myArray);
})->get();
$results = $questions->where('question_title', 'LIKE', "%{$chary}%")->get();
return QuestionLiteResource::collection($results->values());
}
I know it is not my best, but need some help...It would be also cool to have paginated result at the end.
So, how to get collection of questions from questions table where title has char. Any help would be most welcomed!
You might know that once you call get() function, you got the results and not able to query any further. Maybe this is gonna work:
public function showQuestions($category, $queryQuestion)
{
$myArray = array($category);
$chary = $queryQuestion;
$questions = Question::whereIn('question_id', function ($query) use ($myArray) {
$query->select('question_id')
->from('condition_question')
->whereIn('condition_id', $myArray);
})
->where('question_title', 'LIKE', "%{$chary}%")
->get();
return QuestionLiteResource::collection($questions);
}
Since you have called get() on question query, you get the result as an Laravel Collection.
To filter through collection you can use filter() function.
Example Code
$results = $questions->filter(function($question) use ($chary) {
return Str::contains($question->question_title, $chary);
});
i think you can use join():
public function showQuestions($category, $queryQuestion)
{
$myArray = array($category);
$chary = $queryQuestion;
$query = Question::getModel()->newQuery();
$questions = $query
->join('condition_question', function (Builder $join) use ($myArray) {
$join->on('questions.question_id', '=', 'condition_question.question_id');
$join->whereIn('condition_question.condition_id', $myArray);
})
->where('questions.question_title', 'like', $chary)
->orderBy('questions.question_id', 'desc')
->paginate(20)
return QuestionLiteResource::collection($questions);
}

Optional Where Laravel

Given I have a simple join query:
$googleAds = TrackingApi::where("company_id",$companyId)
->leftJoin("googleads",function($join) use ($date){
$join->on("tracking_api.google_id", "googleads.id")
->where("googleads.created", "<=", $date
})
->select(DB::raw('count(googleads.id) as totalAds'))->get();
The data parameter its comming from admin dashboard, but its optional parameter.
Question: how do I go when $date its not given ?
Clarification: when $date not given just perform the query normally.
You can use the when method:
$googleAds = TrackingApi::where("company_id",$companyId)
->leftJoin("googleads",function($join) use ($date){
$join->on("tracking_api.google_id", "googleads.id")
->when($date, function ($query) use ($date) {
return $query->where("googleads.created", "<=", $date
})
})
->select(DB::raw('count(googleads.id) as totalAds'))->get();
As alternative:
$googleAds = TrackingApi::where("company_id", $companyId)
->leftJoin("googleads",function($join) use ($date){
$join->on("tracking_api.google_id", "=", "googleads.id");
if (!empty($date))
$join->where("googleads.created", "<=", $date);
});
->select(DB::raw('count(googleads.id) as totalAds'))
->get();
#user320487 answer was right but, You can also pass the 2nd parameter in method instead of using 'use' keyword in closers that would be a more readable & maintainable code.
$googleAds =
TrackingApi::whereCompany_id($companyId)
->leftJoin("googleads", function ($join) use ($date) {
$join->on("tracking_api.google_id", "googleads.id")
->when($date, function ($query, $date) {
return $query->where("googleads.created", "<=", $date);
});
})
->select(DB::raw('count(googleads.id) as totalAds'))
->get();

Eloquent: Constraining an eager load relation where relation property is 0 or relation doesn't exist

I would like to get all the Report models where the relation ReportUpload's property of status equals 0 or where the ReportUpload relation doesn't exist. The Report and ReportUpload models have a one to one relationship, ReportUpload belongs to a Report.
Somewhat unsure how to go about this using eloquent's relationship constraints or any other method. Any help would be appreciated.
Here's my current code:
// initial query
$reports = Report::whereHas('link', function($query) {
$query->where('status', 'complete');
})->with('student', 'course', 'institution', 'reportUpload');
// apply constraint
if ($request->has('uploadStatus')) {
$uploadStatus = $request->has('uploadStatus'); // 0 or 1
if ($uploadStatus === 0) {
$reports = $reports
->whereDoesntHave('reportUpload')
->orWhereHas('reportUpload', function($query) use ($uploadStatus) {
$query->where('status', $uploadStatus);
});
} else {
$reports = $reports->whereHas('reportUpload', function($query) use ($uploadStatus) {
$query->where('status', $uploadStatus);
});
}
}
The code does not produce the desired results.
Edit
Trying this approach but not sure if it's correct:
$reports = $reports
->where(function ($query) use ($uploadStatus) {
$query
->whereDoesntHave('reportUpload')
->orWhereHas('reportUpload', function($query) use ($uploadStatus) {
$query->where('status', $uploadStatus);
});
});
First, there are some mistakes in your initial code.
1 - You're checking if the request has an uploadStatus. Then, $uploadStatus == $request->has which will always be true.
if ($request->has('uploadStatus')) {
$uploadStatus = $request->has('uploadStatus');
So I guess you might want:
if ($request->has('uploadStatus')) {
$uploadStatus = $request->input('uploadStatus');
2 - You're comparing strictly $uploadStatus === 0 which might not work because the request might return a string '0' and not an integer, so you should either compare with == or cast $uploadStatus to (int).
After this, I think the code you added in your question works as expected:
$reports = $reports
->where(function ($query) use ($uploadStatus) {
$query
->whereDoesntHave('reportUpload')
->orWhereHas('reportUpload', function($query) use ($uploadStatus) {
$query->where('status', $uploadStatus);
});
});
Because the where encapsulating the query will put it between parentheses.
Try to separate the queries. whereDoesntHave might be counting negatively with the orWhereHas even if it is an or statement:
$reportsNoUpload = $reports
->whereDoesntHave('reportUpload')->get();
$reportsIncomplete = $reports
->orWhereHas('reportUpload', function($query) use ($uploadStatus) {
$query->where('status', $uploadStatus);
})->get();
$reports = $reportsNoUpload->merge($reportsIncomplete);

Laravel display relation results

From the URL I am getting either a $filter, $month or both. When I for example want to show only results for November, everything works fine using the code below. But, when a filter has been set ALSO, then it shows all results (also from other months), if the filter has been found in the database.
What I want to achieve is, show only the results if the filter that was set has been found in the database, AND if a month has been set, only show the results from that particular month also.
My Section and Expense models have a belongsTo and hasMany relation respectively.
$query = Section::query();
If a filter has been set:
if ($filter !== 'false') {
$query->with(['expenses' => function ($query) use ($month) {
$query->where('date', 'LIKE', '%2015-' . Carbon::parse($month)->format('m') . '%');
}]);
}
If a month has been set:
if ($month !== 'false') {
$query->with(['expenses' => function ($query) use ($filter) {
$query->where('type', '=', $filter);
}]);
}
I also tried the following code:
if ($filter !== 'false') {
$query->with('expenses')->whereHas('expenses', function($query) use ($filter) {
$query->where('type', '=', $filter);
});
}
if ($month !== 'false') {
$query->with('expenses')->whereHas('expenses', function($query) use ($month) {
$query->where('date', 'LIKE', '%2015-' . Carbon::parse($month)->format('m') . '%');
});
}
$expenses = $query->orderBy('section', 'asc')->paginate(25);
I use a foreach on the $expenses in my view to display the results.
With the way you have it, you're overwriting one eager loading constraint with another. You need to move all your checks into one eager loading constraint, like so:
$query->with(['expenses' => function ($q) use ($month, $filter) {
if ($month !== 'false') {
$q->where('date', 'LIKE', '%2015-' . Carbon::parse($month)->format('m') . '%');
}
if ($filter !== 'false') {
$q->where('type', '=', $filter);
}
}]);
You need to combine both, else the last one is messing with the state set by the first eloquent model.
For a quick fix and understand whats happening try:
if ($filter !== 'false') {
$query = $query->with('expenses')->whereHas('expenses', function($query) use ($filter) {
$query->where('type', '=', $filter);
});
}
if ($month !== 'false') {
$query = $query->with('expenses')->whereHas('expenses', function($query) use ($month) {
$query->where('date', 'LIKE', '%2015-' . Carbon::parse($month)->format('m') . '%');
});
}
$expenses = $query->orderBy('section', 'asc')->paginate(25);
In the correct scenenario you should handle all AND conditions inside the inner closure.
it can be done using
$query->where(condition1);
$query->where(condition2);
or
$query->where(condition1)
->where(condition2);
Take a look to this answer and this documentation

Categories