Get all relations through manyToMany relation - laravel

I have User, Account and Item models.
Account has many User relations, and User has many Account relations. These are defined as many to many.
An Account has many Item relations, and I am wondering how to fetch all Item on all Account relations for a User.
// User.php:
public function accounts()
{
return $this->belongsToMany( Account::class );
}
// Account.php
public function users()
{
return $this->belongsToMany( User::class );
}
// Item.php
public function account()
{
return $this->belongsTo( Account::class );
}
Any idea on how to do a call like auth()->user()->items or auth()->user()->accounts()->items ?

as per your relationship, you can fetch every accounts of a user with every items on each of those accounts as follows:
auth()->user()->accounts()->with('items')->get();
for the above statement to work, you need to define items relationship on your Account model as follows:
//Account.php
public function items()
{
return $this->hasMany( Item::class );
}

You can define a direct BelongsToMany relationship by "skipping" the accounts table:
class User extends Model
{
public function items()
{
return $this->belongsToMany(
Item::class,
'account_user',
'user_id', 'account_id', null, 'account_id'
);
}
}
$items = auth()->user()->items;

If you just want a list a items with those conditions, start from the item model
$userId = auth()->id();
$items = Item::whereHas('account', function($account) use ($userId) {
$account->whereHas('users', function($user) use ($userId) {
$user->where('id','=', $userId);
});
})->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 relations pivot table name trouble

in my app I have 2 conversations types: normal private conversations between users and conversations for people which are interested of user product.
In my User model I declared relations like:
public function conversations()
{
return $this->belongsToMany('App\Conversation', 'conversation_user');
}
public function conversationsProduct()
{
return $this->belongsToMany('App\ConversationProduct', 'conversation_product_user', 'user_id', 'product_id');
}
Where 'conversation_user' and 'conversation_product_user' are pivot tables between 'users'-'conversations' and 'users'-'conversations_product' tables.
My conversation_user pivot table has conversation_id and user_id table properties, but conversation_product_user pivot table has additional property product_id.
In my Conversation Model I have:
public function users()
{
return $this->belongsToMany('App\User');
}
public function messages()
{
return $this->hasMany('App\Message');
}
In ConversationProduct Model I wrote:
protected $table = 'conversations_product';
public function users()
{
return $this->belongsToMany('App\User', 'conversation_product_user');
}
public function messages()
{
return $this->hasMany('App\MessageProduct');
}
In my ConversationProductController I have method to find user conversations:
public function showUserConversationsProduct(Request $request){
$user_id = $request->user_id;
//var_dump($user_id);
$userData = User::where('id', $user_id)->with('conversationsProduct')->first();
}
And there is my problem: In controller ->with('conversationsProduct') don't take relation for conversation_product_user, but for conversation_user pivot table. I can't handle it why its happen if I add second parameter as 'conversation_product_user' in my relation:
public function conversationsProduct()
{
return $this->belongsToMany('App\ConversationProduct', 'conversation_product_user', 'user_id', 'product_id');
}
I need protected $table = 'conversations_product'; to point my ConversationsProductController#store where to save conversation, but I think that can be problem with recognise proper relation.
I really appreciate any help. I attach photo of my db relations.

Trying to display eloquent data base from ID's

Hi I am trying to create a record base from ID of an order transaction.
I have here the ORDERS, CAMPANIES and CURRENCIES models.
Now I want the ORDER to get the ID from a URL Parameter, and then the companies should grab the company_id from Orders same with currency, I want to grab the currency_id from orders.
Here's what I came up so far:
public function create($order_id)
{
$order = Orders::find($order_id)->where('id', '=', $order_id)->get();
$company = Companies::where('id', '=', $order['company_id'])->get();
$currency = Currencies::where('id', '=', $order['company_id'])->get();
$banks = Banks::all('name','acronym','id')->get();
return view('orderPayments.create', compact('order'))
->with('company', $company)
->with('currency', $currency)
->with('banks', $banks);
}
currencies model
public function orderPayments()
{
return $this->hasMany('App\Orderpayments', 'id','currency_id');
}
Companies Model
public function orderPayments()
{
return $this->hasMany('App\Orderpayments', 'id','company_id');
}
Order Payments Model
public function company()
{
return $this->hasOne('App\Companies', 'id','company_id');
}
public function currency()
{
return $this->hasOne('App\Currencies', 'id', 'currency_id');
}
public function bank()
{
return $this->hasOne('App\Bank', 'id', 'currency_id');
}
How can I achieve it? thank you so much in advance!
UPDATE
I just applied #sandy's answer. I checked if the $order has a content so I echod the $order by doing this, {{ $order }} The return value is ok.
but when I calling the other attributes like $order->grandtotal, or $order->companies->comp_name the error is
If your relationship between your models is a One To Many relationship you should use belongsTo in your relations like this:
OrderPayment Model
public function company()
{
return $this->belongsTo('App\Companies','company_id');
}
public function currency()
{
return $this->belongsTo('App\Currencies','currency_id');
}
public function bank()
{
return $this->belongsTo('App\Bank', 'currency_id');
}
Also, the second parameter on the function should be your foreign key.
Answering your question:
If you want to access the relations of a given Order you could do this:
$order = Order::find($order_id);
$order->company; // this will return the company
$order->currency; // this will return the currency
If you want to display in your view:
{{$order->company->anyCompanyAttribute}}
Note:
You should name your models in SINGULAR like Currency, Company. Not in plural.
try like this
$order = Orders::with(['company','currency'])->where('id', '=', $order_id)->get();

Retrieve related models using hasManyThrough on a pivot table - Laravel 5.7

I'm trying to retrieve related models of the same type on from a pivot table.
I have 2 models, App\Models\User and App\Models\Group and a pivot model App\Pivots\GroupUser
My tables are have the following structure
users
id
groups
id
group_user
id
user_id
group_id
I have currently defined relationships as
In app/Models/User.php
public function groups()
{
return $this->belongsToMany(Group::class)->using(GroupUser::class);
}
In app/Models/Group.php
public function users()
{
return $this->belongsToMany(User::class)->using(GroupUser::class);
}
In app/Pivots/GroupUser.php
public function user()
{
return $this->belongsTo(User::class);
}
public function group()
{
return $this->belongsTo(Group::class);
}
I'm trying to define a relationship in my User class to access all other users that are related by being in the same group. Calling it friends. So far I've tried this:
app/Models/User.php
public function friends()
{
return $this->hasManyThrough(
User::class,
GroupUser::class,
'user_id',
'id'
);
}
But it just ends up returning a collection with only the user I called the relationship from. (same as running collect($this);
I have a solution that does work but is not ideal.
app/Models/User.php
public function friends()
{
$friends = collect();
foreach($this->groups as $group) {
foreach($group->users as $user) {
if($friends->where('id', $user->id)->count() === 0) {
$friends->push($user);
}
}
}
return $friends;
}
Is there a way I can accomplish this using hasManyThrough or some other Eloquent function?
Thanks.
You can't do that using hasManyThrough because there is no foreign key on the users table to relate it to the id of the group_user table. You could try going from the user to their groups to their friends using the existing belongsToMany relations:
app/Models/User.php:
// create a custom attribute accessor
public function getFriendsAttribute()
{
$friends = $this->groups() // query to groups
->with(['users' => function($query) { // eager-load users from groups
$query->where('users.id', '!=', $this->id); // filter out current user, specify users.id to prevent ambiguity
}])->get()
->pluck('users')->flatten(); // massage the collection to get just the users
return $friends;
}
Then when you call $user->friends you will get the collection of users who are in the same groups as the current user.

Laravel 5.1 Querying Relationship

Learning Laravel by building a stock portfolio app. Have models for Users, Accounts, Stocks, Options, and Transactions. I believe I have the relationships set up properly.
Question is how do I get a Users->Account->Transactions. I'm sure I could just do something in query builder but I was hoping for a more "eloquent" approach.
User
public function accounts()
{
return $this->hasMany('App\Account');
}
public function stocks()
{
return $this->belongsToMany('App\Stock');
}
public function options()
{
return $this->belongsToMany('App\Option');
}
public function transactions()
{
return $this->hasMany('App\Transaction');
}
Account
class Account extends Model
{
protected $fillable =
[
'name',
'broker'
];
public function user()
{
return $this->belongsTo('App\User');
}
public function stocks()
{
return $this->belongsToMany('App\Stock');
}
public function options()
{
return $this->belongsToMany('App\Option');
}
public function transactions()
{
return $this->hasMany('App\Transaction');
}
Transaction
class Transaction extends Model
{
protected $fillable =
[
'type',
'account_id',
'transaction_date',
'quantity',
'stock_id',
'option_id',
'amount',
'description'
];
public function user()
{
return $this->belongsTo('App\User');
}
public function stock()
{
return $this->belongsTo('App\Stock');
}
public function option()
{
return $this->belongsTo('App\Option');
}
public function account()
{
return $this->belongsTo('App\Account');
}
public function accounts()
{
return $this->hasManyThrough('App\Account', 'App\User');
}
}
Ultimately, I guess I would be looking for a total amount for each account a user may have. (User can have many accounts and each account would have many transactions, stocks and options.)
Thanks for any help or at least letting me know if I am going down the right road!!
If $user is a User object then $user->accounts is a collection of Eloquent models
You can load all of the accounts and their transactions with eager loading:
$user->load([
'accounts',
'accounts.transactions',
]);
But $user->accounts->transactions isn't something you can do because "transactions" is a relation on each individual Account object, not on the collection of account objects. So to get the transactions you'd loop through each account:
foreach ($user->accounts as $account) {
// do something with $account->transactions;
}
I highly don't recommend doing this, as #alexw mentioned in his comment, Eloquent objects are pretty large and having x many x many is an exponentially large amount of data you're loading into memory. But generally, that's how you'd access relations of relations.
You're better off using the query builder
The good news is that relations can make querying really easy! For example, you could do something like this instead:
Note: in Laravel 5.2, the lists method has been replaced with pluck
$user->load(['accounts']);
foreach ($user->accounts as $account) {
$amounts = $account->transactions()->lists('amount');
$total = $amounts->sum();
// - or -
$query = $account->transactions()
->select(\DB::raw('SUM(amount) AS total'))
->first();
$total = $query->total;
}

Resources