Doctrine OneToOne Bi- and Unidirectional with ZF2 Fieldsets not saving/hydrating
Doctrine OneToOne Bi- and Unidirectional with ZF2 Fieldsets not saving/hydrating
我有 2 个 Doctrine 实体(Environment
和 EnvironmentConfig
)。他们有 bi-directional OneToOne 关系。
每个实体都有自己的 Fieldset,因此很容易重复使用。
要创建一个 Environment
它也可以有一个 EnvironmentConfig
,但不是必需的。为了允许它们同时制作,我有一个使用 EnvironmentFieldset
和 EnvironmentConfigFieldset
.
的 EnvironmentForm
表单正确呈现。但是,它保存 Environment
而不是 EnvironmentConfig
。
我的设置哪里出错了,如何解决?
下面的代码,省略 getters/setters 会太多。
实体
// abstract class AbstractEntity has $id + getters/setters.
class Environment extends AbstractEntity
{
/**
* @var string
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* @var EnvironmentConfig
* @ORM\OneToOne(targetEntity="Environment\Entity\EnvironmentConfig", inversedBy="environment")
*/
protected $config;
/**
* @var EnvironmentScript
* @ORM\OneToOne(targetEntity="EnvironmentScript")
*/
protected $script;
//Getters/setters
}
class EnvironmentConfig extends AbstractEntity
{
/**
* @var string
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* @var Environment
* @ORM\OneToOne(targetEntity="Environment\Entity\Environment", mappedBy="config")
*/
protected $environment;
//Getters/setters
}
字段集
class EnvironmentFieldset extends AbstractFieldset
{
/**
* {@inheritdoc}
*/
public function init()
{
//Loads id element validation
parent::init();
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
'label_attributes' => [
'class' => 'col-xs-2 col-form-label',
],
],
'attributes' => [
'id' => 'name',
'class' => 'form-control'
],
]);
$this->add([
'name' => 'environment_config',
'type' => EnvironmentConfigFieldset::class,
'options' => [
'use_as_base_fieldset' => false,
],
]);
$this->add([
'type' => ObjectSelect::class,
'name' => 'environment_script',
'options' => [
'object_manager' => $this->getEntityManager(),
'target_class' => EnvironmentScript::class,
'property' => 'id',
'display_empty_item' => true,
'empty_item_label' => '---',
'label_generator' => function ($targetEntity) {
return $targetEntity->getId() . ' - ' . $targetEntity->getName();
},
],
]);
}
}
class EnvironmentConfigFieldset extends AbstractFieldset
{
/**
* {@inheritdoc}
*/
public function init()
{
//Loads id element validation
parent::init();
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
'label_attributes' => [
'class' => 'col-xs-2 col-form-label',
],
],
'attributes' => [
'id' => 'name',
'class' => 'form-control'
],
]);
}
}
表格
class EnvironmentForm extends AbstractForm
{
/**
* EnvironmentForm constructor.
* @param null $name
* @param array $options
*/
public function __construct($name = null, array $options)
{
//Also adds CSRF
parent::__construct($name, $options);
}
/**
* {@inheritdoc}
*/
public function init()
{
//Call parent initializer. Adds submit button.
parent::init();
$this->add([
'name' => 'environment',
'type' => EnvironmentFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
}
}
编辑:添加调试数据和AddAction()
以上调试在下面函数的 persist()
行完成。
public function addAction($formName, array $formOptions = null, $route, array $routeParams = [])
{
if (!$this->formElementManager instanceof FormElementManagerV2Polyfill) {
throw new InvalidArgumentException('Dependency FormElementManagerV2Polyfill not set. Please check Factory for this function.');
}
if (!class_exists($formName)) {
throw new ClassNotFoundException('Given class could not be found. Does it exist?');
}
/** @var AbstractForm $form */
$form = $this->getFormElementManager()->get($formName, (is_null($formOptions) ? [] : $formOptions));
/** @var Request $request */
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$entity = $form->getObject();
$this->getEntityService()->getEntityManager()->persist($entity);
$this->getEntityService()->getEntityManager()->flush();
$this->flashMessenger()->addSuccessMessage(
_('Successfully created object.')
);
$this->redirectToRoute($route, $this->getRouteParams($entity, $routeParams));
}
}
return [
'form' => $form,
'validationMessages' => $form->getMessages() ?: '',
];
}
您创建了一个名为 'environment_config'
的字段,但在 class Environment
中您调用了 protected $config;
。两个名称必须相同。 'environment_script'
字段和 $script
属性存在同样的问题。
另一件事,您想动态创建一个 EnvironmentConfig
,因此您必须在 $config
注释中添加一个 cascade
选项,以便能够从 Environment
:
/**
* @var EnvironmentConfig
* @ORM\OneToOne(targetEntity="Environment\Entity\EnvironmentConfig", inversedBy="environment", cascade={"persist"})
*/
protected $config;
我有 2 个 Doctrine 实体(Environment
和 EnvironmentConfig
)。他们有 bi-directional OneToOne 关系。
每个实体都有自己的 Fieldset,因此很容易重复使用。
要创建一个 Environment
它也可以有一个 EnvironmentConfig
,但不是必需的。为了允许它们同时制作,我有一个使用 EnvironmentFieldset
和 EnvironmentConfigFieldset
.
EnvironmentForm
表单正确呈现。但是,它保存 Environment
而不是 EnvironmentConfig
。
我的设置哪里出错了,如何解决?
下面的代码,省略 getters/setters 会太多。
实体
// abstract class AbstractEntity has $id + getters/setters.
class Environment extends AbstractEntity
{
/**
* @var string
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* @var EnvironmentConfig
* @ORM\OneToOne(targetEntity="Environment\Entity\EnvironmentConfig", inversedBy="environment")
*/
protected $config;
/**
* @var EnvironmentScript
* @ORM\OneToOne(targetEntity="EnvironmentScript")
*/
protected $script;
//Getters/setters
}
class EnvironmentConfig extends AbstractEntity
{
/**
* @var string
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* @var Environment
* @ORM\OneToOne(targetEntity="Environment\Entity\Environment", mappedBy="config")
*/
protected $environment;
//Getters/setters
}
字段集
class EnvironmentFieldset extends AbstractFieldset
{
/**
* {@inheritdoc}
*/
public function init()
{
//Loads id element validation
parent::init();
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
'label_attributes' => [
'class' => 'col-xs-2 col-form-label',
],
],
'attributes' => [
'id' => 'name',
'class' => 'form-control'
],
]);
$this->add([
'name' => 'environment_config',
'type' => EnvironmentConfigFieldset::class,
'options' => [
'use_as_base_fieldset' => false,
],
]);
$this->add([
'type' => ObjectSelect::class,
'name' => 'environment_script',
'options' => [
'object_manager' => $this->getEntityManager(),
'target_class' => EnvironmentScript::class,
'property' => 'id',
'display_empty_item' => true,
'empty_item_label' => '---',
'label_generator' => function ($targetEntity) {
return $targetEntity->getId() . ' - ' . $targetEntity->getName();
},
],
]);
}
}
class EnvironmentConfigFieldset extends AbstractFieldset
{
/**
* {@inheritdoc}
*/
public function init()
{
//Loads id element validation
parent::init();
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
'label_attributes' => [
'class' => 'col-xs-2 col-form-label',
],
],
'attributes' => [
'id' => 'name',
'class' => 'form-control'
],
]);
}
}
表格
class EnvironmentForm extends AbstractForm
{
/**
* EnvironmentForm constructor.
* @param null $name
* @param array $options
*/
public function __construct($name = null, array $options)
{
//Also adds CSRF
parent::__construct($name, $options);
}
/**
* {@inheritdoc}
*/
public function init()
{
//Call parent initializer. Adds submit button.
parent::init();
$this->add([
'name' => 'environment',
'type' => EnvironmentFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
}
}
编辑:添加调试数据和AddAction()
以上调试在下面函数的 persist()
行完成。
public function addAction($formName, array $formOptions = null, $route, array $routeParams = [])
{
if (!$this->formElementManager instanceof FormElementManagerV2Polyfill) {
throw new InvalidArgumentException('Dependency FormElementManagerV2Polyfill not set. Please check Factory for this function.');
}
if (!class_exists($formName)) {
throw new ClassNotFoundException('Given class could not be found. Does it exist?');
}
/** @var AbstractForm $form */
$form = $this->getFormElementManager()->get($formName, (is_null($formOptions) ? [] : $formOptions));
/** @var Request $request */
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$entity = $form->getObject();
$this->getEntityService()->getEntityManager()->persist($entity);
$this->getEntityService()->getEntityManager()->flush();
$this->flashMessenger()->addSuccessMessage(
_('Successfully created object.')
);
$this->redirectToRoute($route, $this->getRouteParams($entity, $routeParams));
}
}
return [
'form' => $form,
'validationMessages' => $form->getMessages() ?: '',
];
}
您创建了一个名为 'environment_config'
的字段,但在 class Environment
中您调用了 protected $config;
。两个名称必须相同。 'environment_script'
字段和 $script
属性存在同样的问题。
另一件事,您想动态创建一个 EnvironmentConfig
,因此您必须在 $config
注释中添加一个 cascade
选项,以便能够从 Environment
:
/**
* @var EnvironmentConfig
* @ORM\OneToOne(targetEntity="Environment\Entity\EnvironmentConfig", inversedBy="environment", cascade={"persist"})
*/
protected $config;