laravel relation issue in many to many case - laravel

i have three table in mysql:
1-users
table of users
2-projects
table of project
3-project_user
there is id and project_id and user_id for relation
there is two model : user and project
the relation between these table are belongsToMany
when a project create maybe one project define for two person
NOW how can i show the project of each person?

Assuming you properly defined your relationships, do
$users = User::with('projects')->get();
//show each user projects
foreach($users as $user) {
echo $user->projects;
}
//Getting project users
$projects = Project::with('users')->get();
This will give you projects list, in each list you can see which user has access or not.
Updates
Taking project with specified user_id
$projects = Project::with(['users' => function ($query) use ($user_id) {
$query->where('user_id', '=', $user_id);
}])->get();
New code
Or try to to get the user
$user = User::with('projects')->where('id', $user_id)->first();
Or via projects, constraining by user_id
$projects = Project::with('users')->whereHas('users', function ($query) use ($user_id) {
$query->where($user_id);
})->get();

the way i solve it:
//save user_id
$user_id = $request->id;
//select in project_user where user_id = $user_id
$project_user = DB::table('project_user')->where('user_id', '=', $user_id)->get();
//create an empty array
$p_id = array();
//fill empty array with project_id
foreach($project_user as $pro) {
$p_id[] = $pro->project_id;
}
//select code and id in project table where id = one of that [$p_id] array
$data = Project::select('code','id')->whereIn('id', $p_id)->get();
//return your data in json
return response()->json($data);

As far as I understood your question, you want to query Project as per user_id. Here is how you do it.
Project::with('users')->whereHas('users', function ($query) use ($user_id_array) {
$query->whereIn('id',$user_id_array);
})->get();
This will give you projects whose user_id are from $user_id_array. Let me know if you need any further help.

Related

Laravel Eloquent: orderBy related table

I would like to order result of eloquent by field on the other related table.
I have users table. Every user has one profile. Profile has sponsored (which is boolean) field. So when I would like to get all users, I want to display first sponsored users, then non sponsored.
public function profile(){
return $this->hasOne('App\Doctor');
}
There are two ways:
1)You have to join tables,
User::join('profiles','users.id','=','profile.user_id')->orderBy('sponsored','DESC')->get()
2)Order by eager loading
User::with(array('profile' => function($query) {
$query->orderBy('sponsored', 'DESC');
}))
->get();
Try this one
User::leftJoin('profile', 'user.id', '=', 'profile.user_id')
->orderBy('profile.sponsored', 'ASC')
->get();
I highly recommend not using table joins as it would fail you on the scale.
A better solution is to get users, get their profiles and then sort them using laravel collection methods.
You can use this sample to achieve this solution.
//get all users
$users = User::all();
//extract your users Ids
$userIds = $users->pluck('id')->toArray();
//get all profiles of your user Ids
$profiles = Profile::whereIn('user_id', $userIds)->get()->keyBy('user_id');
//now sort users based on being sponsored or not
$users = $users->sort(function($item1, $item2) use ($profiles) {
if($profiles[$item1->id]->sponsored == 1 && $profiles[$item2->id]->sponsored == 1){
return 0;
}
if($profiles[$item1->id]->sponsored == 1) return 1;
return -1;
});
You can check this link which explains on laravel collection sorts.
$order = 'desc';
$users = User::join('profile', 'users.id', '=', 'profile.id')
->orderBy('profile.id', $order)->select('users.*')->get();

How to get data based in comparing value in pivote table with value in required table in laravel 5.6?

I am learning larvel 5.6 so I am trying to retrieve number of messages that have id larger than last_seen_id in pivot table
I have user table which have the default columns generated by:
php artisan make:auth
and messages tables which have the following columns:
id, from, message_content, group_id
and the group table have the columns:
id,type
now there is many to many relation between the users and groups table through the custom pivot table which have the columns:
group_id,user_id,last_id_seen
now if I want to retrieve the messages which belong to same group and have larger id than last_id_seen in the pivot table how to do it?
I think you are looking for something like this:
$groupId = 1; // set to whatever you want
$lastSeenId = \Auth::user()->groups()
->where('group_id', $groupId)
->first()->pivot->last_id_seen;
$messages = Message::where('id', '>', $lastSeenId)->get();
A more robust version, which does not fail when your user does not have an entry for the group yet, would be:
$groupId = 1; // set to whatever you want
$group = \Auth::user()->groups()->where('group_id', $groupId)->first();
$lastSeenId = $group ? $group->pivot->last_id_seen : null;
$messages = Message::when($lastSeenId, function($query, $id) {
$query->where('id', '>', $id);
})->get();
Note: normally you'd use optional() in the second snippet, but Laravel 5.2 does not come with this helper...
If you want both the count() of the results and the results themselves, you can store the query in a variable and perform two queries with it. You then don't have to rewrite the same query twice:
$groupId = 1; // set to whatever you want
$group = \Auth::user()->groups()->where('group_id', $groupId)->first();
$lastSeenId = $group ? $group->pivot->last_id_seen : null;
$query = Message::when($lastSeenId, function($query, $id) {
$query->where('id', '>', $id);
});
$count = $query->count();
$messages = $query->get();

Laravel select * where id =(select id )

Using Laravel eloquent how do I make a query like this:
select * from branches where user_id =(select id from users where name ='sara' )
Assuming that you have a user relationship in your Branch model you could use whereHas:
$branches = Branch::whereHas('user', function ($query) {
$query->where('name', 'sara');
})->get();
Update
If you're using v8.57.0 or above, you can now use the whereRelation() method instead:
Branch::whereRelation('user', 'name', 'sara')->get();
$id = Users::select('id')->where('name','sara')->first();
$barnches = branches::where('id',$id)->get();
Here Users and branches are models , first is using for 1 row and get for many rows
I would split it into two queries. First getting the id, then getting the list. Expecting your models to be called "User" and "Branches"
$user = User::where('name', 'sara');
$id = $user->id;
$branches = Branch::where('id', $id);
This site may help you Link
Try this.
$name = 'sara';
$results = BranchModel::whereIn("user_id", function ($query) use ($name) {
$query->select("id")
->from((new UserModel)->getTable())
->where("name", $name);
})->get();
You can use this:
$users = User::whereName("sara")->get()->pluck('id');
Branch::whereIn('user_id',$users)->get();

Get Model where relationship = id

Would love to know how other people are achieving the following?
Tables:
teams
teams_users (pivot many teams, many users)
users
What i am trying to achieve
$teams->user->where('user_id', $id)->get();
however i am having to run a loop, and create another method on the team model to pluck(id, name)
// foreach ($teams as $team) {
// # code...
// dump($team->getUserIdsAttribute());
// }
Do you know a better way?
If you are trying to get all teams with a specific a user id. Try
$teams = Team::with(['users' => function ($query) use ($id) {
$query->where('id', '=', $id);
}])->get();
Or through the user
$user = User::with('teams')->find($id);
This is assuming you already defined the belongsToMany() relationship in each model.
Maybe you will like to do it in the more traditional way
use Illuminate\Database\Eloquent\Builder;
$team = Team::whereHas('user',function(Builder $query) use ($id){
$query->where( 'user_id' , $id );
})->get();

Creating a search filter and one of the fields is from other table

So I`m trying to create a search filter.
And i have created this:
$data = Input::all();
$ads = new Ads();
if($data['description']) {
$ads = $ads->where('description', 'LIKE', '%' . $data['description'] . '%');
}
if($data['min']) {
$ads = $ads->where('price', '>', $data['min']);
}
if($data['max']) {
$ads = $ads->where('price', '<', $data['max']);
}
And I have $data['city']. But the problem is that $ads dont have a city, it has userID and every user has its city. How would i do something like this but it would actualy search the user that owns this ad and check if the city is like the searched one.
I tried somthing like this:
$resultAds = $ads;
if($data['city']) {
foreach($resultAds as $rAds) {
if($rAds->compareCity($data['city'])) {
$resultAds[] = $rAds;
}
}
}
$resultAds = $resultAds->paginate(12);
But that dosnt work.
It gives this error:
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_ERROR)
Call to a member function compareCity() on a non-object
And $rAds is for somereason boolean? I think thats becouse i havent done the ->get(); but i cannot do that becouse i would like to paginate the results.
Thanks for help.
So now my problem is to create a realationship to get city field out of users table.
Ads table
id
description
price
userID
User table
id
username
password
phone
city
I need to make a releationship so i could get all the ads with the requested city based on what city has the user with the userID taken from ads table.
You would want to use whereHas as long as your relationship methods are setup correctly.
if($data['city'])
{
$ads->whereHas('users', function($q) use ($data)
{
$q->where('city', $data['city']);
});
}
If the ad to user is a belongsTo relationship, then you don't need a table or even to setup a relationship just to filter on city field from users table. You can do a join on the users table. I am assuming your user table is called users:
if($data['city']) {
$ads = $ads->join('users', 'users.id', '=', 'city.userID')
->where('users.city','like','%'.$data['city'].'%');
}
The advantage of a join over whereHas is that it has no subquery that is executed against every row of the ads table, making it more efficient. Additionally, if you always join the users table, whether there is a filter on city or not, then you can pull the city from the users into the ads without having to do additional queries or with() relationships. Like this:
$ads = $ads->join('users', 'users.id', '=', 'city.userID')
if($data['city']) {
$ads = $ads->where('users.city','like','%'.$data['city'].'%');
}
later:
$result = $ads->get(['ads.*', (new Illuminate\Database\Query\Expression('users.city')]);
or if you are going to paginate the result:
$result = $ads->paginate($pageSize, [
'ads.*',
(new Illuminate\Database\Query\Expression('users.city'))
]);
every $ad that is in the $result will have a $ad->city field.
So the answer is like this:
if($data['city']) {
$ads = $ads->whereHas('users', function ($q) use($data) {
$q->where('city','LIKE','%'.$data['city'].'%');
});
}
This is the solution that worked. It is kinda taken from the other answer.
And I needed to add this in the model:
public function users() {
return $this->belongsTo('User');
}
And now it works.
Thanks everyone for help!

Resources