2012-09-17 103 views
15

我正在用Symfony2和Doctrine2創建一個電子商務包。我將EAV方法應用於產品功能和產品價值以實現無限功能。爲此,我有三個基本實體:Product,FeatureKind和FeatureValues。Symfony2形式的動態選擇字段EAV返回值

  • FeatureKind使用OneToMany單向 關係與FeatureValues關聯。
  • 產品通過ManyToMany關係連接到FeatureKind。

問題是我需要FeatureType作爲標籤,它是各種值作爲產品形式的選擇字段。我設法獲得了產品形式中的特徵和相關值,但我不知道如何將它們轉換爲選擇字段。

以下是所有三個實體,控制器和表單代碼以及我的代碼的結果。

注:我已經從代碼中刪除了額外的東西,以保持它的簡短。

Product.php

namespace Webmuch\ProductBundle\Entity; 

/** 
* @ORM\Table() 
* @ORM\Entity 
*/ 
class Product 
{ 
    /** 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @ORM\Column(name="title", type="string", length=255) 
    */ 
    private $title; 

    /** 
    * @ORM\ManyToMany(targetEntity="FeatureKind", inversedBy="product", cascade={"persist"}) 
    * @ORM\JoinTable(name="product_featurekind") 
    **/ 
    private $featurekind; 
} 

FeatureKind.php

namespace Webmuch\ProductBundle\Entity; 

/** 
* @ORM\Table(name="feature_kind") 
* @ORM\Entity 
*/ 
class FeatureKind 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * @ORM\Column(name="name", type="string", length=50) 
    */ 
    protected $name; 

    /** 
    * @ORM\ManyToMany(targetEntity="FeatureValue") 
    * @ORM\JoinTable(name="feature_kind_value", 
    *  joinColumns={@ORM\JoinColumn(name="kind_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@ORM\JoinColumn(name="value_id", referencedColumnName="id", unique=true)} 
    *  ) 
    **/ 
    protected $values; 
} 

FeatureValue.php

namespace Webmuch\ProductBundle\Entity; 

/** 
* @ORM\Table() 
* @ORM\Entity 
*/ 
class FeatureValue 
{ 
    /** 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * @ORM\Column(name="value", type="string", length=100) 
    */ 
    protected $value; 
} 

ProductController.php

public function newAction(Request $request) 
{ 
    $entity = new Product(); 
    $em = $this->getDoctrine()->getEntityManager(); 
    $features = $em->getRepository('ProductBundle:FeatureKind')->findAll(); 

    foreach($features as $feature) 
    { 
     $featurekind = new FeatureKind(); 
     $featurekind->setTitle($feature->getTitle()); 
     foreach($feature->getValue() as $value){ 
      $featurekind->getValue()->add($value); 
     } 
     $entity->getFeaturekind()->add($featurekind); 
    } 

    $form = $this->createForm(new ProductType(), $entity); 

    if ('POST' === $request->getMethod()) { 
     $form->bindRequest($request); 
     if ($form->isValid()) { 
      $em->persist($entity); 
      $em->flush(); 

      return $this->redirect($this->generateUrl('product_show', array(
       'id' => $entity->getId() 
      ))); 
     } 
    } 
    return $this->render('ProductBundle:Product:new.html.twig', array(
     'form' => $form->createView() 
    )); 
} 

ProductType.php

namespace Webmuch\ProductBundle\Form; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilder; 

class ProductType extends AbstractType 
{ 
    public function buildForm(FormBuilder $builder, array $options) 
    { 
     $builder 
      ->add('featurekind', 'collection', array('type' => new FeatureKindType())) 
      ->getForm(); 
     } 

    public function getDefaultOptions(array $options) 
    { 
     return array(
      'data_class' => 'Webmuch\ProductBundle\Entity\Product', 
      'required' => true 
     ); 
    } 

    public function getName() 
    { 
     return 'product'; 
    } 
} 

FeatureKindType.php

namespace Webmuch\ProductBundle\Form; 

class FeatureKindType extends AbstractType 
{ 
    public function buildForm(FormBuilder $builder, array $options) 
    { 
     $builder 
      ->add('title') 
      ->add('value','collection', array(
               'type' => new FeatureValueType(), 
               'allow_add'=>true)) 
      ->getForm(); 
    } 

    public function getDefaultOptions(array $options) 
    { 
     return array(
      'data_class' => 'Webmuch\ProductBundle\Entity\FeatureKind', 
     ); 
    } 

    public function getName() 
    { 
     return 'featurekind'; 
    } 
} 

This is my form result.

編輯:

我工作後的幾天,我現在堅持一個簡單的特徵陣列及其各自的多個值:

Array 
(
    [Color] => Array 
     (
      [Red] => Red 
      [Green] => Green 
     ) 

    [Size] => Array 
     (
      [Large] => Large 
      [Medium] => Medium 
      [Small] => Small 
     ) 

    [Sleeve Style] => Array 
     (
      [Half Sleeved] => Half Sleeved 
      [Full Sleeved] => Full Sleeved 
      [Cut Sleeves] => Cut Sleeves 
     ) 

) 

我試圖創建如下形式:$ this-> choices包含數組。

$builder 
    ->add('name') 
    ->add('slug') 
    ->add('active') 
; 

foreach ($this->choices as $choice) { 
    $builder->add('featurekind', 'choice', array(
     'required' => 'false', 
     'choices' => $choice, 
     'empty_value' => 'Choose an option', 
     'empty_data' => null 
    )); 
} 

$builder->getForm(); 

以上沒有對物業$ featurekind工作。我得到的錯誤:

Notice: Object of class Doctrine\Common\Collections\ArrayCollection could not be converted to int in /vagrant/project/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/ChoiceList/ChoiceList.php line 457 

雖然如果表單字段連接到任何無關聯的屬性,例如:$名稱,它仍然是循環的最後一次迭代只創建一個表單字段。

我沒有選擇。

+0

您沒有顯示您的FeatureKindType –

+0

我的不好。我剛剛添加了它。謝謝! – Aayush

+0

現在你沒有顯示FeatureValueType。你想得到什麼?帶有FeatureKind名稱的標籤,然後是包含所有可能的特徵值的下拉菜單? –

回答

3

你想做的事不能用你現在的結構來完成。讓我試着解釋一下:FeatureKind與FeatureValue有一對多的關係。這意味着你可以有一個「顏色」類型,可以有值「紅色」,「粉紅色」等。這很好。但是你的產品實體有一個FeatureKind對象的集合,所以它可以有一個像「Color」,「Size」等等的列表......但是(這是最重要的部分),它沒有辦法爲任何特定的值賦值這些種類:沒有任何財產具有每種具體的價值。我希望你能解決這個問題,這有點難以解釋。

你需要做的:

定義你的FeatureValue和FeatureKind類,就像他們。

定義它處理種類和對產品的價值之間的關聯一個新的實體:

namespace Webmuch\ProductBundle\Entity; 

/** 
* @ORM\Table() 
* @ORM\Entity 
*/ 
class FeatureKindValue 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    protected $id; 

    /** 
    * @ManyToOne(targetEntity="Product", inversedBy="features") 
    **/ 
    private $product; 

    /** 
    * @ORM\ManyToOne(targetEntity="FeatureKind") 
    **/ 
    protected $kind; 

    /** 
    * @ORM\ManyToOne(targetEntity="FeatureValue") 
    **/ 
    protected $value; 
} 

這個實體處理那種對:值,例如顏色:紅色

最後,您產品實體有這種新類型的屬性:

namespace Webmuch\ProductBundle\Entity; 

/** 
* @ORM\Table() 
* @ORM\Entity 
*/ 
class Product 
{ 
    /** 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @ORM\Column(name="title", type="string", length=255) 
    */ 
    private $title; 

    /** 
    * @ORM\OneToMany(targetEntity="FeatureKindValue", mappedBy="product") 
    **/ 
    private $features; 
} 

然後,以目前的形式,只要你想,做類似於answe給出的說明什麼R鍵這個計算器question

+0

感謝您的答覆,我已經過去了,並嘗試了您的方法,但它不起作用。如果您看到圖像,我的表單中前面的所有正確值都已經連接到正確的類型。我所需要的就是把這些種類變成具有所有值的選擇字段的標籤。這將使產品具有尺寸:大和顏色:綠色。 – Aayush

+0

然後,我將創建多個這些產品並將它們連接到MasterProduct,並再次從多個連接的產品實體的所有值中選擇一個字段。這個問題只詢問單個子產品形式,它已經具有表格中的所有值,但是作爲文本字段,我希望它們作爲選擇字段。 – Aayush

+0

我可能會回答有關答案,而不是像這樣得到整個概念。請讓我知道。再次感謝。 – Aayush

1

這種東西可能會非常棘手,但你可以在你的FeatureKindType類使用this approach

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->addEventListener(
     FormEvents::PRE_SET_DATA, 
     function (DataEvent $event) use ($builder) { 
      /* @var FormBuilderInterface $builder */ 
      $form = $event->getForm(); 
      /* @var FeatureKind $data */ 
      $data = $event->getData(); 
      if ($data !== null) { 
       $form->add(
        $builder->getFormFactory()->createNamed(
         'values', 
         'entity', 
         null, 
         array(
          'label' => $data->getName(), 
          'class' => 'WebmuchProductBundle:FeatureValue', 
         ) 
        ) 
       ); 
      } 
     } 
    ); 
} 

你要知道,我還沒有試過發佈形式,並保存實體您的情況,但現在表單將FeatureKind的名稱作爲標籤和包含相應FeatureKindValues的下拉選擇。

我在一個我的項目中使用這種方法,它適用於我。