#php #laravel #eloquent #relationship #contains
#php #laravel #красноречивый #связь #содержит
Вопрос:
В новой установке Laravel 8.20.1 я создал две модели Company
User
со сводной таблицей между ними, чтобы облегчить связь «многие ко многим». У стержня есть role
атрибут.
Я могу добавить пользователя в компанию, используя:
$company->users()->attach($user);
Я добавил служебный метод addUser
, чтобы сначала проверить наличие связи, чтобы избежать дублирования:
public function addUser(User $user) {
if($this->users->contains($user)) {
// if the user already has a role, update it
Log::info("User #{$user->id} present - updating");
$this->users()->updateExistingPivot($user, ['role' => 'user'], true);
} else {
// if the user doesn't have a role, add it
Log::info("User #{$user->id} not present - adding");
$this->users()->attach($user, ['role' => 'user'], true);
}
}
В первый раз, когда я запускаю это с использованием обновленной базы данных, он должен увидеть, что пользователь еще не связан с компанией, и запустить else
часть переключателя, чтобы добавить нового пользователя. Запустив это в Tinker, кажется, что он делает это — и в журналах отображается «Пользователь № 1 отсутствует — добавление», — но когда я проверяю наличие с помощью contains
, он возвращает false:
$user = User::factory()->create();
$company = Company::factory()->create();
$company->addUser($user);
print_r($company->users->contains($user)); //false
Я пробовал регистрировать запросы для этой функции, и у меня они выглядят нормально — один для проверки существования пользователя, второй для вставки pivot.
Кроме того, я могу видеть сводную запись для пользователя № 1 и компании № 1, и если я затем протестирую это в Tinker, я получу true:
print_r(Company::find(1)->users->contains(User::find(1))); // true
Это почти как если бы база данных работала асинхронно, чего, я знаю, в PHP нет. Я использую Sqlite v3.31.0.
Проблема определенно в моем addUser
методе, как будто я заменяю этот вызов в Tinker attach
прямым вызовом, он работает.
Я действительно очень хочу использовать этот служебный метод (и другие), потому что:
- Я хочу избежать нескольких сводных записей для одной и той же компании / пользователя (без использования составных индексов)
- Мне нужно еще несколько служебных методов, таких как
addAdmin
,addOwner
, и т. Д
Комментарии:
1. Вы пробовали использовать этот
syncWithoutDetaching()
метод?2. Это действительно решает проблему, спасибо! Все еще интересно, почему мой код не работает.
3. Возможно, это
$company->users
, будучи Коллекцией, не обновляетсяattach()
. Если бы вы это сделалиprint_r($company->users()->get()->contains($user))
, вы могли бы увидетьtrue
. Или$company->fresh()->users->contains($user)
(т.е. перезагрузка отношения модели перед попыткой проверкиcontains()
). Не уверен, как это будет вести себя с заводской логикой…4. Вы поняли это?