فهرست منبع

merged branch marcw/form-prototype-attribute (PR #1724)

Commits
-------

257f86c [Form] Collection's prototype is not not a child anymore.
2b4cc9b [Form] Changed collection prototype rendering.

Discussion
----------

[Form] Changed collection prototype rendering

Based on PR #1500. It is now rendered inside an attribute of collection
tag.

The data-attribute can be retrieved using this piece of jQuery code. You aways will need to adapt it. I think this will be also doable with plain JS.

```javascript
<script type="text/javascript">
        jQuery('p.add-child').click(function() {
            var prototype = $('form #id').attr('data-prototype');
            prototype = prototype.replace(/\$\$name\$\$/g, 'levelxx');
            $('#id').append(prototype);
        });
</script>
```

Closes #1497

---------------------------------------------------------------------------

by beberlei at 2011/07/18 06:40:40 -0700

form div[data-prototype]? What about forms with two collections?

---------------------------------------------------------------------------

by marcw at 2011/07/18 07:25:51 -0700

My bad, the javascript snippet is not crystal clear. Actually, you'll have to specify the div's id to retrieve the right `data-prototype` attribute.
The good way of doing this is by specifying the div's id in the selector (like in the 2nd part of the js example), like this :

    var prototype = $('form #level1_level2_level3_level3').attr('data-prototype');

---------------------------------------------------------------------------

by tystr at 2011/07/18 12:32:39 -0700

+1

---------------------------------------------------------------------------

by marcw at 2011/07/22 01:46:08 -0700

thanx @vicb ! :)
Fabien Potencier 14 سال پیش
والد
کامیت
f29da2fcc8

+ 1 - 1
src/Symfony/Bridge/Twig/Extension/FormExtension.php

@@ -223,7 +223,7 @@ class FormExtension extends \Twig_Extension
             }
         }
 
-        $custom = '_'.$view->get('proto_id', $view->get('id'));
+        $custom = '_'.$view->get('id');
         $rendering = $custom.$section;
         $blocks = $this->getBlocks($view);
 

+ 9 - 6
src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig

@@ -9,6 +9,15 @@
 {% endspaceless %}
 {% endblock form_widget %}
 
+{% block collection_widget %}
+{% spaceless %}
+    {% if prototype is defined %}
+        {% set attr = attr|merge({'data-prototype': form_row(prototype) }) %}
+    {% endif %}
+    {{ block('form_widget') }}
+{% endspaceless %}
+{% endblock collection_widget %}
+
 {% block textarea_widget %}
 {% spaceless %}
     <textarea {{ block('widget_attributes') }}>{{ value }}</textarea>
@@ -222,12 +231,6 @@
 {% endspaceless %}
 {% endblock field_row %}
 
-{% block prototype_row %}
-{% spaceless %}
-    <script type="text/html" id="{{ proto_id }}">{{ form_row(form) }}</script>
-{% endspaceless %}
-{% endblock prototype_row %}
-
 {% block hidden_row %}
     {{ form_widget(form) }}
 {% endblock hidden_row %}

+ 4 - 0
src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/collection_widget.html.php

@@ -0,0 +1,4 @@
+<?php if (isset($prototype)): ?>
+    <?php $attr['data-prototype'] = $view->escape($view['form']->row($prototype)) ?>
+<?php endif ?>
+<?php echo $view['form']->widget($form, array('attr' => $attr)) ?>

+ 0 - 3
src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/prototype_row.html.php

@@ -1,3 +0,0 @@
-<script type="text/html" id="<?php echo $view->escape($proto_id) ?>">
-    <?php echo $view['form']->row($form) ?>
-</script>

+ 1 - 1
src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php

@@ -199,7 +199,7 @@ class FormHelper extends Helper
 
         $template = null;
 
-        $custom = '_'.$view->get('proto_id', $view->get('id'));
+        $custom = '_'.$view->get('id');
         $rendering = $custom.$section;
 
         if (isset($this->varStack[$rendering])) {

+ 12 - 2
src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php

@@ -27,7 +27,7 @@ class CollectionType extends AbstractType
     {
         if ($options['allow_add'] && $options['prototype']) {
             $prototype = $builder->create('$$name$$', $options['type'], $options['options']);
-            $builder->setAttribute('prototype', $prototype);
+            $builder->setAttribute('prototype', $prototype->getForm());
         }
 
         $dataClass = isset($options['options']['data_class']) ? $options['options']['data_class'] : null;
@@ -63,7 +63,17 @@ class CollectionType extends AbstractType
         ;
 
         if ($form->hasAttribute('prototype')) {
-            $view->set('prototype', $form->getAttribute('prototype'));
+            $view->set('prototype', $form->getAttribute('prototype')->createView($view));
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function buildViewBottomUp(FormView $view, FormInterface $form)
+    {
+        if ($form->hasAttribute('prototype') && $view->get('prototype')->get('multipart')) {
+            $view->set('multipart', true);
         }
     }
 

+ 0 - 10
src/Symfony/Component/Form/Form.php

@@ -925,16 +925,6 @@ class Form implements \IteratorAggregate, FormInterface
             $childViews[$key] = $child->createView($view);
         }
 
-        if (null !== $prototype = $view->get('prototype')) {
-            $protoView = $prototype->getForm()->createView($view);
-            $protoTypes = $protoView->get('types');
-            $protoTypes[] = 'prototype';
-            $childViews[$prototype->getName()] = $protoView
-                ->set('types', $protoTypes)
-                ->set('proto_id', $view->get('id').'_prototype');
-            ;
-        }
-
         $view->setChildren($childViews);
 
         foreach ($types as $type) {

+ 4 - 3
tests/Symfony/Tests/Component/Form/AbstractLayoutTest.php

@@ -1692,9 +1692,10 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
         $html = $this->renderWidget($form);
 
         $this->assertMatchesXpath($html,
-'//script
-    [@id="na&me_items_prototype"]
-    [@type="text/html"]
+            '//div[@id="na&me_items"][@data-prototype]
+            |
+             //table[@id="na&me_items"][@data-prototype]
+
 '
         );
     }

+ 25 - 0
tests/Symfony/Tests/Component/Form/Extension/Core/Type/CollectionTypeTest.php

@@ -178,4 +178,29 @@ class CollectionFormTest extends TypeTestCase
         $bound = $form->getData();
         $this->assertInstanceOf('Symfony\Tests\Component\Form\Fixtures\Author', $bound[0]);
     }
+
+    public function testGetDataDoesNotContainsProtypeNameBeforeDataAreSet()
+    {
+        $form = $this->factory->create('collection', array(), array(
+            'type'      => 'file',
+            'prototype' => true,
+            'allow_add' => true,
+        ));
+
+        $data = $form->getData();
+        $this->assertFalse(isset($data['$$name$$']));
+    }
+
+    public function testGetDataDoesNotContainsPrototypeNameAfterDataAreSet()
+    {
+        $form = $this->factory->create('collection', array(), array(
+            'type'      => 'file',
+            'allow_add' => true,
+            'prototype' => true,
+        ));
+
+        $form->setData(array('foobar.png'));
+        $data = $form->getData();
+        $this->assertFalse(isset($data['$$name$$']));
+    }
 }