在symfony上集成外部服务和表单类型(动态表单)

时间:2014-01-23 23:39:59

标签: php symfony doctrine-orm event-handling

我在symfony中有一个动态表单。目前我有一个外部服务,数据存在这个服务提供了一种呈现数据表单的方法,但我需要将我的bussines逻辑集成到我的应用程序中。

为了解决这个问题,我实现了一个注释和一个CustomType。注释是外部服务中表的名称的简单持有者

在我的应用中,我有一个实体

/**
 * Person
 *
 * @ORM\Table("person")
 * @ORM\Entity
 * @EService("person_data")
 */
class Person extends AbstractEntityEService
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
   private $id;

   /**/
}

/**
 * AbstractEntityEService
 *
 */
abstract AbstractEntityEService
{
   /**
    * @var integer
    *
    * @ORM\Column(name="uuid", type="string")
    */
   protected $uuid;

   /**
    * Holder for the data 
   protected $data;

   /* setters and getters... */
}

外部服务在我存储数据时提供uuid,使用此uuid我可以在我的视图中打印字段,使用此uuid我可以更新数据。

这是我的CustomType

class ExternalType extends AbstractType {

    /**
     * @var Reader
     */
    private $reader;

    /**
     * @var ExternalService
     */
    private $ts;

    public function __construct(Reader $reader, ExternalService $ts){
        $this->reader = $reader;
        $this->ts = $ts;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function(FormEvent $event) use ($options) {
                $annotation = $this->reader->getClassAnnotation(
                    new \ReflectionClass($options['class']),
                    'MyBundle\Lib\Annotation\EServiceAnnotation'
                );

                // this is only form a empty form
                if (null === $event->getData()) {
                    // here get the annotated value from entity and get a uuid
                    $event->setData($this->ts->getForm($annotation->getformName()));
                }

                $event->getForm()->getParent()->add('data', 'collection', array(
                    'allow_add' => true,
                    'label' => false
                ));
            });
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver
            ->setDefaults(array(
                'required'       => false,
                'error_bubbling' => true
            ))
            ->setRequired(array(
                'class',
            ));
    }

    /**     
     * @inheritdoc
     */
    public function getName()
    {
        return 'external';
    }

    /**
     * @inheritdoc
     */
    public function getParent()
    {
        return 'hidden';
    }
}

这是CustomType

的模板
{% block external_widget %}
    {% spaceless %} 
        <div data-form-name="{{ form.parent.vars.name }}" data-form-uuid="{{uuid}}"></div>
        {% set type = type|default('hidden') %}
        {{ block('form_widget_simple') }}
    {% endspaceless %}
{% endblock external_widget %}

我将我的ExternalType注册服务用于我的主要表单PersonType

class AsociacionType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('uuid', 'external', array('class' => $options['data_class']));
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'MyBundle\Entity\Person'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'my_bundle_person';
    }
}

在最后我使用doctrine.event_subscriber

  • postLoad:使用uuid进行呼叫外部服务填充我的实体中的数据属性
  • prePersist:用于保留用户发送到外部服务的数据
  • preUpdate:用于更新用户发送到外部服务的数据

这里的事件

public function postLoad(LifecycleEventArgs $args)
{
    $entity = $args->getEntity();

    if ($entity instanceof AbstractEntityEService && null !== $entity->getUuid())
    {
        $t = $this->externalService->get($entity->getUuid());
        $entity->setData((array)$t->getData());
    }
}

public function prePersist(LifecycleEventArgs $args)
{
    $entity = $args->getEntity();

    if ($entity instanceof AbstractEntityEService) {
        $t = $this->externalService->persist($entity->getData(), $entity->getUuid());
        $entity->setUuid($t->getUuid());
    }
}

public function preUpdate(LifecycleEventArgs $args)
{
    $this->prePersist($args);
}

新的和创造工作正常。但是当我要以未知原因更新数据时 preUpdate事件永远不会被称为。我认为这是因为表格并不意味着数据已经改变。 我需要知道如何告诉Symfony the form has changed

0 个答案:

没有答案