Managing many types of users and its behaviours

Hi!

I have found that the code I have, has many user type checks, for example, if user is of type 1 then do this, else if it is type 2, then do this, and so on.

I thought of using interfaces, inheritance, abstraction for this, but I don’t think it will work in my case. Let me explain a little bit. Notice that the types and the behaviours are not defined or decided by me, but I would like to make the code better, if possible.

My User can currently be of 5 types. These 5 types have different access to different areas, and depending of the type, the behaviour in each area may vary (sometimes slightly, sometimes pretty much). Also these 5 types, may have sub-types.

So, let’s say that user is of type 1, and has no sub-type, so this would mean that the user is a standard of type 1. But if user is type 1 and has sub-type ‘lite’, then they are a lite version of the type 1.

The reason I discarded interfaces is because of the ‘rule’ that classes should not implement interfaces or functions that they do not need.

My issue right now, it is that I have many if elseif cases. For example, if it is type 1, do this, else if it is type 2 or type 1 with subtype ‘lite’, do this, else if it is type 3 subtype ‘lite’ or type 2 subtype ‘lite’ then do this other thing. I also have views that checks for this to determine what to display, or what options to show.

Summing up: is there anything you might think of that could interest me to boost this system? My problem is basically that there are so many checks and so many different tasks for each one that some views are huge, and some functions become really long.

Something I have thought of is refactoring the functions and separating the functions into smaller functions, but is there anything else that might help? I hope my explanation is not very confusing, but I omitted many details because they make it even more complicated to understand.

Hi,

From reading, it sounds like a typical RBAC-job for me.

Basically:
Parts of your code need a specific permission to be accessed.

So you can simply use one single if to check for the permission:
if (Yii::$app->user->can(‘createPost’)) {
// only accessible with permission
}

A role (in your case user “type”) is a collection of permissions.
Roles can also contain other roles. (“sub-types”)

Take a look at the guide here:
https://www.yiiframework.com/doc/guide/2.0/en/security-authorization#rbac

It explains everything very well.
Of couse it would probably be much work to change everything, but you will benefit from it in the long run.

Regards

1 Like

Hi @MetaCrawler,

Thank you for your reply!

Though you are partly right, there is still something missing. Some areas are accesible for users of certain types, let’s say type 1, type 2 and type 3. BUT, the behaviour of the application changes depending on the type.

For example:

function showEmployees(){
    // do something generic for all users
    if($user->type == 1){
         // do something
    } elseif (($user->type == 2 && $user->subtype == 'small') || $user->type == 3) {
         // do something completely different
    }

    // keep doing stuff that don't belong to the user
}

I first thought of creating an interface or an abstract class, and then implementing the functionality in the model, but I think that the function does not have to do at all with the user itself (in my example it does a little bit, but in the project they have nothing to do with the user, so I don’t think it would be correct to put it inside the model).

I believe that sometimes DRY concept will lay an extra unnecessary burden to our backs. I mean, sometimes we would make a complicated thing much more complicated by trying to apply DRY concept to it.

Both A and B uses P in common, then we can extract P out of A and B to avoid code duplication. Good. Then comes C. It also uses P but there’s a slight difference. Never mind. we can manage it. … If A or B then P else Pc … Great. It works. Eh? You need D? OK … If A or B then P else if C then Pc else Pd … OK? OK. But no E please, or I can’t manage P anymore.

It may be DRY but not very simple and easy.

IMO it’s Divide-And-Rule strategy with “I don’t mind the code repetition” attitude that will help you out of this DRY swamp.

Think about the possibility of creating 5 independent modules dedicated to all user types. Or, more realistically, 5 dedicated controllers and views when necessary. Don’t hesitate to repeat the code. Less code lines don’t always mean simpler code.

It’s just my opinion, but worth considering, isn’t it?

Have you looked at Yii2 Usuario … https://github.com/2amigos/yii2-usuario

The extension includes a fully functional and powerful RBAC system that you can easily extend for allowing or preventing Access to your controller actions.

1 Like