浏览代码

Merge branch 'master' into form-collection-rendering

Victor Berchet 14 年之前
父节点
当前提交
ef8cb967f5

+ 6 - 0
src/Symfony/Bundle/SwiftmailerBundle/DependencyInjection/Configuration.php

@@ -81,6 +81,12 @@ class Configuration implements ConfigurationInterface
                     ->end()
                 ->end()
                 ->scalarNode('sender_address')->end()
+                ->arrayNode('antiflood')
+                    ->children()
+                        ->scalarNode('threshold')->defaultValue(99)->end()
+                        ->scalarNode('sleep')->defaultValue(0)->end()
+                    ->end()
+                ->end()
                 ->scalarNode('delivery_address')->end()
                 ->booleanNode('disable_delivery')->end()
                 ->booleanNode('logging')->defaultValue($this->debug)->end()

+ 9 - 1
src/Symfony/Bundle/SwiftmailerBundle/DependencyInjection/SwiftmailerExtension.php

@@ -91,11 +91,19 @@ class SwiftmailerExtension extends Extension
         }
         $container->setParameter('swiftmailer.spool.enabled', isset($config['spool']));
 
+        // antiflood?
+        if (isset($config['antiflood'])) {
+            $container->setParameter('swiftmailer.plugin.antiflood.threshold', $config['antiflood']['threshold']);
+            $container->setParameter('swiftmailer.plugin.antiflood.sleep', $config['antiflood']['sleep']);
+
+            $container->findDefinition('swiftmailer.transport')->addMethodCall('registerPlugin', array(new Reference('swiftmailer.plugin.antiflood')));
+        }
+
         if ($config['logging']) {
             $container->findDefinition('swiftmailer.transport')->addMethodCall('registerPlugin', array(new Reference('swiftmailer.plugin.messagelogger')));
             $container->findDefinition('swiftmailer.data_collector')->addTag('data_collector', array('template' => 'SwiftmailerBundle:Collector:swiftmailer', 'id' => 'swiftmailer'));
         }
-        
+
         if (isset($config['sender_address']) && $config['sender_address']) {
             $container->setParameter('swiftmailer.sender_address', $config['sender_address']);
             $container->findDefinition('swiftmailer.transport')->addMethodCall('registerPlugin', array(new Reference('swiftmailer.plugin.impersonate')));

+ 9 - 0
src/Symfony/Bundle/SwiftmailerBundle/Resources/config/swiftmailer.xml

@@ -16,6 +16,10 @@
         <parameter key="swiftmailer.plugin.blackhole.class">Swift_Plugins_BlackholePlugin</parameter>
         <parameter key="swiftmailer.plugin.impersonate.class">Swift_Plugins_ImpersonatePlugin</parameter>
         <parameter key="swiftmailer.plugin.messagelogger.class">Symfony\Bundle\SwiftmailerBundle\Logger\MessageLogger</parameter>
+        <parameter key="swiftmailer.plugin.antiflood.class">Swift_Plugins_AntiFloodPlugin</parameter>
+        <parameter key="swiftmailer.plugin.antiflood.threshold">99</parameter>
+        <parameter key="swiftmailer.plugin.antiflood.sleep">0</parameter>
+
         <parameter key="swiftmailer.data_collector.class">Symfony\Bundle\SwiftmailerBundle\DataCollector\MessageDataCollector</parameter>
     </parameters>
 
@@ -63,6 +67,11 @@
         </service>
 
         <service id="swiftmailer.plugin.blackhole" class="%swiftmailer.plugin.blackhole.class%" public="false" />
+        
+        <service id="swiftmailer.plugin.antiflood" class="%swiftmailer.plugin.antiflood.class%" public="false">
+            <argument>%swiftmailer.plugin.antiflood.threshold%</argument>
+            <argument>%swiftmailer.plugin.antiflood.sleep%</argument>
+        </service>
 
         <service id="swiftmailer.plugin.impersonate" class="%swiftmailer.plugin.impersonate.class%" public="false">
             <argument>%swiftmailer.sender_address%</argument>

+ 30 - 37
src/Symfony/Bundle/TwigBundle/Resources/views/Form/div_layout.html.twig

@@ -1,18 +1,21 @@
-{% block field_rows %}
-{% spaceless %}
-    {{ form_errors(form) }}
-    {% for child in form %}
-        {{ form_row(child) }}
-    {% endfor %}
-{% endspaceless %}
-{% endblock field_rows %}
-
 {% block field_enctype %}
 {% spaceless %}
     {% if multipart %}enctype="multipart/form-data"{% endif %}
 {% endspaceless %}
 {% endblock field_enctype %}
 
+{% block field_label %}
+{% spaceless %}
+    <label for="{{ id }}"{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans }}</label>
+{% endspaceless %}
+{% endblock field_label %}
+
+{% block collection_label %}
+{% spaceless %}
+    <label {% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans }}</label>
+{% endspaceless %}
+{% endblock collection_label %}
+
 {% block field_errors %}
 {% spaceless %}
     {% if errors|length > 0 %}
@@ -25,6 +28,15 @@
 {% endspaceless %}
 {% endblock field_errors %}
 
+{% block field_rows %}
+{% spaceless %}
+    {{ form_errors(form) }}
+    {% for child in form %}
+        {{ form_row(child) }}
+    {% endfor %}
+{% endspaceless %}
+{% endblock field_rows %}
+
 {% block field_rest %}
 {% spaceless %}
     {% for child in form %}
@@ -35,18 +47,6 @@
 {% endspaceless %}
 {% endblock field_rest %}
 
-{% block field_label %}
-{% spaceless %}
-    <label for="{{ id }}"{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans }}</label>
-{% endspaceless %}
-{% endblock field_label %}
-
-{% block collection_label %}
-{% spaceless %}
-    <label {% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans }}</label>
-{% endspaceless %}
-{% endblock collection_label %}
-
 {% block attributes %}
 {% spaceless %}
     id="{{ id }}" name="{{ full_name }}"{% if read_only %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
@@ -61,6 +61,15 @@
 {% endspaceless %}
 {% endblock container_attributes %}
 
+{% block form_widget %}
+{% spaceless %}
+    <div {{ block('container_attributes') }}>
+        {{ block('field_rows') }}
+        {{ form_rest(form) }}
+    </div>
+{% endspaceless %}
+{% endblock form_widget %}
+
 {% block field_widget %}
 {% spaceless %}
     {% set type = type|default('text') %}
@@ -239,19 +248,12 @@
 {% endspaceless %}
 {% endblock file_widget %}
 
-{% block collection_widget %}
-{% spaceless %}
-    {{ block('form_widget') }}
-{% endspaceless %}
-{% endblock collection_widget %}
-
 {% block repeated_row %}
 {% spaceless %}
     {{ block('field_rows') }}
 {% endspaceless %}
 {% endblock repeated_row %}
 
-
 {% block field_row %}
 {% spaceless %}
     <div>
@@ -262,15 +264,6 @@
 {% endspaceless %}
 {% endblock field_row %}
 
-{% block form_widget %}
-{% spaceless %}
-    <div {{ block('container_attributes') }}>
-        {{ block('field_rows') }}
-        {{ form_rest(form) }}
-    </div>
-{% endspaceless %}
-{% endblock form_widget %}
-
 {% block email_widget %}
 {% spaceless %}
     {% set type = type|default('email') %}

+ 0 - 6
src/Symfony/Bundle/TwigBundle/Resources/views/Form/table_layout.html.twig

@@ -36,12 +36,6 @@
 {% endspaceless %}
 {% endblock hidden_row %}
 
-{% block repeated_errors %}
-{% spaceless %}
-    {{ block('form_errors') }}
-{% endspaceless %}
-{% endblock repeated_errors %}
-
 {% block form_widget %}
 {% spaceless %}
     <table {{ block('container_attributes') }}>

+ 15 - 5
src/Symfony/Component/Form/FormView.php

@@ -112,7 +112,21 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
      */
     public function isRendered()
     {
-        return $this->rendered;
+        if (true === $this->rendered || 0 == count($this->children)) {
+            return $this->rendered;
+        }
+
+        if (count($this->children) > 0) {
+            foreach ($this->children as $child) {
+                if (!$child->isRendered()) {
+                    return false;
+                }
+            }
+
+            return $this->rendered = true;
+        } else {
+            return false;
+        }
     }
 
     /**
@@ -258,10 +272,6 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
      */
     public function getIterator()
     {
-        if (count($this->children)) {
-            $this->rendered = true;
-        }
-
         return new \ArrayIterator($this->children);
     }
 

+ 149 - 0
tests/Symfony/Tests/Component/Form/AbstractDivLayoutTest.php

@@ -116,6 +116,155 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
         );
     }
 
+    public function testRestWithChildrenForms()
+    {
+        $child1 = $this->factory->createNamedBuilder('form', 'child1')
+            ->add('field1', 'text')
+            ->add('field2', 'text')
+            ->getForm();
+
+        $child2 = $this->factory->createNamedBuilder('form', 'child2')
+            ->add('field1', 'text')
+            ->add('field2', 'text')
+            ->getForm();
+
+        $view = $this->factory->createNamedBuilder('form', 'parent')
+            ->getForm()
+            ->add($child1)
+            ->add($child2)
+            ->createView();
+
+        // Render child1.field1 row
+        $this->renderRow($view['child1']['field1']);
+
+        // Render child2.field2 widget (remember that widget don't render label)
+        $this->renderWidget($view['child2']['field2']);
+
+        // Rest should only contain child1.field2 and child2.field1
+        $html = $this->renderRest($view);
+
+        $this->assertMatchesXpath($html,
+'/input
+    [@type="hidden"]
+    [@id="parent__token"]
+/following-sibling::div
+    [
+        ./label[@for="parent_child1"]
+        /following-sibling::div
+            [@id="parent_child1"]
+            [
+                ./div
+                    [
+                        ./label[@for="parent_child1_field2"]
+                        /following-sibling::input[@id="parent_child1_field2"]
+                    ]
+            ]
+    ]
+/following-sibling::div
+    [
+        ./label[@for="parent_child2"]
+        /following-sibling::div
+            [@id="parent_child2"]
+            [
+                ./div
+                    [
+                        ./label[@for="parent_child2_field1"]
+                        /following-sibling::input[@id="parent_child2_field1"]
+                    ]
+                /following-sibling::div
+                    [
+                        ./label[@for="parent_child2_field2"]
+                    ]
+            ]
+    ]
+'
+        );
+    }
+
+    public function testRestAndRepeatedWithRow()
+    {
+        $view = $this->factory->createNamedBuilder('form', 'name')
+            ->add('first', 'text')
+            ->add('password', 'repeated')
+            ->getForm()
+            ->createView();
+
+        $this->renderRow($view['password']);
+
+        $html = $this->renderRest($view);
+
+        $this->assertMatchesXpath($html,
+'/input
+    [@type="hidden"]
+    [@id="name__token"]
+/following-sibling::div
+    [
+        ./label[@for="name_first"]
+        /following-sibling::input[@type="text"][@id="name_first"]
+    ]
+    [count(.//input)=1]
+'
+        );
+    }
+
+    public function testRestAndRepeatedWithRowPerField()
+    {
+        $view = $this->factory->createNamedBuilder('form', 'name')
+            ->add('first', 'text')
+            ->add('password', 'repeated')
+            ->getForm()
+            ->createView();
+
+        $this->renderRow($view['password']['first']);
+        $this->renderRow($view['password']['second']);
+
+        $html = $this->renderRest($view);
+
+        $this->assertMatchesXpath($html,
+'/input
+    [@type="hidden"]
+    [@id="name__token"]
+/following-sibling::div
+    [
+        ./label[@for="name_first"]
+        /following-sibling::input[@type="text"][@id="name_first"]
+    ]
+    [count(.//input)=1]
+    [count(.//label)=1]
+'
+        );
+    }
+
+    public function testRestAndRepeatedWithWidgetPerField()
+    {
+        $view = $this->factory->createNamedBuilder('form', 'name')
+            ->add('first', 'text')
+            ->add('password', 'repeated')
+            ->getForm()
+            ->createView();
+
+        // The password form is considered as rendered as all its childrend
+        // are rendered
+        $this->renderWidget($view['password']['first']);
+        $this->renderWidget($view['password']['second']);
+
+        $html = $this->renderRest($view);
+
+        $this->assertMatchesXpath($html,
+'/input
+    [@type="hidden"]
+    [@id="name__token"]
+/following-sibling::div
+    [
+        ./label[@for="name_first"]
+        /following-sibling::input[@type="text"][@id="name_first"]
+    ]
+    [count(//input)=2]
+    [count(//label)=1]
+'
+        );
+    }
+
     public function testCollection()
     {
         $form = $this->factory->createNamed('collection', 'name', array('a', 'b'), array(