2012-09-17 11 views
15

Estoy creando un paquete de comercio electrónico con Symfony2 y Doctrine2. Estoy aplicando el enfoque EAV para las características del producto y los valores del producto para funciones ilimitadas. Para esto, tengo tres entidades básicas: Product, FeatureKind y FeatureValues.Campo de elección dinámica de formulario Symfony2 con valores devueltos por EAV

  • FeatureKind está conectado con FeatureValues ​​con un OneToMany unidireccional relación.
  • El producto está conectado a FeatureKind con una relación ManyToMany.

El problema es que necesito el FeatureType como etiquetas y sus diversos valores como campo de elección en el formulario del producto. Logré obtener la característica y los valores asociados en el formulario del producto, pero no sé cómo convertirlos en campos de elección.

Las siguientes son las tres Entidades, Controlador y Código de formulario y el resultado de mi código.

Nota: He eliminado las cosas adicionales del código para que quede corto.

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.

EDIT:

que después de unos días de trabajo, ahora estoy atascado con un simple conjunto de características y sus respectivos valores múltiples:

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 
     ) 

) 

He tratado de crear la forma de la siguiente manera: $ this-> opciones contiene la matriz.

$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(); 

Lo anterior no funciona en la propiedad $ featurekind. Me sale el error:

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 

Aunque si el campo de formulario se adjunta a cualquier propiedad no-asociado, por ejemplo: $ nombre, todavía crea sólo un campo de formulario para la última iteración del bucle.

No tengo más opciones.

+0

No mostró su FeatureKindType –

+0

Mi mal. Acabo de agregarlo. ¡Gracias! – Aayush

+0

Y ahora no mostró FeatureValueType. ¿Qué quieres obtener? ¿Una etiqueta con el nombre de FeatureKind y luego un menú desplegable con todos los valores de características posibles? –

Respuesta

3

Lo que quiere hacer no se puede hacer con su estructura actual. Déjame intentar explicar: FeatureKind tiene una relación uno a muchos con FeatureValue. Esto significa que puede tener un tipo de "color" que puede tener valores "rojo", "rosa", etc. Esto está bien. Pero su entidad de producto tiene una colección de objetos FeatureKind, por lo que puede tener una lista como "Color", "Tamaño", etc. PERO (esta es la parte más importante) no tiene forma de asiginig un valor específico a cualquier de estos tipos: no hay ninguna propiedad que tenga el valor específico para cada tipo. Espero que puedas entender esto, es un poco difícil de explicar.

Lo que hay que hacer:

definir su FeatureValue y FeatureKind clases tal y como son.

definir una nueva entidad que se ocupa de una asociación entre una clase y un valor para un producto:

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; 
} 

Esta entidad se encarga de pares de tipo: valor, por ejemplo los colores: rojo

Por último, su entidad de producto tiene una propiedad de este nuevo tipo:

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; 
} 

Luego, con el fin de presentar la forma que desee, hacer algo similar a las instrucciones dadas en el answe r para este stackoverflow question

+0

Gracias por la respuesta, he ido y probado su método, pero no funciona.Si ve la imagen, tengo todos los valores correctos al frente en mi formulario ya conectado a los tipos correctos. Todo lo que necesitaba era convertir los tipos en etiquetas para un campo de elección con todos los valores. Esto hará que un producto tenga Tamaño: Grande y Color: Verde, por ejemplo. – Aayush

+0

Luego crearé varios de estos productos y los conectaré a un producto maestro y de nuevo crearé un campo de elección entre todos los valores de las múltiples entidades de producto conectadas. Esta pregunta solo pregunta sobre el formulario de subproducto único que ya tiene todos los valores en el formulario, pero como campos de texto, los quiero como campos de elección. – Aayush

+0

Podría estar muy lejos de la respuesta y no tener todo el concepto como tal. Déjame saber. Gracias de nuevo. – Aayush

1

Este tipo de cosas puede ser complicado, pero se puede utilizar this approach en su clase FeatureKindType:

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', 
         ) 
        ) 
       ); 
      } 
     } 
    ); 
} 

Eso sí, no he tratado de publicar el formulario y guardar las entidades en las su caso, pero el formulario ahora muestra el nombre del FeatureKind como etiqueta y un menú desplegable que contiene los respectivos FeatureKindValues.

Uso este enfoque en un proyecto mío, y funciona para mí.

Cuestiones relacionadas