Доктрина - заменить предметы в отношении один ко многим - PullRequest
0 голосов
/ 17 сентября 2018

У меня есть две сущности для продуктов и переводов:

class ProductEntity
{
    /**
    * @Id
    * @var string
    * @Column(type="string", length=3)
    */
    protected $code;

    /**
     * @OneToMany(targetEntity="ProductTranslationEntity", mappedBy="product")
     */
    private $translations;

    public function __construct()
    {
        $this->translations = new ArrayCollection();
    }


    /.../ getters and setters


    public function addTranslation(ProductTranslationEntity $productTranslation)
    {
        $this->translations->add($productTranslation);
    }

    public function clearTranslations()
    {
        $this->translations->clear();
    }
}

.

class ProductTranslationEntity
{
    /**
    * @ManyToOne(targetEntity="ProductEntity", inversedBy="translations")
    * @JoinColumn(name="product_code", referencedColumnName="code", onDelete="CASCADE")
    * @Id
     */
    private $product;

    /**
    * @var string
    * @Column(type="string", name="language_code", length=5)
    * @Id 
    */
    protected $languageCode;

    /**
    * @var string
    * @Column(type="string", name="product_name", length=128)
    */
    protected $productName;

    /.../ getters and setters
}

Мне нравится заменять все переводы новыми, из массива, подобного этому:

['en' => ['name' => 'name_en'], 'de' => ['name' => 'name_de']];

Поскольку в этом массиве у меня есть набор всех поддерживаемых языков, лучший способ, который я вижу, - удалить все существующие переводы и поставить новые:

$product // Existing product entity
$product->clearTranslations();
$this->entityManager->flush($product);

foreach ($translations as $code => $translation) {
    $t = new ProductTranslationEntity();
    $t->setProduct($product);
    $t->setLanguageCode($code);
    $t->setProductName($translation['name']);
    $this->entityManager->persist($t);
    $product->addTranslation($t);
}

$this->entityManager->flush($product);

Эторешение не работает, потому что после первого $this->entityManager->flush($product); в базе данных все еще есть переводы, поэтому я получаю сообщение об ошибке дубликатов.

Что я сделал неправильно в своем решении?Или, может быть, есть другой способ решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Как указывается в документации Учения:

Изменения, внесенные только в обратную сторону ассоциации, игнорируются. Обязательно обновите обе стороны двунаправленной ассоциации (или на наименьшая сторона, с точки зрения Доктрины).

Таким образом, чтобы правильно очистить переводы продукта, вы должны изменить функцию clearTranslations () внутри сущности Product на:

public function clearTranslations()
{
    foreach ($this->translations as $translation) {
        $translation->setProduct(null);
    }
    $this->translations->clear();
}

, чтобы вы также обновили сторону-владельца ассоциации перед удалением.

0 голосов
/ 17 сентября 2018

Это может быть немного перегружено, но все равно он не использует дополнительные запросы к базе данных:

$current_translations = $product->getTranslations();
foreach ($translations as $code => $translation) {
    $translation_found = false;
    foreach ($current_translations as $current_translation) {
        if ($current_translation->getLanguageCode() === $code) {
            // you've found the translation - replace value
            $current_translation->setProductName($translation['name']);
            $translation_found = true;
            break;
        }
    }

    if (!$translation_found) {
        // translation with such code not found - add a new one
        $t = new ProductTranslationEntity();
        $t->setProduct($product);
        $t->setLanguageCode($code);
        $t->setProductName($translation['name']);
        $this->entityManager->persist($t);
        $product->addTranslation($t);
    }
}
$this->entityManager->persist($product);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...