How to search data from 3 (multiple) table in laravel controller? - laravel

I want to make search to show speaker where the input contain speaker name and also show speaker where the input contain topicname that the speaker had
I try to make
$speaker = Speaker::where ('name','like','%'.$search.'%')->orWhere ........
What should I make in andWhere clause?

From what I understand is you wanna search either by speaker name or speakers topic name
heres my code for that assuming you have relationships setup between your models:
$speaker = Speaker::where('name','like','%'.$search.'%')
->orWhereHas('Detail', function(Builder $query) use ($search){
$query->whereHas('Topic', function(Builder $subQuery) use ($search){
$subQuery->where('topicname', 'like','%'. $search . '%');
});
})->get();
reference : https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

First join table
$speaker = Speaker::where('name', 'LIKE', "%{$searchTerm}%")
->orWhere('topicname', 'LIKE', "%{$searchTerm}%") ->get();

You can do that by adding relations between Speaker, Detail, Topic models.
Add this to Speaker model:
public function detail()
{
return $this->hasMany('\App\Speaker', 'speakerID');
}
public function topic()
{
return Topic::find(this->detail->topicID);
}
add this to Topic model
public function detail()
{
return $this->belongsTo('\App\Detail');
}
and to access data you do it like this
$speaker->detail -to get detail info
$speaker->topic() -to get topic info
and to search on database is easy like this:
if you have the speaker name:
$speaker = Speaker::where('name','=',$searchName)->first();
if you have the topic name:
$topic = Topic::where('topicname',=',$searchTopicName)->first();
$detail = topic->detail;
$speaker = Speaker::find($detail->speakerID);
so you have all infos you need on all three $topic, $detail, $speaker.
and if you want to use querybuilder you can do like this:
$speaker =Detail::join('speaker', 'detail.speakerID', '=','speaker.detID')
->join('topic', 'detail.topicID', '=','topic.topicID')
->where('speaker.name', '=', $searchName)
->orWhere('topic.topicname', '=', $searchTopicName)
->get();

Related

API filtering with pivot table

I'm using laravel 7 and i've made an API to fetch data with a VUE component.
I want to filter restaurants based on their type of food. So if i query "pizza" i want to show only restaurants that make pizza.
getTypes is a many to many relation.
public function restaurants(Request $request)
{
$ricerca = $request->input('query');
$users = Restaurant::with(array('getTypes' => function ($query) use ($ricerca) {
$query->where('name', "LIKE", "%" . $ricerca . "%");
}))->get();
return response()->json($users);
}
I tried this, but this way i don't have access to other genres, if a restaurant make pizza and meat, i don't see meat anymore.
Any advice?
create a many to many relation with restaurant and pizza.
get an array which restaurant make pize,
$array = [];
or simple var
$array = $request('query');
and put this array in query.
$data = Project::whereHas('restorant_pizza', function ($q) use ($array) {
$q->whereIn('restorant_pizza.pizza_id', $array);
})->get();
I think this idea will help you

Laravel whereHas not getting any results?

I have a Restaurant Model, each restaurant has a Contact Model,
and each Contact is related to a City Model:
Restaurant.php:
public function contact()
{
return $this->hasOne('App\Contact','rest_id');
}
Contact.php:
public function restaurant()
{
return $this->belongsTo('App\Restaurant','rest_id','id');
}
public function city()
{
return $this->belongsTo('App\City');
}
City.php:
public function contacts()
{
return $this->hasMany('App\Contact');
}
now, what I want to do is search the restaurant names, alongside city names.
my controller code for searching is like this:
// the purpose of this condition is to keep the query empty until applying desired filters
$data = Restaurant::where('id', '=', '0');
$cityRest=$request->cityRest ;
if (!empty($cityRest)) {
$nameFilter = Restaurant::where('name', 'like', "%$cityRest%");
$contactFilter = Restaurant::whereHas('contact', function ($contact) use ($cityRest) {
$contact->where('address', 'like', "%$cityRest%");
$contact->whereHas('city', function ($city) use ($cityRest) {
$city->where('cityName', 'like', "%$cityRest%");
});
});
$data = $data->union($nameFilter);
$data = $data->union($contactFilter);
}
$data->get();
when searching for restaurant name,the results are returned correctly,but when searching for city names nothing is returned, although there is restaurants with contact models that has a city???
You have to use a orWhereHas instead of a whereHas.
With the whereHas you are searching for restaurants where the contact.address AND the city.name match your input.
By using the orWhereHas you are searching for restaurants where the contact.address OR the city.name match your input.
The AND and OR operators are used to filter records based on more than one condition:
The AND operator displays a record if all the conditions separated by AND are TRUE.
The OR operator displays a record if any of the conditions separated by OR is TRUE.
source
Try this:
$contactFilter = Restaurant::whereHas('contact', function ($contact) use ($cityRest) {
$contact->where('address', 'like', "%$cityRest%");
$contact->orWhereHas('city', function ($city) use ($cityRest) {
$city->where('cityName', 'like', "%$cityRest%");
});
});
You are searching "%$cityRest%" as string.
I think it should be like this:
Restaurant::where('name', 'like', "%".$cityRest."%");

Eloquent: How to find in text fileds via polymorphic relations?

Table structure
entity
id - integer
title - string
...
person
id - integer
name - string
...
customers
id - integer
body - text
concrete_id - integer
concrete_type - string
Models:
class Customer extends Model
{
...
public function concrete()
{
return $this->morphTo();
}
...
}
Person and Entity models have
public function customers()
{
return $this->morphMany(Customer::class, 'concrete');
}
How to find all customers where type is 'entity' and where entity.title = 'abc'?
I try do something like this,
$obj = Customer::whereHas(['concrete' => function($query){
$query->where('title', 'like', 'foo%');
}])->get();
but I have an error:
ContextErrorException in Builder.php line 825: Warning: strpos()
expects parameter 1 to be string, array given
For example, i can do this via native MySQL request:
SELECT *
FROM `customers`
LEFT JOIN `entities` ON (entities.id = customers.concrete_id )
WHERE `concrete_type` = "entity" AND entities.title LIKE "%foo%"
How to do this via Eloquent?
You work in right way, try this code:
Customer::whereHas('concrete', function ($query) {
$query->where('title', 'like', 'foo%')
})->get();
Or you can try another way:
Entity::has('concrete')->where('title', 'like', 'foo%')->get()
Rewrote the answer according to your raw MySQL:
Customer::
->join('entities', function($join)
{
$join->on('entities.id', '=', 'customers.concrete_id')
->where('entities.title', 'like', 'foo%');
})
->get();
I hope this helps :)
Laravel now not support 'whereHas' for 'MorphTo' relations.
Look laravel/framework issue 5429
And, if you want to do what is planned, you can use BelongsToMorph relation.
I added to Customer model:
public function entity()
{
return BelongsToMorph::build($this, Entity::class, 'concrete');
}
and after that, request working as need it:
Customer::whereHas('entity', function ($query) {
$query->where('entities.title', 'like', '%foo%');
})->get()->toArray();

Laravel Scope using different Model (has a relationship)

Trying to get a scope setup that will let me filter through one model (Properties), based on a column (name) in another model (Users).
I have a relationship setup to where a User has many properties, and a Property belongs to a user.
Right now I've tried this...
public function scopeFilterByUser($query, $user)
{
return $query->join('users', function($join) use ($user)
{
$join->on('properties.user_id', '=', 'users.id')
->where('name', 'LIKE', '%'.$user.'%');
});
}
which "works" except that it breaks my Accessor on the Property model.
Both the Property and User have their own tables, with columns for address, city, state, and zipcode. Only the Property has a full_address column which I'm using an accessor for like this...
public function getFullAddressAttribute($value)
{
$address = $this->address;
$city = $this->city;
$state = $this->state;
$zipcode = $this->zipcode;
return $address.', '.$city.', '.$state.', '.$zipcode;
}
Both of these are in the Property model. For some reason when accessing the $property->full_address after filtering the properties with this filterByUser.. full_address is returning the combined values from the User table and not the Property table.
I'm wondering what the best way would be to set this up so I can filter Properties by the Users name. The property DOES have a user_id column, but I'm looking to filter based on user name.
It all works if I rename all of the property address fields to prop_address, prop_city, etc... but this is not ideal.
Any ideas? I've tried everything I can think of.
Can you try changing your scope to this :
public function scopeFilterByUser($query, $user)
{
return $query->whereHas('users', function($q) use ($user) {
$q->where('name', 'like', '%' . $user . '%');
});
}
You can then use it as
$properties = Property::filterByUser('name')->get();
// Then
$properties->first()->full_address
Let me know in the comments if this doesn't work :)

Where NOT in pivot table

In Laravel we can setup relationships like so:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Allowing us to to get all items in a pivot table for a user:
Auth::user()->items();
However what if I want to get the opposite of that. And get all items the user DOES NOT have yet. So NOT in the pivot table.
Is there a simple way to do this?
Looking at the source code of the class Illuminate\Database\Eloquent\Builder, we have two methods in Laravel that does this: whereDoesntHave (opposite of whereHas) and doesntHave (opposite of has)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
this works correctly for me!
For simple "Where not exists relationship", use this:
User::doesntHave('Role')->get();
Sorry, do not understand English. I used the google translator.
For simplicity and symmetry you could create a new method in the User model:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
To use call:
Auth::user()->availableItems();
It's not that simple but usually the most efficient way is to use a subquery.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
If this was something I did often I would add it as a scope method to the Item model.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Then use that later like this.
$items = Item::whereNotRelatedToUser($user_id)->get();
How about left join?
Assuming the tables are users, items and item_user find all items not associated with the user 123:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();
this should work for you
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);
Ended up writing a scope for this like so:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
And then call:
Items::avail()->get();
Works for now, but a bit messy. Would like to see something with a keyword like not:
Auth::user()->itemsNot();
Basically Eloquent is running the above query anyway, except with a = instead of a <>.
Maybe you can use:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Source: http://laravel.com/docs/4.2/queries#advanced-wheres
This code brings the items that have no relationship with the user.
$items = $this->item->whereDoesntHave('users')->get();

Resources