Как создать оптимизированную модель, таблицы и отношения между ними? - PullRequest
0 голосов
/ 21 октября 2018

У меня есть пользовательский проект разработки, в котором есть таблицы базы данных:

  • пользователей
  • кандидатов
  • компаний
  • областей
  • навыки

Таблица пользователей:

Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('nickname')->unique();
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->boolean('type')->default(0); // 0 = candidate and 1 = company
    $table->rememberToken();
    $table->timestamps();
});

Таблица кандидатов:

Schema::create('candidates', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->foreign('user_id')
          ->references('id')
          ->on('users')
          ->onDelete('cascade');
    $table->string('name')->nullable();
    $table->string('lastname')->nullable();
    $table->string('surname')->nullable();
    $table->text('about')->nullable();
    $table->timestamps();
});

КомпанииТаблица:

Schema::create('companies', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->foreign('user_id')
          ->references('id')
          ->on('users')
          ->onDelete('cascade');
    $table->unsignedInteger('logo');
    $table->foreign('logo')
          ->references('id')
          ->on('images')
          ->onDelete('cascade');
    $table->string('name')->nullable();
    $table->text('about')->nullable();
    $table->string('website')->nullable();
    $table->integer('employees')->nullable();
    $table->timestamps();
});

Таблица областей применения:

Schema::create('scopes', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name')->unique();
    $table->timestamps();
});

Таблица навыков:

Schema::create('skills', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name')->unique();
    $table->timestamps();
});

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

Таблица атрибутов:

Schema::create('attributes', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->foreign('user_id')
          ->references('id')
          ->on('users')
          ->onDelete('cascade');
    $table->morphs('model');
    $table->timestamps();
});

Пример данных внутри атрибуты таблица:

----------------------------------------
| id | user_id | model_id | model_type |
----------------------------------------
| 15 |   176   |  34458   | App\Scope  |
----------------------------------------
| 29 |   245   |  17654   | App\Skill  |
----------------------------------------

Но в этом решении есть одна плохая сторона для меня, это повторение строкового имени модели в каждой строке записи в таблице.Например:

Таблица моделей:

Schema::create('models', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name')->unique();
    $table->timestamps();
});

Примечание: Может быть невозможно создать модуль с именем Модель , поэтому вам может потребоваться создать ее с другим именем, например: Ссылка

Пример данных внутри Модели Таблица:

-------------------
| id |    name    |
-------------------
| 10 | App\Scope  |
-------------------
| 11 | App\Skill  |
-------------------

После создания таблицы models структура таблицы attribute изменится на:

Таблица атрибутов:

Schema::create('attributes', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->foreign('user_id')
          ->references('id')
          ->on('users')
          ->onDelete('cascade');
    $table->foreign('model_id')
          ->references('id')
          ->on('models')
          ->onDelete('cascade');
    $table->unsignedInteger('content_id');
    $table->timestamps();
});

Теперь, как я могу создать правильные отношения внутри моделей, чтобы получить навыки или области для кандидатов или пользователей компании?

У меня есть пользовательские отношения внутри модели Users:

public function candidate()
{
    return $this->hasOne(Candidate::class);
}

public function company()
{
    return $this->hasOne(Company::class);
}

Теперь мне нужно внутри Кандидат и Компания Модель, подобная этой взаимосвязи:

public function skills()
{
    // Some code here
}

public function scopes()
{
    // Some code here
}

В общем, получите навыки пользователей или области видимости как это:

$user->candidate->scopes
$user->company->skills

Если у вас есть другое предложение для решения моей проблемы, пожалуйста, предложите ваше предложение.Если я где-то допустил ошибку, поправьте меня, если это возможно.

1 Ответ

0 голосов
/ 21 октября 2018

Представьте, что ваша основная ошибка построения ORM находится в этой строке:

$table->boolean('type')->default(0); // 0 = candidate and 1 = company

Это не решаемо с использованием ORM Laravel.Вам придется заменить эту строку на

$table->unsignedInteger('candidate_id')->nullable()->index();
$table->unsignedInteger('company_id')->nullable()->index();

и начать оттуда.Поскольку это может быть либо кандидат, либо компания, одно из значений будет пустым.Легко проверить.Поскольку есть только 2 возможных варианта, полиморфные отношения на самом деле не нужны.После того, как вы пройдете эту проверку, ваша иерархия ORM очерчится сама собой.

Вам нужно только позаботиться о том, чтобы , если кандидат стал компанией, или наоборот, вы должны убедиться, что другое значение будет аннулировано.Все это может быть сделано в мутаторах Model или в персонализированной публичной функции, поэтому вам не нужно беспокоиться об этом в Controllers / Views.

Например, $user->choice->scopes;, где вы добавляете функцию пользовательской модели getChoiceAttribute()

public function getChoiceAttribute() {
  if ($this->candidate) {
    return $this->candidate;
  }
  if ($this->company) {
    return $this->company;
  }
  return null;
}

То же самое относится к функции сеттера setChoiceAttribute() в случае, если кандидат становится компанией.Это применимо только в случае сохранения или обновления записи.

Чтобы узнать в представлении, работаете ли вы с кандидатами или компаниями, просто отметьте $user->choice->getTable();.

...