- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
I have a
OneToMany
association between aServer
entity andClient
entities in the database. One server can have many clients. I want to make a form where the user can choose a server from a dropdown, fill in some details for a new client, and submit it.
要创建一个表单,用户可以在其中将数据输入到Client
的字段中,请从下拉列表中选择一个Server
,然后单击提交并获得此数据(以及association)通过 Doctrine 持续存在。
很简单吧?一定不行。我们会做到这一点。这是目前的漂亮形式:
注意事项:
Server
实体 (EntityRepository::findAll()
) 填充以我无限的智慧,我已经声明我的 Client
实体具有以下构造函数签名:
class Client
{
/** -- SNIP -- **/
public function __construct($type, $port, $endPoint, $authPassword, $authUsername);
/** -- SNIP -- **/
}
这不会改变。要创建有效的 Client
对象,存在上述构造函数参数。它们不是可选的,如果没有在对象实例化时给出上述参数,则无法创建此对象。
潜在问题:
type
属性是不可变的。一旦创建了客户端,就无法更改类型。
我没有type
的setter。它只是一个构造函数参数。这是因为一旦创建了客户端,您就不能更改类型。因此,我在实体级别强制执行此操作。因此,没有 setType()
或 changeType()
方法。
我没有标准的 setObject
命名约定。我声明要更改端口,例如,方法名称是 changePort()
而不是 setPort()
。在使用 ORM 之前,这就是我要求我的对象 API 运行的方式。
我正在使用 __toString()
连接 name
和 ipAddress
成员以显示在表单下拉列表中:
class Server
{
/** -- SNIP -- **/
public function __toString()
{
return sprintf('%s - %s', $this->name, $this->ipAddress);
}
/** -- SNIP -- **/
}
我使用 Building Forms with Entities 作为我的代码的基线。
这是我为构建表单而创建的 ClientType
:
class ClientType extends AbstractType
{
/**
* @var UrlGenerator
*/
protected $urlGenerator;
/**
* @constructor
*
* @param UrlGenerator $urlGenerator
*/
public function __construct(UrlGenerator $urlGenerator)
{
$this->urlGenerator = $urlGenerator;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** Dropdown box containing the server name **/
$builder->add('server', 'entity', [
'class' => 'App\Model\Entity\Server',
'query_builder' => function(ServerRepository $serverRepository) {
return $serverRepository->createQueryBuilder('s');
},
'empty_data' => '--- NO SERVERS ---'
]);
/** Dropdown box containing the client names **/
$builder->add('client', 'choice', [
'choices' => [
'transmission' => 'transmission',
'deluge' => 'deluge'
],
'mapped' => false
]);
/** The rest of the form elements **/
$builder->add('port')
->add('authUsername')
->add('authPassword')
->add('endPoint')
->add('addClient', 'submit');
$builder->setAction($this->urlGenerator->generate('admin_servers_add_client'))->setMethod('POST');
}
/**
* {@inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'data_class' => 'App\Model\Entity\Client',
'empty_data' => function(FormInterface $form) {
return new Client(
$form->getData()['client'],
$form->getData()['port'],
$form->getData()['endPoint'],
$form->getData()['authPassword'],
$form->getData()['authUsername']
);
}
]);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'client';
}
}
上面的代码实际上生成了要在客户端使用的表单(通过 twig)。
首先也是最重要的,使用上面的代码,提交表单会给我:
NoSuchPropertyException in PropertyAccessor.php line 456: Neither the property "port" nor one of the methods "addPort()"/"removePort()", "setPort()", "port()", "__set()" or "__call()" exist and have public access in class "App\Model\Entity\Client".
所以它找不到端口
方法。那是因为它是 changePort()
,正如我之前解释的那样。我如何告诉它应该使用 changePort()
来代替?根据 docs,我必须为端口、端点等使用 entity
类型。但它们只是文本字段。我该如何以正确的方式解决这个问题?
我试过:
['mapped' => false]
。这为所有客户端字段提供了 null
,但 确实如此 似乎有相关的服务器详细信息。无论如何,$form->isValid()
都会返回 false。以下是 var_dump()
向我显示的内容:基本上,“它不起作用”。但这就是我所知道的。 我做错了什么?我一遍又一遍地阅读手册,但一切都相距甚远,以至于我不知道我是否应该使用 DataTransformer 、 Entity Field Type 或其他方式。我几乎要完全放弃 Symfony/Forms,只用十分之一的时间自己写这个。
有人可以就如何到达我想去的地方给我一个可靠的答案吗?这也可能有助于 future 的用户:-)
最佳答案
There are a few problems with the above solution, so here's how I got it working!
事实证明,在 setDefaultOptions()
中,代码:$form->getData['key']
返回 null,因此屏幕截图中的所有 null .这需要更改为 $form->get('key')->getData()
return new Client(
$form->get('client')->getData(),
$form->get('port')->getData(),
$form->get('endPoint')->getData(),
$form->get('authPassword')->getData(),
$form->get('authUsername')->getData()
);
结果,数据按预期通过,所有值都完好无损(id 除外)。
根据documentation您可以在表单选项中设置 csrf_protection => false
。如果不这样做,则需要在表单中呈现隐藏的 csrf 字段:
{{ form_rest(form) }}
这会为您呈现其余的表单字段,包括隐藏的 _token
一个:
Symfony2 has a mechanism that helps to prevent cross-site scripting: they generate a CSRF token that have to be used for form validation. Here, in your example, you're not displaying (so not submitting) it with form_rest(form). Basically form_rest(form) will "render" every field that you didn't render before but that is contained into the form object that you've passed to your view. CSRF token is one of those values.
这是我在解决上述问题后遇到的错误:
The CSRF token is invalid. Please try to resubmit the form.
我正在使用 Silex,在注册 FormServiceProvider 时,我有以下内容:
$app->register(new FormServiceProvider, [
'form.secret' => uniqid(rand(), true)
]);
This Post显示 Silex 如何为您提供一些已弃用的 CsrfProvider 代码:
Turned out it was not due to my ajax, but because Silex gives you a deprecated DefaultCsrfProvider which uses the session ID itself as part of the token, and I change the ID randomly for security. Instead, explicitly telling it to use the new CsrfTokenManager fixes it, since that one generates a token and stores it in the session, such that the session ID can change without affecting the validity of the token.
因此,我不得不删除 form.secret 选项,并将以下内容添加到我的应用程序 Bootstrap 中,在注册表单提供程序之前:
/** Use a CSRF provider that does not depend on the session ID being constant. We change the session ID randomly */
$app['form.csrf_provider'] = $app->share(function ($app) {
$storage = new Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage($app['session']);
return new Symfony\Component\Security\Csrf\CsrfTokenManager(null, $storage);
});
通过上述修改,现在表单发布并且数据正确保存在数据库中,包括学说协会!
关于php - 使用 Symfony2 的表单 - 具有一些不可变构造函数参数和 OneToMany 关联的 Doctrine Entity,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24530776/
为什么禁用类型像 type t = A of int | B of string * mutable int 虽然允许此类类型: type t = A of int | B of string * i
我正在寻找一种类似结构的数据结构,我可以从中创建多个实例并具有某种类型提示而不是不可变的。 所以我有这样的东西: class ConnectionConfig(NamedTuple): nam
我需要转到引用的结构: class SearchKnot { var isWord : Bool = false var text : String = "" var to
如sec 10.4.3中所述 当控制进入执行时,执行以下步骤 功能对象F(调用者)中包含的功能代码的上下文 提供thisArg,而调用方提供argumentsList: 如
i make a game that start display Activity indicator And activity indicator bottom display UiLable wi
编辑:我在这里不断获得支持。只是为了记录,我认为这不再重要。自从我发布它以来我就不再需要它了。 我想在 Scala 中执行以下操作... def save(srcPath: String, destP
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
如果您在Kotlin中访问List类型的Java值,则将获得(Mutable)List!类型。 例如。: Java代码: public class Example { public stati
我编写了 str 类(内置)的以下扩展,以便执行以下操作:假设我有字符串 "Ciao" ,通过做"Ciao" - "a"我想要的结果是字符串 "Cio" 。这是执行此操作的代码,并且运行良好: cla
使用可变对象作为 Hashmap 键是一种不好的做法吗?当您尝试使用已修改足以更改其哈希码的键从 HashMap 中检索值时,会发生什么? 例如,给定 class Key { int a; /
我正在为我的公司设计一个数据库来管理商业贷款。每笔贷款都可以有担保人,可以是个人或公司,在借款业务失败时作为财务支持。 我有 3 个表:Loan、Person 和 Company,它们存储明显的信息。
我使用二进制序列化从 C# 类中保存 F# 记录。一切正常: F#: type GameState = { LevelStatus : LevelStatus
import javax.swing.JOptionPane; public class HW { public static void main(String[] args) { Strin
使用 flatbuffer mutable 有多少性能损失? 是否“正确”使用 FlatBuffers 来拥有一个应该可编辑的对象/结构(即游戏状态) 在我的示例中,我现在有以下类: class Ga
std::function create_function (args...) { int x = initial_value (args...); return [x] () mut
我需要在 for 循环中找到用户输入的字符。我通常会这样做 如果(句子[i] == 'e') 但是因为在这里,'e' 将是一个单字母字符变量,我不知道如何获取要比较的值。我不能只输入 if (sent
我有一个这样的算法: let seed: Foo = ... let mut stack: Vec = Vec::new(); stack.push(&seed); while let Some(ne
这个问题可能看起来非常基础,但我很难弄清楚如何做。我有一个整数,我需要使用 for 循环来循环整数次。 首先,我尝试了—— fn main() { let number = 10; // An
如果我有以下结构: struct MyStruct { tuple: (i32, i32) }; 以及以下函数: // This will not compile fn function(&mut s
我希望在每个 session 的基础上指定列的默认值。下面的脚本不起作用,但描述了我想如何使用它。我目前使用的是 MySQL 5.5.28,但如果需要可以升级。 CREATE TABLE my_tbl
我是一名优秀的程序员,十分优秀!