草庐IT

php - 隐藏字段上的 Symfony2 数据转换器

coder 2024-04-26 原文

我已经搜索过,但没有找到遇到此问题的人。

我已经按照食谱中的说明创建了自己的 Data Transformer,看起来一切正常,但出现错误:

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

错误消息使我感到困惑,因为它似乎已将 BusinessUser 类转换为整数。我还尝试通过放入 data_class => null 然后加载表单,但是在提交时我得到一个错误,该字段为空,尽管隐藏字段中的 ID 在生成表单时正确显示。

有人能给我指出正确的方向吗,因为我觉得它很简单,但我没有看到。

谢谢

更新:我做了一些更改,意识到我应该在 Controller 中设置公司并将其传递到表单中,这一切似乎都有效,但是当提交表单时,我仍然在数据库中得到 null 或者如果我设置@Assert\NotBlank() 的字段表单不会提交,因为字段不能为空,即使当我检查源时我可以在隐藏字段中看到 BusinessUser 的 ID。

*更新 - 在实现下面 Coma 的建议时,我终于意识到我哪里出错了 - 是转换器没有返回对象 * - 如果其他人遇到这个问题,我会推荐 Coma 的下面的解决方案比每次都必须创建一个隐藏要好得多。如果是一次性解决方案,上面的解决方案已更新为返回对象并且应该可以正常工作。

最佳答案

这是我处理带有隐藏输入的实体的方式:

数据转换器

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

}

配置(服务.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');

然后在你的 Controller 中

$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 来设置转换器上的数据类是令人讨厌的,你怎么看?

关于php - 隐藏字段上的 Symfony2 数据转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16905490/

有关php - 隐藏字段上的 Symfony2 数据转换器的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  5. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  6. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  7. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  8. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  9. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  10. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

随机推荐