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

rene's avatar
Level 2

Construct Eloquent Model with default parameter for getters?

Hi, My application has two different types of Users: Teacher & Student. Both are stored in the Users table, but with a different role_id.

The User Model has already:

public function scopeOfType($query, $type)
    {
        return $query->with(['role' => function ($query) use ($type) {
            $query->where('name', $type);
        }]);
    }

For now I'm doing always: User::ofType('student')->get(), but I wanna do something like: Student::get();.

I created the Student and Teacher Model already, with a protected $table = 'users';, but still you have to do the ofType-thing. Isn't there a way to hardcode the default role-getter when I use that specific model?

0 likes
3 replies
martinbean's avatar

Isn't there a way to hardcode the default role-getter when I use that specific model?

@rene Yup! Scopes. You could create Student and Teacher models that extend your base User model, but boot a class that scopes queries to users of either type.

Example of a Teacher model:

class Teacher extends User
{
    protected static function boot()
    {
        static::addGlobalScope(new UserTypeScope('teacher'));
        parent::boot();
    }
}
class UserTypeScope implements ScopeInterface
{
    protected $type;
    
    public function __construct($type)
    {
        $this->type = $type;
    }

    public function apply(Builder $builder, Model $model)
    {
        $builder->where('type', '=', $this->type);

        $this->extend($builder);
    }

    public function remove(Builder $builder, Model $model)
    {
        $query->wheres = collect($query->wheres)->reject(function ($where) {
            return $where['column'] == 'role';
        })->values()->all();
    }
}

Note: this was written off the cuff so you’ll have to modify for your particular schema, but it should be enough to illustrate the steps you need to take.

Usage is straightforward:

$teachers = Teacher::all(); // Users, but scoped to teacher role
rene's avatar
Level 2

@martinbean Looks promising!

It doesn't work:

Call to undefined method App\UserTypeScope::extend()

So I removed the line: $this->extend($builder); > that should be right I guess?

It doens't work with my Relations models. Whats wrong with my Apply method? Can you help me out with the remove method? I don't know what to do there.

# added this to User Model file on the bottom:

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ScopeInterface;

class UserTypeScope implements ScopeInterface
{
    protected $type;
    
    public function __construct($type)
    {
        $this->type = $type;
    }

    public function apply(Builder $builder, Model $model)
    {
        $type = $this->type;
        $builder->with(['role' => function ($builder) use ($type) {
            $builder->where('name', $type);
        }]);

       #### $this->extend($builder); ### not needed
    }

    public function remove(Builder $builder, Model $model)
    {
        $query->wheres = collect($query->wheres)->reject(function ($where) {
            return $where['column'] == 'role';
        })->values()->all();
    }
}
# Teacher Model:
<?php

namespace App;

use App\User;

class Teacher extends User
{
    protected static function boot()
    {
        static::addGlobalScope(new UserTypeScope('teacher'));
        parent::boot();
    }
}
martinbean's avatar

@rene As I say, it was written off the cuff. It was not meant to be a working solution you could copy and paste, but enough to point you in the right direction.

Please or to participate in this conversation.