我遇到了一个问题,我无法自己解决嵌入式表格问题。
我将Silex 1.3与作曲家一起使用,composer.json
文件将在下面复制。我没有使用Doctrine,而且我制作了自己的DAO,因此我没有使用注释。
我认为我的问题来自我的验证或我的数据映射。
背景信息:我尝试使用以下对象:
Region
(如欧洲,北美等),Country
(法国,加拿大等)属于Region
(因此将其作为属性)State
(Ile de France,Quebec),属于Country
(因此将其作为属性)我的目标是使用我称之为SelectType
的内容,它基本上是一种允许我逐步选择某个对象的表单,而不必直接选择一个巨大的列表。
表单与对象具有相同的逻辑,我有:
RegionType
,允许我编辑或添加Region
,RegionSelectType
,允许我选择现有的Region
,CountryType
,使用RegionSelectType
,CountrySelectType
,其中RegionSelectType
允许我选择Region
,然后选择Country
中的Region
,StateType
,使用CountrySelectType
StateSelectType
当我尝试通过ajax或手动提交表单(StateType
)时,$form->isSumbitted()&&$form->isValid()
会返回true
,Region
已填充,但没有{填充{1}}(这是显而易见的,因为我没有选择它)。
我的表格有问题吗?
我注意到当我没有使用Country
时,一切都很顺利,但是当我为每个表单手动填充表单选项时(导致很多代码被重新调整)。表格已经过适当的验证。
感谢您的时间和帮助!
Composer.json:
SelectType
执行表单管理的StateController:
{
"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.*",
"symfony/monolog-bridge": "*"
},
"require-dev": {
"phpunit/phpunit": "*",
"symfony/browser-kit": "*",
"symfony/css-selector": "*",
"silex/web-profiler": "*"
},
"autoload":{
"psr-4":{"Easytrip2\\": "src"}
},
"autoload-dev":{
"psr-4":{"Easytrip2\\": "tests"}
}
}
public function stateAddAction(Request $request, Application $app) {
$formView = null;
if ($app ['security.authorization_checker']->isGranted ( 'ROLE_ADMIN' ) and $app ['security.authorization_checker']->isGranted ( 'ROLE_ADMIN' )) {
// A user is fully authenticated : he can add comments
$new = new State ();
$form = $app ['form.factory']->create ( new StateType ( $app ), $new );
$form->handleRequest ( $request );
//this returns true, event if the country is not filled.
if ($form->isSubmitted () && $form->isValid ()) {
if ($app ['dao.state']->save ( $new )) {
$app ['session']->getFlashBag ()->add ( 'success', 'Succesfully added.' );
return $app->redirect ( $app ['url_generator']->generate ( 'state' ) );
} else {
$app ['session']->getFlashBag ()->add ( 'error', 'Error in SQL ! Not added...' );
}
}
$formView = $form->createView ();
return $app ['twig']->render ( 'form.html.twig', array (
'title' => 'Add state',
'scripts_ids' => StateType::getRefNames (),
'form' => $formView
) );
} else {
$app ['session']->getFlashBag ()->add ( 'error', 'Don\'t have the rights...' );
return $app->redirect ( $app ['url_generator']->generate ( 'home' ) );
}
}
,基本上是注入应用程序以便能够使用DAO:
AbstractEasytrip2Type
<?php
namespace Easytrip2\Form;
use Silex\Application;
use Symfony\Component\Form\AbstractType;
abstract class AbstractEasytrip2Type extends AbstractType {
/**
*
* @var Application
*/
protected $app;
public function __construct(Application $app/*, $data*/) {
$this->app = $app;
}
public static function getRefNames() {
return null;
}
}
:
RegionSelectType
RegionSelectDataMapper:
<?php
namespace Easytrip2\Form\Select;
use Easytrip2\Form\AbstractEasytrip2Type;
use Easytrip2\Form\Select\DataMapper\RegionSelectDataMapper;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RegionSelectType extends AbstractEasytrip2Type {
public function buildForm(FormBuilderInterface $builder, array $options) {
$obj = $this->app ['dao.region']->findAll ();
$builder->add ( 'choice', 'choice', array (
'choices' => $obj,
'choices_as_values' => true,
'choice_label' => function ($value) {
// if nothing exists, then an empty label is generated.
return is_null ( $value ) ? "" : $value->getName ();
},
'choice_value' => function ($value) {
// here i only have int unsigned in database, so -1 is safe. This is probably used for comparison for selecting the stored object between the list and the stored object.
return is_null ( $value ) ? - 1 : $value->getId ();
},
'placeholder' => 'Select a region',
'label' => 'Region'
) );
$builder->setDataMapper ( new RegionSelectDataMapper () );
}
/**
*
* {@inheritDoc}
*
* @see \Symfony\Component\Form\AbstractType::setDefaultOptions()
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults ( array (
'data_class' => 'Easytrip2\Domain\Region',
'cascade_validation' => true
) );
}
public function getName() {
return 'region';
}
public static function getRefNames() {
return array ();
}
}
CountrySelectType:
<?php
namespace Easytrip2\Form\Select\DataMapper;
use Symfony\Component\Form\DataMapperInterface;
class RegionSelectDataMapper implements DataMapperInterface {
public function mapDataToForms($data, $forms) {
$forms = iterator_to_array ( $forms );
$forms ['choice']->setData ( $data );
}
public function mapFormsToData($forms, &$data) {
$forms = iterator_to_array ( $forms );
$data = $forms ['choice']->getData ();
}
}
CountrySelectDataMapper:
<?php
namespace Easytrip2\Form\Select;
use Easytrip2\Domain\Region;
use Easytrip2\Form\AbstractEasytrip2Type;
use Easytrip2\Form\Select\DataMapper\CountrySelectDataMapper;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class CountrySelectType extends AbstractEasytrip2Type {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add ( 'region', new RegionSelectType ( $this->app ), array (
'label' => false,
'cascade_validation' => true
) );
$builder->addEventListener ( FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$this->modifyFormFromRegion ( $event->getForm (), $event->getData () ? $event->getData ()->getRegion () : null );
} );
$builder->get ( 'region' )->addEventListener ( FormEvents::POST_SUBMIT, function (FormEvent $event) {
$this->modifyFormFromRegion ( $event->getForm ()->getParent (), $event->getForm ()->getData () );
} );
$builder->setDataMapper ( new CountrySelectDataMapper () );
}
public function modifyFormFromRegion(FormInterface $builder, Region $data = null) {
$obj = array ();
if (! is_null ( $data )) {
$obj = $this->app ['dao.country']->findByRegionId ( $data->getId () );
} else {
// change this if you do not want the country to be filled with all countries.
// $obj = $this->app ['dao.country']->findAll ();
$obj = array ();
}
$builder->add ( 'choice', 'choice', array (
'choices' => $obj,
'choices_as_values' => true,
'choice_label' => function ($value) {
// if nothing exists, then an empty label is generated.
return is_null ( $value ) ? "" : $value->getName ();
},
'choice_value' => function ($value) {
// here i only have int unsigned in database, so -1 is safe. This is probably used for comparison for selecting the stored object between the list and the stored object.
return is_null ( $value ) ? - 1 : $value->getId ();
},
'placeholder' => 'Select a country',
'label' => 'Country',
'required' => true,
'data_class' => 'Easytrip2\Domain\Country',
'cascade_validation' => true
) );
}
/**
*
* {@inheritDoc}
*
* @see \Symfony\Component\Form\AbstractType::setDefaultOptions()
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults ( array (
'data_class' => 'Easytrip2\Domain\Country',
'cascade_validation' => true
) );
}
function getName() {
return 'country';
}
public static function getRefNames() {
$ret = array (
'in' => 'country_region_choice',
'out' => 'country_choice'
);
return array (
$ret
);
}
}
StateType:
<?php
namespace Easytrip2\Form\Select\DataMapper;
use Symfony\Component\Form\DataMapperInterface;
class CountrySelectDataMapper implements DataMapperInterface {
public function mapDataToForms($data, $forms) {
$forms = iterator_to_array ( $forms );
$forms ['choice']->setData ( $data );
if (isset ( $forms ['region'] )) {
if ($data) {
$forms ['region']->setData ( $data->getRegion () );
}
}
}
public function mapFormsToData($forms, &$data) {
$forms = iterator_to_array ( $forms );
$data = $forms ['choice']->getData ();
// $data->getRegion() === $forms['']
}
}
答案 0 :(得分:1)
我设法在我的课程中使用loadValidatorMetadata
并使用一些解决方法。
这样,Silex进行验证,甚至将其发送给浏览器以基本验证数据。
我也简化了很多地图制作者。
如果您对此项目有任何疑问,请随时问我。
编辑:因为,我有:DataMappers
表单的select
cascade_validation
并使用data_class
setDefaultOptions
选项填充到我的表单中
loadValidatorMetadata
,我不确定它是否有所作为(也许它可以检查特定选择是否有效,由cascade_validation
触发?自从我修复它以来已经有很多时间了,所以我可能会在这里忘记一些事情。
但基本上,我理解的是我的验证没有正确进行,验证实体中的数据,将正确的数据映射到实体和级联验证以确保属性得到验证也是必要的。