2013-06-03 15 views
3

我搜索了並沒有發現任何人有這個問題。Symfony2隱藏字段上的數據轉換器

我已經創建了自己的數據轉換器所載的食譜,這一切似乎是正確的,但我得到的錯誤:

The form's view data is expected to be an instance of class Niche\SecurityBundle\Entity\BusinessUser, but is a(n) integer. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) integer to an instance of 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'; 
} 
} 

該錯誤消息令我困惑,因爲它似乎已經轉換了BusinessUs呃類到一個整數。我也嘗試通過放入data_class => null和表單然後加載,但提交時我得到一個錯誤,該字段是空的,雖然隱藏字段中的ID顯示正確,但表單生成後。

有人能指出我在正確的方向,因爲有一種感覺,它非常簡單,我沒有看到。

感謝

更新:我做了一些變化意識到我應該設定該公司在控制並將其傳遞到表單,並且所有似乎工作,但是當提交表單時我仍然可以在空數據庫或如果我將字段設置爲@Assert \ NotBlank()表單將不會提交爲字段不能爲空即使當我檢查源時,我可以在隱藏字段中看到BusinessUser的Id。

* 更新 - 雖然implemeting下面我終於實現科馬的建議下,我出了毛病 - 這是它沒有返回變壓器對象* - 若有其他人到這個問題,我建議如下昏迷的解決方案是多少比每次創建隱藏都要好。如果它是一個關閉上面的解決方案已更新爲返回對象,應該工作正常。

回答

7

這是我處理實體隱藏的輸入方式:

DataTransformer

<?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; 
    } 

} 

FormType

<?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 } 

JobType

$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),因爲我不想設置字段數據的類,所以我想出了這個(btw,現在我正在使用在form.type_guesser.doctrine服務來獲取類):

配置

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

DataTransformer

<?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設置變壓器上的數據類是討厭的,你覺得呢?

+0

謝謝,這看起來更有效率,我會嘗試並將其用於我的網站,但我仍然擔心爲什麼我的版本不工作,因爲我覺得我沒有理解它。 – lflanagan

+0

我解決了我所描述的問題,但感謝您的幫助,並將在未來使用您的實施。再次感謝。 – lflanagan

+0

很高興看到它! – coma

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:我知道你想創建你的數據轉換器,但是如果你的問題持續存在對象機智h父母身份證,它會幫助你。