Laravel implicit binding with pivot relation on user - laravel

I don't think this is possible in Laravel, but I am still going to ask it ;)
I have a Group model that has a pivot relation(via group_user) to User. I have a group controller where this is the index method:
public function index(Request $request)
{
return $request->user()->groups;
}
groups in User is a belongsToMany relation. It will load all groups that have a relation to a user. This will also load the pivot table in the pivot relation.
But now I want to get a single group, this is the controller to get a group with pivot relation:
public function show($id, Request $request)
{
$group = $request->user()->groups()->findOrFail($id);
$this->authorize('view', $group); // Authorization....
return $group;
}
But I would like to use Implicit binding like this:
public function show(Group $group)
{
$this->authorize('view', $group);
return $group;
}
But it won't load the pivot table because I don't get it via the user...
So I should get the group via the user. But how can I do this with implicit binding?
When this isn't possible: How can I load a pivot relation when I already have the group model?
public function show(Group $group, Request $request)
{
// Load the pivot relation here in $group by using the user in $request->user()?
$this->authorize('view', $group);
return $group;
}

Put this is the RouteServiceProvider:
Route::bind('group', function ($value) {
if (auth()->check()) {
return auth()->user()->groups()->findOrFail($value);
} else {
abort(404);
}
});
The view policy isn't even needed this way because the group is from the groups relation:
public function show(Group $group)
{
return $group;
}

Related

How can I paginate Laravel's Eloquent's relationships' relationships?

I have two tables, users and profiles. A user has one profile. Also a user has referrals. The referrals are referenced by the column referrer_id in the users' table. So a user has a referrer, and a user can have many referrals.
Define a one-to-one relationship on the User's Model:
public function profile()
{
return $this->hasOne(Profile::class);
}
Define an inverse one-to-one relationship on the User's Model:
public function referrer()
{
return $this->belongsTo(User::class);
}
Define a one-to-many relationship on the User's Model:
public function referrals()
{
return $this->hasMany(User::class, 'referrer_id');
}
Define an inverse one-to-one or many relationship on the Profile's Model:
public function user()
{
return $this->belongsTo(User::class);
}
I wish to retrieve the user's profile, the user's referrals along with their profiles, and the referrals' referrals along with a count of each of the referrals' referrals.
The following Eloquent query works, but doesn't paginate:
namespace App\Http\Controllers;
class ReferralsController extends Controller
{
public function index(Request $request)
{
return $request->user()->loadMissing(['profile', 'referrals' => function ($query) {
$query->with(['profile', 'referrals'])->withCount('referrals');
}]);
}
}
I've tried to add ->paginate() to the query (on both as show below and also one or the other) but it doesn't work:
return $request->user()->loadMissing(['profile', 'referrals' => function ($query) {
$query->with(['profile', 'referrals'])->withCount('referrals')->paginate(2);
}])->paginate(2);
Adding it to the inner function doesn't do anything, and adding it to the main query just retrieves the entire users table.
EDIT
I've realized that adding ->paginate() to the inner function actually does limit the number of rows in the collection, but there is no Paginator instance anywhere, so I don't have access to any of the links to move pages.
Got it to work by doing it separately:
$profile = $request->user()->profile()
->firstOrFail();
$referralsPaginator = $request->user()->referrals()
->with('profile')
->withCount('referrals')
->paginate(2);

Problem with eager loading inside policy N+1 - laravel

Customer Controller
public function index()
{
$customers = Customer::query()
->withSum('accounts', 'credit')
->withSum('accounts', 'debit')
->orderBy('customers.name')
->get();
return view('customer.index', compact('customers'));
}
Customer Policy
public function delete(User $user, Customer $customer)
{
return $customer->accounts_sum_debit === $customer->accounts_sum_credit;
}
The problem is I need some way to put WithSum in model by default like protected $with property , I Can make query for every customer to check accounts sum but it will problem n+1

Laravel query builder with the User and Auth

How to List all rows from a table (agendas) in my DB where records are saved by the connected user.I'm using default Auth from Laravel.
public function index ($id = null)
{
$agendas = Agenda::where('id', Auth::user()->id)->get();
$users = User::all();
return view('admin.agendas.index', compact('agendas','users','id'));
}
My controller here.
Need help
Assuming
agendas table (containing records for Agenda model) has a column user_id which references the id column on users table
User hasMany Agenda
Agenda belongTo User
class User extends Model
{
public function agendas()
{
return $this->hasMany(Agenda::class);
}
//... rest of class code
}
class Agenda extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
//... rest of class code
}
public function index($id = null)
{
$user = User::with('agendas')->findOrFail(auth()->id());
return view('admin.agendas.index', [
'user' => $user,
'agendas' => $user->agendas,
'id' => $id
]);
}
Your User model should have a relationship:
public function agendas()
{
return $this->hasMany(Agenda::class);
}
In your controller, you could then simplify the use as such:
public function index (Request $request, $id = null)
{
$agendas = $request->user()->agendas;
$users = User::all();
return view('admin.agendas.index', compact('agendas','users','id'));
}
if you wanna get data related to another data , you have to join those tables together by a field. in this case i guess you have a column in Agenda table named 'user_id'.
you have two way :
join tables in your Model.
search in Agenda table in your controller
if you want to use joining your tables from model :
// in App\User.php
...
class User ...{
...
public function Agenda(){
return $this->hasMany(Agenda::class);
}
...
}
...
then you can access to all of "Agenda" from everywhere like this :
Auth()->user()->agenda
if you want to search in table from your controller you can do :
Agenda::where('id', Auth::user()->id)
you can read more about eloquent-relationships in : https://laravel.com/docs/8.x/eloquent-relationships

Get all relations through manyToMany relation

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();

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.

Resources