How to make Laravel Eloquent Query more dynamic? - php

Based on some inputs, whether they are not null, I want to perform a Eloquent Query. I want to add the following attributes to query if they are not null.
How to make this query work?
$property = Property::
where('published','=','1');
if(!empty($searchInput)){
$property+=$property
->orWhere('name', 'like', $percentageSearch)
->orWhere('village', 'like', $percentageSearch)
->orWhere('address', 'like', $percentageSearch)
->orWhere('reference_point', 'like', $percentageSearch)
->orWhere('price', 'like', $percentageSearch);
}
if(!empty($typeInput)){
$property+=$property
->orWhere('type', '=', $typeInput);
}
if(!empty($categoryInput)){
$property+=$property
->orWhere('category_id', '=', $categoryInput);
}
$prop=$property->get();

Use a local scope and conditional queries.
$property = Property::where('published_at', 1)->search($searchInput, $typeInput, $categoryInput)->get();
// Property Model
public function scopeSearch($builder, $search, $type, $category)
{
return $builder->where(function ($query) use ($search, $type, $category) {
$query->when($search, function ($property, $search) {
$property->orWhere('name', 'like', $search)
->orWhere('village', 'like', $search)
->orWhere('address', 'like', $search)
->orWhere('reference_point', 'like', $search)
->orWhere('price', 'like', $search);
})
->when($type, function ($property, $type) {
$property->orWhere('type', '=', $type);
})
->when($category, function ($property, $category) {
$property->orWhere('category_id', '=', $category);
});
});
}
Logical Grouping
Conditional Clauses
Local Scopes

Related

Using whereHas and with laravel

Can this code be written using WhereHas and with only and not using Join? am filtering few data from multiple tables
public function filterByOffer(Request $request, User $user, Offer $offer)
{
$query = TradeRequest::query()
->select(
'trade_requests.uuid as trade_request_uuid',
'trade_requests.card_images_url',
'trade_requests.status',
'trade_requests.card_value',
'trade_requests.amount_payable',
'offers.*',
'cards.name',
'card_currencies.currency'
)
->join('offers', 'trade_requests.offer_id', 'offers.id')->where('offers.uuid', $offer->uuid)
->join('card_currencies', 'offers.card_currency_id', 'card_currencies.id')
->join('cards', 'offers.card_id', 'cards.id')->where('offers.user_id', $user->id)
->orderBy('trade_requests.created_at', 'DESC');
$request->whenHas('card', function ($value) use ($query) {
return $query->where('cards.name', 'like', '%' . $value . '%');
});
$request->whenHas('currency', function ($value) use ($query) {
return $query->where('card_currencies.currency', 'like', '%' . $value . '%');
});
$request->whenHas('status', function ($value) use ($query) {
return $query->where('trade_requests.status', 'like', '%' . $value . '%');
});
return $query->paginate();
}
Can this code be written using WhereHas and with only and not using Join?

Laravel Search Query which meets conditions

Hi I have this code that is to search for records.
Admins are able to see all records, this is the query for admins
$trainings = Training::where('staffName', 'LIKE', "%{$request->search}%")
->orWhere('programTitle', 'LIKE', "%{$request->search}%")
->orWhere('trainer', 'LIKE', "%{$request->search}%")
->paginate();
Whereas Employees should only see their records, so how do I add this condition into the existing query for the search function? This is the query I have for the Employee search currently
$employees = Training::where('staffName',$username)
->orWhere('staffName', 'LIKE', "%{$request->search}%")
->orWhere('programTitle', 'LIKE', "%{$request->search}%")
->orWhere('trainer', 'LIKE', "%{$request->search}%")
->paginate();
I have another version for Managers, which is meant to also refer to their roles from a different table. I am trying it like this but it only is working properly when it comes to the Manager, but when the function fetches anything related to staff under them it fetches all records instead of specific records.
$managers = DB::table('trainings')
->join('users','users.id','=','trainings.staff_id')
->select('trainings.staffName','programTitle','trainer','trainingDate','hours')
->where('trainings.staffName',$username)
->orWhere('reportingTo',$username)
->where(function ($query) use ($request) {
$query->where('trainings.staffName', 'LIKE', "%{$request->search}%")
->orWhere('programTitle', 'LIKE', "%{$request->search}%")
->orWhere('trainer', 'LIKE', "%{$request->search}%");
})
->paginate();
Your usage of orWhere is wrong because orWhere remove all conditions if it's true try this code below
Training::where('staffName', $username)
->where(function ($query) {
$query->where('staffName', 'LIKE', "%{$request->search}%")
->orWhere('programTitle', 'LIKE', "%{$request->search}%")
->orWhere('trainer', 'LIKE', "%{$request->search}%");
})
->paginate();
For the last query
$managers = DB::table('trainings')
->join('users', 'users.id', '=', 'trainings.staff_id')
->select('trainings.staffName', 'programTitle', 'trainer', 'trainingDate', 'hours')
->where(function ($query) use ($username) {
$query->where('trainings.staffName', $username)
->orWhere('reportingTo', $username);
})
->where(function ($query) use ($request) {
$query->where('trainings.staffName', 'LIKE', "%{$request->search}%")
->orWhere('programTitle', 'LIKE', "%{$request->search}%")
->orWhere('trainer', 'LIKE', "%{$request->search}%");
})
->paginate();
here's when query scopes comes to the rescue.
class Training extends Eloquent {
public function scopeFilterByRole($query, $roleId, $searchInput)
{
if ($roleId === 3) {
return $query->where('staffName', 'LIKE', "%{$searchInput}%")
}
return $query;
}
}
Then in your controller
Training::where('programTitle', 'LIKE', "%{$request->search}%")
->orWhere('trainer', 'LIKE', "%{$request->search}%")
->FilterByRole(3, $request->search)
->get();
You can write a global scope for that it will automatically apply in all existing queries:
protected static function boot()
{
parent::boot();
static::addGlobalScope(function (Builder $builder) {
if (auth()->check() and auth()->user()->role == 3) {
$builder->where('staffName', 'LIKE', "%{request()->get('search_name')}%")
}
});
}

Complex query in Laravel using Query Builder

On my website I am trying to implement search functionality. When someone enters keyword I am supposed to find all posts and users that may match that keyword based on posts title or body, or based on users name, username or bio. However I am having trouble with executing this query.
public function search(Request $request) {
$keyword = $request->get('q');
$posts = Post::where('deleted', 0)
->where('title', 'like', '%'.$keyword.'%')
->orWhere('body', 'like', '%'.$keyword.'%')
->orderBy('title')
->get();
$users = User::where('name', 'like', '%'.$keyword.'%')
->where('active', 1)
->orWhere('username', 'like', '%'.$keyword.'%')
->orWhere('bio', 'like', '%'.$keyword.'%')
->orderBy('username')
->get();
return view('searchresults', compact('users', 'posts'));
}
The specific problem I am having is that after function search $posts variable contains posts which were deleted.
This is what I actually need:
select * from posts where deleted = 0 and (title like $keyword or body like $keyword)
I appreciate any help.
Thanks. :)
Use closure to group where() and orWhere() like this:
$posts = Post::where('deleted', 0)
->where(function($q) use($keyword) {
$q->where('title', 'like', '%' . $keyword . '%')
->orWhere('body', 'like', '%' . $keyword . '%');
})
->orderBy('title')
->get();
public function search(Request $request) {
$keyword = $request->get('q');
$posts = Post::whereNull('deleted')
->where('title', 'like', '%'.$keyword.'%')
->orWhere('body', 'like', '%'.$keyword.'%')
->orderBy('title')
->get();
$users = User::where(function($query) use($keyword){
$query->where('name', 'like', '%'.$keyword.'%');
$query->orWhere('username', 'like', '%'.$keyword.'%');
$query->orWhere('bio', 'like', '%'.$keyword.'%');
})
->where('active', 1)
->orderBy('username')
->get();
return view('searchresults', compact('users', 'posts'));
}
Hope it's help you!!

Fetching first or latest first from many to many relationship in eager loading in laravel

I'm building a small application in laravel 5.4, where I'm having two models Contact and Companies I've many to many relationship between them, something like this in my Contact Model:
public function company()
{
return $this
->belongsToMany('App\Company', 'company_contact','contact_id', 'company_id')->withTimestamps();
}
Now at someplace I want to have current company i.e. I want to have latest() first(). Or orderBy, created_by desc and get first() row. For this I have to do something like this:
$contacts = Contact::where('name', 'LIKE', '%'. $request->search_input. '%')
->orWhere('email', 'LIKE', '%'. $request->search_input. '%')
->orWhereHas('company', function ($q) use($request) {
$q->where('name', 'LIKE', '%'. $request->search_input. '%');
})
->with('company')
->orderBy('created_at', 'desc')
->paginate(50);
foreach ($contacts as $contact)
{
$contact->company = $contact->company()->withPivot('created_at')->orderBy('pivot_created_at', 'desc')->first();
}
For this to remove foreach I tried using a new relation in my Contact model:
public function currentCompany()
{
return $this
->belongsToMany('App\Company', 'company_contact','contact_id', 'company_id')
->withTimestamps()
->orderBy('created_at', 'desc')
->first();
}
But while fetching in controller:
$contacts = Contact::where('name', 'LIKE', '%'. $request->search_input. '%')
->orWhere('email', 'LIKE', '%'. $request->search_input. '%')
->orWhereHas('currentCompany', function ($q) use($request) {
$q->where('name', 'LIKE', '%'. $request->search_input. '%');
})
->with('CurrentCompany')
->orderBy('created_at', 'desc')
->paginate(50);
But it is throwing me error, is there any eloquent way or Collection way to remove this foreach.
use first() inside closure-
$contacts = Contact::where('name', 'LIKE', '%'. $request->search_input. '%')
->orWhere('email', 'LIKE', '%'. $request->search_input. '%')
->with(['company'=>function ($q) use($request) {
$q->where('name', 'LIKE', '%'. $request->search_input. '%')->first();
}])
->orderBy('created_at', 'desc')
->paginate(50);
Or like this-
$contacts = Contact::where('name', 'LIKE', '%'. $request->search_input. '%')
->orWhere('email', 'LIKE', '%'. $request->search_input. '%')
->orWhereHas('company', function ($q) use($request) {
$q->where('name', 'LIKE', '%'. $request->search_input. '%');
})
->with(['company'=>function($q){
$q->first();
}])
->orderBy('created_at', 'desc')
->paginate(50);
this way you don't need to do any additional foreach loop.
You can't really do what you are trying to do directly. The relationships are query shortcuts. You can ensure you only get the first but that will still be a part of a collection if your relationship is one/many to many.
Consider this:
$contacts = Contact::where('name', 'LIKE', '%'. $request->search_input. '%')
->orWhere('email', 'LIKE', '%'. $request->search_input. '%')
->orWhereHas('company', function ($q) use($request) {
$q->where('name', 'LIKE', '%'. $request->search_input. '%');
})
->with([ 'company' => function ($query) {
return $query->latest(); //Take the latest only
})
->orderBy('created_at', 'desc')
->paginate(50);
However to access the company you need to do something like $contacts[index]->company->first() because it will still produce a collection of related companies even.
The problem is the ORM will perform 2 queries, the first one will retrieve all the Contact models which fulfil the query and the 2nd one will retrieve all related models for all contacts it retrieved. This means if you do things like limiting it to 1 related result you might end up only getting one for all contacts retrieved.

How can I use wherehas and join simultaneously?

I use Laravel 5.3
My code is like this :
public function getWishlist($param)
{
$num = 20;
$q = $param['q'];
$location = $param['location'];
$result = $this->product_repository->whereHas('favorites', function ($query) use($q, $location) {
$query->where('favorites.user_id', '=', auth()->user()->id)
->where('products.status', '=', 1);
if($q)
$query->where('products.name', 'like', "%$q%");
})
->join('stores', 'stores.id', '=', 'products.store_id');
if($location)
$result->where('stores.address', 'like', "%$location%");
if($q)
$result->where('products.name', 'like', "%$q%")
->where('stores.address', 'like', "%$q%", 'or');
dd($result->toSql());
// ->paginate($num);
return $result;
}
When executed, the result is empty
Seems wherehas and join not work simultaneously
Is there any solution to solve my problem?
I think you can use advanced where
$result = $result->where(function($query) use ($q) {
$query->where('products.name', 'like', "%$q%")
->where('stores.address', 'like', "%$q%", 'or');
})

Categories