Implement query based property - laravel-4

I've been trying to figure if it is possible to implement query based properties in Eloquent, such that the following data structure for example would allow having an is_admin property on the User model, which returns true or false depending on whether or not the user has been assigned the role named Admin.
Since relationships in some sense work like this, I figured it would be possible, but how exactly eludes me.
users
int id
string name
roles
int id
string name
user_roles
int id
int user_id
int role_id

This is untested code, but I'm pretty sure it will work:
class User extends Eloquent {
public function roles()
{
return $this->belongsToMany('Role', 'user_roles');
}
public function hasRole($roleName)
{
return count($this->roles()->where('name',$roleName)->get()) > 0;
}
}
And then use it:
$user = User::find(1);
if ($user->hasRole('Amdin'))
{
/// do something
}

not quite a property, but you could implement a $user->isAdmin() method in User like so:
public function isAdmin()
{
// check if the user has an admin role
if ($this->roles()->where('name', '=', 'Admin')->count() > 0)
{
// return true if he does
return true;
}
// return false if he doesn't
return false
}
Alternatively you could create a 'is_admin' column in the User table as an Integer with a length of 1. Set default to 0, if the user is an admin set to 1, then you could use $user->is_admin in boolean tests.

Related

Laravel HasMany relation with parameters

i have a relation between User model and Friend model
User.php
public function friends()
{
return $this->hasMany(Friend::class);
}
the relation actually returns all the records where the foreign key column (user_id) between User and Friend equals the current user's id but i want to return also the records where current user's id is in another column in friends table which's name is friend_id, this is my try
public function friends()
{
return $this->hasMany(Friend::class,'user_id','friend_id');
}
it's actually not returning the correct records
I don't think there is a direct way to that but you could try making 2 relations and merge them into one relation
public function friends() {
return $this->hasMany(Friend::class);
}
public function additionalfriends() {
return $this->hasMany(Friend::class, 'friend_id');
}
public function allfreinds() {
return $this->friends->merge($this->additionalfriends);
}
another solution you might try is
public function friends()
{
return Friend::where(function($query) {
$query->where('user_id',$this->id)
->orWhere('friend_id',$this->id);
});
}

Laravel getting realtionship with auth()

I have the following relationship in User.
public function partner()
{
return $this->hasOne('App\Partner','partner_id');
}
And I am accessing that relationship
auth()->user()->partner()->name
But it gives me exception where name is available in partners table:
Undefined property: Illuminate\Database\Eloquent\Relations\HasOne::$name`
And the user object from auth()->user()->partner() is also empty.
What am I missing?
auth()->user()->partner() returns the relation binding, not the model itself.
try auth()->user()->partner->name instead.
First, ensure you setup the right relationship:
User.php
public function partner()
{
return $this->hasOne('App\Partner');
}
Partner.php
public function user()
{
return $this->belongsTo('App\User');
}
To access the user's partner:
// Get the user's Partner instance:
$partner = auth()->user()->partner;
// Access the user's partner properties:
$partner_name = auth()->user()->partner->name;
Also, check that your partners table has the column user_id.
I think you are doing it wrong, All you have to do is that to change :
public function partner()
{
return $this->hasOne('App\Partner','partner_id');
}
to
public function partner()
{
return $this->belongsTo('App\Partner');
}
A user belongs to a partner, Cause partner is a meta table.

Laravel Eloquent - Order users relationship by a method on the user model

I'm working on an API endpoint with Laravel Spark.
This endpoint returns the given Team along with its users.
// in App\Team
public function users()
{
return $this->belongsToMany(
'App\User', 'team_users', 'team_id', 'user_id'
)->withPivot('role');
}
However, I wish to order those users by a method that is on the user model.
On my App\User model I have a method:
public function currentQueueLength()
{
returns an integer based upon the users current appointments,
}
Is there any way I can return the users relationship but order the users by the result of that method?
If you add current_queue_length as an attribute to the User model, you can then order by this attribute.
You can add the attribute by adding it to the $appends array and creating an accessor:
class User extends Model {
protected $appends = ['currentQueueLength'];
public function getCurrentQueueLengthAttribute()
{
return $this->currentQueueLength();
}
}
Credit to this question: Add a custom attribute to a Laravel / Eloquent model on load?
Then in Team you can add the method like so:
class Team extends Model {
public function users()
{
return $this->belongsToMany(
'App\User', 'team_users', 'team_id', 'user_id'
)->withPivot('role');
}
public function usersByCurrentQueueLength()
{
return $this->users->orderBy('current_queue_length');
}
}
As mentioned in my comment, the issue with this approach is that it sounds like currentQueueLength() is a costly operation (based on your comment) so ideally, it would be something you could do conditionally, however, I'm unsure how to do that! You may want to reconsider your approach to implementing currentQueueLength() which may open up more options to the way you structure this query.
You can acheave this by sorting the users like this :
Team::with('users')
->all();
$team->users->sort(
function ($user1, $user2) {
return $user1->currentQueueLength() - $user2->currentQueueLength();
}
);
More information about sort : To sort in ascending order, return -1 when the first item is less than the second item. So you can use :
return $user1->currentQueueLength() < $user2->currentQueueLength() ? -1 : 1;
And to sort in descending order, return +1 when the first item is less than the second item.
return $user1->currentQueueLength() < $user2->currentQueueLength() ? 1 : -1;
And if it's a field in the users model you can do it like this :
$teams = Team::with(['users' => function ($q) {
$q->orderBy('Field', 'asc'); // or desc
}])->all();
For the case of property :
// asc
$team->users->sortBy('userProperty');
// desc
$team->users->sortByDesc('userProperty');
Hope that helps :)

Many to Many to One relationship

I've got four tables Users[user_id] - role_user[user_id,role_id] - Roles[role_id] - Permissions[role_id]. A User could have many Roles, while the Role has many Permissions. So, a Permission has one Role, while a Role belongs to many Users.
// User.php ...
class User extends Model
{
public function roles()
{
return $this->belongsToMany('Role');
}
}
// Roles.php
class Role extends Model
{
public function users()
{
return $this->belongsToMany('App\User');
}
public function permissions()
{
return $this->hasMany('Permission');
}
}
// Permission.php
class Permission extends Model
{
public function role()
{
return $this->belongsTo('Role');
}
}
I guess the real question is; can you chain relationship methods, like: App\User::find(1)->roles->permissions; I don't think you can because the ->roles returns a Collection and not an eloquent model, so the permissions method doesn't exists off roles.
Is there another way I can get the collection of permissions for all roles for a given use, preferably with a single line?
I haven't tested it, but I think this will work or work with very small twick. Add this function in your User Model.
public function getPermission($id){
$roles = Roles::where('user_id','=', id)->get();
$permissions = array();
foreach($roles as $role){
array_push($permissions, $role->permissions);
}
return $permissions;
}
and access as $user->getPermission($user->id);. This might not be the best solution, but it should solve the problem.
UPDATED CODE
You can use accessor like the example bellow and this will return a permission collection. Use this function in your User Model
public function getPermissions($value){
$role_ids = Roles::where('user_id','=', $value)
->select(array('permission_id'))
->toArray();
return Permission::find($role_ids);
}
and access it like $permissions = App\User::find(1)->permissions;. I believe this will work as you expected.

laravel display only specific column from relation

I have read a few topics about this, but they managed to solve my problem partially ...
this is my controller
class DeskController extends BaseController{
public function getDeskUsers($deskId){
$user = DeskUserList::where(function($query) use ($deskId){
$query->where('deskId', $deskId);
})->with('userName')->get(array('deskId'));
if (!$user->isEmpty())
return $user;
return 'fail';
}
this is the model
class DeskUserList extends Eloquent {
protected $table = 'desk_user_lists';
public function userName(){
return $this->belongsTo('User', 'userId')->select(array('id','userName'));
}
}
the method getDeskUsers may returns ALL the DeskUserList table records, related with the User table record (on deskUserList.userId = User.id).
practically I want each record returned is composed of:
DeskUserList.deskId
User.userName
eg. [{"deskId":"1","user_name":antonio}]
What i get is
[{"deskId":"1","user_name":null}]
As you can see the user name is a null value...
BUT
if I edit my controller code:
->with('userName')->get(array('userId')); //using userId rather than deskId
then i get
[{"userId":"2","user_name":{"id":"2","userName":"antonio"}}]
By this way I still have two problem:
the userId field is twice repeated
I miss the deskId field (that I need...)
hope be clear, thanks for your time!
You need belongsToMany, no need for a model representing that pivot table.
I assume your models are Desk and User:
// Desk model
public function users()
{
return $this->belongsToMany('User', 'desk_user_list', 'deskId', 'userId');
}
// User model
public function desks()
{
return $this->belongsToMany('Desk', 'desk_user_list', 'userId', 'deskId');
}
Then:
$desks = Desk::with('users')->get(); // collection of desks with related users
foreach ($desks as $desk)
{
$desk->users; // collection of users for particular desk
}
// or for single desk with id 5
$desk = Desk::with('users')->find(5);
$desk->users; // collection of users
$desk->users->first(); // single User model

Resources