Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

alchermd's avatar

So I've been told that any entity that needs to be "logged in" should all reside within the \App\User eloquent model, while their "types" or "roles" stored away in a separate table. Where do I put the role-specific logic then?

Bonne journée my dudes.

Say I have an app that allows students to enroll on their desired courses, and instructors to manage their students and schedules. Ideally, I think the following API makes sense

$bob = new Student([/** Bob's credentials */]);
$calculus = Course::find(['name' => 'calculus'])->first();
$application = $bob->enrollTo($calculus);

$mrSmith = new Professor([/** Mr. Smith's credentials */]);
$mrSmith->accept($application);

Now, how do I apply the same API above if I'd just use the App\User model for both "types" of users? Is something like this good enough?

class User extends Model
{
    // ...

    public function enrollTo(Course $course)
    {
        if ($this->role->name != 'student') {
            throw new Exception('Invalid access.');
        }

        // Logic for applying this student to $course.
    }

    public function accept(Application $application)
    {
        if ($this->role->name != 'professor') {
            throw new Exception('Invalid access.');
        }

        // Logic for accepting the $application.
    }
}

... that feels icky. How would you do it yourself? I'd really appreciate your thoughts and tips for this one. Thanks!

0 likes
3 replies
Borisu's avatar

Well yes and no. You can have a single User model, which will make logging in much simpler etc, but you can also have two models, a professor and student. Then you'll have to add some more logic when registering and logging in users.

Having said that, the logic to enroll and to accept should probably be part of your controllers, not your User model, nor your Student or Professor models. You can use Policy objects to authorize requests a user sends. For example a student wants to enroll, so they fill out a form and click 'submit'. The data is sent to your EnrollmentController@store and there it is being processed. The basic flow is: authorize the request (can the current user actually do that?), validate the data provided, do your logic, return some kind of response.

martinbean's avatar

@alchermd You could create classes that extend your User model but also register a global scope to restrict it to users of a specific type. You can then add role-specific methods to those classes:

class Student extends User
{
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('student', function ($builder) {
            $builder->where('role', '=', 'student');
        });
    }

    public function enrollOn(Course $course)
    {
        // Logic
    }
}
class Professor extends User
{
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('professor', function ($builder) {
            $builder->where('role', '=', 'professor');
        });
    }

    public function accept(Application $application)
    {
        // Logic
    }
}

You’d then be able to use the API you specified in your post.

alchermd's avatar

@martinbean that looks neat! Mind diving a little bit and explain what exactly is happening on that boot() method? Admittedly, I have never used scopes before as well.

Please or to participate in this conversation.