Laravel with where like condition in relationship - laravel

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();

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);
});
});
});
}

Laravel search in nested relationships

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.

Laravel join database table with where clause and like from $request

public function search(Request $request)
{
if ($request->get('search') != '') {
$franchise = DB::table('operators')
->join('franchises', function ($join) {
$join->on('operators.id', '=', 'franchises.operator_id')
->where('case_number', 'like', '%' . $request->get('search') . '%');
})
->get();
return view('franchise-home', compact('franchise'));
} else {
$franchise = DB::table('operators')
->join('franchises', 'operators.id', '=', 'franchises.operator_id')
->get();
return view('franchise-home', compact('franchise'));
}
}
how to make this work with both where clause and get a request from a user? Any help is much appreciated. thanks.
You need to add use() to access your variable, for example :
$search = $request->get('search'); // define it before query
...
->join('franchises', function ($join) use($search) { //use it inside
$join->on('operators.id', '=', 'franchises.operator_id')
->where('case_number', 'like', '%' . $search . '%');
})
Below is the sort code
public function search(Request $request) {
$franchise = DB::table('operators')
->join('franchises', 'operators.id', '=', 'franchises.operator_id')
->when($request->get('search'), function($query) use($request) {
$query->where('case_number', 'like', '%' . $request->get('search');
})
->get();
return view('franchise-home', compact('franchise'));
}

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.

Is there a way for Eloquent whereHas to only get() the matching results?

I have the following function
public function index(Request $request)
{
$results = Service::whereHas('conditions', function ($query) use ($request){
$query->whereIn('id', $request->conditions);
})
->whereHas('locations', function ($query) use ($request){
$ran = false;
foreach($request->locations as $location)
{
if(!$ran)
{
$query->Where('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
else
{
$query->orWhere('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
$ran = true;
}
})
->with('types', 'contacts', 'locations.datetimes')->toSql();
dd($results);
}
which produces
select * from `services` where exists
(select * from `conditions` inner join `condition_service` on `conditions`.`id` = `condition_service`.`condition_id` where `services`.`id` = `condition_service`.`service_id` and `id` in (13, 14) and `conditions`.`deleted_at` is null)
and exists
(select * from `service_locations` inner join `service_location_service` on `service_locations`.`id` = `service_location_service`.`service_location_id` where `services`.`id` = `service_location_service`.`service_id` and
(`town` like 'manchester' or `city` like 'manchester' or `town` like 'crewe' or `city` like 'crewe')
and `service_locations`.`deleted_at` is null) and `services`.`deleted_at` is null
The problem is the whereHas on locations brings back all results, whereas I only want the result where the town/city is a match. Whats the best way to achieve this?
i think you need to group your location query using the callback which wraps the query in () and just process the first location directly remove it from array and iterate over loop. so below code should work in your case.
$results = Service::whereHas('conditions', function ($query) use ($request){
$query->whereIn('id', $request->conditions);
})
->whereHas('locations', function ($query) use ($request){
$locations = $request->locations;
$query->where(function($builder) use($locations){
$builder->where('town', 'like', '%' . $locations[0] . '%')
->orWhere('city', 'like', '%'.$locations[0].'%');
unset($locations[0]); //remove first item as it is processed
foreach($locations as $location) {
$builder->orWhere('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
});
});
let me know if you find any problem with it. :)
I managed to figure it out late last night.
I moved the with() to the top of the query and made a callback on locations.
public static function newGetSearchResults($request)
{
return Service::with(['types', 'contacts', 'locations.datetimes', 'locations' => function($query) use($request) {
$ran = false;
foreach($request->locations as $location)
{
if(!$ran)
{
$query->Where('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
else
{
$query->orWhere('town', 'like', '%'.$location.'%')
->orWhere('city', 'like', '%'.$location.'%');
}
$ran = true;
}
}])
->whereHas('conditions', function ($query) use ($request){
$query->whereIn('id', $request->conditions);
})->get();
}

Resources