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
Related
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,
I have a HasOne relationship between 2 models.
In Laravel Nova, is it possible to merge them into a single panel when viewing details, and update both model together when updating details.
This feature is not officially supported in laravel nova. but there is a workaround to achieve it using model accessors and mutators. this answer can help you
Example:
// in the model
public function getProfilePictureAttribute()
{
// Don't forget to check the relation here if you don't want any error on Nova.
return $this->profile ? $this->profile->picture : null;
}
public function setProfilePictureAttribute($value)
{
$profile = $this->profile;
$profile->fill(['picture' => $value]);
$profile->save();
}
// in the resource
Image::make('Profile picture')
This question is quite old... but for Nova 4, this could be easily done by adding ->required()...
HasOne::make('Address')->required(),
MorphOne::make('Address')->required(),
etc... This will display the fields of second resource on the same page, and insert/update accordingly.
Here is model structure of my Laravel 5.3 project,
User.php (Model)
it has one invitation method that returns the invitation of a user.
public function invitations()
{
return $this->hasMany( 'App\Invitation', 'invitee_id', 'id' );
}
Invitation.php (Model)
This model has another method that would return the inviter detail of an invitation.
public function inviter()
{
return $this->hasOne( 'App\User', 'id', 'invited_by' );
}
If i want to retrieve all invitations of current user it works,
\Auth::user()->invitations;
But if i try to get the information about the inviter it won't work! (Question: How to do it?)
\Auth::user()->invitations->inviter;
Though i can query the inviter from a invitation eloquent object like this,
\App\Invitation::first()->inviter;
But this is not working when i try to access it from the user model -> invitation -> inviter!
Also can i use eager loading here?
\Auth::user()->invitations->inviter;
Looking at this, it appears that you're attempting to retrieve the inviter property from a collection of invitations. The reason Ken's suggestion to use \App\Invitation::first()->inviter; worked is because you are retrieving the inviter of only one invitation (in this instance, the first). To resolve this, loop through your invites before attempting to retrieve the properties for each one:
$invitations = \Auth::user()->invitations;
foreach ($invitations as $invitation) {
$inviter = $invitation->inviter;
}
There is also an each() method specific to Laravel Collections that will allow you to loop through your object.
Currently my db tables are defined as below:
site_roles - Contains different roles
site_user_roles - Links Users to many roles
site_permission_modules - Contains different access levels [eg. view admin controls, ban users]
site_role_permissions - Links permission modules to roles
My models in laravel are correctly defined to query these many to many relations. In code I want to check if a user has a certain permission module linked to him.
For better understanding, here are my models as well:
User
public function SiteRoles()
{
return $this->belongsToMany('App\SiteRole', 'site_user_roles', 'users_id', 'site_roles_id');
}
SiteRole
public function Users()
{
return $this->belongsToMany('App\User', 'site_user_roles', 'site_roles_id', 'user_id');
}
public function SitePermissionModules()
{
return $this->belongsToMany('App\SitePermissionModule', 'site_role_permissions', 'site_roles_id', 'site_permission_modules_id');
}
SitePermissionModule
public function SiteRoles()
{
return $this->belongsToMany('App\SiteRole', 'site_role_permissions', 'site_permission_modules_id', 'site_roles_id');
}
Here is what I currently did:
Auth::User()->SiteRoles()->with('SitePermissionModules')->get()
The with() keyword retrieves a nested array of permissions associated with each role.
I need to check if the user has a specific permission module linked to him.
What would be the best laravel way to do this?
EDIT:
Basically I'm just asking what would be the best way to chain 2 many to many relationships.
Auth::User()->SiteRoles()->with(['SitePermissionModules' => function ($query) {
$query->where('site_role_permissions','=','admin');
//use where as per your requirment.
}])->get();
Querying Relaionship
I'm trying to learn Laravel, but don't quite understand how i can accomplish my task the best way.
Scenario,
A user (user_id 5) may create a todo list, with the id of 3 (todo_id 3). Each of them live in their own model, so users model, and todo model. I'm currently checking if they created the todo by passing this into the method,
public function show($id)
{
TodoList::where('id',$id)->where('user_id', auth::id())->firstOrFail();
return 'ok';
}
So, i was thinking it would be possible to filter all this, using middleware. I have more models that requires the same action, so user 2, can't change/edit the todo_list for user 5 etc. And this needs to be attached to all methods, to block their access. Show, View, Delete etc.
Is there any way of doing this, so i don't have to create a new middleware for each model?
Laravel Eloquent provides Query Scopes for you, this might be what you're looking for.
Your Model:
class TodoList extends Model {
public function scopeFiltered($query, $id, $user_id)
{
return $query->where('id',$id)->where('user_id', $user_id);
}
}
Calling:
TodoList::filtered($id, Auth::user()->id)
->get();