Symfony DataMapper не обновляет объект - PullRequest
0 голосов
/ 14 января 2019

Я использую DataMapper согласно документам: https://symfony.com/doc/current/form/data_mappers.html, чтобы обновить дату из 1 из 3 полей в форме:

Форма класса

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('period_start_daily', DateType::class, [
            'widget' => 'single_text',
            'label' => 'Day',
            'html5' => false,
            'attr' => ['class' => 'js-datepicker'],
            'mapped' => false,
            'required' => false
        ])
        ->add('period_start_weekly', DateType::class, [
            'widget' => 'single_text',
            'label' => 'Week',
            'html5' => false,
            'attr' => ['class' => 'js-datepicker'],
            'mapped' => false,
            'required' => false
        ])
        ->add('period_start_monthly', ChoiceType::class, [
            'required' => true,
            'label' => 'Month',
            'choice_loader' => new CallbackChoiceLoader(function () {
                $months = [];
                for ($i = 0; $i <= 12; $i++) {
                    $month = strtotime('first day of this month + ' . $i . ' months');
                    $months[date('M Y', $month)] = date('Y-m-d', $month);
                }
                return $months;
            }),
            'mapped' => false,
            'required' => false
        ])
...
$builder
        ->setDataMapper($this);
...
public function mapFormsToData($forms, &$data)
{
    /** @var FormInterface[] $forms */
    $forms = iterator_to_array($forms);

    switch (intval($forms['Type']->getViewData())){
        case 1:
            $start = $forms['period_start_daily']->getNormData();
            $end = clone $start;

            break;
        case 2:
            $start = $forms['period_start_weekly']->getNormData();
            $end = clone $start;
            $end->add(new \DateInterval('P6D'));
            break;
        case 3:
            $start = $forms['period_start_daily']->getNormData();
            $end = (new \DateTime(
                strtotime($this->getData()['period_start_monthly']->format('Y-m-d').' last day of month')
            ));
            break;
    }
    $data = (new DataSet())
        ->setPeriodStart($start)
        ->setPeriodEnd($end)
        ->setType($forms['Type']->getNormData())
        ->setUpload($forms['upload']->getNormData());

Контроллер

    $form = $this->createForm(DataSetType::class, $dataset);

    $form->handleRequest($request->getCurrentRequest());

    if ($form->isSubmitted() && $form->isValid()){
        $dataset
            ->setPeriodStart($form->getNormData()->getPeriodStart())
            ->setPeriodEnd($form->getNormData()->getPeriodEnd());
        $dataset->setType($form->getNormData()->getType());
        $dataset->setActive(false);
        $dataset->setUpload($form->getNormData()->getUpload());
        $dataset->getPeriodStart()->setTime(0, 0, 0);
        $dataset->getPeriodEnd()->setTime(0, 0, 0);

        $em->persist($dataset);
        $em->flush();

Я ожидал, что DataMapper обновит мой объект напрямую, однако мне все еще нужно скопировать данные из $ form-> getNormData ().

Версия Symfony - 4.2

1 Ответ

0 голосов
/ 23 января 2019

Я загрузил ваш проект , чтобы отладить его, и я обнаружил ошибку - это было трудно обнаружить :) Я начал думать, что с Symfony 4 может быть что-то не так, но это не так. Все отлично и все отлично работает.

Посмотрите:

enter image description here

spl_object_hash - вернуть хеш-идентификатор для данного объекта

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

$beforeHash и $afterHash имеют разные значения - следовательно, это не один и тот же объект

В DataSetType.php (строка 138) вы создаете новый экземпляр DataSet, теряя ссылку на предыдущий объект, переданный в качестве второго параметра в mapFormsToData:

enter image description here

Вы должны изменить объект в параметре $data вместо создания нового экземпляра DataSet.

Шаг 1:

Изменить этот код:

$data = (new DataSet())
        ->setPeriodStart($start)
        ->setPeriodEnd($end)
        ->setType($forms['Type']->getNormData())
        ->setUpload($forms['upload']->getNormData())
        ->setActive($forms['active']->getNormData())
    ;

К этому коду:

$data->setPeriodStart($start)
     ->setPeriodEnd($end)
     ->setType($forms['Type']->getNormData())
     ->setUpload($forms['upload']->getNormData())
     ->setActive($forms['active']->getNormData());

Шаг 2:

Удалите ненужный код с вашего контроллера. create метод должен выглядеть следующим образом:

public function create(RequestStack $request)
{
    $dataset = new DataSet();

    $form = $this->createForm(DataSetType::class, $dataset);

    $form->handleRequest($request->getCurrentRequest());

    if ($form->isSubmitted() && $form->isValid()){
        $em = $this->getDoctrine()->getManager();
        $em->persist($dataset);
        $em->flush();

        if ($dataset->getUpload()) {
            $em->getRepository('App:DataSet')
                ->disableUploadOthers($dataset->getId(), $dataset->getType());
        }
        $this->addFlash('success', 'Dataset created.');
        return $this->redirectToRoute('dataset_index');
    }

    return $this->render('dataset/create.html.twig', [
        'form' => $form->createView()
    ]);
}

Значения в $dataset должны измениться без вашей помощи:)


Документация может немного сбивать с толку, но обратите внимание, что пример из документации основан на неизменяемом объекте

enter image description here

Кстати - было бы хорошо расширить документацию и показать, как DataMapper работает с моделями Doctrine ...

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