Manage 5 User profiles in Laravel 5 - php

I have 5 user profiles: SuperAdmin, FederationPresident, AssociationPresident, ClubPresident, simpleUser
I could grow with time.
So the relations are simple:
A simpleUser belongsTo a club
A club belongsTo an association
An association belongsTo a federation.
Right now, I just have a "type" field in my user table to diferenciate them.
Now, I'm building it, but I write all along my code:
if (Auth::user()->isSuperAdmin){
...
}elseif (Auth::user()->isPresidentFederation()){
...
}
And I want to refactor it, because it is an hugly way to code it.
Now, first, I managed Roles, and used #can('dothis') in my code, but it is kind of too much in my case and it doesn't fit so well to my use case, so I deleted it.
Everywhere, I have to test what kind of user is logged to know what he is able to perform.
I already use Middlewares to restrict access to unauthorized pages.
For a list of user, a SuperAdmin can see all users, a FederationPresident can see all user of his federation, an AssociationPresident can see all user of his association, etc.
So, I manage it like that:
$associations = Association::with('federation.country')
->whereHas('federation', function ($query) {
if (!Auth::user()->isSuperAdmin()) {
$query->where('president_id', Auth::user()->id);
}
})->get();
But in the case I would do it for a list of clubs, query would grow, because I would need to check what kind of user is logged.
All those "if" in my code are a bit annoying, as they will be everywhere...
Any help will be appreciated!

Related

Structuring Laravel Controllers

I have
users
id
username
companies
id
areas
id
area_company
id
area_id
company_id
area_company_user
id
area_company_id
user_id
company_user
id
company_id
user_id
area_user
id
area_id
user_id
where
one user has 0 to many areas AND one area can have 0 to many users
one area can have 0 to many companies AND one company can have 0 to many areas
one company can have 0 to many users AND one user can have 0 to many companies
one area_company can have 1 to many users AND one user can have 0 to many area_company
area_company_user has attributes specific to that kind of user
Also, I'm structuring the routes in the following manner
/users - all existing users
/areas - all existing areas
/companies - all existing companies
/areas/{area}/companies - all existing companies in a specific area
/users/{user}/companies - all existing companies from a specific user
/companies/{company}/areas - all existing areas the company is in
/areas/{area}/companies/{company}/users - all existing users from a company that exists in a specific area
For 1., 2. and 3. I'm creating controllers that follow the next pattern
AreaController with methods index(), create(), store(), show(), edit(), update() and destroy()
GET /areas, index() method,
GET /areas/create, create() method,
POST /areas, store() method,
GET /areas/{area}, show() method,
GET /areas/{area}/edit, edit() method,
PUT/PATCH /areas/{area}, update() method,
DELETE /areas/{area}, destroy() method.
There's now basically two cases left from that route list
Case 1: 4., 5. and 6.
Case 2: 7.
My question is, should I create new controllers for each case since I'd like to perform various actions in each? If yes, that'd mean, respectively
Case 1: AreaCompanyController, UserCompanyController and CompanyAreaController
Case 2: AreaCompanyUserController
Note: this was a helpful answer but didn't exactly address my concern.
You can see there is already something called nested resource in docs which can cover your cases 4,5,6. In docs there is PhotoCommentController which you've described that you're using it (question case 1).
For question case 2 you can for example make model for pivot table and have it that way for route and controller. For example AreaCompanyUserController if I understand well, you have here area_company pivot table with association of user. So many users can be part of same area_company association.
You can circumvent Area and Company models use with use of AreaCompany model that would be the pivot model. Knowing id of that pivot model you can easily get associating area, company and users.
class AreaCompany extends Pivot
{
/** code here */
}
Having this, you can name your resource route /area-companies and /area-companies/{$areaCompany}/users to avoid triple nesting.
I presume any of these decisions have own consequences like subdirectory planning for controllers, form request files, providers, sometimes even route files.
Probably heard and read for thousand times, but important is to stick with consistent way of it. Consider what could be lesser technical debt in some potential upgrade.
In order to simplify the debugging and maintenance process of the project it's better to define the controller for each case in case if anything goes wrong it's easy to debug and solve the problem so you will be having
AreaController , UserController , CompanyController

Laravel/Eloquent - Modeling a HasOne relationship via a BelongsToMany relationship

Say I have four tables:
users
groups
activities
group_activities
Where a group can have any number of activities and an activity can belong to any number of groups through their intermediate table group_activities, and a user belongs to one group via users.group_id. I want to correctly model a relationship between users and activities so that a user can have any one activity, but only if the group that user belongs to has a relation to that activity.
HasOneThrough doesn't seem to work here, since the group the user is related through has multiple activities. HasManyThrough doesn't work since the user can only have one.
I want to properly model this relationship so that it can be picked up for selection automatically via a Nova relationship field, but I'm struggling to figure out exactly how I would do so. My first thought is a HasOneThrough relation with some set of subqueries, but I can't quite piece together where to start.
How would I do this, or conversely, is it possible via Eloquent's automatic relationship system at all?
To ensure we are on the same idea of your relationships:
The relationship between Groups and Activities is a Many To Many relationship (Many To Many - Larvel Documentation).
The group_activities table is the pivot table.
The relationship between users and groups is a One To Many relationship One To Many - Larvel Documentation and the inverse of it One To Many (Inverse) - Larvel Documentation.
To actually answer your question:
If you want to use a shortcut from users to their activities, the Has Many Through is the correct way. If a group can have arbitrary many activities, and a user belongs to one group, the user will be associated to these arbitrary many activities through the group -hence Has Many Through. Note that this is not really a separate relationship though, it's just a convient shortcut.
If you wan't to associate a user with a single Activity directly, you need to to this via a separate One to Many relationship between Users and Activities.
I'm not entirely sure if I interpret your question correctly, so the following is just an assumption, but do you want to ensure a user can only be associated to an activity thats also associated with the user group? So to restrict possible activites by group? If that is the case, you'd simply need to check if the selected activity is in the activities associated with the users group:
With your relationships set up like this:
class User {
public function activity(){
return $this->belongsTo('App\Activity');
}
public function possibleActivities(){
return $this->hasManyThrough('App\Activity','App\Group');
}
}
you can check and associate activities like this:
if( $user->possibleActivities()->contains( $activity ) ){
$user->activity()->associate($activity);
}

Complex relationships with Eloquent/Laravel

Same story as many other questions on this site: I've banged my head into the wall for hours on end trying to figure out these relationships.
I have 3 models where the relationship should work like this:
Model: User
User can belong to many schools.
User belongs to one “Role” separately on each school.
User can be activated/deactivated separately on each school.
Model: School.
School can belong to many users
Model: Role.
Roles would be “Standard” or “Administrator”.
I have a pivot table that connects users and schools.
On the pivot table, I've also experimented with adding 'role_id' and 'is_activated' columns - which I doubt is the correct way about doing this?
I want to access data like this:
User
Get schools belonging to the user.
Get role for current school.
Get activated/deactivated status for current school.
School
Get all users belonging to the school.
Get role for each user.
Get activated/deactived status for each user.
I would've solved this if users could only belong to one school each, but since the same user can belong to several schools it got too complicated for me.
What kind of relationships should I apply on each model?
I would very much appreciate if anyone can point me in the right direction here. Thanks!
You can have a many-to-many relationship between user and school. This would require a pivot table between them to store the ids of the two models. At the end your relationship from a user point of view will end up being:
public function schools() {
return $this->belongsToMany('App\Models\School', 'pivot_table', 'user_id', 'school_id');
}
You can have a look at laravel docs on Many-to-Many

Laravel multiple relationships

I am trying to get my head around some relationships between models in Laravel.
I would like to define the relationship between the following models:
User - the users
Campaign - a campaign
Call - a phone call
Lead - Lead/client
Sale - A sale
Appointment - A scheduled phone call.
This is the way the relationship should be:
A user can be assigned to many campaigns.
A user can have many calls.
One user can have many appointments.
One call belongs to one user.
One call belongs to one campaign.
A campaign can have many calls.
A campaign can have many sales
A lead can be assigned to many campaigns.
A lead can have many sales
One lead belongs to one user in one campaign.
One lead can have many calls
One sale belongs to one campaign
One sale belongs to one user
One appointments belongs to one lead.
I uncertain about how to setup the relationship. Its easy with the one-to-one or many-to-one.
But what about this:
Call->User (one-to-one)
Call->Campaign (one-to-one)
Campaign->Call (one-to-many)
User->Call (one-to-many)
Hopefully I managed to explain it clear enough. Thanks.
I'd recommend reading the Laravel docs on relationships again.
Taking the Call/User relationship as an example, here's what you're looking at:
User --------> Call
(one) (many)
This is clearly a one to many relationship. And if you want to set up both sides of this relationship in terms of an Eloquent model, the relationships are this:
A User hasMany Calls
A Call belongsTo a User
These terms are taken directly from the documentation, in the section entitled One To Many.
So, in code...
User Model
public function Calls()
{
$this->hasMany("Call");
}
(notice that I've made the method name plural - this is my own preference, since using $user->Calls will return a collection if items).
Call Model
public function User()
{
$this->belongsTo("User");
}
Rather than taking the two sides of a relationship in isolation, as you seem to have done in your analysis, consider both sides of the relationship at the same time.

User Roles DB Schema Design

I am thinking about a schema design that involves having users and user roles, but I am not sure what would be the better route.
Option 1
Create three tables, one with the user information, one with the role information, and one with th user role relation.
users {
u_id,
etc
}
roles {
r_id,
r_name,
etc
}
user_roles {
u_idm
r_id
}
Option 2
Create two tables, one with the user information, and the other with role, role info,and relation info.
users {
u_id,
etc
}
roles {
r_id,
u_id,
r_name,
etc
}
Option 1 is more robust but requires an extra join. Option 2 will require an extra primary key but will only be one join. If I ever change the role name, it would take longer to update with option, but I don't forsee updates being frequent.
For a scalable solution, which would be better? What other insights in my missing? This is for a mysql and postgresql solution.
Option 1.
What good is a role if only one user can have each role?
If you have 100 registered users there would be 100 duplicate definitions for "registered user".
The more "etc" there is the bigger your db will get.
Having that many duplicates will slow down your database and in the end things will be a lot slower even if you have one join less.
If you run lots of role based querys and relly eel like you need a database like the one from option two you can still create a view and have the database cache it, but I doubt that this will do you any good.
I would go with the first option with some changes:
- each user can belong to ONLY ONE group
- create a table defining privileges
- each group has a list of privileges
The privileges defined could be mapped to various modules of the application or to specific functionality.
The solution is simple, flexible and fast.
Both privileges and groups tables should be pretty small, so extra JOINs won't have such a critical impact. Also, the authenticated user privileges could be stored in session and not loaded everytime.
There will be more benefits in long term, since the solution is very flexible and easy to extend.
For example, you will create a new module called "Configuration" and you want to create a new user group called "superadmin" to have access everywhere and "configuration". You would simply make changes in the database: create group 'superadmin', add privilege 'configuration', set all privileges and that's it.

Categories