#laravel #eloquent
#laravel #красноречивый
Вопрос:
У меня есть две модели EventLocation
и EventDepartment
. Модели и отношения показаны ниже:
class EventLocation extends Model
{
public function event_departments()
{
return $this->hasMany(EventDepartment::class);
}
}
class EventDepartment extends Model
{
public function event_location()
{
return $this->belongsTo(EventLocation::class, 'location_id');
}
}
Миграция для EventDepartment
содержит в location_id
качестве внешнего ключа, как показано:
Schema::create('event_departments', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->foreignId('location_id')->constrained('event_locations');
$table->softDeletes();
$table->timestamps();
});
Проблема, с которой я сталкиваюсь сейчас, заключается в том, как мне сделать столбец уникальным в EventDepartment
таблице при создании нового отделения на основе внешнего ключа, который есть location_id
?
т.е. EventDepartment не может иметь столбцов с одинаковым именем, если они принадлежат одному и тому же EventLocation, но я могу создать другой EventDepartment с существующим именем, если он принадлежит другому EventLocation
Я пробовал с этим, но не работает:
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|min:3|unique:event_departments,location_id',
'location_id' => 'required',
]);
$department = EventDepartment::create([
'name' => $request->name,
'location_id' => $request->location_id,
]);
return new EventDepartmentResource($department);
}
Ответ №1:
При создании миграции вы должны установить уникальность по связанным полям. В вашем примере это должно быть по name
и location_id
public function up()
{
Schema::create('event_departments', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->foreignId('location_id')->constrained('event_locations');
$table->softDeletes();
$table->timestamps();
$table->unique(['name', 'location_id'], 'unique_name_location');
});
}
public function down()
{
Schema::enableForeignKeyConstraints();
Schema::table('event_departments', function (Blueprint $table) {
$table->dropForeign(['location_id']);
$table->dropUnique('unique_name_location');
})
Schema::disableForeignKeyConstraints();
Schema::drop('event_departments');
}
Это обеспечит уровень БД, установленные правила таблицы, и не будет более одного одинакового имени с одинаковым location_id. Документы.
На уровне PHP вы должны написать свой собственный класс правил, который будет запускать и проверять правило, которое может принять DB.
-Создать класс правил
php artisan make:rule UniqueNameLocationRule
-Код класса правил
public function __construct(string $name, int $locationId)
{
$this->name = $name;
$this->locationId = $locationId;
}
public function passes($attribute, $value)
{
return !EventDepartment::where([
'name' => $this->name,
'location_id' => $this->locationId,
])->exists();
}
-Код проверки
'name' => ['bail', 'required', 'min:3', new UniqueNameLocationRule((string)$request->name, (int)$request->location_id)],
'location_id' => ['required', 'exists:event_locations,id'],
Это должно сработать, пожалуйста, протестируйте и сообщите, есть ли какая-то ошибка.
Комментарии:
1. Привет, @Tpojka. Похоже, действительно хороший и хорошо продуманный подход, поэтому я поддержал это. Тем не менее, я постараюсь реализовать в будние дни и принять в качестве ответа, если это сработает для меня. Спасибо
2. Имея в виду ваш запрос из вопроса, я представил, что бы я сделал в этой ситуации.
Ответ №2:
Я думаю, что при вашей проверке ваше свойство uniqiue находится не в том месте. Вы проверяете, что ‘является ли переменная «name» уникальной в таблице event_departments в столбце location_id’ в вашем коде, но вы не хотите проверять name. Вы хотите проверить location_id. Если я неправильно понял ваш вопрос, извините.
$this->validate($request, [
'name' => 'required|min:3',
'location_id' => 'required|unique:event_departments,location_id',
]);
Можете ли вы попробовать это? Или, если вы хотите проверить имя, попробуйте это;
$this->validate($request, [
'name' => 'required|min:3|unique:event_departments,name',
'location_id' => 'required',
]);
Комментарии:
1. Я проверяю имя.
EventDepartment
Имя должно быть уникальным для каждогоEventLocation
примераEventDepartment
, которое может быть названо «ИТ-отдел», и это имя может появляться в таблице дважды, если они принадлежат разнымEventLocation
, т.е.location_id
вEventDepartment
таблице не совпадают.