Laravel Search Reference Second Model/Collection/Table with orWhereHas? - php

I'm trying to implement search functionality within my blade for my Script model. It performs fine for everything related to searching directly within the Script collection/table. However, my users also will need to be able to enter in a Patient first_name or last_name and search for the script records within the Script table that belong to the Patient being searched for. These are connected with a hasMany/belongsTo relationship. I'm trying to reference data from the Patient table in the Script results.
I've tried (with help from SO already) to implement orWhereHas and reference the patients table, but something with my syntax must be off.
The error messages I'm getting from trying to reference 'patients' with orWhereHas returns:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'scripts.patients_id' in 'where clause' (SQL: select count(*) as aggregate from `scripts` where exists (select * from `patients` where `scripts`.`patients_id` = `patients`.`id` and (`first_name` like %% or `last_name` like %%)))
This probably would work if it referenced patient_id, which is the column name for the patients foreign key. I don't know if there is a way to do that?
When I change 'patients' to 'patient', I receive the error:
Call to undefined method App\Script::patient()
Models
Patient hasMany Script
Script belongsTo Patient (patient_id)
Script Blade
{{ Form::text('search', $search, ['class' => 'form-control form-control-sm', 'placeholder' => 'Search Scripts...']) }}
{{Form::submit('Search', ['class' => 'btn btn-primary btn-sm'])}}
ScriptController
$search = $request->search;
$patients = Patient::all();
$scripts = Script::
when($search, function ($query) use ($search) {
$query->where(function ($query) use ($search) {
$query
->where('prescribe_date', 'LIKE', '%' . $search . '%')
->orWhere('status', 'LIKE', '%' . $search . '%')
->orWhere('efax_reference', 'LIKE', '%' . $search . '%')
->orWhere('efax_confirmation', 'LIKE', '%' . $search . '%');
});
})
->orWhereHas('patients', function ($query) use ($search) {
$query->where('first_name', 'like', '%' . $search . '%')
->orWhere('last_name', 'like', '%' . $search . '%');
})
->paginate(25);
I expect that if someone searches for a patient name within the search input on the Scripts table/model, they are able to cross-reference the Patients table/model and display the Scripts records that are foreign_key'ed to those Patients.
EDIT:
Patient model
// One Patient has Many Scripts relationship
public function scripts() {
return $this->hasMany('App\Script');
}
Script model
// Many Scripts to One Patient relationship
public function patients() {
return $this->belongsTo('App\Patient');
}

Related

orWhere in Laravel misbehaving when fetching data from relationship

I have this controller method that am using to search users in a given user group using email and name.
I have two groups customer and staff, when I search staff it returns customers too.
Here is the controller code
public function index(Request $request, UserGroup $group) { //group=staff
$users = $group->users();
if ($request->has('search') && $request->search) {
$users->where('name', 'LIKE', '%' . $request->search . '%')
->orWhere(function ($builder) use ($request) {
$builder->where('email', 'LIKE', '%' . $request->search . '%');
});
}
return response()->json($users->get());
}
Inside the UserGroup model here is the implementation of the code
class UserGroup extends Model{
//...
public function users(): BelongsToMany | User | Collection
{
return $this->belongsToMany(User::class, 'user_user_group');
}
//...
}
All I want is users with UserGroup staff and has name or email as typed in the search key.
Instead, the system is returning even users who do not have the staff user group.
What am I doing wrong?
You are doing it in the wrong way in writing the where clause. When you use orWhere outside, it tells laravel query to join the users table on the groups table and the first condition or the second condition. It should be join on group table and (the first condition or the second condition). It should wrap in the round brackets when it executes the query.
Your query should be:
$users = $group->users();
if ($request->has('search') && $request->search) {
$users->where(function ($builder) use ($request) {
$builder->orWhere('name', 'LIKE', '%' . $request->search . '%');
$builder->orWhere('email', 'LIKE', '%' . $request->search . '%');
});
}
I hope this will help you. For more information, I would suggest to read the laravel official documentation. Laravel Query Builder
You can also query this from the User::class perspective
User::query()
->where("name", "LIKE", "%{$request->search}%")
->orWhere("email", "LIKE", "%{$request->search}%")
->where(function(Builder $query) {
$query->whereRelation('#group', '#groupColumn','staff')
})->get();
This query will fetch the users that has the searched name or email with the group of staff.
I don't know the relationship of your usergroup and users just change the word with # to match the yours.
#group = relation of the UserGroup and User just like the users() to your UserGroup::class.
#groupColumn = column the staff belongs to.
Hope it helpful.

How to apply search on deep relation in Laravel?

I want to apply search on the item members which is associated with the item.
I've members relation on my Item model like this
public function members()
{
return $this->hasManyDeep(
'App\Models\Users\TeamMember',
['App\Models\Users\Team'],
[['teamable_type', 'teamable_id'], 'team_id'],
['id', 'id']
);
}
I've done this code for apply search on items on the bases of item's members
$items = Item::query();
->where('title', 'Like', '%' . $keyword . '%')
->with('members')
->orWhereHas('members', function ($query) use($keyword) {
$query->from('users')->where('name', 'Like', '%' . $keyword . '%');
})->get();
this relation will be return an array of members. Now It's giving me error called -
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'team_members.team_id' in 'on clause' (SQL: select * from `items` and `title` Like %test% or exists

Fetch data from same field name in two different tables and detect which filed name we mean

I have assigned search method for my application and i have made relationship between two tables "users " table and "posts" table both of them have same field name "created_at" and when i want to fetch data that when this post has been created it will bring the date in users table created_at field not in posts table created_at field.
All i want is how to tell the system make difference between which table field name i mean .
This date comes from created_at field in users table
I wand to come date in this created_at field in posts table
ListingController.php
public function search(Request $request){
$posts = Post::with(['comments','category','creator'])
->join('users', 'posts.created_by', '=', 'users.id')
->where('slug', 'LIKE', '%'.$request->search. '%')
->orWhere('users.name', 'LIKE', '%'.$request->search. '%')
->where('status',1)->orderBy('posts.id','DESC')->paginate(5);
return view('front.listing',compact('posts'));
}
listing.blade.php
<div class="article_date">
by: {{ $post->creator->name }} , {{$post->created_at->diffForHumans()}}
</div>
You are calling your relationship improperly. You should not use a join there. Use constrained eager loading instead
There will be no conflict in the created_at date since there will be no join.
While still keeping your search query inside the closure of the relationship.
$posts = Post::with(['comments', 'category'])
->with(['creator' => function ($query) use ($request) {
$query->where('name', 'LIKE', '%' . $request->search . '%');
}])
->where('slug', 'LIKE', '%' . $request->search . '%')
->where('status', 1)
->orderBy('id', 'DESC')
->paginate(5);

Laravel eloquent "with" and "where" with multiple tables

I've 3 tables on my project:
Mall
Shop
Product
I've a page to search for products in the whole database. I need an option where they can search the product by the mall name. So I built my code like this:
$query = Product::with('shop', 'shop.mall');
if (!empty($data["keyword"])) {
$query = $query->where(function($q) use($data) {
$q->where('shop.mall.name', 'LIKE', '%' . $data["keyword"] . '%')->orWhere('shop.mall.keyword', 'LIKE', '%' . $data["keyword"] . '%');
});
}
But it is showing this error:
Column not found: 1054 Unknown column 'shop.mall.name' in 'where clause'
Is there any problem with my query? Thank you
To search within relation use whereHas(), it creates subquery and returns data filtered in shop.mall.
$query = Product::with('shop', 'shop.mall');
if (!empty($data["keyword"])) {
$query = $query->whereHas('shop.mall',function($q) uses ($data){
$q->where('name', 'LIKE', '%' . $data["keyword"] . '%')->
orWhere('keyword', 'LIKE', '%' . $data["keyword"] . '%');
});
}

Search in multiple tables by eloquent query

I have two tables: posts and pages. Based on the keyword, I want to search different columns of the two tables for the occurrence of keyword. The two tables do not have related content.
I have written two queries one for each table. Following are the queries:
$result1 = Post::where('title_en', 'LIKE', '%' . $keyword . '%')
->or_where('title_np', 'LIKE', '%' . $keyword . '%')
->order_by('id', 'desc')
->paginate(10);
$result2 = Page::where('title', 'LIKE', '%' . $keyword . '%')
->or_where('content', 'LIKE', '%' . $keyword . '%')
->order_by('id', 'desc')
->paginate(10);
The above queries return two different Laravel\Paginator object. But I want a single Laravel\Paginator object so that a single pagination is displayed on the page which works for both the queries or on a single query which achieves the functionality of both the above queries. How would I be able to do that?
Since they are unrelated tables, you need to do some trickery that's simply too complex for Eloquent to handle, you need to do something similar to the following to join the two queries together, and still be able to do your limit / ordering on the combined queries:
$results = DB::query('SELECT id, title FROM (
SELECT id, title FROM `post` where `title_np` LIKE "%'.$keyword.'%" OR `title_en` LIKE "%'.$keyword.'%"
UNION ALL
SELECT id, title FROM `page` where `title` LIKE "%'.$keyword.'%" OR `content` LIKE "%'.$keyword.'%"
) temp_table
ORDER BY `id` desc
LIMIT 0, 10
')
NB the above is untested, purely an example of the approach you'll need to take, not sure this will actually work.
I know this question has been answered ages ago but If someone ends up here like me, I had a very similar issue, and here is how I did it using the eloquent way :
$users = User::where('active', 1)
->where(function ($subQuery) use ($searchKeyword) {
$subQuery->where('pseudo', 'LIKE', "%$searchKeyword%")
->orWhere('first_name', 'LIKE', "%$searchKeyword%")
->orWhere('last_name', 'LIKE', "%$searchKeyword%")
->orWhere('email', 'LIKE', "%$searchKeyword%");
})
->whereHas('addressPrincipal')
->select(array_merge(['id', 'pseudo', DB::raw("CONCAT(users.first_name,' ',users.last_name) as name")],
[DB::raw('"user" as source')]));
$usersAll = Subsidiary::where('active', 1)
->where(function ($subQuery) use ($searchKeyword) {
$subQuery->where('slug', 'LIKE', "%$searchKeyword%")
->orWhere('name', 'LIKE', "%$searchKeyword%")
->orWhere('email_principal', 'LIKE', "%$searchKeyword%");
})
->unionAll($users)
->select(array_merge(['id', 'slug as pseduo', 'name'],
[DB::raw('"subsidiary" as source')]))
->paginate(10);
You must have noticed that I have used array_merge in the select statement, I have done this as I needed to know from which table respective records were getting fetched.

Categories