3

私は検索しましたが、この問題を抱えている人は見つかりませんでした。

クックブックに記載されているように独自の Data Transformer を作成しましたが、すべて正しいように見えますが、次のエラーが表示されます。

フォームのビュー データはクラス Niche\SecurityBundle\Entity\BusinessUser のインスタンスであると予想されますが、(n) 整数です。「data_class」オプションを null に設定するか、(n) 整数を Niche\SecurityBundle\Entity\BusinessUser のインスタンスに変換するビュー トランスフォーマーを追加することで、このエラーを回避できます。

トランスは以下です。

<?php
namespace Niche\SecurityBundle\Form\DataTransformer;

use JMS\SecurityExtraBundle\Security\Util\String;

use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\Common\Persistence\ObjectManager;
use Niche\SecurityBundle\Entity\BusinessUser;

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

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

/**
 * Transforms an object (BusinessUser) to a string (number)
 * 
 * @param BusinessUser|null $businessUser
 * @return String
 */
public function transform($businessUser)
{
    if (null === $businessUser) {
        return "";
    }

    return $businessUser->getId();
}

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

    $businessUser = $this->om
        ->getRepository('NicheSecurityBundle:BusinessUser')
        ->findOneById($id);

    if (null === $businessUser) {
        throw new TransformationFailedException(sprintf(
                'An issue with number "%s" does not exist!',
                $number
                ));

    }
            return $businessUser
}
}

私のフォームコードは

<?php

namespace Niche\JobBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Niche\SecurityBundle\Form\DataTransformer\BusinessUserToIdTransformer;

class JobType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{

    $entityManager = $options['em'];
    $transformer = new BusinessUserToIdTransformer($entityManager);

    //Get the BusinessUser object passed in.
    $businessUser = $options['businessUser'];


    $builder->add('title', 'text');
    $builder->add('jobDescription', 'textarea', array(
            "label" => "Job Description", )
        );
    $builder->add('companyDescription', 'textarea', array(
            "label" => "Company Description", )
        );
    $builder->add('salary', 'text');
    $builder->add('category', 'entity', array(
        'class' => 'NicheJobBundle:Category',
        'property' => 'name',   
    ));
    $builder->add('responsibilities', 'textarea');
    $builder->add('closingDate', 'datetime');
    //Add Business User to the form - Need a way for a job to be added by site admin in addition, could just be site admin users logged in with a Business user account
    $builder->add(
            $builder->create('company', 'hidden', array(
                'data' => $businessUser,

            ))->addViewTransformer($transformer)

    );

}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Niche\JobBundle\Entity\Job'
    ));

    $resolver->setRequired(array(
            'em', 'businessUser'
    ));

    $resolver->setAllowedTypes(array(
        'em' => 'Doctrine\Common\Persistence\ObjectManager',
    ));
}

public function getName()
{
    return 'niche_jobbundle_jobtype';
}
}

エラー メッセージは、BusinessUser クラスを整数に変換したように見えるので、私を混乱させます。また、 data_class => null を入力してフォームをロードしてみましたが、フォームが生成されたときに非表示フィールドの ID が正しく表示されたにもかかわらず、送信時にフィールドが空であるというエラーが発生しました。

誰かが私を正しい方向に向けることができますか?

ありがとう

更新:コントローラーで会社を設定してフォームに渡す必要があることに気付いたので、いくつかの変更を加えました。すべてが機能しているように見えますが、フォームが送信されたときにデータベースでnullを取得するか、フィールドを@Assert\NotBlank() ソースを確認すると非表示フィールドに BusinessUser の ID が表示されていても、フィールドを空白にすることはできないため、フォームは送信されません。

*更新 - 以下の Coma の提案を実装しているときに、最終的にどこが間違っていたかに気付きました - オブジェクトを返さなかったのはトランスフォーマーでした * - 他の誰かがこの質問に出くわした場合は、以下の Coma のソリューションを作成するよりもはるかに優れていることをお勧めします毎回隠しています。それが 1 つの場合、上記のソリューションはオブジェクトを返すように更新されており、正常に動作するはずです。

4

2 に答える 2

7

これは、非表示の入力を持つエンティティを処理する方法です。

データトランスフォーマー

<?php

namespace Comakai\CQZBundle\Form\DataTransformer;

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

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

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

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

        return $entity->getId();
    }

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

        $entity = $this->om->getRepository($this->entityClass)->findOneById($id);

        if (null === $entity) {

            throw new TransformationFailedException(sprintf(
                    'An entity of class ' . $this->entityClass . ' with id "%s" does not exist!', $id
            ));
        }

        return $entity;
    }

}

フォームタイプ

<?php

namespace Comakai\CQZBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\ObjectManager;
use Comakai\CQZBundle\Form\DataTransformer\EntityToIdTransformer;

class EntityHiddenType extends AbstractType
{
    /**
     * @var ManagerRegistry
     */
    private $registry;

    /**
     * @var ObjectManager
     */
    private $om;
    private $cache;

    /**
     * @param ObjectManager $om
     */
    public function __construct(ManagerRegistry $registry)
    {
        $this->registry = $registry;
        $this->om = $registry->getManager();
        $this->cache = [];
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $class = (empty($options['data_class'])) ? $this->getClassFromMetadata($builder->getName(), $builder->getParent()->getDataClass()) : $options['data_class'];

        $transformer = new EntityToIdTransformer($this->om, $class);
        $builder->addViewTransformer($transformer);

        $builder->setAttribute('data_class', $class);
    }

    public function getParent()
    {
        return 'hidden';
    }

    public function getName()
    {
        return 'entity_hidden';
    }

    protected function getClassFromMetadata($name, $parentClass)
    {
        /* @var $md \Doctrine\ORM\Mapping\ClassMetadata */
        $md = $this->getMetadata($parentClass)[0];
        $a = $md->getAssociationMapping($name);
        $class = $a['targetEntity'];

        return $class;
    }

    protected function getMetadata($class)
    {
        if (array_key_exists($class, $this->cache)) {
            return $this->cache[$class];
        }

        $this->cache[$class] = null;
        foreach ($this->registry->getManagers() as $name => $em) {
            try {
                return $this->cache[$class] = array($em->getClassMetadata($class), $name);
            } catch (MappingException $e) {
                // not an entity or mapped super class
            } catch (LegacyMappingException $e) {
                // not an entity or mapped super class, using Doctrine ORM 2.2
            }
        }
    }

}

構成 (services.yml)

services:
    cqz.form.type.entity_hidden:
        class: Comakai\CQZBundle\Form\Type\EntityHiddenType
        arguments: ["@doctrine"]
        tags:
                -  { name: form.type, alias: entity_hidden }

ジョブタイプ

$builder->add('company', 'entity_hidden');

次に、コントローラーで

$job = new \Niche\JobBundle\Entity\Job();
$type = new \Niche\JobBundle\Form\JobType();

$job->setCompany($businessUser);

$form = $this->createForm($type, $job);

このようにして、再利用可能な entity_hidden タイプが得られます。

2.3 の更新

$builder->getParent() がもうないため ( https://github.com/symfony/symfony/blob/master/UPGRADE-2.2.md )、フィールドのデータのクラスを設定したくないため、私はこれを思いつきました(ところで、今は form.type_guesser.doctrine サービスを使用してクラスを取得しています):

設定

cqz.form.type.suggest:
        class: Comakai\CQZBundle\Form\Type\SuggestType
        arguments: ["@doctrine.orm.entity_manager", "@form.type_guesser.doctrine"]

データトランスフォーマー

<?php

namespace Comakai\CQZBundle\Form\DataTransformer;

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

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

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

    /**
     * Transforms an object to an id.
     *
     * @param  Object|null $object
     * @return mixed
     */
    public function transform($object)
    {
        if (null === $object) {

            return '';
        }

        return $object->getId();
    }

    /**
     * Transforms an id to an object.
     *
     * @param  mixed $id
     *
     * @return Object|null
     *
     * @throws TransformationFailedException if object is not found.
     */
    public function reverseTransform($id)
    {
        if (!$id) {

            return null;
        }

        $object = $this->om
            ->getRepository($this->objectClass)
            ->find($id)
        ;

        if (null === $object) {

            throw new TransformationFailedException(sprintf(
                'An instance of "%s" with id "%s" does not exist!',
                $this->objectClass,
                $id
            ));
        }

        return $object;
    }

    public function getObjectClass()
    {
        return $this->objectClass;
    }

    public function setObjectClass($class)
    {
        $this->objectClass = $class;
    }
}

タイプ

<?php

namespace Comakai\CQZBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Comakai\CQZBundle\Form\DataTransformer\ObjectToIdTransformer;

use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;

use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;

class SuggestType extends AbstractType
{
    /**
     * @var ObjectManager
     */
    private $om;
    private $guesser;

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

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $transformer = new ObjectToIdTransformer($this->om);
        $builder->addModelTransformer($transformer);

        if($options['class'] === null) {

            $builder->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use ($transformer, $builder) {

                /* @var $form \Symfony\Component\Form\Form */
                $form = $event->getForm();
                $class = $form->getParent()->getConfig()->getDataClass();
                $property = $form->getName();
                $guessedType = $this->guesser->guessType($class, $property);
                $options = $guessedType->getOptions();

                $transformer->setObjectClass($options['class']);

            });

        } else {

            $transformer->setObjectClass($options['class']);

        }
    }
    ...

PRE_SET_DATA を使用してトランスフォーマーにデータ クラスを設定するのは厄介だと思いますが、どう思いますか?

于 2013-06-03T21:14:35.897 に答える
1

非表示の入力タイプを作成しました:

$builder->add('child_id', 'hidden', array('mapped' => false))

newAction では、親 ID を入力しました。

$childForm->get('parent_id')->setData($parentEntity->getId());

そして最後に createAction に入れました:

$child->setParent($em->getReference('MyBundle:Parent', $form["child_id"]->getData()))

PS: Data Transformer を作成したかったことは理解していますが、問題が親 ID を持つオブジェクトの永続化である場合は、それが役立ちます。

于 2013-09-17T14:42:33.450 に答える