فهرست منبع

[Form] moved csrf listener to its own class

Kris Wallsmith 14 سال پیش
والد
کامیت
fe4382eb73

+ 66 - 0
src/Symfony/Component/Form/Extension/Csrf/EventListener/EnsureCsrfFieldListener.php

@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Form\Extension\Csrf\EventListener;
+
+use Symfony\Component\Form\Event\DataEvent;
+use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
+use Symfony\Component\Form\FormFactoryInterface;
+
+/**
+ * Ensures the CSRF field.
+ *
+ * @author Bulat Shakirzyanov <mallluhuct@gmail.com>
+ * @author Kris Wallsmith <kris@symfony.com>
+ */
+class EnsureCsrfFieldListener
+{
+    private $factory;
+    private $name;
+    private $intention;
+    private $provider;
+
+    /**
+     * Constructor.
+     *
+     * @param FormFactoryInterface  $factory   The form factory
+     * @param string                $name      A name for the CSRF field
+     * @param string                $intention The intention string
+     * @param CsrfProviderInterface $provider  The CSRF provider
+     */
+    public function __construct(FormFactoryInterface $factory, $name, $intention = null, CsrfProviderInterface $provider = null)
+    {
+        $this->factory = $factory;
+        $this->name = $name;
+        $this->intention = $intention;
+        $this->provider = $provider;
+    }
+
+    /**
+     * Ensures a root form has a CSRF field.
+     *
+     * This method should be connected to both form.pre_set_data and form.pre_bind.
+     */
+    public function ensureCsrfField(DataEvent $event)
+    {
+        $form = $event->getForm();
+
+        $options = array();
+        if ($this->intention) {
+            $options['intention'] = $this->intention;
+        }
+        if ($this->provider) {
+            $options['csrf_provider'] = $this->provider;
+        }
+
+        $form->add($this->factory->createNamed('csrf', $this->name, null, $options));
+    }
+}

+ 12 - 23
src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php

@@ -12,9 +12,10 @@
 namespace Symfony\Component\Form\Extension\Csrf\Type;
 
 use Symfony\Component\Form\AbstractTypeExtension;
-use Symfony\Component\Form\Event\DataEvent;
+use Symfony\Component\Form\Extension\Csrf\EventListener\EnsureCsrfFieldListener;
 use Symfony\Component\Form\FormBuilder;
 use Symfony\Component\Form\FormView;
+use Symfony\Component\Form\FormEvents;
 use Symfony\Component\Form\FormInterface;
 
 class FormTypeCsrfExtension extends AbstractTypeExtension
@@ -40,30 +41,18 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
             return;
         }
 
-        $listener = function(DataEvent $event) use ($options, $builder)
-        {
-            $form = $event->getForm();
-
-            if (!$form->isRoot()) {
-                return;
-            }
-
-            $csrfOptions = array('intention' => $options['intention']);
-
-            if ($options['csrf_provider']) {
-                $csrfOptions['csrf_provider'] = $options['csrf_provider'];
-            }
-
-            $form->add(
-                $builder
-                    ->create($options['csrf_field_name'], 'csrf', $csrfOptions)
-                    ->getForm()
-            );
-        };
+        $listener = new EnsureCsrfFieldListener(
+            $builder->getFormFactory(),
+            $options['csrf_field_name'],
+            $options['intention'],
+            $options['csrf_provider']
+        );
 
+        // use a low priority so higher priority listeners don't remove the field
         $builder
-            ->addEventListener('form.pre_set_data', $listener, -10)
-            ->addEventListener('form.pre_bind', $listener, -10)
+            ->setAttribute('csrf_field_name', $options['csrf_field_name'])
+            ->addEventListener(FormEvents::PRE_SET_DATA, array($listener, 'ensureCsrfField'), -10)
+            ->addEventListener(FormEvents::PRE_BIND, array($listener, 'ensureCsrfField'), -10)
         ;
     }
 

+ 73 - 0
tests/Symfony/Tests/Component/Form/Extension/Csrf/EventListener/EnsureCsrfFieldListenerTest.php

@@ -0,0 +1,73 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\Form\Extension\Csrf\EventListener;
+
+use Symfony\Component\Form\Event\DataEvent;
+use Symfony\Component\Form\Extension\Csrf\EventListener\EnsureCsrfFieldListener;
+
+class EnsureCsrfFieldListenerTest extends \PHPUnit_Framework_TestCase
+{
+    private $form;
+    private $formFactory;
+
+    protected function setUp()
+    {
+        $this->formFactory = $this->getMock('Symfony\\Component\\Form\\FormFactoryInterface');
+        $this->form = $this->getMock('Symfony\\Tests\\Component\\Form\\FormInterface');
+        $this->field = $this->getMock('Symfony\\Tests\\Component\\Form\\FormInterface');
+        $this->event = new DataEvent($this->form, array());
+    }
+
+    public function testAddField()
+    {
+        $this->formFactory->expects($this->once())
+            ->method('createNamed')
+            ->with('csrf', '_token', null, array())
+            ->will($this->returnValue($this->field));
+        $this->form->expects($this->once())
+            ->method('add')
+            ->with($this->isInstanceOf('Symfony\\Tests\\Component\\Form\\FormInterface'));
+
+        $listener = new EnsureCsrfFieldListener($this->formFactory, '_token');
+        $listener->ensureCsrfField($this->event);
+    }
+
+    public function testIntention()
+    {
+        $this->formFactory->expects($this->once())
+            ->method('createNamed')
+            ->with('csrf', '_token', null, array('intention' => 'something'))
+            ->will($this->returnValue($this->field));
+        $this->form->expects($this->once())
+            ->method('add')
+            ->with($this->isInstanceOf('Symfony\\Tests\\Component\\Form\\FormInterface'));
+
+        $listener = new EnsureCsrfFieldListener($this->formFactory, '_token', 'something');
+        $listener->ensureCsrfField($this->event);
+    }
+
+    public function testProvider()
+    {
+        $provider = $this->getMock('Symfony\\Component\\Form\\Extension\\Csrf\\CsrfProvider\\CsrfProviderInterface');
+
+        $this->formFactory->expects($this->once())
+            ->method('createNamed')
+            ->with('csrf', '_token', null, array('csrf_provider' => $provider))
+            ->will($this->returnValue($this->field));
+        $this->form->expects($this->once())
+            ->method('add')
+            ->with($this->isInstanceOf('Symfony\\Tests\\Component\\Form\\FormInterface'));
+
+        $listener = new EnsureCsrfFieldListener($this->formFactory, '_token', null, $provider);
+        $listener->ensureCsrfField($this->event);
+    }
+}