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

У меня довольно простое отношение «многие ко многим» с дополнительным полем, реализованным, например, в этот пример (двойное отношение "один ко многим"). Это хорошо работает при создании новых сущностей и сохранении их в базе данных. Сейчас я пытаюсь создать функцию редактирования и столкнулся с некоторыми проблемами.

Допустим, моя основная сущность называется Recipe, которая имеет отношение «многие ко многим» с сущностью Ingredient. Дополнительные поля, такие как «количество», находятся в объекте RecipeIngredient. Класс Recipe имеет метод setRecipeIngredient, который добавляет объект RecipeIngredient в массив ингредиентов.

Должен ли я создать некоторый метод «clearRecipeIngredients» для класса Recipe, который удалит все объекты RecipeIngredient? Я бы назвал это при редактировании рецепта, а затем создал новые объекты RecipeIngredient из моих данных и заполнил массив ингредиентов, как при создании нового объекта? Я признаю, что мои настройки каскада, вероятно, настроены неправильно, чтобы это работало, но я попытаюсь исправить это дальше.

Любые связанные примеры были бы замечательными.

0
jaylinen 21 Дек 2011 в 11:54

1 ответ

Строго говоря, как вы упомянули, здесь нет отношения «многие ко многим», а есть отношение «один ко многим», за которым следует «многие к одному».

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

Ниже я привел пример реализации:

class Recipe
{
  /**
   * @OneToMany(targetEntity="RecipeIngredient", mappedBy="recipe")
   */
  protected $recipeIngredients;

  public function addIngredient(Ingredient $ingredient, $quantity)
  {
    // check if the ingredient already exists
    // if it does, we'll just update the quantity
    $recipeIngredient = $this->findRecipeIngredient($ingredient);
    if ($recipeIngredient) {
      $quantity += $recipeIngredient->getQuantity();
      $recipeIngredient->updateQuantity($quantity);
    }
    else {
      $recipeIngredient = new RecipeIngredient($this, $ingredient, $quantity);
      $this->recipeIngredients[] = $recipeIngredient;
    }
  }

  public function removeIngredient(Ingredient $ingredient)
  {
    $recipeIngredient = $this->findRecipeIngredient($ingredient);
    if ($recipeIngredient) {
      $this->recipeIngredients->removeElement($recipeIngredient);
    }
  }

  public function updateIngredientQuantity(Ingredient $ingredient, $quantity)
  {
    $recipeIngredient = $this->findRecipeIngredient($ingredient);
    if ($recipeIngredient) {
      $recipeIngredient->updateQuantity($quantity);
    }
  }

  protected function findRecipeIngredient(Ingredient $ingredient)
  {
    foreach ($this->recipeIngredients as $recipeIngredient) {
      if ($recipeIngredient->getIngredient() === $ingredient) {
        return $recipeIngredient;
      }
    }
    return null;
  }
}

Примечание. Вам необходимо настроить каскадное сохранение и удаление потерянных файлов, чтобы этот код работал правильно.

Конечно, если вы выберете этот подход, ваш пользовательский интерфейс не должен отображать полную форму со всеми ингредиентами и количествами, которые можно редактировать одновременно. Вместо этого должны быть перечислены все ингредиенты с кнопкой «удалить» в каждой строке, а также кнопкой «изменить количество», которая, например, выводит всплывающую форму (с одним полем) для обновления количества.

1
BenMorel 21 Дек 2011 в 19:04