Silex - Symfony2:自动填充文本表单的表单,而不是选择
Silex - Symfony2 : Forms autofilled for text forms, not for choices
首先,祝大家2016年新年快乐!
我遇到了一个我自己无法解决的问题。
我正在开发 Silex (~1.3
) 应用程序。我在我的域 classes 上编写了简单的 CRUD。我还创建了一些类型表单,以便能够修改我的基本域 classes。在这种情况下,我必须在 Country
中管理 State
的概念。每个都是一个特定的 class,State
有一个 Country
属性。
在我的表格中,我声明了一些文本字段,以及一个 Choice
字段,以便能够 select 国家(下面复制表格 class)。
我的问题是,当我尝试使用以下控制器修改现有 State
时,文本字段 name
、code
、unloc
填充了来自数据库的数据,但不是选项 country
或 hub
(下面复制了控制器 class)。
请注意,我使用的不是 Doctrine,而是一个自制的(非常基本的)DAO。
这是我的代码和一些信息:
视图是使用 twig 完成的,'standard' bootstrap 示例可在此处找到:Form Customization, using Bootstrap layout and Form layout:
{% extends 'layout.html.twig' %} {% block title %}{{ title }}{% endblock %}
{% block content %}
{% if form and is_granted('IS_AUTHENTICATED_FULLY') and is_granted('ROLE_ADMIN')%}
{% form_theme form 'bootstrap_3_layout.html.twig' %} {{ form_start(form) }}
<div class="form-group">
{{ form_errors(form) }}
{{ form_widget(form) }}
<input type="submit" class="btn btn-primary" value={% if button is not defined %} "Save"{% else %}"{{ button }}"{% endif %} />
</div>
{{ form_end(form) }}
{% else %}
<div>
<p>Ask an admin to add/modify information.</p>
</div>
{% endif %}
{% endblock %}
composer.json内容:
{
"require": {
"silex/silex": "~1.3",
"doctrine/dbal": "2.5.*",
"symfony/security": "2.7.*",
"twig/twig": "1.21.*",
"symfony/twig-bridge": "2.7.*",
"symfony/form": "2.7.*",
"symfony/translation": "2.7.*",
"symfony/config": "2.7.*",
"jasongrimes/silex-simpleuser": "*",
"twig/extensions": "1.3.*",
"symfony/validator": "2.*",
"phpoffice/phpexcel": "1.*"
},
"require-dev": {
"phpunit/phpunit": "*",
"symfony/browser-kit": "*",
"symfony/css-selector": "*",
"silex/web-profiler": "*",
"symfony/monolog-bridge": "*"
},
"autoload":{
"psr-4":{"Easytrip2\": "src"}
}
}
表格代码:
<?php
namespace Easytrip2\Form\Type;
use Easytrip2\DAO\CountryDAO;
use Easytrip2\DAO\GeopointDAO;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class StateType extends AbstractType {
/**
* @CountryDAO
* \Easytrip2\DAO\CountryDAO
* allow to find the Country for the form.
*/
private $countryDAO;
/**
* @GeopointDAO
* \Easytrip2\DAO\GeopointDAO
* allow to find the Country for the form.
*/
private $geopointDAO;
/**
*
* {@inheritDoc}
*
* @see \Symfony\Component\Form\AbstractType::buildForm()
*/
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add ( 'name', 'text', array (
'label' => 'State name'
) );
$builder->add ( 'code', 'text', array (
'label' => 'State code'
) );
$builder->add ( 'unloc', 'text', array (
'label' => 'State code'
) );
$countries = $this->countryDAO->findAll ();
$choices = array ();
$labels = array ();
foreach ( $countries as $value ) {
$choices [] = $value;
$labels [] = $value->getName ();
}
$builder->add ( 'country', 'choice', array (
'choice_list' => new ChoiceList ( $choices, $labels )
) );
$hubs = $this->geopointDAO->findAllHubs ();
$choices = array ();
$labels = array ();
foreach ( $hubs as $value ) {
$choices [] = $value;
$labels [] = $value->getName ();
}
$builder->add ( 'hub', 'choice', array (
'choice_list' => new ChoiceList ( $choices, $labels ),
'required' => false
) );
}
/**
*
* {@inheritDoc}
*
* @see \Symfony\Component\Form\AbstractType::configureOptions()
*/
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults ( array (
'data_class' => 'Easytrip2\Domain\State'
) );
}
/**
*
* {@inheritDoc}
*
* @see \Symfony\Component\Form\FormTypeInterface::getName()
*/
public function getName() {
return 'state';
}
/**
* allow use of a CountryDAO
*/
public function __construct(CountryDAO $countryDAO, GeopointDAO $geopointDAO) {
$this->geopointDAO = $geopointDAO;
$this->countryDAO = $countryDAO;
}
}
控制器内容:
public function stateUpdateByIdAction($id, Request $request, Application $app) {
if ($app ['security.authorization_checker']->isGranted ( 'IS_AUTHENTICATED_FULLY' ) and $app ['security.authorization_checker']->isGranted ( 'ROLE_ADMIN' )) {
$obj = $app ['dao.state']->findById ( $id );
$form = $app ['form.factory']->create ( new StateType ( $app ['dao.country'], $app ['dao.geopoint'] ), $obj );
$form->handleRequest ( $request );
if ($form->isSubmitted () && $form->isValid ()) {
if ($app ['dao.state']->save ( $obj )) {
$app ['session']->getFlashBag ()->add ( 'success', 'The state was succesfully updated.' );
return $app->redirect ( $app ['url_generator']->generate ( 'state' ) );
} else {
$app ['session']->getFlashBag ()->add ( 'error', 'Something went wrong...' );
}
}
return $app ['twig']->render ( 'form.html.twig', array (
'form' => $form->createView (),
'title' => 'Edit states'
) );
} else {
$app ['session']->getFlashBag ()->add ( 'error', 'Don\'t have the rights...' );
return $app->redirect ( $app ['url_generator']->generate ( 'home' ) );
}
}
假设由于国家和枢纽id没有传输到ChoiceList,所以选择没有填充来自DB的数据
$choices = array();
foreach ($countries as $value) {
$choices[$value->getId()] = $value->getName();
}
$builder->add('country', 'choice', array(
'choices' => $choices
));
我设法找到了解决方案(可能不是最好的,但它有效)。
我的理解是:我们将对象作为 choices
,将其用作值,然后使用闭包获取 ids
和 labels
,而不是进行工作我们自己并向表格提供 'ready-to-use' 数据。
有更简洁的方法吗?
$obj = $this->countryDAO->findAll ();
$list = array ();
foreach ( $obj as $value ) {
$list [$value->getId ()] = $value;
}
$builder->add ( 'country', 'choice', array (
'choices' => $list,
'choices_as_values' => true,
'choice_label' => function ($value) {
return $value->getName ();
},
'choice_value' => function ($value) {
// you mightwant to check for null here, is your form concern
// a attribute that can be null, as the closure appear to be called
// on the attribute, and not only on the $obj contents;
return $value->getId ();
},
'placeholder' => 'Select a country'
) );
将此行添加到您的选择选项中:
'choices_as_values' => true,
必须激活新的选择类型API
http://symfony.com/doc/current/reference/forms/types/choice.html#example-usage
首先,祝大家2016年新年快乐!
我遇到了一个我自己无法解决的问题。
我正在开发 Silex (~1.3
) 应用程序。我在我的域 classes 上编写了简单的 CRUD。我还创建了一些类型表单,以便能够修改我的基本域 classes。在这种情况下,我必须在 Country
中管理 State
的概念。每个都是一个特定的 class,State
有一个 Country
属性。
在我的表格中,我声明了一些文本字段,以及一个 Choice
字段,以便能够 select 国家(下面复制表格 class)。
我的问题是,当我尝试使用以下控制器修改现有 State
时,文本字段 name
、code
、unloc
填充了来自数据库的数据,但不是选项 country
或 hub
(下面复制了控制器 class)。
请注意,我使用的不是 Doctrine,而是一个自制的(非常基本的)DAO。
这是我的代码和一些信息:
视图是使用 twig 完成的,'standard' bootstrap 示例可在此处找到:Form Customization, using Bootstrap layout and Form layout:
{% extends 'layout.html.twig' %} {% block title %}{{ title }}{% endblock %} {% block content %} {% if form and is_granted('IS_AUTHENTICATED_FULLY') and is_granted('ROLE_ADMIN')%} {% form_theme form 'bootstrap_3_layout.html.twig' %} {{ form_start(form) }} <div class="form-group"> {{ form_errors(form) }} {{ form_widget(form) }} <input type="submit" class="btn btn-primary" value={% if button is not defined %} "Save"{% else %}"{{ button }}"{% endif %} /> </div> {{ form_end(form) }} {% else %} <div> <p>Ask an admin to add/modify information.</p> </div> {% endif %} {% endblock %}
composer.json内容:
{ "require": { "silex/silex": "~1.3", "doctrine/dbal": "2.5.*", "symfony/security": "2.7.*", "twig/twig": "1.21.*", "symfony/twig-bridge": "2.7.*", "symfony/form": "2.7.*", "symfony/translation": "2.7.*", "symfony/config": "2.7.*", "jasongrimes/silex-simpleuser": "*", "twig/extensions": "1.3.*", "symfony/validator": "2.*", "phpoffice/phpexcel": "1.*" }, "require-dev": { "phpunit/phpunit": "*", "symfony/browser-kit": "*", "symfony/css-selector": "*", "silex/web-profiler": "*", "symfony/monolog-bridge": "*" }, "autoload":{ "psr-4":{"Easytrip2\": "src"} } }
表格代码:
<?php namespace Easytrip2\Form\Type; use Easytrip2\DAO\CountryDAO; use Easytrip2\DAO\GeopointDAO; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class StateType extends AbstractType { /** * @CountryDAO * \Easytrip2\DAO\CountryDAO * allow to find the Country for the form. */ private $countryDAO; /** * @GeopointDAO * \Easytrip2\DAO\GeopointDAO * allow to find the Country for the form. */ private $geopointDAO; /** * * {@inheritDoc} * * @see \Symfony\Component\Form\AbstractType::buildForm() */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add ( 'name', 'text', array ( 'label' => 'State name' ) ); $builder->add ( 'code', 'text', array ( 'label' => 'State code' ) ); $builder->add ( 'unloc', 'text', array ( 'label' => 'State code' ) ); $countries = $this->countryDAO->findAll (); $choices = array (); $labels = array (); foreach ( $countries as $value ) { $choices [] = $value; $labels [] = $value->getName (); } $builder->add ( 'country', 'choice', array ( 'choice_list' => new ChoiceList ( $choices, $labels ) ) ); $hubs = $this->geopointDAO->findAllHubs (); $choices = array (); $labels = array (); foreach ( $hubs as $value ) { $choices [] = $value; $labels [] = $value->getName (); } $builder->add ( 'hub', 'choice', array ( 'choice_list' => new ChoiceList ( $choices, $labels ), 'required' => false ) ); } /** * * {@inheritDoc} * * @see \Symfony\Component\Form\AbstractType::configureOptions() */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults ( array ( 'data_class' => 'Easytrip2\Domain\State' ) ); } /** * * {@inheritDoc} * * @see \Symfony\Component\Form\FormTypeInterface::getName() */ public function getName() { return 'state'; } /** * allow use of a CountryDAO */ public function __construct(CountryDAO $countryDAO, GeopointDAO $geopointDAO) { $this->geopointDAO = $geopointDAO; $this->countryDAO = $countryDAO; } }
控制器内容:
public function stateUpdateByIdAction($id, Request $request, Application $app) { if ($app ['security.authorization_checker']->isGranted ( 'IS_AUTHENTICATED_FULLY' ) and $app ['security.authorization_checker']->isGranted ( 'ROLE_ADMIN' )) { $obj = $app ['dao.state']->findById ( $id ); $form = $app ['form.factory']->create ( new StateType ( $app ['dao.country'], $app ['dao.geopoint'] ), $obj ); $form->handleRequest ( $request ); if ($form->isSubmitted () && $form->isValid ()) { if ($app ['dao.state']->save ( $obj )) { $app ['session']->getFlashBag ()->add ( 'success', 'The state was succesfully updated.' ); return $app->redirect ( $app ['url_generator']->generate ( 'state' ) ); } else { $app ['session']->getFlashBag ()->add ( 'error', 'Something went wrong...' ); } } return $app ['twig']->render ( 'form.html.twig', array ( 'form' => $form->createView (), 'title' => 'Edit states' ) ); } else { $app ['session']->getFlashBag ()->add ( 'error', 'Don\'t have the rights...' ); return $app->redirect ( $app ['url_generator']->generate ( 'home' ) ); } }
假设由于国家和枢纽id没有传输到ChoiceList,所以选择没有填充来自DB的数据
$choices = array();
foreach ($countries as $value) {
$choices[$value->getId()] = $value->getName();
}
$builder->add('country', 'choice', array(
'choices' => $choices
));
我设法找到了解决方案(可能不是最好的,但它有效)。
我的理解是:我们将对象作为 choices
,将其用作值,然后使用闭包获取 ids
和 labels
,而不是进行工作我们自己并向表格提供 'ready-to-use' 数据。
有更简洁的方法吗?
$obj = $this->countryDAO->findAll ();
$list = array ();
foreach ( $obj as $value ) {
$list [$value->getId ()] = $value;
}
$builder->add ( 'country', 'choice', array (
'choices' => $list,
'choices_as_values' => true,
'choice_label' => function ($value) {
return $value->getName ();
},
'choice_value' => function ($value) {
// you mightwant to check for null here, is your form concern
// a attribute that can be null, as the closure appear to be called
// on the attribute, and not only on the $obj contents;
return $value->getId ();
},
'placeholder' => 'Select a country'
) );
将此行添加到您的选择选项中:
'choices_as_values' => true,
必须激活新的选择类型API http://symfony.com/doc/current/reference/forms/types/choice.html#example-usage