How to access a relationship through another relationship - laravel

I am working on a survey system and I have a problem accessing one relationship through another.
I have these models and these relationships
Post
id
survey_id
public function survey()
{
return $this->belongsTo(Survey::class);
}
Surveys
id
survey_type_id
public function surveyOptions()
{
return $this->belongsToMany(Survey_options::class);
}
public function surveyType()
{
return $this->belongsTo(Survey_type::class);
}
public function posts()
{
return $this->hasMany(Post::class);
}
Survey_types
id
public function surveyOptions()
{
return $this->belongsToMany(Survey_options::class);
}
Survey_options
id
survey_type_id
public function values()
{
return $this->hasMany(Option_value::class);
}
options_values
survey_options_id
survey_id
public function surveyOptions()
{
return $this->belongsTo(Survey_options::class);
}
Survey_Survey_options (pivot)
survey_id
survey_options_id
I need to do a query with eadger loading to bring me all the posts with survey, surveyOptions, withCount comments y options_values of each surveyOptions. Something like this:
$post->survey->surveyOptions->options_values_count
I have managed to create this query that works for me everything except fetching the option_values count from each SurveyOption. How can I do it?
$posts = Post::with([
'survey' => function ($query) {
$query->withCount('totalSurveys');
},
'survey.surveyOptions',
'image',
'categories'
])
->withCount('comments')
->get();

Related

How to get users from a group, with a union between two relationships in laravel?

I want to recieve all users from a group.
The problem is in this group their are student users (with a pivot table) and normal users.
So i have to merge them together, but i still want to maintain all possibilities from eloquent.
I came to this:
dd($this->belongsToMany(User::class)->union($this->hasManyThrough(User::class,Student::class,'class_id','id','id','user_id'))->get());
But as result i get:
My database relationships
Users
- id
Group
- id
Students
- id
- user_id (fk to users)
- class_id (fk to groups)
User_Group
- user_id (fk to users)
- group_id (fk to groups)
User-model:
public function students()
{
return $this->hasMany(Student::class);
}
public function groups()
{
return $this->belongsToMany(Group::class);
}
Student-model
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function class()
{
return $this->belongsTo(Group::class, 'class_id');
}
Group-model
public function students()
{
return $this->hasMany(Student::class, 'class_id');
}
public function users()
{
return $this->belongsToMany(User::class);
}
public function members()
{
//this causes the problem!!
return $this->belongsToMany(User::class)->union($this->hasManyThrough(User::class,Student::class,'class_id','id','id','user_id'));
}
in User model relationship
public function group(){
return $this->belongsToMany(Group::class);
}
in Group model relationship
public function user(){
return $this->belongsToMany(User::class, 'user_group');
}
in Students model relationship
public function user(){
return $this->belongsToMany(User::class, 'user_id', 'id');
}
public function group(){
return $this->belongsToMany(Group::class, 'class_id', 'id');
}
you can call now
$users = User::whereHas('groups',function ($query){
$query->where('group_id',1);
})->get();
Sometimes you have two relations from one model to another, due pivot tables. In my example you could go from users to groups with the relation user_groups and the relation students. To get all users that belong to a certain group i need to call both relations. To solve this issue, i made use of Abdulmajeed's example to solve it. You can see the code below. Thanks for helping me out.
public function members()
{
return User::whereHas('groups', function($q)
{
$q->where('id',$this->id);
})->orWhereHas('students', function($q)
{
$q->where('class_id',$this->id);
});
}

Laravel 5.5. Many-to-Many. Receive the latest instance

I have such models (Many-to-Many)
class Driver
{
public function cars()
{
return $this->belongsToMany(Car::class);
}
}
class Car
{
public function drivers()
{
return $this->belongsToMany(Driver::class);
}
}
My Car has activated_at column, that can be null.
How can I retrieve the latest activated car per drivers in a specific parking?
Something like this
Parking::find(2)->drivers()->lastActivatedCars...?
You can just create a scope for the car.
// Car.php
public function scopeActivated($query)
{
return $query->whereNotNull('activated_at')->orderBy('activated_at', 'DESC');
}
And then in your Driver.php:
// Driver.php
public function latestActivatedCar()
{
return $this->cars()->activated()->first();
}
Then you can just:
$latest = $driver->latestActivatedCar();
Or you can create a relationship, so you can eager load.
// Driver.php
public function latestActivatedCar()
{
return $this->belongsToMany(Car::class)
->whereNotNull('activated_at')
->orderBy('activated_at', 'DESC')
->limit(1);
}
Then you can just:
$drivers = Parking::find(2)->drivers;
$drivers->load('latestActivatedCar');
I hope this would help:
Parking::with(['drivers' => function ($driverQuery) {
$driverQuery->with(['cars' => function ($carsQuery) {
$carsQuery->orderBy('activated', 'desc')
->limit(1);
}]);
}])->find(2);

Multiple nested queries in Laravel Eloquent

I have a chat app, and I need to filter those user conversations that have attachment[s] in the groups last message, by using eloquent ORM. I have following DB tables/models:
Groups & Users. Relation is N-N between them, so there's a pivot table between groups and users, named group_user. Although this table has been expanded with some extra fields, as a result group_user have it's own model now.
Messages. Relations are 1-N from both groups and users.
Attachments. Relation is 1-N from messages.
The algorithm of this filtering isn't the problem - take user (because I need specific users groups) and his groups, find all group messages, sort them by date of creation in descending order and take the top one. And then check whether this message have any records in 'attachments' table. Obivously I do have all the relations defined in the respective Models. Right now I have this code, but it returns all groups that have attachments in any of the messages.
Also, I need to sort the query by the last message 'created_at' date.
return $user->user_groups()->whereHas('group', function($query) {
$query->whereHas('messages', function ($query) {
$query->whereHas('attachments');
});
})->with('group')->latest()->paginate($this->group->getPerPage());
Edit.
class User
{
public function messages()
{
return $this->hasMany('App\Models\Message');
}
public function user_groups()
{
return $this->hasMany('App\Models\GroupUser');
}
}
class Message
{
public function attachments()
{
return $this->hasMany('App\Models\Attachment');
}
public function author()
{
return $this->belongsTo('App\Models\User');
}
public function group()
{
return $this->belongsTo('App\Models\Group');
}
}
class Attachment
{
public function message()
{
return $this->belongsTo('App\Models\Message');
}
}
class GroupUser
{
public function user()
{
return $this->belongsTo('App\Models\User');
}
public function group()
{
return $this->belongsTo('App\Models\Group');
}
}
class Group()
{
public function messages()
{
return $this->hasMany('App\Models\Message');
}
public function group_users()
{
return $this->hasMany('App\Models\GroupUser');
}
}
Add a groups relationship to your User model:
public function groups() {
return $this->belongsToMany('App\Models\Group');
}
Then try this:
$user->groups()
->select('groups.*')
->join('messages', function($join) {
$join->on('groups.id', 'messages.group_id')
->where('created_at', function($query) {
$query->selectRaw('max(created_at)')
->from('messages')
->where('group_id', DB::raw('groups.id'));
});
})
->whereExists(function($query) {
$query->from('attachments')
->where('attachments.message_id', DB::raw('messages.id'));
})
->orderByDesc('messages.created_at')
->paginate($this->group->getPerPage());

Laravel Eloquent self relations

I'm new in Laravel and have problem with self relations in eloquent.
I have table users with fields id and referrer, where referrer is foreign key to table users (each user have one referrer which is also users). And table invoice has relation to users.
I want to get all invoices for user and for referrer.
In model I made relations:
public function referrer()
{
return $this->hasOne('User', 'referrer');
}
public function referral()
{
return $this->belongsTo('User','id');
}
public function invoice()
{
return $this->hasMany('invoice', 'user_id');
}
And query:
$this->model->with(['invoice'])
->with(['referrer'=> function($q)
{
$q->with(['invoice']);
}]);
}]);
But this query returns me users and their invoices but do not return referrer just empty array key referrer =>
Updated
I change relations :
public function referrer()
{
return $this->hasOne('User', 'referrer');
}
public function referral()
{
return $this->belongsTo('User','referrer');
}
public function invoice()
{
return $this->hasMany('invoice', 'user_id');
}
And now dumping result I see referrer relation but when I trying to get $user->referrer I got just referrer id instead of referrer object
Try this:
public function referrer()
{
return $this->hasOne('App\User', 'referrer', 'id');
}
public function referral()
{
return $this->belongsTo('App\User','id','referrer');
}
So finally I found solution.
Relations:
public function referrerBelong()
{
return $this->belongsTone('User', 'referrer');
}
public function referral()
{
return $this->hasOne('User','referrer');
}
public function invoice()
{
return $this->hasMany('invoice', 'user_id');
}
Relation should be like that, I change name to referrerBelong, because I have referrer column and it make conflicts and return referrer id instead of referrer object.
Query:
$this->model->with(['invoice'])
->with(['referrerBelong'=> function($q)
{
$q->with(['invoice']);
}]);
}]);
And in controller you can get referrer object using $user-referrerBelong and $user-referrer to get referrer id.
Answer was here : http://laravel.io/forum/01-22-2015-eloquent-belongsto-not-returning-relationships

Laravel - Retrieving specific column from a releted query

I have 4 tables:
conversations
- id (pk)
- userId1 (fk)
- userId2 (fk)
users
- id (pk)
- name
- surname
.
.
.
- roleId (fk)
- userStatusId (fk)
roles
- id (pk)
- type (fk)
user_status
- id (pk)
- description (fk)
this are my models:
class Conversation extends Eloquent {
public function user1(){
return $this->hasOne('User', 'id', 'userId1');
}
public function user2(){
return $this->hasOne('User', 'id', 'userId2');
}
}
class User extends Eloquent {
public function role(){
return $this->hasOne('Role', 'id', 'roleId');
}
public function userStatus(){
return $this->hasOne('UserStatus', 'id', 'userStatusId');
}
// public function conversation1(){
// return $this->belongsToMany('Conversation', 'id', 'userId1');
// }
// public function conversation2(){
// return $this->belongsToMany('Conversation', 'id', 'userId2');
// }
}
class UserStatus extends Eloquent {
public $timestamps = false;
protected $table = 'user_status';
public function user(){
return $this->belongsToMany('User', 'id', 'userStatusId');
}
}
class Role extends Eloquent {
public $timestamps = false;
public function user(){
return $this->belongsToMany('User', 'id', 'roleId');
}
}
Now what I want to do is, for example, take all the conversations where the "userId1" (on conversations) is of a "user" who have the status "description" equal to "registered".
That's what I do:
Route::get('/', function(){
$conversation = Conversation::with(array('user1.userStatus' => function ($query){
$query->where('description', '=', 'registered');
}))->get();
foreach ($conversation as $conv) {
echo '<br \>';
echo $conv;
}
});
I expect to receive all the conversations record where the status of the userId1 is "registered" and nothing else... Instead what I receive are all the conversations records and, for each one, the user records and the records of the userStatus table (of this last I receive just the one who match the where clause and the ones who are not have a null value).
I know my english is terrible but I hope someone could understand and help me. Thanks!
All your relations are wrong. You need to read http://laravel.com/docs/eloquent#relationships and in your case it's:
class Conversation extends Eloquent {
public function user1(){
return $this->belongsTo('User', 'userId1');
}
public function user2(){
return $this->belongsTo('User', 'userId2');
}
}
class User extends Eloquent {
public function role(){
return $this->belongsTo('Role', 'roleId');
}
public function userStatus(){
return $this->belongsTo('UserStatus', 'userStatusId');
}
}
class UserStatus extends Eloquent {
public $timestamps = false;
protected $table = 'user_status';
public function user(){
return $this->hasMany('User', 'userStatusId');
}
}
class Role extends Eloquent {
public $timestamps = false;
public function user(){
return $this->hasMany('User', 'roleId');
}
}
Now, to retrieve only those conversations you want this:
Conversation::whereHas('user1', function ($q) {
$q->whereHas('userStatus', function ($q) {
$q->where('description', 'registered');
});
})->get();
or using this PR https://github.com/laravel/framework/pull/4954
Conversation::whereHas('user1.userStatus', function ($q) {
$q->where('description', 'registered');
})->get();
Also, to make it more verbose, you can wrap that code in a scope:
// User model
public function scopeRegistered($query)
{
$q->whereHas('userStatus', function ($q) {
$q->where('description', 'registered');
});
}
then:
Conversation::whereHas('user1', function ($q) {
$q->registered();
})->get();
You may try this:
$conversations = Conversation::whereHas('user1.userStatus', function ($query){
$query->where('description', '=', 'registered');
})->get();
This will return only the Conversation models whose related user1.userStatus is registered.

Resources