1

Zend\Form\FieldsetsとZend\Form\Collectionsは入れ子にすることができ、複雑なオブジェクト構造をそれらにマップする非常に快適な方法を提供し、フォーム入力からcomleteオブジェクト(保存する準備ができている)を多少自動的に得ることができます。 Form Collections tutorialは非常に良い例です。データベースとZF2アプリケーションで異なる参照方向を扱うにはどうすればよいですか?

私が現在持っているケースは、参照反転を含んでいるため、少し複雑です。それは意味:

私は2つのエンティティがある - MyAMyBを、データベースにそれらの間の関係はmyb.mya_idからmya.idFOREIGN 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' => [...], 
     ]); 
    } 
} 

しかし、偽のオブジェクトも少し汚れています。

+0

データベースの逆転が私の意見ではオブジェクトの関係に影響しないので、私は複雑さを正しく理解しているかわかりません。 doctrineについて読むことができれば、すべての関係に所有側と逆側があり、実際のデータベース関係を示すことができます。私の意見では、クリーンな実装は、あなたがオブジェクトのリレーションシップをどのように見るかです。 myAにはmyBがあるので、myAとmyBの両方のオブジェクトを保存するようにmyAを選択できます。 – Pradeep

+0

コメントありがとうございます!実際、私は重要な精神的なステップについては説明しませんでした。ちょうど質問を更新しました。今問題を理解していますか? – automatix

+0

Aの内部にBの参照を設定すると、同じ設定がAのBの参照を設定することもできます。 – Pradeep

答えて

0

マップを独自に処理するための新しいテーブルを作成する方法その複雑さを、それらを利用するオブジェクトから分離することができます。

だから、あなたはその後、新しいオブジェクトAtoBMappings

namespace My\DataObject; 

class MyA { 
    /** 
    * @var integer 
    */ 
    private $id; 
    /* 
    * @var text 
    */ 
    private $foo; 
    /** 
    * @var MyAtoB 
    */ 
    private $myAtoB; 
} 

namespace My\DataObject; 

class MyB { 
    /** 
    * @var integer 
    */ 
    private $id; 

    /** 
    * @var AtoBMapperID 
    */ 
    private $myAtoB; 
} 

class MyAtoBMapper { 
    /** 
    * @var myB 
    */ 
    private $myB 

    /** 
    * @var myA 
    ** 
    private $myA 
} 

を持つことができ、代わりにあなたのマッパー方法をハッキングのは、単にMYBの作成にMYAで割り当てを行うことができます。

class MyAMapper 
{ 
    ... 
    public function save(MyA $myA) 
    { 

     $myAtoB = new MyAtoBMapper(); 
     //.... instert new myAtoB into DB 

     $data = []; 
     $data['foo'] = [$myA->getFoo()]; 
     $data['myAtoB'] = $myAtoB->getId(); 
     // 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(); 
     $myA->setMyAtoB($newAtoB); 
     $myAtoBMapper->myA = $newId; 
     // common saving stuff #stop# 
     // and only after all that we can save the MyB 
     $myB = $this->myBMapper->save($myB); 
     $myB->setMyAtoB($newAtoB); 
     $myAtoBMapper->myB = $myB; 
     ... 
    } 
} 

これはうまくいくと思いますか、これはあまりにも多くのハックだと思いますか?

関連する問題