0

今日、私は Zend\Form の機能を読み始めました。Michael Gallego によるすばらしいチュートリアルを見つけました。このチュートリアルでは、いくつかの新しいクールな機能の使用方法を説明しています。

1 対 1 の関係を処理している場合、この例はこれまでのところ問題なく動作します。教義はそれらをうまくカバーしています。

私がやりたいことは

  • 関連する値のテキストエリアの代わりに、選択ボックスが欲しい
  • データベースの内容に応じて、選択ボックスには有効なオプションが必要です
  • 後で編集するために、現在選択されている値を選択する必要があります
  • Doctrine は One-Table に新しい行を追加すべきではありません

私のgithubソースでわかるように、チュートリアルの例を使用しましたが、「製品」と「ブランド」に短縮しました. 私の例では、Brands は事前定義された Brands (Nike、Adidas、Puma など) を含む DB テーブルであり、フォームから新しい Product を作成すると、それらの Brands が選択メニューとして取得されます。

現在、オプションを追加する方法が機能していません。次のような配列を使用してオプションを手動で設定できることを知っています

$form->get('product')->get('brand')->setAttribute('options', array('Nike'=>'1', 'Adidas'=>'2', etc);

しかし、これを行うためのより自動化された方法があると強く思います。Zend で提供されている Hydrator クラスのすべてを理解しているわけではありません。

問題は、上記のように配列を手動で定義しても、製品とブランドのマッピングが正しく機能しないことです。今のダンプは$productこんな感じ

object(Application\Entity\Product)[210]
  protected 'id' => null
  protected 'name' => string 'asdasd' (length=6)
  protected 'price' => string '123123' (length=6)
  protected 'brand' => 
    object(Application\Entity\Brand)[215]
      protected 'id' => null
      protected 'name' => string '1' (length=1)

明らかに、ブランドは完全に間違ってマッピングされています (私が達成したいことについては、私の選択の値が 1 であるため、おそらく zend はこれを正しいと見なします)。

質問選択値をマップされたオブジェクト ID にマップするようにフォームに指示するにはどうすればよいですか? その場合、製品モデルの設定方法が間違っている可能性があります。

どんな助けでも大歓迎です:)

4

3 に答える 3

1

BrandFieldSet を見ると、InputFilterProvider に名前のみを指定しているため、ID が渡されることはありません。

次に、レジストリを削除することをお勧めします。ServiceManager を使用して作成されたクラスは、コンストラクターを使用して指定されていない場合、他の何かにアクセスする必要がある場合、ServiceManagareAwareInterface を実装できます/実装する必要があります。

したがって、レジストリを使用する代わりにコントローラーでサービスマネージャーにアクセスします

$this->getServiceLocator()
     ->get('FQCN_OR_ALIAS');

フレームワークの貢献者によって書かれたいくつかの素晴らしい例があり、そこにある github リポジトリのいくつかをここにリストします。

https://github.com/ZF-Commonsおよびhttps://github.com/EvanDotPro (評判が悪いため、これ以上投稿できません)

さらに質問がある場合は、irc.freenode.org の #zftalk.2 に参加してください。

于 2012-07-18T12:16:09.977 に答える
0

これは古い質問ですが、とにかく答えると思いました。ObjectSelect前の回答では、Doctrine を使用していません。

OneToOne の関係を持ち、「One-table」にレコードを追加したくないと言います。ここでは、単方向の OneToOne関係があると想定しています。

ただし、エンティティとして「製品」と「ブランド」を取得した場合は、OneToMany 双方向の関係がより適している可能性があります;)

ただし、OneToOne を使用すると、エンティティは次のようになります。

class Brand {
    /**
     * @var int
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(name="name", type="string", nullable=false, length=128)
     */
    protected $name;

    //Getters/Setters
}

class Product {
    /**
     * @var int
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * @var string
     * @ORM\Column(name="name", type="string", nullable=false, length=128)
     */
    protected $name;

    //Change below "OneToOne" to "ManyToOne" for proper product + brand relationship. Just this change will leave it as uni-directional.
    /**
     * @var Brand
     * @ORM\OneToOne(targetEntity="Brand", fetch="EAGER")
     * @ORM\JoinColumn(name="brand", referencedColumnName="id")
     */
    protected $brand;

    //Getters/Setters
}

エンティティが正しいと仮定すると、ObjectSelectDoctrine へのビルドを使用する必要があります。

class ProductForm
{
    /** @var  ObjectManager */
    protected $objectManager;

    public function __construct($name = 'product-form', $options = [])
    {
        parent::__construct($name, $options);
    }

    public function init()
    {
        $this->add([
            'type' => 'DoctrineModule\\Form\\Element\\ObjectSelect',
            'name' => 'brand',
            'required' => true,
            'attributes' => [
                'id' => 'selectBrand',
                'multiple' => false,
                'value' => null,
            ],
            'options' => [
                'label' => 'Select brand',
                'object_manager' => $this->getObjectManager(),
                'target_class' => Brand::class,
                'property' => 'id',
                'is_method' => true,
                'find_method' => [
                    'name' => 'findBy',
                    'params' => [
                        'criteria' => [],
                        'orderBy' => ['name' => 'ASC'],
                    ],
                ],
                'empty_option' => '--- Select Brand ---',
                'label_generator' => function (Brand $entity) {
                    return $entity->getName();
                }
            ],
        ]);
    }

    /**
     * @return ObjectManager
     */
    public function getObjectManager()
    {
        return $this->objectManager;
    }

    /**
     * @param ObjectManager $objectManager
     */
    public function setObjectManager(ObjectManager $objectManager)
    {
        $this->objectManager = $objectManager;
    }
}

Module.phpこのフォームをロードできるようにを設定してください。getServiceConfig()それに関数を追加します。

public function getServiceConfig()
    {
        /** @var ServiceManager $sm */
        return [
            'factories' => [
                'product_form' => function ($sm)
                {
                    $form = new ProductForm();
                    $form->setInputFilter(new ProductInputFilter());

                    /** @var EntityManager $entityManager */
                    $entityManager = $sm->get('doctrine.entitymanager.orm_default');

                    //Set Doctrine ObjectManager
                    $form->setObjectManager($entityManager);
                    //Set Doctrine Object as Hydrator
                    $form->setHydrator(new DoctrineObject($entityManager, Product::class));
                    //Set Doctrine Entity
                    $form->setObject(new Product());
                    //Initialize elements onto form
                    $form->init();

                    return $form;
                },
            ],
        ];
    }
}

次に、コントローラーにフォームをロードします。

$form = $this->getServiceLocator()->get('product_form');

===========================

注: これは Zend Framework 2.5.2 まで機能します。

于 2016-06-18T17:29:31.660 に答える