Самоссылающийся объект Doctrine 2 ZF3 не обновляет все поля родителя

У меня есть самоссылающийся объект с родителем и детьми. Странно то, что когда я добавляю элементы формы (DoctrineModule ObjectSelect) для родительского и дочернего элементов в форму, некоторые другие поля родительского объекта не обновляются, когда я сохраняю объект. Дочерние объекты обновляются нормально.

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

Когда я удаляю элементы формы для родительского и дочернего элементов в форме, все работает нормально, а родительский объект обновляет/сохраняет все поля.

/**
 * @var string
 *
 * @Gedmo\Translatable
 * @ORM\Column(type="text")
 */
private $teaser;

/**
 * @var string
 *
 * @Gedmo\Translatable
 * @ORM\Column(type="text")
 */

private $description;

/**
 * One Category has Many Categories.
 * @var Collection
 * @ORM\OneToMany(targetEntity="Rental\Entity\Rental", mappedBy="parent")
 */
private $children;

/**
 * Many Categories have One Category.
 * @ORM\ManyToOne(targetEntity="Rental\Entity\Rental", inversedBy="children")
 * @ORM\JoinColumn(name="parent_id", referencedColumnName="houses_id", nullable=true, onDelete="SET NULL")
 */
private $parent;

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

/**
 * Get teaser
 *
 * @return string
 */
public function getTeaser()
{
    return $this->teaser;
}

/**
 * Set teaser
 *
 * @param string $teaser
 */
public function setTeaser($teaser)
{
    $this->teaser = $teaser;
}

/**
 * Get description
 *
 * @return string
 */
public function getDescription()
{
    return $this->description;
}

/**
 * Set description
 *
 * @param string $description
 */
public function setDescription($description)
{
    $this->description = $description;
}

/**
 * Add $child
 * @param Collection $children
 */
public function addChildren(Collection $children)
{
    foreach ($children as $child) {
        $this->addChild($child);
    }
}


/**
 * @param Rental $child
 * @return void
 */
public function addChild(Rental $child)
{
    if ($this->children->contains($child)) {
        return;
    }
    $child->setParent($this);
    $this->children[] = $child;
}

/**
 * Remove children
 * @param Rental $children
 */
public function removeChildren(Collection $children)
{
    foreach ($children as $child) {
        $this->removeChild($child);
    }
}

/**
 * Remove child.
 *
 * @param \Rental\Entity\Rental $child
 *
 * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
 */
public function removeChild(Rental $child)
{
    return $this->children->removeElement($child);
}

/**
 * Get children.
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getChildren()
{
    return $this->children;
}

/**
 * Set parent.
 *
 * @param \Rental\Entity\Rental|null $parent
 */
public function setParent(Rental $parent = null)
{
    $this->parent = $parent;
}

/**
 * Get parent.
 *
 * @return \Rental\Entity\Rental|null
 */
public function getParent()
{
    return $this->parent;
}

comment
Из того, что я вижу, я думаю, что обработка Doctrine верна. Вы настроили дочернее/родительское отношение таким образом, что сохранение изменений родительского или дочернего объекта из объекта в форме не допускается. Только текущий добавленный/редактируемый объект может быть изменен. Если вы хотите изменить родительский/дочерний объект из любой текущей сущности, вам нужно добавить cascade={"persist"} (чтобы разрешить удаление, также добавьте ,"remove" в похвалах).   -  person rkeet    schedule 02.05.2018
comment
@rkeet Спасибо за ваш комментарий. Я также пытался использовать cascade={persist}, но проблема в том, что Doctrine не распознает все остальные поля, кроме $children и $parent в родительском объекте. Эти другие поля не сохраняются.   -  person Oskar    schedule 03.05.2018
comment
Ради тщательности, не могли бы вы скопировать некоторые другие свойства?   -  person rkeet    schedule 03.05.2018
comment
@rkeet Я добавил еще два поля. Когда я добавляю в свою форму элементы формы для $children и $parent, другие поля не обновляются. Когда я удаляю два элемента формы, все работает нормально.   -  person Oskar    schedule 03.05.2018
comment
Выглядит абсолютно нормально. Проблема должна быть в настройке формы. Не могли бы вы поделиться своей формой, набором полей, входным фильтром и / или фабриками, а также конфигурацией? Становится много, но проблема есть проблема. Чтобы узнать, сможете ли вы найти его самостоятельно, взгляните на рабочий пример Form + Fieldset + InputFilter (как отдельные классы ) настраивать. Включает классы Factory, конфигурацию и партиал для внешнего интерфейса.   -  person rkeet    schedule 04.05.2018
comment
Моя форма работает нормально, и действительно, это было бы много. Когда я выгружаю данные перед оператором persist, все данные из формы существуют и верны. Но по-прежнему выполнять только оператор SQL UPDATE аренда SET type = ?, updated_at = ? ГДЕ house_id = ? Не установлены все обновленные поля. Только типа и updated_at. Я не могу понять.   -  person Oskar    schedule 04.05.2018
comment
Да я поэтому и спросил. Ваше описание звучит так, как будто вы делаете ошибку или 2 с привязкой и проверкой данных. Чтобы получить больше информации о методе isValid(), прочитайте это. Затем убедитесь, что до проверки вы выполняете: $form->bind(new Entity()) и $form->setData($this->getRequest()->getData()). Затем после проверки выполните: $entity = $form->getObject(); $this->getObjectManager()->persist($entity); $this->getObjectManager()->flush($entity);. ... Ок, напишу в маленьком ответе.   -  person rkeet    schedule 04.05.2018
comment
Если мой ответ ответил на ваш вопрос, не стесняйтесь принять его ;-) Если у вас все еще есть проблемы, дайте мне знать.   -  person rkeet    schedule 12.05.2018
comment
У меня все еще есть проблемы, но на самом деле нет времени. Я не против, я свяжусь с вами, когда у меня будет время. Заранее большое спасибо.   -  person Oskar    schedule 12.05.2018


Ответы (1)


Ответ основан (и все еще может измениться) на основе обсуждения в комментариях с обсуждаемым OP.


Простой вариант использования: объект Doctrine, ссылающийся на самого себя, неправильно обновляет свойства объекта Entity, связанные с родительским/дочерним элементом, при действии при сохранении.


OP предоставил Entity.

Я предполагаю, что у вас есть настройка формы для этого объекта. Я также предполагаю, что он настроен правильно, поскольку вы не предоставили его после того, как его спросили (потому что, правильно, это означало бы много кода). Однако, предполагая что-то с кодом, вы совершаете много ошибок, поэтому я упоминаю об этом здесь.

Таким образом, я предполагаю, что обработка вашей формы в контроллере может быть ошибочной. Чтобы проверить, используйте следующую упрощенную функцию addAction и попробуйте ее (заводской код ниже).

/**
 * @var RentalForm
 */
protected $form;

/**
 * @var ObjectManager
 */
protected $objectManager;

public function __construct(ObjectManager $objectManager, RentalForm $form)
{
    $this->form = $form;
    $this->objectManager = $objectManager;
}

public function addAction()
{
    /** @var RentalForm $form */
    $form = $this->getForm();

    /** @var Request $request */
    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setData($request->getPost());

        if ($form->isValid()) {
            $entity = $form->getObject();

            $this->getObjectManager()->persist($entity);

            try {
                $this->getObjectManager()->flush();
            } catch (\Exception $e) {
                $message = sprintf(
                    'Was unable to save the data. Saving threw an error. <br />Code: %s. <br />Message: %s',
                    $e->getCode(),
                    $e->getMessage()
                );

                $this->flashMessenger()->addErrorMessage($message);

                return [
                    'form' => $form,
                    'validationMessages' => $form->getMessages() ?: '',
                ];
            }

            $this->flashMessenger()->addSuccessMessage(
                $this->getTranslator()->translate('Successfully created object.')
            );

            // TODO replace vars with your own: return $this->redirect()->route($route, $routeParams);
        }

        $this->flashMessenger()->addWarningMessage(
            'Your form contains errors. Please correct them and try again.'
        );
    }

    return [
        'form' => $form,
        'validationMessages' => $form->getMessages() ?: '',
    ];
}

Фабрика для класса с вышеперечисленным, измените по мере необходимости для вашей ситуации

class RentalControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        /** @var ObjectManager $objectManager */
        $objectManager = $container->get(EntityManager::class);

        /** @var FormElementManagerV3Polyfill $formElementManager */
        $formElementManager = $container->get('FormElementManager');

        /** @var RentalForm $form */
        $form = $formElementManager->get(RentalForm::class);

        return new RentalController($objectManager, $form);
    }
}
person rkeet    schedule 04.05.2018