Laravel трехходовой полиморф c отношение безумия - PullRequest
1 голос
/ 28 марта 2020

Laravel 7.0

Я пытаюсь настроить систему, в которой пользователи могут принадлежать к различным моделям, таким как курсы или области. Я называю это «членством».

У пользователя, который является участником Царства или Курса, всегда есть роль в этом Царстве, например «amdin», «editor» или «guest»

У меня есть модели для пользователей, ролей, членов и предметов курса / области.

Примерно так:

Role ⇦1:N⇦ Memberable ⇨N:1⇨ User
               ⇩
            poly 1:1
               ⇩
      Realm/Course/YouNameIt

В настоящее время я использую дикую смесь отношений, чтобы получить больше или меньше, чем я хочу. Но мой подход кажется мне довольно грубым или даже неправильным.

Например, чтобы получить список моделей, членом которых я являюсь, я пишу:

User::find(2)->memberships()->get()

Но это дает я Коллекция Счетов, а не Царств или Курсов, которые отстой. Можно ли это исправить?

Чтобы получить мой первый Царство / Курс, я должен написать:

User::find(2)->memberships()->first()->memberable  // YUCK!

Вот мои модели:

class User {
    public function memberships()
    {
        return $this->hasMany(Memberable::class)->with('memberable');
    }

    public function roles()
    {
        return $this->belongsToMany(Role::class, 'memberables')
            ->withPivot(['memberable_id', 'memberable_type']);
    }

}
class Memberable extends Model
{
    public function role()
    {
        return $this->hasOne(Role::class, 'id', 'role_id');
    }

    public function memberable()
    {
        return $this->morphTo('memberable');
    }
}
trait HasMembers
{
    public function members()
    {
        return $this->morphToMany(User::class, 'memberable', 'memberables')
            ->withPivot('role_id')
            ->join('roles', 'roles.id', 'memberables.role_id')
            ->addSelect(['role' => Role::select('name')
            ->whereColumn('role_id', 'roles.id')]);
    }
}
class Realm extends Model
{
    use HasMembers;
}

class Course extends Model
{
    use HasMembers;
}

Я знаю, что на такие вопросы, как "это хорошо" или "это плохо", трудно ответить, поэтому я задам вопрос:

  • Это так неправильно, что я должен волноваться ?
  • Как мне улучшить этот дизайн?
  • У меня, вероятно, никогда не будет больше моделей, чем областей и курсов, в которых могут быть участники. Разумнее ли отбросить весь мембранный полиморфизм в пользу двух отдельных таблиц? Приятно сохранять гибкость, которую предлагает подход polymorphi c.

1 Ответ

0 голосов
/ 28 марта 2020

Вы можете просто установить больше отношений

  • User принадлежит ToMany Roles
  • Roles принадлежит ToMany Users
  • User morphedByMany Realm с использованием Memberable
  • User morphedByMany Courses с использованием Memberable
  • User morphedByMany YouNameIt с использованием Memberable
  • Realm morphToMany User с использованием Memberable
  • Courses morphToMany User с использованием Memberable
  • YouNameIt morphToMany User используя Memberable

Я бы сделал Memberable опорным морфом.

class Memberable extends MorphPivot { ... }

При этом доступ к отношениям не будет ' t hard.

$user->roles      // Get an Eloquent Collection made up from $user's roles.
$role->users      // Get an Eloquent Collection made up from users that have $role.
$user->realms     // Get an Eloquent Collection made up from $user's realms.
$user->courses    // Get an Eloquent Collection made up from $user's courses.
$user->youNameIt  // Get an Eloquent Collection made up from $user's youNameIt.
$realm->users     // Get an Eloquent Collection made up from users associated with $realm.
$course->users    // Get an Eloquent Collection made up from users associated with $course.
$youNameIt->users // Get an Eloquent Collection made up from users associated with $youNameIt.

И, может быть, заставить отношения между ролями пользователя <---> использовать отдельный стержень. Если нет, то также сделайте это морфологическим отношением (User morphedByMany Role с использованием Memberable, Role morphToMany User с использованием Memberable)

Дело в том, что если вы используете центральный стол, чтобы все переделать, он сильно вырастет. По сути, вы заставляете его выполнять работу из 3-4 опорных точек (в этом примере). Если ваши данные сильно растут, это может стать проблемой .

Кроме того, для разных отношений могут потребоваться разные данные из сводной таблицы, но поскольку вы используете только одну таблицу, это может привести к усложнять ситуацию, если вы не решите использовать поле json.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...