Php 使用'更新表格;选择列表';至Symfony>;=2.8

Php 使用'更新表格;选择列表';至Symfony>;=2.8,php,symfony,symfony-forms,Php,Symfony,Symfony Forms,我想将表单类更新为Symfony2.8(以及更高版本的Symfony3)。现在表单被转换,除了一个不再受支持的属性选项列表。我不知道该怎么做 我有以下也被定义为服务的表单类型: class ExampleType extends AbstractType { /** @var Delegate */ private $delegate; public function __construct(Delegate $delegate) { $thi

我想将表单类更新为Symfony2.8(以及更高版本的Symfony3)。现在表单被转换,除了一个不再受支持的属性
选项列表
。我不知道该怎么做

我有以下也被定义为服务的表单类型:

class ExampleType extends AbstractType
{

    /** @var Delegate */
    private $delegate;

    public function __construct(Delegate $delegate)
    {
        $this->delegate = $delegate;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('list', ChoiceType::class, array(
            'choice_list' => new ExampleChoiceList($this->delegate),
            'required'=>false)
        );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
            $resolver->setDefaults(array(
                'data_class' => 'ExampleClass',
            ));
    }
}
我有以下课程作为选择列表:

class ExampleChoiceList extends LazyChoiceList
{

    /** @var Delegate  */
    private $delegate;

    public function __construct(Delegate $delegate)
    {
        $this->delegate = $delegate;
    }


    /**
     * Loads the choice list
     * Should be implemented by child classes.
     *
     * @return ChoiceListInterface The loaded choice list
     */
    protected function loadChoiceList()
    {
        $persons = $this->delegate->getAllPersonsFromDatabase();
        $personsList = array();
        foreach ($persons as $person) {
            $id = $person->getId();
            $personsList[$id] = (string) $person->getLastname().', '.$person->getFirstname();
        }
        return new ArrayChoiceList($personsList);
    }


}

课堂示例ChoiceList生成了我想要的选项列表,直到现在它仍然有效。但是属性
choice\u list
不再受支持,我的问题是“如何在不做太多工作的情况下将其转换?”。我读到我应该使用简单的
选项
,但我如何在Symfony 2.8中获得我想要的(数据库中的特定标签)。我希望有人能帮助我。

是的,SYmfony 2.8不推荐使用“choice_list”,但您可以使用“choices”,它也接受数组。发件人:

选项是一个数组,其中数组键是项的 标签,数组值是项的值

您必须注意的是,在Symfony 3.0中,键和值是反向的,而在Symfony 2.8中,建议使用新的反向顺序,并将“选项”指定为“值”=>true

因此,在表单类型中:

$builder->add('list', ChoiceType::class, array(
               'choices' => new ExampleChoiceList($this->delegate),
               'choices_as_values' => true,
               'required'=>false));
例如,ChoiceList:

protected function loadChoiceList()
    {
        $persons = $this->delegate->getAllPersonsFromDatabase();
        $personsList = array();
        foreach ($persons as $person) {
            $id = $person->getId();
            $personsList[(string) $person->getLastname().', '.$person->getFirstname()] = $id; // <== here
        }
        return new ArrayChoiceList($personsList);
    }

通过使用
选择界面
,您就快到了

我建议您更改
示例ChoiceList
以实现
Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface
,它需要您实现3种方法:

<?php
// src/AppBundle/Form/ChoiceList/Loader/ExampleChoiceLoader.php

namespace AppBundle\Form\ChoiceList\Loader;

use Acme\SomeBundle\Delegate;
use Symfony\Component\Form\ArrayChoiceList;
use Symfony\Component\Form\Loader\ChoiceLoaderInterface;

class ExampleChoiceLoader implements ChoiceLoaderInterface
{
    /** $var ArrayChoiceList */
    private $choiceList;

    /** @var Delegate  */
    private $delegate;

    public function __construct(Delegate $delegate)
    {
        $this->delegate = $delegate;
    }

    /**
     * Loads the choice list
     * 
     * $value is a callable set by "choice_name" option
     *
     * @return ArrayChoiceList The loaded choice list
     */
    public function loadChoiceList($value = null)
    {
        if (null !== $this->choiceList) {
            return $this->choiceList;
        }

        $persons = $this->delegate->getAllPersonsFromDatabase();
        $personsList = array();
        foreach ($persons as $person) {
            $label = (string) $person->getLastname().', '.$person->getFirstname();
            $personsList[$label] = (string) $person->getId();
            // So $label will be displayed and the id will be used as data
            // "value" will be ids as strings and used for post
            // this is just a suggestion though
        }

        return $this->choiceList = new ArrayChoiceList($personsList);
    }

    /**
     * {@inheritdoc}
     *
     * $choices are entities or the underlying data you use in the field
     */
    public function loadValuesForChoices(array $choices, $value = null)
    {
        // optimize when no data is preset
        if (empty($choices)) {
            return array();
        }

        $values = array();
        foreach ($choices as $person) {
            $values[] = (string) $person->getId();
        }

        return $values;
    }

    /**
     * {@inheritdoc}
     * 
     * $values are the submitted string ids
     *
     */
    public function loadChoicesForValues(array $values, $value)
    {
        // optimize when nothing is submitted
        if (empty($values)) {
            return array();
        }

        // get the entities from ids and return whatever data you need.
        // e.g return $this->delegate->getPersonsByIds($values);
    }
}
然后将表单类型更改为使用加载器:

<?php
// src/AppBundle/Form/Type/ExampleType.php

namespace AppBundle\Form\Type;

use AppBundle\Form\ChoiceList\Loader\ExampleChoiceLoader;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class ExampleType extends AbstractType
{
    /** @var ExampleChoiceLoader */
    private $loader;

    public function __construct(ExampleChoiceLoader $loader)
    {
        $this->loader = $loader;
    }

    public function buildForm(FormBuilderInterface $builder, array $options = array())
    {
        $builder->add('list', ChoiceType::class, array(
            'choice_loader' => $this->loader,
            'required' => false,
        ));
    }

    // ...

}

很抱歉,您的解决方案无效。现在我得到了以下错误:
值为ExampleChoiceList的选项“choices”应为“null”或“array”或“\Traversable”类型,但类型为“ExampleChoiceList”。500内部服务器错误-无效选项异常
抱歉,没有查看ExampleCooiceList的详细信息。你能把LazyChoiceList的相关代码放进去看看扩展了什么吗?它来自Symfony:
名称空间Symfony\Component\Form\ChoiceList
。我用它来获取
choice\u列表的数据
,但它现在似乎出了问题。LazyChoiceList实现了
ChoiceListInterface
Ok,因此我建议做一些更简单的事情:使用EntityType而不是ChoiceType。请看我的更新。如果我使用条令进行数据库查询,这将是一个解决方案,但我不使用条令,我使用推进。所以在我的情况下,你的解决方案不起作用。但是谢谢你的帮助,谢谢你的帮助。我没有为每种类型的服务生成服务,我现在使用了
'choice\u loader'=>newexampleCooiceLoader($this->delegate),
。我为所有要扩展的案例编写了一个类,这样我只需实现
loadChoiceList
方法。如果我有10个不同类型的选项列表(我想为所有类型使用服务),那么我还必须为每个加载程序实现,并将它们全部放在构造函数中?因为在这种情况下,只有选择列表看起来有点太大了。当您将表单类型声明为服务时,您可以像往常一样简单地使用FQCN,注入由。因此,您不需要传递表单类型的构造实例。这样,它将在所有类型中只使用一个加载程序实例。也许你可以做一个抽象类型,所有需要加载程序的类型都可以扩展。是的,我已经做过了。我编写了一个抽象类,它实现了
ChoiceLoaderInterface
,并实现了
loadValuesForChoices
loadChoicesForValues
方法,因此只返回id而不返回对象。在我的选择列表中,我将类更改为
实现LazyChoiceList
扩展MyNewChoiceListHelper
并只编写
加载ChoiceList
方法。在这里,我只需要更改一些行(主要是更改数组标签和值)。因此,我可以在不做太多更改的情况下对其进行转换。
# app/config/services.yml

services:
    # ...
    app.delegate:
        class: Acme\SomeBundle\Delegate

    app.form.choice_loader.example:
        class: AppBundle\Form\ChoiceList\Loader\ExampleChoiceLoader
        arguments: ["@app.delegate"]

    app.form.type.example:
        class: AppBundle\Form\Type\ExampleType
        arguments: ["@app.form.choice_loader.example"]
<?php
// src/AppBundle/Form/Type/ExampleType.php

namespace AppBundle\Form\Type;

use AppBundle\Form\ChoiceList\Loader\ExampleChoiceLoader;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class ExampleType extends AbstractType
{
    /** @var ExampleChoiceLoader */
    private $loader;

    public function __construct(ExampleChoiceLoader $loader)
    {
        $this->loader = $loader;
    }

    public function buildForm(FormBuilderInterface $builder, array $options = array())
    {
        $builder->add('list', ChoiceType::class, array(
            'choice_loader' => $this->loader,
            'required' => false,
        ));
    }

    // ...

}