在entityType中添加选项

时间:2016-09-21 11:35:58

标签: php symfony

我自己学习symfony框架(我的工作不是开发,我不是开发人员)而且我发现大多数情况下解决方案但是在这里,我不知道如何管理

我有2个实体:

产品:

/**
 * Product
 *
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="ProductBundle\Repository\ProductRepository")
 * @UniqueEntity("productNumber")
 */
class Product
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="productNumber", type="string", length=255, unique=true)
     * @Assert\Regex(
     *     pattern="/[0-9][.][0-9]{3}/",
     *     message="It should be like 1.234"
     * )
     */
    private $productNumber;    

    /**
     * @ORM\ManyToOne(targetEntity="ProductGroup")
     */
    private $productGroup;

    /**
     * Constructor
     */    
    public function __construct()
    {       

    }
}

相机:

/**
 * Camera
 *
 * @ORM\Table(name="camera")
 * @ORM\Entity(repositoryClass="ProductBundle\Repository\CameraRepository")
 */
class Camera
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="modele", type="string", length=255, unique=true)
     */
    private $modele;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text")
     */
    private $description;

    /**
     *
     * @ORM\ManyToOne(targetEntity="Product")
     */
    private $product;

    /**
     * @ORM\ManyToMany(targetEntity="CustomField", inversedBy="camera", cascade={"persist", "remove"}, orphanRemoval=true)
     */
    protected $customFields;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->customFields = new ArrayCollection();
    }
}

我的表格:

namespace ProductBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;

class CameraType extends AbstractType {

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options) {

        $builder
            ->add('product', EntityType::class, [
                'class' => 'ProductBundle:Product',

                'query_builder' => function (EntityRepository  $er) {
                    return $er->createQueryBuilder('p')
                        ->select('p')
                        ->leftJoin('ProductBundle:Camera', 'c', 'WITH', 'c.product = p.id')
                        ->where('c.product IS NULL')
                        ;
                    },
                'attr' => [     
                    'required' => true, 
                ],

                'choice_label' => 'productNumber',

            ])
            ->add('modele', TextType::class, [
                'label' => "Modele",
            ])
            ->add('description', TextType::class, [
                'label' => "Description",
            ])
            ->add('customFields', CollectionType::class, [
                'entry_type' => CustomFieldType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'prototype' => true,
                'required' => false,
                'attr' => [
                    'class' => 'customfield'
                ]
            ])
           ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'ProductBundle\Entity\Camera'
        ));
    }

}

当我添加一个摄像头时,我想只有Product:productNumber可用(不是通过摄像头),querybuilder正在工作,但我的问题涉及编辑表单,它只显示可用的productNumber,所以它每次都在改变我需要编辑这个相机。

我能处理什么?我应该尝试找到另一种方法来添加productNumber吗?你有“诡计”吗?

我希望你能理解这个问题和我的英语,因为它不是我的第一语言。

度过愉快的一天。

编辑:我在Symfony 3.1.4上

1 个答案:

答案 0 :(得分:1)

我假设在新表单上你的选择字段只显示未使用的ProductBundle:Camera实体,在编辑表单上它应该显示已保存的ProductBundle:Camera实体和所有未使用的。

您应该查看Form Event Subscribers

您需要实现两个事件侦听器PRE_SET_DATA和PRE_SUBMIT。

这是一种方法。这样的东西适用于SF 2.8 首先,您必须从自定义ProductFieldSubscriber创建产品实体表单,该表单将成为EventSubscriberInterface:

$builder->addEventSubscriber(new ProductFieldSubscriber('product', [])

现在ProductFieldSubscriber应该看起来像这样(未经测试)

namespace ProductBundle\Form\EventListener;

use Symfony\Component\Form\FormInterface,
    Symfony\Component\Form\FormEvent,
    Symfony\Component\EventDispatcher\EventSubscriberInterface,
    Symfony\Component\Form\FormEvents,
    Doctrine\ORM\EntityRepository,
    Symfony\Bridge\Doctrine\Form\Type as DoctrineTypes
;


class ProductFieldSubscriber implements EventSubscriberInterface
{
    private $propertyPathToSelf;

    public function __construct($propertyPathToSelf, array $formOptions=[]) {
        $this->propertyPathToSelf = $propertyPathToSelf;
        $this->formOptions = $formOptions;
    }

    public static function getSubscribedEvents() {
        return [
            FormEvents::PRE_SET_DATA => 'onPreSetData',
            FormEvents::PRE_SUBMIT => 'onPreSubmit',
        ];
    }

    private function addForm(FormInterface $form, $selfId = null) {

        $formOptions = array_replace_recursive ([
                    'class'         => 'ProductBundle:Product',
                    'placeholder'   => null,
                    'compound'      => false,
                    'query_builder' => function (EntityRepository $er) use ($selfId) {
                        $qb = $er->createQueryBuilder('p')
                            ->select('p')
                            ->leftJoin('ProductBundle:Camera', 'c', 'WITH', 'c.product = p.id')
                            ->where('c.product IS NULL')
                        ;

                        if (null !== $selfId) {
                            $qb
                                ->orWhere($qb->expr()->eq('p.product', ':existingId'))
                                ->setParameter('existingId', $selfId->getId())
                            ;
                        }

                        return $qb;
                    },
                ],
                $this->formOptions
            );

        if ($selfId) {
            $formOptions['data'] = $selfId;
        }

        $form->add($this->propertyPathToSelf, DoctrineTypes\EntityType::class, $formOptions);

    }

    public function onPreSetData(FormEvent $event) {
        $data = $event->getData();
        $form = $event->getForm();

        if (null === $data) {
            return;
        }

        $selfIdTypeMethod = "get{$this->propertyPathToSelf}";
        $selfId = $data->$selfIdTypeMethod();

        $this->addForm($form, $selfId);
    }

    public function onPreSubmit(FormEvent $event) {
        $data = $event->getData();
        $form = $event->getForm();

        $selfId = array_key_exists($this->propertyPathToSelf, $data) ? $data[$this->propertyPathToSelf] : null;

        $this->addForm($form, $selfId);
    }
}
如果您已映射实体关系,

查询构建器会更简单。

奖金更新:

  1. 表单选项'placeholder'=> null,请注意没有默认的'empty'选项可用。
  2. 表单选项'required'=> true,强制html5表单弹出验证。
  3. 然后你应该使用类似实体@assert表示法的东西,并在实体属性上使用验证器约束:

    use Symfony\Component\Validator\Constraints as Assert;
    
    /**
     * @var string
     *
     * @Assert\NotNull()
     * @ORM\Column(name="modele", type="string", length=255, unique=true)
     */
    private $modele;
    
  4. 你也可以通过控制器editAction(可能是一些重定向)和twig禁止编辑表单,你可以在其中隐藏编辑按钮。