模型变换器和预期的表单视图数据不匹配

时间:2015-02-25 10:48:12

标签: symfony doctrine-orm

我有一个Symfony 2应用程序,其表单需要在隐藏字段中存储对另一个实体(项目)的引用。项目实体是通过表单选项传递的,我的计划是要有一个隐藏式'它只包含实体id,然后在提交表单时将其转换为项目实体。

我通过使用模型转换器将实体转换为字符串(它的ID)来解决这个问题。但是,当我尝试查看表单时,出现以下错误:

  

表单的视图数据应该是类Foo \ BarBundle \ Entity \ Project的实例,但是是(n)字符串。您可以通过设置" data_class"来避免此错误。 null的选项或添加视图转换器,将(n)字符串转换为Foo \ BarBundle \ Entity \ Project的实例。

这是我的表单类:

<?php

namespace Foo\BarBundle\Form\SED\Waste;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Foo\BarBundle\Form\DataTransformer\EntityToEntityIdTransformer;

/**
 * Class WasteContractorEntryType
 * @package Foo\BarBundle\Form\CommunityInvestment\Base
 */
class WasteContractorEntryType extends AbstractType
{

    protected $name;

    protected $type;

    protected $phase;

    protected $wasteComponent;

    public function __construct($formName, $type, $phase, $wasteComponent)
    {
        $this->name = $formName;
        $this->type = $type;
        $this->phase = $phase;
        $this->wasteComponent = $wasteComponent;
    }

    /**
     * @return mixed
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * @return mixed
     */
    public function getPhase()
    {
        return $this->phase;
    }

    /**
     * @return mixed
     */
    public function getProject()
    {
        return $this->project;
    }

    /**
     * @return mixed
     */
    public function getWasteComponent()
    {
        return $this->wasteComponent;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $em = $options['em'];

        $wasteComponentTransformer = new EntityToEntityIdTransformer($em,
            'Foo\BarBundle\Entity\SED\Waste\WasteComponent');

        $projectTransformer = new EntityToEntityIdTransformer($em, 'Foo\BarBundle\Entity\Project');

        $builder->add('id', 'hidden');

        $builder->add(
            $builder->create('project', 'hidden', array(
                'data' => $options['project'],
                'by_reference' => false
            ))
                ->addModelTransformer($projectTransformer)
        );

        $builder->add(
            $builder->create('wasteComponent', 'hidden', array(
                'data' => $this->getWasteComponent()
            ))
                ->addModelTransformer($wasteComponentTransformer)
        );

        $builder->add('phase', 'hidden', array(
            'data' => $this->getPhase()
        ));

        $builder->add('type', 'hidden', array(
            'data' => $this->getType()
        ));

        $builder->add('percentDivertedFromLandfill', 'text', array());

        $builder->add('wasteContractor', 'entity', array(
            'class' => 'Foo\BazBundle\Entity\Contractor',
            'property' => 'name',
            'attr' => array(
                'class' => 'js-select2'
            )
        ));
    }


    public function getName()
    {
        return $this->name;
    }

    /**
     * {@inheritDoc}
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'csrf_protection' => true,
            'data_class' => 'Foo\BarBundle\Entity\SED\Waste\WasteContractorEntry'
        ))
            ->setRequired(array(
                'em',
                'project'
            ))
            ->setAllowedTypes(array(
                'em' => 'Doctrine\Common\Persistence\ObjectManager',
                'project' => 'Foo\BarBundle\Entity\Project'
            ));

    }

} 

我的模型变换器类:

<?php

namespace Foo\BarBundle\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\Common\Persistence\ObjectManager;

class EntityToEntityIdTransformer implements DataTransformerInterface
{
    /**
     * @var ObjectManager
     */
    private $om;

    /**
     * @var Entity class
     */
    protected $entityClass;

    /**
     * @param ObjectManager $om
     */
    public function __construct(ObjectManager $om, $className)
    {
        $this->om = $om;
        $this->entityClass = $className;
    }

    protected function getEntityClass()
    {
        return $this->entityClass;
    }

    /**
     * Transforms an object (project) to a string (id).
     *
     * @param  Project|null $issue
     * @return string
     */
    public function transform($entity)
    {
        if (null === $entity) {
            return "";
        }

        return $entity->getId();
    }

    /**
     * Transforms a string (id) to an object (project).
     *
     * @param  string $id
     *
     * @return Issue|null
     *
     * @throws TransformationFailedException if object (project) is not found.
     */
    public function reverseTransform($id)
    {
        if (!$id) {
            return null;
        }

        $entity = $this->om
            ->getRepository($this->getEntityClass())
            ->find($id);

        if (null === $entity) {
            throw new TransformationFailedException(sprintf(
                'An entity of class %s with id "%s" does not exist!',
                $this->getEntityClass(),
                $id
            ));
        }

        return $entity;
    }
}

我尝试使用添加变压器作为视图变换器而不是模型变换器,但是我只是得到了一个稍微不同的错误:

  

表单的视图数据应该是类的实例   Foo \ BarBundle \ Entity \ Project,但是是(n)整数。你可以避免这种情况   设置&#34; data_class&#34; null的选项或添加视图的选项   将(n)整数转换为实例的变换器   FOO \ BarBundle \实体\项目。

1 个答案:

答案 0 :(得分:0)

似乎将上述异常消息建议的'data_class'设置为null是解决方案。我之前拒绝了这一点,因为当我们知道该领域的目的是引用项目实体时,它似乎是违反直觉的。

当'data_class'选项设置为null时,隐藏的项目字段包含项目ID,并且在提交时,在创建的实体上调用getProject()将返回正确的项目对象。

相关问题