laravel 5 - Eloquent Relationships (permissions table) - php

I think am struggling to get the relationships correctly in the scenario I have.
I have three tables
Table: users
| id | username |
----------------------
| 1 | pluto |
|------|-------------|
Table: permissions
| id | user_id | level_id | app_id |
--------------------------------------------------
| 1 | 1 | 2 | 9 |
|------|-------------|--------------|------------|
Table: levels
| id | level |
----------------------
| 1 | admin |
|------|-------------|
| 2 | manager |
|------|-------------|
| 3 | editor |
|------|-------------|
The result I am looking to get is
manager //through User:: model or Auth::
I would like to get a value from levels table in level column either through User model. This is the last version on what I have in my classes...
class User extends Authenticatable
{
public function permissions()
{
return $this->hasOne('App\Permissions');
}
}
class Permissions extends Model
{
public function user()
{
return $this->hasMany('App\User');
}
public function levels()
{
return $this->hasMany('App\Levels');
}
}
class Levels extends Model
{
public function permissions()
{
return $this->belongsTo('Modules\Ecosystem\Entities\permissions');
}
}
Using this in the controller I am able to retrieve values from permissions table. However I am unable to get values from levels table...
$user = User::with('permissions')->find(Auth::user()->id);
However I am unable to get values from levels table when I try this...
$user = User::with('permissions.levels')->find(Auth::user()->id);
That produces an error:
Column not found: 1054 Unknown column 'levels.permissions_id' in 'where clause' (SQL: select * from `levels` where `levels`.`permissions_id` in (1))
I understand that I am not understanding exactly how relationships would work in this instance but I don't want to just guess a solution. I'd like to understand it.
The thing is ,, Levels table serves only as a list of permission levels (roles). I recognize that I can define permission levels in some other way but for the moment this is how everything is set up.

If you are making a usual user permission system, where 'roles' is replaced by 'levels', then you need to reorganized your tables and relationships.
Table: users
| id | username | level_id |
---------------------------------------
| 1 | pluto | 2 |
|------|-------------|----------------|
Table: levels
| id | level |
----------------------
| 1 | admin |
|------|-------------|
| 2 | manager |
|------|-------------|
| 3 | editor |
|------|-------------|
Table: permissions
| id | level_id | app_id |
-----------------------------------
| 1 | 2 | 9 |
|------|-------------|------------|
So now User
hasOne('App\Levels', 'level_id');
Levels
hasMany('Modules\Ecosystem\Entities\permissions', 'level_id');
Permissions
belongsTo('App\Levels', 'level_id');
That is probably what you were trying to do, and it will works.
However, if many roles may have similar permissions, e.g: admin, manager & editor can all have access to a 'Page' or 'Content' or whatever that they all have access to, then you will need a 4th table to have many-to-many relationship between permissions and levels.
Table: permissions
| id | app_id |
---------------------
| 1 | 9 |
|------|------------|
Table: levels_permissions
| level_id | permission_id |
-----------------------------------
| 2 | 1 |
|-------------|-------------------|
With this, in Levels
belongsToMany('Modules\Ecosystem\Entities\permissions', 'levels_permissions', 'level_id', 'permission_id');
Inverse the relation in Permissions
belongsToMany('App\Levels', 'levels_permissions', 'permission_id', 'level_id');
In both approaches, you can now do
$user = User::with('levels.permissions')->find(Auth::user()->id);

Related

Laravel Relationship - Additional fields in pivot table linking to additional models

I have simplified the problem to get to the point. I have three tables, users, roles, account.
Normally I would set up the User model to have a many to many relationships with roles but I want those roles to be specific to each account. So I have added an additional field to the pivot table. Here are the tables and fields that I have;
‘users’ table
|—————————
| id | name |
|—————————
| 1 | Bob |
| 2 | Jim |
| 3 | Fred |
|—————————
‘roles’ table
|—————————
| id | title |
|—————————
| 1 | Administrator |
| 2 | Manager |
| 3 | Approver |
|—————————
‘accounts’ table
|—————————
| id | name |
|—————————
| 1 | ABC Company |
| 2 | XYZ Shipping |
| 3 | KLM Transport |
|—————————
I then have the pivot table role_user with an additional pivot field for the account;
|—————————
| role_id | user_id | account_id
|—————————
| 1 | 3 | 1
| 2 | 2 | 1
| 3 | 2 | 3
| 3 | 1 | 2
|—————————
I have used the withPivot function on the belongsToMany function when setting up the many to many relationships. This allows me to get the information using $user->roles->pivot->account_id but what I need is to be able to get the name of that company. All it’s passing to the blade template is the id from the pivot table and not linking that to an actual Account model.
Is there a way with Eloquent to get this entire model in the same way as the original relationship?
Create a Custom Pivot Model
use Illuminate\Database\Eloquent\Relations\Pivot;
class RoleUserAccountPivot extends Pivot
{
public function user()
{
return $this->belongsTo(User::class);
}
public function role()
{
return $this->belongsTo(Role::class);
}
public function account()
{
return $this->belongsTo(Account::class);
}
}
Update your belongsToMany relationships
Bellow is an example with the User::roles relationship
class User //extends...
{
public function roles()
{
return $this->belongsToMany(Role::class, /*other parameters*/)->using(RoleUserAccountPivot::class)->withPivot('account_id');
}
}
Usage
$user->roles->first()->pivot->account // returns Account model
Hope it helps.
Reference links:
Laravel doc on custom pivots

Database inheritance Laravel 5.4

I am looking forward to implement a website dealing with teachers, students and parents. In the database I made, I've created a user table and 3 children tables : teachers, students, parents.
See below the table structure
User table
+--------+----------+----------+-------+
| id (PK)| username | password | email |
+--------+----------+----------+-------+
| 1 | user1 | 123 | ... |
+--------+----------+----------+-------+
| 2 | user2 | 132 | ... |
+--------+----------+----------+-------+
| 3 | user3 | 321 | ... |
+--------+----------+----------+-------+
Student table
+---------------+--------------+
| users_id (PK) | class |
+---------------+--------------+
| 1 | highschool |
+---------------+--------------+
| 3 | middleschool |
+---------------+--------------+
Teacher table
+--------------+-------------------+---------------------+
| users_id (PK)| subscription_type | end_of_subscription |
+--------------+-------------------+---------------------+
| 2 | monthly | 2017-10-25 |
+--------------+-------------------+---------------------+
And the parents table also have a PK which corresponds to a user id.
I just started to learn laravel and I really wonder how could I handle this properly maybe with eloquent with Laravel 5.4.
I am giving you some hints I think you can do rest and as your question is not specific I am guessing you are thinking how can you relate/join tables, so
Create three model let say User, Student, Teacher.
In Student & Teacher model create a method like below
public function user()
{
return $this->hasOne(User::class, 'id', 'users_id');
}
Now you can query like :
$student = Student::find($id) ;
$name = $student->user->name;
$email = $student->user->email ;
Or
$teachers = Teacher::where('subscription_type', 'monthly')->with(['user'])->get();
dd($teachers);
I think you need to update your database structure, you need pk & fk
column separated.

How can I make a relation between tables in Laravel?

I have three tables like these:
// users
+----+-----------+
| id | user_name |
+----+-----------+
| 1 | Jack |
| 2 | Peter |
| 3 | John |
+----+-----------+
// skills
+----+------------+
| id | skill_name |
+----+------------+
| 1 | PHP |
| 2 | HTML |
| 3 | Laravel |
| 4 | MySQL |
| 5 | jQuery |
+----+------------+
// skill_user
+----------+---------+
| skill_id | user_id |
+----------+---------+
| 2 | 1 |
| 5 | 1 |
| 1 | 2 |
| 2 | 2 |
| 4 | 2 |
+----------+---------+
Now I want to get all skills of one specific user. I can do that by using a join clause in a raw sql query:
SELECT s.skill_name
FROM skills s
JOIN skill_user su ON s.id = su.skill_id
WHERE su.user_id = :user_id
/* output (assuming :user_id is 1)
+------------+
| HTML |
| jQuery |
+------------+
Ok All fine. Now I want to know, how can I do that by adding a method in the model of Laravel framework? All I'm trying to do is using belongsTo(), hasOne(), hasMany() etc ..
To do in Eloquent way, you need to add the relationship. In your case, it is many-to-many relationship so in User.php, add this function to declare the relationship:
public function skills() {
$this->belongsToMany(\App\Skill::class, 'skill_user', 'user_id', 'skill_id');
}
Then,
Access it like this to eager load it:
$users = \App\User::with('skills')->get();
OR
Say you have a single user,
$user = User::where('id', 1)->first(); // Get the user with id = 1
and to get the skill for that user:
$user->skills;
OR
If you don't want to do using Eloquent way, you can use Query Builder. Note that, using this method, you basically join it manually so you don;t need to add any method to the Model:
\DB::table('users')
->join('skill_user', 'skill_user.user_id','=', 'users.id')
->join('skills', 'skill_user.skill_id', '=', 'skills.id')
->select('*')
->where('users.id', 1)
->get();
You have to use belongsToMany relationships. Assuming you will create SkillUser model for skill_user table. Add the following code to User Model
public function skills() {
$this->belongsToMany('App\SkillUser', 'skill_user', 'user_id', 'skill_id');
}
Now you can access it by
$users->skills();
I assume you are talking about Many to Many relationship between Users and skills, then the example given in Laravel many-to-many speaks about it.

Laravel Eloquent how to return one to many to many collection

Is it possible to get an eloquent relation based on a One->Many->Many relationship? In the below example, I would want to get all of the gallery_votes for a given user.
users
+----+---------------+
| id | user_name |
+----+---------------+
| 1 | bob |
| 2 | sam |
+----+---------------+
galleries
+----+---------------+-----------+
| id | gallery_name | user_id |
+----+---------------+-----------+
| 1 | Alaska Pics | 1 |
| 2 | Texas Pics | 1 |
| 3 | California | 2 |
| 4 | Cars | 2 |
+----+---------------+-----------+
gallery_votes
+----+---------------+--------+
| id | gallery_id | vote |
+----+---------------+--------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 1 |
| 4 | 2 | 1 |
+----+---------------+--------+
The relationships are setup as follows.
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {{
...
public function galleries()
{
return $this->hasMany('App\Gallery');
}
}
and
class Gallery extends Model {
....
public function votes()
{
return $this->hasMany('App\GalleryVote');
}
}
$user->galleries returns a collection of associated galleries, so that works correctly. and $gallery->votes returns a collection of associate votes, so that also works correctly. But $user->galleries->votes gives
Undefined property: Illuminate\Database\Eloquent\Collection::$votes on line 1
Is what I'm trying to do even possible with straight Laravel? Or do I need to write the SQL directly?
The "has many through" relation provides a convenient short-cut for accessing distant relations via an intermediate relation.
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {{
...
public function galleries()
{
return $this->hasMany('App\Gallery');
}
public function votes()
{
return $this->hasManyThrough('App\GalleryVote', 'App\Gallery');
}
}
Now $user->votes will return all votes for that user. Remember you need to create the GalleryVote eloquent model as well.
You can read more about that type of relation, as well as some example usage in the documentation.

Laravel getting results from model belongsToMany relationship back to controller

I'm using Laravel 5 and Eloquent, I have 3 tables setup:
photos
+----+---------------+------------------+
| id | photo_name | photo_location |
+----+---------------+------------------+
| 1 | kittens.jpg | C:\kittens.jpg |
| 2 | puppies.jpg | C:\puppies.jpg |
| 3 | airplanes.jpg | C:\airplanes.jpg |
| 4 | trains.jpg | C:\trains.jpg |
+----+---------------+------------------+
photo_set (pivot table)
+------------+----------+
| set_id | photo_id |
+------------+----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 2 | 4 |
+------------+----------+
sets
+----+----------------+
| id | description |
+----+----------------+
| 1 | cute animals |
| 2 | transportation |
+----+----------------+
I created a belongsToMany relationship in my photos and sets models to link these two together.
class Photo extends Model {
public function sets()
{
return $this->belongsToMany('App\Set');
}
}
and
class Set extends Model {
public function photos()
{
return $this->belongsToMany('App\Photo');
}
}
However I'm trying to reference the $Sets->photos() model function in my controller, so that given a set of id=1, I can return the photo_location value for each row [C:\kittens.jpg,C:\puppies.jpg], but I don't know how to access it..
Also, I can "sort of" access this information in the view with:
#foreach($sets as $set)
{{$set->images}}
#endforeach
but it looks like it only iterates through once and returns a json (?) of the necessary information, though I'm not sure how to parse that to regular HTML either.
So in short, I'm having trouble accessing this data (photo_location) from both the controller and the view
Use Collection::lists()
$locations = Set::find(1)->photos->lists('photo_location');
It will return an array ['C:\kittens.jpg', 'C:\puppies.jpg']
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Collection.html#method_lists
In your controller try this :
$result = PhotoSet::where('set_id', $set_id)
->with('sets')
->with('photos')
->get();
$photo_location = $result->photos->photo_location;
here PhotoSet is the model for photo_set table, because it is a pivot table we will be able to access both sets and photos table from it.

Categories