我正在按照以下文档使用DataMapper:https://symfony.com/doc/current/form/data_mappers.html以以下形式从3个字段中的1个更新日期:
表单类
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
答案 0 :(得分:1)
我下载了your project进行调试,但发现一个错误-很难发现:)我开始认为Symfony 4可能有问题,但不是。一切都很好,一切都很好。
看:
spl_object_hash —返回给定对象的哈希ID
此函数返回对象的唯一标识符。只要未破坏对象,此id可用作存储对象或标识对象的哈希键。一旦对象被销毁,其哈希可以重新用于其他对象。
$beforeHash
和$afterHash
具有不同的值-因此,它不是同一对象
在DataSetType.php
(第138行)中,您创建了DataSet
的新实例,该实例丢失了对先前对象的引用,该对象是在mapFormsToData
中作为第二个参数传递的:
您应该在$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
中的值必须在没有您帮助的情况下进行更改:)
Documentation可能有点令人困惑,但请注意,example from documentation基于不可变的对象
顺便说一句-扩展文档并说明DataMapper如何与Doctrine模型一起使用...