Laravel search in nested relationships - laravel

I have problem with my search engine in Laravel. I have 3 models: Post, Comment and CommentUser.
My relations are: Post has many comments and comment has one user. I want create search for this relationship. Now I have following code:
$posts = Post::where('page_id', Auth::user()->page)
->with([
'comments' => function($q) use($sort, $search) {
if($search){
$q->where('content', 'like', '%'.$search.'%');
}
if($sort == 'answered'){
$q->where('answered', '=', 1);
}
if($sort == 'new'){
$q->where('answered', '=', 0);
}
},
'comments.user' => function($q) use($sort, $search) {
if($search){
$q->where('name', 'like', '%'.$search.'%')
->orWhere('lastname', 'like', '%'.$search.'%');
}
},
])
->whereHas('comments', function($q) use($sort, $search){
if($search){
$q->where('content', 'like', '%'.$search.'%');
}
if($sort == 'answered'){
$q->where('answered', '=', 1);
}
if($sort == 'new'){
$q->where('answered', '=', 0);
}
})
->orWhereHas('comments.user', function($q) use($search){
if($search){
$q->where('name', 'like', '%'.$search.'%')
->orWhere('lastname', 'like', '%'.$search.'%');
}
})
->orderBy('created_at', 'asc')
->paginate(10);
I try using next with and orWhereHas but isn't working because for example when I have comment content like "best regards" I don't have user with this name or lastname and vice versa. I want search search posts where comment content is like search term or posts where user name or lastname is like search term but now two options are disclaims.

Related

How to do laravel eloquent table with joins, orwhere and pagination correctly?

This is my original code where i display all data for team users.
$data = Teamuser::join('teams', 'teams.id', '=', 'team_user.team_id')
->join('users', 'users.id', '=', 'team_user.user_id')
->get(['users.name as username','teams.name','users.email','team_user.role','team_user.id','team_user.user_id','team_user.team_id']);
However, since im developing a search function for the table. I try adding orwhere to the function.
$data = Teamuser::join('teams', 'teams.id', '=', 'team_user.team_id')
->join('users', 'users.id', '=', 'team_user.user_id')
->get(['users.name as username','teams.name','users.email','team_user.role','team_user.id','team_user.user_id','team_user.team_id'])
->where('users.name', 'like', '%'.$request->search2.'%')
->orWhere('teams.name', 'like', '%'.$request->search2.'%')
->orWhere('team_user.role', 'like', '%'.$request->search2.'%')
->orWhere('users.email', 'like', '%'.$request->search2.'%')->paginate(5);
But the search function doesnt work, how do i format the syntax in a correct way?
I'm not sure you are using get() correctly, but i purpose you an alternative syntax
$data = Teamuser::select(['users.name as username','teams.name','users.email','team_user.role','team_user.id','team_user.user_id','team_user.team_id'])
->join('teams', 'teams.id', '=', 'team_user.team_id')
->join('users', 'users.id', '=', 'team_user.user_id')
->where('users.name', 'like', '%'.$request->search2.'%')
->orWhere('teams.name', 'like', '%'.$request->search2.'%')
->orWhere('team_user.role', 'like', '%'.$request->search2.'%')
->orWhere('users.email', 'like', '%'.$request->search2.'%')
->paginate(5);
Check if your join is correct, maybe you could use leftJoin() instead of join()
class TeamUserController extends Controller
{
public function index()
{
$teamUsers = Teamuser::query()
->with('team', 'user')
->search(request('search2'))
->paginate(5);
...
// App/Models/TeamUser
public function team()
{
return $this->belongsTo(Team::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function scopeSearch($query, string $terms = null)
{
collect(explode(' ', $terms))->filter()->each(function ($term) use ($query) {
$term = '%'.$term.'%';
$query->where(function ($query) use ($term) {
$query->where('role', 'like', $term)
->orWhereHas('team', function ($query) use ($term) {
$query->where('name', 'like', $term);
})
->orWhereHas('user', function ($query) use ($term) {
$query->where('name', 'like', $term)
->where('email', 'like', $term);
});
});
});
}

Searching with multiple tables in laravel

I have this search query
$products = Product::query()
->where('name', 'LIKE', "%{$search}%")
->orWhere('slug', 'LIKE', "%{$search_any}%")
->where('status', 'Active')
->get();
i have user table which stores the user who listed the product and its relation is as follows
Product Model:
public function user()
{
return $this->belongsTo(User::class);
}
I have one field type in user table, i want if user enters search string matches type also then also all the products added by them should be returned i was trying this code but how can i combine both the queries
$products = Product::query()
->where('name', 'LIKE', "%{$search}%")
->orWhere('slug', 'LIKE', "%{$search_any}%")
->where('status', 'Active')
->get();
$productsAddedByUser = User::where('type', 'LIKE', "%{$search_any}%")->get();
// saved $productsAddedByUser result in this array $userIdarray
$productnew = Product::whereIn('user_id', $userIdarray)->get();
I want to combine both the results of $productnew and $products
At first save result in $userIdarray, then in products query:
$userIdarray = User::where('type', 'LIKE', "%{$search_any}%")->pluck('id');
$products = Product::query()
->where(
fn($query) => $query->where('name', 'LIKE', "%{$search}%")
->orWhere('slug', 'LIKE', "%{$search_any}%")
)
->where('status', 'Active')
->when(count($userIdarray), fn($query) => $query->whereIn('user_id', $userIdarray))
->get();

Laravel with where like condition in relationship

I have a WorkPackage model with below relationship.
public function work_items()
{
return $this->hasMany(WorkItem::class);
}
And WorkPackage has 'title','project_id' columns and work_items has 'title','work_package_id' columns. Now I want to search user typed keyword is matching with title in both table.
Here is my tried function
public function getWorkPackageProposals($projectId, $title)
{
$result['data'] = $this->workPackage->with(['work_items' => function ($query) {
$query->where('title', 'LIKE', "%{$title}%");
}])
->where('project_id', $projectId)
->where('title', 'LIKE', "%{$title}%")
->get();
return $result;
}
but its not working.
Please find the below code for I used to create object of WorkPackage.
public function __construct(WorkPackage $workPackage)
{
$this->workPackage = $workPackage;
$this->setModel(WorkPackage::class);
$this->workItemRepository = app(WorkItemRepository::class);
}
whereHas() works to specify additional filters for the related model to check :
$result['data'] = $this->workPackage->whereHas('work_items', function ($query) use ($title) {
$query->where('title', 'LIKE', "%{$title}%");
})
->where('project_id', $projectId)
->where('title', 'LIKE', "%{$title}%")
->get();
return $result;
Below code works for me. Thanks to everyone for help to get right answer.
$result['data'] = $this->workPackage->with(['work_items' => function ($q) use ($title) {
$q->where('title', 'LIKE', "%{$title}%");
}])
->where('project_id', $projectId)
->where('title', 'LIKE', "%{$title}%")
->get();
return $result;
I think your problem will be solved with join method:
$result = $this->workPackage
->join('work_items', 'work_packages.id', '=', 'work_items.package_id')
->where('work_items.title', 'LIKE', '%{$term}%')
->orWhere('work_packages.title', 'LIKE', '%{$term}%')
->get();

How I can ignore current row id one time only

I have custom query where ignored current row id:
$relatedVacancies = \App\Vacancy::whereHas('skills', function ($q) use ($vacancy) {
return $q->whereIn('skill_id', $vacancy->skills->pluck('skill_id'));
})->where('id', '!=', $vacancy->id)
->orWhere('employment', $vacancy->employment)->where('id', '!=', $vacancy->id)
->orWhere('title', 'like', '%'.$vacancy->title.'%')->where('id', '!=', $vacancy->id)
->get();
How I can use this condition one time only:
->where('id', '!=', $vacancy->id)
If you are trying to select based on three conditions:
->where([
('id', '!=', $vacancy->id),
('employment', '=', $vacancy->employment),
('title', 'like', '%'.$vacancy->title.'%'),
])->get();
Try this (based on https://laravel.com/docs/5.7/queries#parameter-grouping):
$relatedVacancies = \App\Vacancy::where('id', '!=', $vacancy->id)
->whereHas('skills', function ($q) use ($vacancy) {
return $q->whereIn('skill_id', $vacancy->skills->pluck('skill_id'));
})
->where(function ($query) {
$query->where('employment', $vacancy->employment)
->orWhere('title', 'like', '%'.$vacancy->title.'%');
})
->get();
Also check for this answer: https://stackoverflow.com/a/23009807/5458355

How can I Refactor this search filter query?

I need to search in multiple tables. I'm checking every single request object. For example: I am checking if the request has that object then concating it to my main query and getting that query result at the last. It doesn't looks and isn't good. How can I make this search query filter better in laravel?
Note: I have searched questions in stackoverflow but they are dealing with only one model.
$query = DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0');
if(!is_null($request->fname)){
$query+=->where('clients.fname', 'like', '%$request->fname%');
}
if(!is_null($request->lname)){
$query+=->where('clients.lname', 'like', '%$request->lname%');
}
if(!is_null($request->gender)){
$query+=->where('clients.sex', $request->sex);
}
if(!is_null($request->number)){
$query+=->where('ecommerce_contacts.sex', 'like', $request->number);
}
if(!is_null($request->registered_date)){
}
if(!is_null($request->purchase)){
}
$client = $query->get();
$data = json_encode($clients);
return $data;
Use conditional clauses:
DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0')
->when(request()->has('fname'), function ($query) {
return $query->where('clients.fname', 'like', '%' . request()->fname . '%');
})
->when(request()->has('lname'), function ($query) {
return $query->where('clients.lname', 'like', '%' . request()->lname . '%');
})
->when(request()->has('gender'), function ($query) {
return $query->where('clients.sex', '=', request()->gender);
})
...
$query=DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0');
$search_fields=['fname','lname','gender','number','registered_date','purchase'];
foreach($search_fields as $key){
if(!is_null($key)){
$query->orWhere('clients.'.$key, 'LIKE', '"%" . '.$request->$key.' . "%"');
}
}
$client = $query->get();
$data = json_encode($client);
return $data;
I upvoted #DigitalDrifter 's answer because i liked it but I prefer my filter pattern.
Have a look at this:
$query = DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0');
!isset($request->fname) ?: $query->where('clients.fname', 'like', '%$request->fname%');
!isset($request->lname) ?: $query->where('clients.lname', 'like', '%$request->lname%');
!isset($request->gender) ?: $query->where('clients.sex', $request->sex);
!isset($request->number) ?: $query->where('ecommerce_contacts.sex', 'like', $request->number);
$client = $query->get();
$data = json_encode($clients);
return $data;
I think this is more readable and requires less line of code.

Resources