Laravel check if belongstomany contains belongstomany - php

in my system:
a lead belongstomany salespeople
a manager belongstomany salespeople
i am trying to check if a lead has a manager through the salespeople. this is for a policy so i can make sure a manager can see the leads of their salespeople.
something like this:
$lead->salespeople->contains($manager->salespeople)
is there a collection method that will allow me to do this? i've also tried stuff like this which isn't working either:
$lead->salespeople->contains('id', $manager->salespeople->pluck('id')->toArray())
edit, i think i got it. does this look correct?:
$lead->salespeople->intersect($manager->salespeople)->count() > 0

Ended up solving this problem with this package: https://github.com/staudenmeir/eloquent-has-many-deep
Here's my relationship method now:
public function managers()
{
return $this->hasManyDeepFromRelations($this->salespeople(), (new User)->setAlias('salesperson')->managers());
}

Related

Showing relational data of a Filament resource

I've started using Filament PHP for creating a Laravel based intranet application but stumbled across a question I couldn't answer myself using the official documentation:
What's the easiest way to show relational data inside the view page of a resource?
I have two resources ClientResource and ProjectResource which results in two Laravel relationships:
Client model:
public function projects(): HasMany
{
return $this->hasMany(Project::class);
}
Project model:
public function client(): BelongsTo
{
return $this->belongsTo(Client::class);
}
I have implemented a BelongsToSelect field inside project resource to assign a client:
Components\BelongsToSelect::make('client')
->relationship('client', 'first_name')
->required(),
Everything works fine so far, but (obviously) all I can see on the project's view page is the disabled select field showing the customer's first name. I'd like to have all related fields listed. Have I missed something crucial in the documentation or what's the best way to approach this?
I've had a look into the RelationManager but it seems there is only a belongsToMany relationship (no belongsTo).
This can also be done with a select component by specifying a relation like this:
Select::make('client_id')
->relationship('client', 'first_name');
You also have access to the eloquent query builder instance to play with like so:
Select::make('client_id')
->relationship('client', 'first_name',
fn (Builder $query) => $query->where('status', 'actif'))
);
Document reference: https://filamentphp.com/docs/2.x/forms/fields#populating-automatically-from-a-relationship

Setting up a kind of BelongsToThrough relationship in Laravel

Here is my current situation:
I have a Task model.
Tasks have owners (a belongsTo relationship)
Owners have accounts (yet another belongsTo relationship)
I'd like to set up a "belongsToThrough" relationship from Tasks to Accounts.
My first solution was to define a relationship in the Tasks model, like this:
public function account(): BelongsTo
{
return $this->owner->account();
}
With it I could call $task->account and retrieve a task's account easily. The problem is that this doesn't work with load/with, which in turn causes problems because I can't refresh() a task that has had the account loaded in (because refresh uses load). The error just states Trying to call account() on null which was honestly expected.
My second solution was to change the relationship method to:
public function account(): BelongsTo
{
return $this->owner()->first()->account();
}
With this, I can also simply call $task->account and retrieve the model, and when loading, it doesn't work (returns null), but also doesn't throw any errors. I don't need to load this relationship in, it just happens that sometimes I need to refresh models and having the load method throw an error is not ok.
In summary
What I'm looking for is kind of a BelongsToThrough, as a Task would BelongTo an Account through an Owner (User). Is there a way to do this that works using both $task->account and $task->load('account'). Before you tell me I can load it using owner.account, I know that, but refresh() will do it automatically with load('account') so I need it to work like that, not with the dot notation.
To get it working with load(), you'll need to define an account relationship on the owner model, if you haven't done so already. Like this:
public function account() :BelongsTo
{
return $this->belongsTo(AccountsTable);
}
Then use dot notation when calling load() on your task model like:
$task->load('owner.account');
You can do that using eager loading
public function account()
{
return $this->belongsTo('App\ParentModel', 'foreignkey', 'localkey');
}
After that you can easily fetch relation data with load/with.
Thanks,

how can do a multiple has() /orHas() in laravel 5.4 orm

First of all I should say I want to Use laravel ORM not query builder and not the Raw sql methods. so here is my question.
I have a model called bots that has belongTo(User::class) relation and 6 hasMany(TextPost::class) - hasMany(PhotoPost::class) and so on. I want to get bots that has at least one record in any of the hasMany(...) relations. so if a bot has a record in TextPost it should be returned and if a bot has no post in none of the hasMany(...) relations it should not be returned.
so far I have something like this in my User model
public function broadCasters()
{
return $this->bots->has('text_post')->orHas('photo_post')->orHas('media_post')->orHas('video_post')->orHas('audio_post')->orHas('document_post');
}
but its not going to work and says Call to a member function orHas() on boolean
so I wanted to change it to something like this:
public function broadCasters(){
return $this->bots->where(function($query){
return $query->has('TextPost')->orHas('PhotoPost') ...;
});
}
but this is not gonna work either and says Missing argument 2 for Illuminate\Support\Collection::where(). what should I do?
I use laravel 5.4. bu I saw this Question whereHas on multiple relationships - laravel 5.4 and its pretty close to what I want but no answers yet!!
also this question is another of my questions too, Combining AND/OR eloquent query in Laravel
but its not working either.
AND NOW THIS IS EXACTLY WHAT I WANT BUT NOT WORKING, I THINK BECAUSE ITS FOR LARAVEL 4 AND I USE LARAVEL 5.4
Laravel eloquent multiple has and where clause
enter code hereIf you user $this->bots, the result will be laravel collection array. You need to use $this->bots() like this :
public function broadCasters(){
return $this->bots()->where(function($query){
return $query->has('TextPost')->orHas('PhotoPost') ...;
})->get();
}

Creating Laravel authorisation policy using something either than 'user->id'

I would like to create a Laravel Authorisation Policy, however rather than checking the user->id I would like to check the related users Business model (like $user->business()->id)
I've tried using the following in my OrderPolicy but it does not work.
OrderPolicy
class OrderPolicy
{
....
public function edit(User $user, Order $order)
{
if ($user->business()->id === $order->business_id) {
return true;
}
}
}
Blade
...
#can('edit', $business->orders())
Edit Link
#endcan
...
Could someone show me how I could do this correctly?
Assuming business() is a relationship method.
$user->business->id would be the id of the Business model that is related to the user.
May want to check that ->business isn't null first.
You can also query directly on the relationship if you don't want to load that relationship. $user->business()->where('id', $order->business_id)->exists()
Laravel 5.4 Docs - Eloquent - Relationships - Relationship Methods vs Dynamic Properties

Laravel 5 - Error accessing many-to-many data

In a Laravel 5 app, I have a "User" model and a "Permission" model, both with corresponding tables, that have a many-to-many relationship. There is a pivot table as well: "permission_user".
The User model contains the following method:
public function permissions()
{
return $this->belongsToMany('App\Permission');
}
And the Permission model contains the following method:
public function users()
{
return $this->belongsToMany('App\User');
}
I have been accessing user permissions in custom middleware with the following code, and it's been working splendidly until today.
$permissions = \Auth::user()->permissions()->get();
All of a sudden, this is breaking. I get the following error:
ErrorException in BelongsToMany.php line 177: Argument 1 passed to
Illuminate\Database\Eloquent\Relations\BelongsToMany::hydratePivotRelation()
must be of the type array, object given, called in
/Server/sites/app/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
on line 158 and defined
Really not sure what's going on here. In an attempt to follow the docs more closely, I also tried this:
foreach (\Auth::user()->permissions as $permission)
{
// do something with $permission
}
But I get the same thing (the stack trace shows that the lines shown here are the last ones executed before heading into the Laravel source). I did update Laravel with Composer around the time this happened, but thought it unlikely that something in Laravel source has caused the problem. Can anyone see what I might be doing wrong here, and how I can fix it?
Sit tight, I believe this might actually just a current bug with Laravel 5 (which is still technically in alpha, so breaking changes are to be expected).
Taylor Otwell (the creator of Laravel) tweeted this earlier:
https://twitter.com/taylorotwell/status/553262692426059776
However, it looks like several parts of Laravel 5 core still need to be updated to be compatible with this change.
If you need your app to work right now, just change this in your composer.json file:
"laravel/framework": "~5.0",
to this:
"laravel/framework": "dev-master#9b108d85ce19300dfdd479fa4e05d9ea6e4e3abc",
And then run a composer update. This will pull in yesterdays version of Laravel 5, which was working.
Don't forget to change it back though once this is fixed!

Categories