Relations with 4 tables [Laravel 5] - php

I have 4 tables:
projects: id, text
comments: id, text
comment_project: project_id, comment_id
project_group: project_id, user_id
My goal is to take all commets and user details for some project.
Currently I am able to get all comments for projects like this:
class Project extends Model {
public function comments(){
return $this->belongsToMany('App\Comment','comment_project');
}
}
and in controller I do like this:
$comments = Project::find(1)->comments()->get();
return $comments;
Any idea how to take only comments and user details for selected project if project_id and user_id exists in project_group table?

You'll need to set another relation method for project_group in your Model, then you should be able to get this like so:
$comments = Project::with(['comments','project_group'])
->whereHas('project_group',function($q){
$q->whereNotNull('user_id');
$q->whereNotNull('project_id');
});
dd($comments);
Model:
class Project extends Model {
public function comments(){
return $this->hasMany('App\Comment','comment_project');
}
public function project_group(){
return $this->hasMany('App\project_group','comment_project'); // < make sure this is the name of your model!
}
}
Try this:
$comments = Project::whereHas('groups',function($q){
$q->where('project_id',1);
})->whereHas('comments', function($q){
$q->where('user_id',Auth::id())->where('project_id',1);
})
->get();
return $comments;

Here is how I do this, if anyone has better idea pls comment...
Both methods are belongToMany()
$userCondition = function($q){
$q->where('user_id',Auth::id())->where('project_id',1);
};
$commentsCondition = function($q){
$q->where('project_id',1);
};
$comments = Project::with(['comments' => $commentsCondition,'groups' => $userCondition])
->whereHas('groups', $userCondition)
->whereHas('comments', $commentsCondition)
->get();
return $comments;

Related

Order data by pivot table when try to use With

I have tables Polfzms <- Genes
Polfzm model have next relation
public function gene()
{
return $this->belongsTo('App\Gene');
}
I need get all data from Polfzms table with data from Genes table and order it by name from pivot table (Genes). I try next
$data = Polfzm::with([
'gene' => function ($query) {
$query->orderBy('name', 'asc');
},
])->get();
but it not order data by name. How can I do it?
You could try to set this in the relationship definition:
Polfzm.php
public function gene()
{
return $this->belongsTo('App\Gene')->orderBy('name', 'asc');
}
Then in your controller:
$data = Polfzm::with('gene')->get();
If I understand correctly, you could use a collection sortBy helper for this one.
An example could be:
$data = Polfzm::with('gene')
->get()
->sortBy(function ($polfzm) {
return $polfzm->gene->name;
});

Laravel With and wherePivot

I'm trying to extract all companies and contacts with pivot.main_contact = 1.
Tables:
Company: id, name
Company_contacts: id, company_id, contact_id, main_contact
Contacts: id, name
Model:
class Company extends Model
{
public function mainContact()
{
return $this->belongsToMany('App\Contact', 'company_contacts')
->wherePivot('main_contact', '=', 1);
}
}
Controller:
$query = Company::with('mainContact')->get();
This returns companies + ALL contacts for the companies and NOT ONLY the ones with main_contact = 1.
First, for reasons I'm unsure of, you need to add withPivot('main_contact'); to your relation. This will return main_contact in your collection under pivot
class Company extends Model
{
public function mainContact()
{
return $this->belongsToMany('App\Contact', 'company_contacts')
->withPivot('main_contact');
}
}
The second thing you need to do is use withPivot() while constraint eager loading like so:
$companies = Company::with(['mainContact'=> function($query){
$query->wherePivot('main_contact', 1);
}])->get();
I've checked it, it works.
Just to go a bit above and beyond. Sometimes you'll want to query a pivot table without knowing the value. You can do so by:
$companies = Company::with(['mainContact'=> function($query) use ($contact){
$query->wherePivot('main_contact', $contact);
}])->get();
Try to add withPivot():
return $this->belongsToMany('App\Contact', 'company_contacts')
->withPivot('main_contact')
->wherePivot('main_contact', '=', 1);
Company::with('mainContact')->get(); returns all compaines and all contacts. You should be doing $company->mainContacts()->get(); instead.
$companies=Company::all();
foreach($companies as $company)
{
print_r($company->mainContact()->get());
}
die;

Laravel 5: Eloquent - order by relation when returning single record

im trying build query in eloquent with data sorted by relation. Imagine this DB structure:
TABLE: Station
id
name
...
TABLE: station_status:
id
station_id
status_type_id
date
...
TABLE: status_type:
id
description
...
MODELS
class Station extends \Eloquent
{
public function stationStatus() {
return $this->hasMany('App\StationStatus', 'station_id', 'id');
}
}
class StationStatus extends \Eloquent
{
public function statusType() {
return $this->hasOne('App\StatusType', 'id', 'status_type_id');
}
}
class StatusType extends \Eloquent
{
...
}
Now the question. How can i query Station model by station ID, but sort by related status types description?
So far i have:
// This just do not work
$query = Station::join('station_status', 'station.id', '=', 'station_status.station_id')
->join('status_type', 'station_status.status_type_id', '=', 'status_type.id')
->orderBy('status_type.description', 'ASC')
->select(['stations.*'])
->with(['stationStatus.statusType']
->find(110);
I think the problem is that i'm not returning collection but only one item using find() method, how can i overcome this problem?
Many thanks for any help !
Try this:
$query = Station::with(['stationStatus' => function($q){
$q->join('status_type', 'station_status.status_type_id', '=', 'status_type.id')
->orderBy('status_type.description', 'ASC');
}])->find(110);
With is a convienent way of getting the related objects, but it doesn't perform a join. It performs a new query and attaches all the elements to your collection. You can add your own logic to the query, like I did with $q->orderBy(...).

Laravel 5 relationships

I have two tables. Like this
**
user_accounts usersonglists
-------------- ---------------
id id
username user_account_id
slug etc..
etc..
**
I created a route like this
/u/{slug}/songlists
This relation method in songlist model
public function userAccounts()
{
return $this->belongsTo('App\Models\User\UserAccounts','user_account_id','id');
}
I created controller method like this
$songLists = $SongListRepository->getSongListsByUserSlug($slug);
This is getSongListByUserSlug($slug) method
$songList = $this->model->with('userAccounts')->get();
I want to get songlists by user with $slug.
Can someone help me?
You're looking for the whereHas method:
$query = $this->model->with('userAccounts');
$query->whereHas('userAccounts', function($query) use ($slug) {
$query->where('slug', $slug);
})
$lists = $query->get();
BTW, you should probably rename that userAccounts method to the singular userAccount.
An easier way might be to start from the account:
$lists = UserAccount::where('slug', $slug)->songLists;
Assuming you've set up the inverse relationship.

Creating a query in Laravel by using `with` and `where`

I'm wondering it would be possible to add a where condition to a with.
Such as:
Comment::with('Users')->where('allowed', 'Y')->get();
I was trying to find a more simple way to make queries avoiding the whereHas method which looks quite verbose:
$users = Comment::whereHas('users', function($q)
{
$q->where('allowed', 'Y');
})->get();
The raw query I want internally to generate should be like so:
select * from comments, users
where users.id = comments.user_id and
users.allowed = 'Y'
I'm used to work with CakePHP in which this queries look very simple:
$this->Comments->find('all', array('Users.allowed' => 'Y'));
The relationships I have defined are:
//Comments.php
public function Users()
{
return $this->belongsTo('Users');
}
//Users.php
public function Comments(){
return $this->hasMany('Comments');
}
You may try this
$users = User::with(array('comments' => function($q)
{
$q->where('attachment', 1);
}))->get();
Update : Alternatively you may use a where clause in your relationship in your User model
// Relation for comments with attachment value 1
// and if hasMany relation is used
public function commentsWithAttachment()
{
return $this->hasMany('Comment')->where('attachment', 1);
}
// Relation for all comments
// and if hasMany relation is used
public function comments()
{
return $this->hasMany('Comment');
}
So, you can just use
// Comments with attachment value 1
User::with('commentsWithAttachment')->get();
// All comments
User::with('comments')->get();
Update : I think you want all comments with users where attachment is 1, if this what you want then it should be Comment not User
Comment::with('user')->where('attachment', 1)->get();
In this case your relation should be
public function user()
{
return $this->belongsTo('User'); // if model name is User
}
Because one comment belongs to only one user.

Categories