Symfony - создание новой сущности вместо обновления существующей - PullRequest
0 голосов
/ 01 мая 2020

У меня есть следующая структура:

Свойство категории, содержащее ссылку на свойство и его значение:

<?php


class CategoryProperty
{

// ...

/**
 * @var Property
 *
 * @ORM\ManyToOne(targetEntity="App\Entity\Property")
 * @ORM\JoinColumn(onDelete="cascade", nullable=false)
 */
private $property;

/**
 * Набор значений свойства доступных в product builder, null если любое значение.
 *
 * @var PropertyValueEntry
 * @Assert\Valid
 *
 * @ORM\OneToOne(targetEntity="App\Entity\Properties\PropertyValues\PropertyValueEntry",
 * cascade={"persist", "remove"})
 */
private $propertyValue;

// ...

}

Абстрактный тип значения свойства с картой дискриминатора:

<?php

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="type", type="integer")
 * @ORM\DiscriminatorMap({
 *     "1": "StringValue",
 *     "2": "IntegerValue",
 *     "3": "BooleanValue",
 *     "4": "TextValue",
 *     "6": "EnumValue",
 *     "7": "SetValue",
 *     "9": "LengthValue",
 *     "10": "AreaValue",
 *     "11": "VolumeValue",
 *     "12": "MassValue",
 * })
 * @ORM\Table(name="properties_values__value_entry")
 */
abstract class PropertyValueEntry
{
    /**
     * @var Property
     *
     * @ORM\ManyToOne(targetEntity="App\Entity\Property")
     */
    private $property;

    public function __construct(Property $property)
    {
        $this->property = $property;
    }

    public function getProperty(): Property
    {
        return $this->property;
    }

    /**
     * @return mixed
     */
    abstract public function getValue();

    /**
     * @param mixed $value
     */
    abstract public function setValue($value): void;
}

И пример конкретного типа значения:

<?php

/**
 * @ORM\Entity
 * @ORM\Table(name="properties_values__integer_value")
 */
class IntegerValue extends PropertyValueEntry
{
    /**
     * @var int
     * @Assert\NotNull
     *
     * @ORM\Column(type="integer")
     */
    private $value = 0;

    public function getValue(): int
    {
        return $this->value;
    }

    /**
     * @param int|null $value
     */
    public function setValue($value): void
    {
        if (!\is_int($value)) {
            throw new InvalidArgumentException('BooleanValue accepts integer values only');
        }
        $this->value = $value;
    }
}

По какой-то причине при отправке формы вместо обновления значения для IntegerValue создается новая сущность и новая строка в properties_values__value_entry / properties_values__integer_value. Я попытался отследить через $ this-> em-> persist ($ entity), где $ entity - это CategoryProperty, и кажется, что IntegerValue помечается как грязный и создается заново. Как я могу отследить причину этого? Моя обработка формы довольно стандартная:

<?php

public function editAction(): Response
{
    $id = $this->request->query->get('id');
    $easyadmin = $this->request->attributes->get('easyadmin');
    $entity = $easyadmin['item'];

    $isReload = 'reload' === $this->request->request->get('action');
    $editForm = $this->createForm(CategoryPropertyType::class, $entity, [
        'category' => $this->getCatalog(),
        'is_reload' => $isReload,
    ]);
    $deleteForm = $this->createDeleteForm($this->entity['name'], $id);

    $editForm->handleRequest($this->request);
    if ($editForm->isSubmitted() && $editForm->isValid()) {
        if (!$isReload) {
            $this->em->persist($entity);
            $this->em->flush();

            return $this->redirectToReferrer();
        }
    }

    return $this->render($this->entity['templates']['edit'], [
        'form' => $editForm->createView(),
        'entity' => $entity,
        'delete_form' => $deleteForm->createView(),
    ]);
}

ОБНОВЛЕНИЕ # 1 Что я уже пробовал: Получить свойство категории по идентификатору из менеджера сущностей через

$entity = $this->em->find(CategoryProperty::class, $id);

В целом это Кажется, это может быть связано с тем, что у меня есть динамическая форма c, созданная на основе выбора. Когда я добавляю свойство категории, я отображаю раскрывающийся список со списком типов свойств (целое число, строка, область, объем и т. Д. c), и после выбора отображается новая форма для этого свойства. Хотя это работает нормально и добавляет новое свойство без проблем, похоже, что в коде для РЕДАКТИРОВАНИЯ того же свойства что-то отсутствует, и вместо обновления оно создает его заново.

Ответы [ 2 ]

1 голос
/ 01 мая 2020

Возможность # 1: загрузка объекта непосредственно из диспетчера объектов

Похоже, вы вообще не извлекаете существующий объект для изменения.

$entity = $easyadmin['item'];

Если это не используется Doctrine восстановить существующую сущность? Например:

if (!($entity = $this->getRepository(CategoryProperty::class)->findOneById($id))) {
    throw $this->createNotFoundException("Category property not found.");
}

Полусвязанный: Вы также можете проверить, что целочисленный идентификатор был указан вообще, поскольку $id = $this->request->query->get('id'); очень предположительно:

if (intval($id = $this->request->query->get('id')) < 1) {
    throw $this->createNotFoundException("Category property not specified.");
}

Возможность 2 : Отсутствует ссылка на идентификатор с отношением «один к одному»

Я думаю, что вы можете получить дублирование, потому что CategoryProperty не сохраняет никаких ссылок на PropertyValueEntry.

/**
 * Набор значений свойства доступных в product builder, null если любое значение.
 *
 * @var PropertyValueEntry
 * @Assert\Valid
 *
 * @ORM\OneToOne(targetEntity="App\Entity\Properties\PropertyValues\PropertyValueEntry", cascade={"persist", "remove"})
 */
private $propertyValue;

Однако PropertyValueEntry не имеет обратной связи обратно к CategoryProperty.

Однонаправленный один-к-одному хорош, но он должен иметь директиву @ORM\JoinColumn для обеспечения идентификатора иностранного PropertyValueEntry сохраняется. В противном случае форма редактирования не будет иметь никакой информации, чтобы знать, какой из существующих PropertyValueEntry (или его производных) нужно редактировать. Вот почему ваше поле формы "properties_values__value_entry" сбрасывается с новым экземпляром PropertyValueEntry (или производным), созданным при отправке формы.

Вы не показали источник для класса сущности Property, поэтому Я не могу проверять какие-либо дальнейшие проблемы в отношениях вашей сущности.

0 голосов
/ 03 мая 2020

Спасибо всем, кто участвовал, я прочитал документацию Symfony и наткнулся на атрибут формы 'by_reference' . Учитывая, что моя структура form в целом выглядит так:

Category => CategoryPropertyType => PropertyValueType => [Set, Enum, Integer, Boolean, String, Volume]

для формы, я решил установить ее значение true в методе configureOalpeTimepe configureOptions. Как объяснено в документации, при значении false объект клонируется (что в моем случае истинно), и в конце создается новый объект.

Обратите внимание, что я Я все еще учусь Symfony и буду уточнять ответ, когда получу лучшее понимание того, что происходит за кулисами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...