Zend\Form\Fieldset
sとZend\Form\Collections
は入れ子にすることができ、複雑なオブジェクト構造をそれらにマップする非常に快適な方法を提供し、フォーム入力からcomleteオブジェクト(保存する準備ができている)を多少自動的に得ることができます。 Form Collections tutorialは非常に良い例です。データベースとZF2アプリケーションで異なる参照方向を扱うにはどうすればよいですか?
私が現在持っているケースは、参照反転を含んでいるため、少し複雑です。それは意味:
私は2つのエンティティがある - MyA
とMyB
を、データベースにそれらの間の関係はmyb.mya_id
からmya.id
にFOREIGN KEY
として実装されている間、アプリケーションが反転参照使用している:
MyA has MyB
しますか、いくつかのコードを::
namespace My\DataObject;
class MyA {
/**
* @var integer
*/
private $id;
/*
* @var text
*/
private $foo;
/**
* @var MyB
*/
private $myB;
}
namespace My\DataObject;
class MyB {
/**
* @var integer
*/
private $id;
/*
* @var text
*/
private $bar;
/*
Actually it's even bidirectional, but it's not crucial for this issue.
For this problem it's not important,
wheter the class MyB has a property of type MyA.
We get the issue already,
when we define a property of type MyB in the class MyA.
Since the direction of the reference MyA.myB->MyB differes
from the direction of the reference my_b.my_a.id->my_a.id.
*/
/**
* @var MyA
*/
// private $myA;
}
私Mapper
オブジェクトが引数として渡さDataObject
秒を取得しますおよびMyBMapper#save(MyB $object)
。意味
namespace My\Mapper;
use ...
class MyAMapper
{
...
public fuction save(MyA $object)
{
// save the plain MyA propertis a new entry in the my_a table
...
$myMapperB->save($myA->getMyB());
}
}
namespace My\Mapper;
use ...
class MyBMapper
{
...
public fuction save(MyB $object)
{
// save the plain MyB propertis a new entry in the my_b table
...
}
}
、MyAMapper#save(...)
はevrythingがmy_a
テーブルにMyA
オブジェクトを保存するのに必要があります。しかしMyBMapper
にはmy_b.my_a_id
のデータがありません。
そして私はまた、(MyBMapper#save(...)
にmy_b.my_a_id
のためにデータを渡すために)MyA#MyB#MyA
を埋めるためにMyAFieldset
にネストされたフィールドセットMyBFieldset
と巣フィールドセットMyBFieldset
とフィールドセットMyAFieldset
を作成することはできません。
class MyAFieldset {
$this->add([
'name' => 'my_b',
'type' => 'My\Form\Fieldset\MyBFieldset',
'options' => []
]);
}
class MyBFieldset {
$this->add([
'name' => 'my_a',
'type' => 'My\Form\Fieldset\MyAFieldset',
'options' => []
]);
}
これは再帰的な依存関係を引き起こし、動作しません。
アプリケーションレベルの参照方向がデータベースの方向と異なる場合のケースの処理方法はありますか?どのように完全な( "保存する準備ができて")オブジェクトを提供するフィールドセット構造を作成するには?
回避策1
フォームは、フォームから得た、処理され、さらにMyA
オブジェクトを作成することができ、MyB
オブジェクトに追加:多分、
class MyConrtoller {
...
public function myAction() {
$this->myForm->bind($this->myA);
$request = $this->getRequest();
$this->myForm->setData($request->getPost());
// here the hack #start#
$this->myB->setMyA($this->myA);
// here the hack #stop#
$this->myAService->saveMyA($this->myA);
}
}
コントローラーではなく、マッパーがそれより良い場所かもしれません:
class MyAMapper
{
...
public function save(MyA $myA)
{
$data = [];
$data['foo'] = [$myA->getFoo()];
// common saving stuff #start#
$action = new Insert('my_a');
$action->values($data);
$sql = new Sql($this->dbAdapter);
$statement = $sql->prepareStatementForSqlObject($action);
$result = $statement->execute();
$newId = $result->getGeneratedValue()
// common saving stuff #stop#
...
// hack #start#
if(! $myA->getB->getA()) {
$myA->getB->setA(new MyA());
$myA->getB->getA()->setId($newId);
}
// hack #stop#
// and only after all that we can save the MyB
$myB = $this->myBMapper->save($myB);
$myA->setMyB($myB);
...
}
}
しかし、とにかくそれはちょうどハックです。
回避策2
MyB
クラスはプロパティ$myAId
を取得します。しかし、それはまたクリーンな方法ではありません。
MyBFieldset
策3サブフィールドセットとしてMyAFieldsetFake
を取得します。このフィールドセットクラスは、MyA
データオブジェクトのための唯一のID
が含まれていMyAFieldset
の単なる「浅い」コピー、次のとおりです。
class MyAFieldset {
...
public function init()
{
$this->add([
'type' => 'text',
'name' => 'id',
'options' => [...],
]);
$this->add([
'type' => 'text',
'name' => 'foo',
'options' => [...],
]);
}
}
class MyAFieldset {
...
public function init()
{
$this->add([
'type' => 'text',
'name' => 'id',
'options' => [...],
]);
$this->add([
'type' => 'text',
'name' => 'bar',
'options' => [...],
]);
$this->add([
'type' => 'text',
'name' => 'foo',
'type' => 'My\Form\Fieldset\MyAFakeFieldset',
'options' => [...],
]);
}
}
class MyAFieldset {
...
public function init()
{
$this->add([
'type' => 'text',
'name' => 'id',
'options' => [...],
]);
}
}
しかし、偽のオブジェクトも少し汚れています。
データベースの逆転が私の意見ではオブジェクトの関係に影響しないので、私は複雑さを正しく理解しているかわかりません。 doctrineについて読むことができれば、すべての関係に所有側と逆側があり、実際のデータベース関係を示すことができます。私の意見では、クリーンな実装は、あなたがオブジェクトのリレーションシップをどのように見るかです。 myAにはmyBがあるので、myAとmyBの両方のオブジェクトを保存するようにmyAを選択できます。 – Pradeep
コメントありがとうございます!実際、私は重要な精神的なステップについては説明しませんでした。ちょうど質問を更新しました。今問題を理解していますか? – automatix
Aの内部にBの参照を設定すると、同じ設定がAのBの参照を設定することもできます。 – Pradeep