Jelajahi Sumber

Add list edit on one-to-one association

Thomas 14 tahun lalu
induk
melakukan
fb91b85749

+ 0 - 10
Admin/Admin.php

@@ -530,16 +530,6 @@ abstract class Admin extends ContainerAware
         return $this->baseControllerName;
     }
 
-    public function setBaseRoute($baseRoute)
-    {
-        $this->baseRoute = $baseRoute;
-    }
-
-    public function getBaseRoute()
-    {
-        return $this->baseRoute;
-    }
-
     public function setConfigurationPool($configurationPool)
     {
         $this->configurationPool = $configurationPool;

+ 12 - 3
Admin/EntityAdmin.php

@@ -302,7 +302,7 @@ abstract class EntityAdmin extends Admin
         ));
 
         // create the "embedded" field
-        if($fieldDescription->getType() == ClassMetadataInfo::ONE_TO_MANY) {
+        if ($fieldDescription->getType() == ClassMetadataInfo::ONE_TO_MANY) {
             $field = new \Bundle\Sonata\BaseApplicationBundle\Form\EditableFieldGroup($fieldName, array(
                 'value_transformer' => $transformer,
             ));
@@ -377,8 +377,10 @@ abstract class EntityAdmin extends Admin
      */
     protected function getOneToOneField($object, FieldDescription $fieldDescription)
     {
-        
+
+        // tweak the widget depend on the edit mode
         if ($fieldDescription->getOption('edit') == 'inline') {
+
             return $this->getRelatedAssociatedField($object, $fieldDescription);
         }
 
@@ -388,9 +390,14 @@ abstract class EntityAdmin extends Admin
                 'className' => $fieldDescription->getTargetEntity()
             ))
         );
-
         $options = array_merge($options, $fieldDescription->getOption('form_field_options', array()));
 
+
+        if ($fieldDescription->getOption('edit') == 'list') {
+
+            return new \Symfony\Component\Form\TextField($fieldDescription->getFieldName(), $options);
+        }
+
         $class = $fieldDescription->getOption('form_field_widget', 'Symfony\\Component\\Form\\ChoiceField');
 
         // set valid default value
@@ -467,6 +474,7 @@ abstract class EntityAdmin extends Admin
     {
 
         switch ($fieldDescription->getType()) {
+
             case ClassMetadataInfo::ONE_TO_MANY:
 
                 return $this->getOneToManyField($object, $fieldDescription);
@@ -475,6 +483,7 @@ abstract class EntityAdmin extends Admin
 
                 return $this->getManyToManyField($object, $fieldDescription);
 
+            case ClassMetadataInfo::MANY_TO_ONE:
             case ClassMetadataInfo::ONE_TO_ONE:
 
                 return $this->getOneToOneField($object, $fieldDescription);

+ 21 - 0
Controller/CoreController.php

@@ -146,6 +146,27 @@ class CoreController extends Controller
         return $this->createResponse($extension->renderFormElement($fieldDescription, $form, $form->getData()));
     }
 
+    public function getShortObjectDescriptionAction($code, $object_id)
+    {
+
+        $admin            = $this->container->get('base_application.admin.pool')->getInstance($code);
+
+        $object = $admin->getObject($object_id);
+
+        if (!$object) {
+            throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $object_id));
+        }
+
+        $description = 'no description available';
+        foreach (array('getTitle', 'getName', '__toString') as $method) {
+            if (method_exists($object, $method)) {
+                $description = $object->$method();
+                break;
+            }
+        }
+
+        return $this->createResponse($description);
+    }
 
     public function dashboardAction()
     {

+ 4 - 0
Resources/config/routing/base_application.xml

@@ -16,4 +16,8 @@
         <default key="_controller">SonataBaseApplicationBundle:Core:appendFormFieldElement</default>
     </route>
 
+    <route id="sonata_base_application_short_object_information" pattern="/core/{code}/get-short-object-description/{object_id}">
+        <default key="_controller">SonataBaseApplicationBundle:Core:getShortObjectDescription</default>
+    </route>
+
 </routes>

+ 13 - 1
Resources/public/css/layout.css

@@ -42,4 +42,16 @@ td.pager ul li a {
     border: 1px solid #cccccc;
     padding: 4px;
     margin: 2px;
-}
+}
+
+
+div.sonata-ba-modal-edit-one-to-one td.sonata-ba-list-field-batch,
+div.sonata-ba-modal-edit-one-to-one div.sonata-ba-list-actions,
+div.sonata-ba-modal-edit-one-to-one th.sonata-ba-list-field-header-batch
+{
+    display: none;
+}
+
+div.sonata-ba-modal-edit-one-to-one div.sonata-ba-list-actions {
+    display: none;
+}

+ 3 - 3
Resources/views/CRUD/base_list.twig.html

@@ -28,9 +28,9 @@ file that was distributed with this source code.
                 <tr>
                     {% for field_description in fields %}
                         {% if field_description.getOption('code') == '_batch' %}
-                          <th><input type="checkbox" id="list_batch_checkbox" /></th>
+                          <th class="sonata-ba-list-field-header sonata-ba-list-field-header-batch"><input type="checkbox" id="list_batch_checkbox" /></th>
                         {% else %}
-                          <th>{{ field_description.name }}</th>
+                          <th class="sonata-ba-list-field-header sonata-ba-list-field-header-{{ field_description.type}}">{{ field_description.name }}</th>
                         {% endif %}
                     {% endfor %}
                 </tr>
@@ -74,7 +74,7 @@ file that was distributed with this source code.
             });
         </script>
 
-        <div>
+        <div class="sonata-ba-list-actions">
             <select name="action" >
                 {% for action, label in batch_actions %}
                     <option value="{{ action }}">{{ label }}</option>

+ 9 - 7
Resources/views/CRUD/base_list_field.twig.html

@@ -9,10 +9,12 @@ file that was distributed with this source code.
 
 #}
 
-{% if field_description.getOption('identifier') %}
-    <a href="{{ admin.generateUrl('edit', {'id': object.id}) }}">
-        {% block field %}{{ value }}{% endblock %}
-    </a>
-{% else %}
-    {{ block('field') }}
-{% endif %}
+<td class="sonata-ba-list-field sonata-ba-list-field-{{ field_description.type }}" object_id="{{ object.id }}">
+    {% if field_description.options.identifier is defined %}
+        <a href="{{ admin.generateUrl('edit', {'id': object.id}) }}">
+            {% block field %}{{ value }}{% endblock %}
+        </a>
+    {% else %}
+        {{ block('field') }}
+    {% endif %}
+</td>

+ 145 - 13
Resources/views/CRUD/edit_many_association_script.twig.html

@@ -18,8 +18,40 @@ This code manage the many-to-[one|many] association field popup
 
 <script>
 
+
+    {#
+      handle link click in a list :
+        - if the parent has an object_id defined then the related input get updated
+        - if the parent has NO object then an ajax request is made to refresh the popup
+    #}
+    var field_dialog_form_list_link_{{ admin.code }}_{{ field_element.id }} = function(event) {
+        event.preventDefault();
+
+        var element = jQuery(this).parents('td.sonata-ba-list-field');
+
+        // the user does does click on a row column
+        if(element.length == 0) {
+            // make a recurive call (ie: reset the filter)
+            jQuery.ajax({
+                type: 'GET',
+                url: jQuery(this).attr('href'),
+                success: function(html) {
+                   field_dialog_{{ admin.code }}_{{ field_element.id }}.html(html);
+                }
+            });
+
+            return;
+        }
+
+        jQuery('#{{ field_element.id}}').val(element.attr('object_id'));
+        jQuery('#{{ field_element.id}}').change();
+
+        field_dialog_{{ admin.code }}_{{ field_element.id }}.dialog('close');
+    }
+
+
     // handle the add link
-    var field_dialog_form_add_{{ admin.code }}_{{ field_element.id }} = function(event) {
+    var field_dialog_form_list_{{ admin.code }}_{{ field_element.id }} = function(event) {
         event.preventDefault();
 
         var a = jQuery(this);
@@ -30,12 +62,60 @@ This code manage the many-to-[one|many] association field popup
         jQuery.ajax({
             url: a.attr('href'),
             success: function(html) {
-                var html = jQuery(html);
+                // populate the popup container
+                field_dialog_{{ admin.code }}_{{ field_element.id }}.html(html);
+
+                // capture the submit event to make an ajax call, ie : POST data to the
+                // related create admin
 
+                // make sure we have a clean state
+                jQuery('a', field_dialog_{{ admin.code }}_{{ field_element.id }}).die('click');
+                jQuery('form', field_dialog_{{ admin.code }}_{{ field_element.id }}).die('submit');
 
+                // add live event
+                jQuery('a', field_dialog_{{ admin.code }}_{{ field_element.id }}).live('click', field_dialog_form_list_link_{{ admin.code }}_{{ field_element.id }});
+                jQuery('form', field_dialog_{{ admin.code }}_{{ field_element.id }}).live('submit', function(event) {
+                    event.preventDefault();
+
+                    var form = jQuery(this);
+
+                    jQuery.ajax({
+                        type: form.attr('method'),
+                        url: form.attr('action'),
+                        data: form.serializeArray(),
+                        success: function(html) {
+                           field_dialog_{{ admin.code }}_{{ field_element.id }}.html(html);
+                        }
+                    });
+                });
+
+                // open the dialog in modal mode
+                field_dialog_{{ admin.code }}_{{ field_element.id }}.dialog({
+                    height: 'auto',
+                    width: 980,
+                    modal: true,
+                    resizable: false,
+                    title: '{{ field_description.associationadmin.label }}'
+
+                });
+            }
+        });
+    };
+
+    // handle the add link
+    var field_dialog_form_add_{{ admin.code }}_{{ field_element.id }} = function(event) {
+        event.preventDefault();
+
+        var a = jQuery(this);
+
+        field_dialog_{{ admin.code }}_{{ field_element.id }}.html('');
+
+        // retrieve the form element from the related admin generator
+        jQuery.ajax({
+            url: a.attr('href'),
+            success: function(html) {
                 // populate the popup container
-                field_dialog_{{ admin.code }}_{{ field_element.id }}.html(html[0]);
-                field_dialog_{{ admin.code }}_{{ field_element.id }}.append(html[1]);
+                field_dialog_{{ admin.code }}_{{ field_element.id }}.html(html);
 
                 // capture the submit event to make an ajax call, ie : POST data to the
                 // related create admin
@@ -48,7 +128,6 @@ This code manage the many-to-[one|many] association field popup
                     modal: true,
                     resizable: false,
                     title: '{{ field_description.associationadmin.label }}'
-
                 });
             }
         });
@@ -103,6 +182,19 @@ This code manage the many-to-[one|many] association field popup
 
     var field_dialog_{{ admin.code }}_{{ field_element.id }} = false;
 
+    function initialize_popup_{{ admin.code }}_{{ field_element.id }}() {
+        // initialize component
+        if(!field_dialog_{{ admin.code }}_{{ field_element.id }}) {
+            field_dialog_{{ admin.code }}_{{ field_element.id }} = jQuery("#field_dialog_{{ admin.code }}_{{ field_element.id }}");
+
+            // move the dialog as a child of the root element, nested form breaks html ...
+            jQuery(document).append(field_dialog_{{ admin.code }}_{{ field_element.id }});
+        }
+    }
+
+    {#
+        This code is used to defined the "add" popup
+    #}
     // this function initialize the popup
     // this can be only done this way has popup can be cascaded
     function start_field_dialog_form_add_{{ admin.code }}_{{ field_element.id }}(event) {
@@ -112,14 +204,9 @@ This code manage the many-to-[one|many] association field popup
         var a = jQuery(event.target).closest('a');
         a.attr('onclick', '');
 
+        initialize_popup_{{ admin.code }}_{{ field_element.id }}();
 
-        // initialize component
-        field_dialog_{{ admin.code }}_{{ field_element.id }} = jQuery("#field_dialog_{{ admin.code }}_{{ field_element.id }}");
-
-        // move the dialog as a child of the root element, nested form breaks html ...
-        jQuery(document).append(field_dialog_{{ admin.code }}_{{ field_element.id }});
-
-        // add the jQuery event to the a element
+       // add the jQuery event to the a element
         a.click(field_dialog_form_add_{{ admin.code }}_{{ field_element.id }});
 
         // trigger the event
@@ -129,5 +216,50 @@ This code manage the many-to-[one|many] association field popup
     }
 
     BaseApplication.add_pretty_errors(field_dialog_{{ admin.code }}_{{ field_element.id }});
-    
+
+
+    {% if field_description.options.edit == 'list' %}
+        {#
+            This code is used to defined the "list" popup
+        #}
+        // this function initialize the popup
+        // this can be only done this way has popup can be cascaded
+        function start_field_dialog_form_list_{{ admin.code }}_{{ field_element.id }}(event) {
+            event.preventDefault();
+
+            // remove the html event a
+            var a = jQuery(event.target).closest('a');
+            a.attr('onclick', '');
+
+            initialize_popup_{{ admin.code }}_{{ field_element.id }}();
+
+            // add the jQuery event to the a element
+            a.click(field_dialog_form_list_{{ admin.code }}_{{ field_element.id }});
+
+            // trigger the event
+            a.trigger('click');
+
+            return false;
+        }
+
+        {#
+          attach onchange event on the input
+        #}
+
+        // update the 
+        jQuery('#{{ field_element.id}}').change(function(event) {
+            jQuery.ajax({
+                type: 'GET',
+                url: '{{ url('sonata_base_application_short_object_information', {
+                    'code': field_description.associationadmin.code,
+                    'object_id': 'OBJECT_ID'
+                })}}'.replace('OBJECT_ID', jQuery(this).val()),
+                success: function(html) {
+                    jQuery('#field_widget_{{ admin.code }}_{{ field_element.id}}').html(html);
+                }
+            });
+        });
+
+    {% endif %}
+
 </script>

+ 1 - 1
Resources/views/CRUD/edit_one_to_many.twig.html

@@ -13,7 +13,7 @@ file that was distributed with this source code.
 
 
 {% block field %}
-    {% if edit == 'inline' %}
+    {% if field_description.options.edit == 'inline' %}
 
         <div id="field_container_{{ admin.code }}_{{ field_element.id}}">
             <span id="field_widget_{{ admin.code }}_{{ field_element.id}}" >

+ 24 - 4
Resources/views/CRUD/edit_one_to_one.twig.html

@@ -16,18 +16,38 @@ file that was distributed with this source code.
         {% for nested_field_description in field_description.associationadmin.formfields %}
             {{ nested_field_description|render_form_element(field_element, value) }}
         {% endfor %}
+
     {% else %}
 
         <div id="field_container_{{ admin.code }}_{{ field_element.id}}">
-            <span id="field_widget_{{ admin.code }}_{{ field_element.id}}" >
-                {{ form_field(field_element) }}
-            </span>
 
+            {% if field_description.options.edit == 'list' %}
+                <span id="field_widget_{{ admin.code }}_{{ field_element.id}}" >
+                    {% if value.id %}
+                        {% render 'SonataBaseApplicationBundle:Core:getShortObjectDescription' with {
+                            'code': field_description.associationadmin.code,
+                            'object_id': value.id
+                        }%}
+                    {% endif %}
+                </span>
+                <span style="display: none" >
+                    {{ form_field(field_element) }}
+                </span>
+            {% else %}
+                <span id="field_widget_{{ admin.code }}_{{ field_element.id}}" >
+                    {{ form_field(field_element) }}
+                </span>
+            {% endif %}
             <span id="field_actions_{{ admin.code }}_{{ field_element.id}}" >
+
+                {% if field_description.options.edit == 'list' %}
+                    <a href="{{ field_description.associationadmin.generateUrl('list') }}" onclick="start_field_dialog_form_list_{{ admin.code }}_{{ field_element.id }}(event)" class="action"><img src="{{ asset('bundles/baseapplication/famfamfam/application_view_list.png') }}" alt="{% trans 'btn_add' from 'BaseApplicationBundle' %}" /></a>
+                {% endif %}
+
                 <a href="{{ field_description.associationadmin.generateUrl('create') }}" onclick="start_field_dialog_form_add_{{ admin.code }}_{{ field_element.id }}(event)" class="action"><img src="{{ asset('bundles/baseapplication/famfamfam/add.png') }}" alt="{% trans 'btn_add' from 'BaseApplicationBundle' %}" /></a>
             </span>
 
-            <div style="display: hidden" id="field_dialog_{{ admin.code }}_{{ field_element.id }}">
+            <div class="container sonata-ba-modal sonata-ba-modal-edit-one-to-one" style="display: none" id="field_dialog_{{ admin.code }}_{{ field_element.id }}">
 
             </div>
         </div>

+ 1 - 1
Resources/views/CRUD/list.twig.html

@@ -15,7 +15,7 @@ file that was distributed with this source code.
     {% for element in datagrid.results %}
         <tr>
             {% for field_description in fields %}
-                <td>{{ element|render_list_element(field_description) }}</td>
+                {{ element|render_list_element(field_description) }}
             {% endfor %}
         </tr>
     {% endfor %}

+ 3 - 3
Resources/views/CRUD/list__batch.twig.html

@@ -9,6 +9,6 @@ file that was distributed with this source code.
 
 #}
 
-{% extends 'SonataBaseApplicationBundle:CRUD:base_list_field.twig.html' %}
-
-{% block field%}<input type="checkbox" name="idx[]" value="{{ object.id }}" />{% endblock %}
+<td class="sonata-ba-list-field sonata-ba-list-field-batch">
+  <input type="checkbox" name="idx[]" value="{{ object.id }}" />
+</td>

+ 9 - 0
Resources/views/ajax_layout.twig.html

@@ -12,4 +12,13 @@ file that was distributed with this source code.
     {% block preview %}{% endblock %}
     {% block form %}{% endblock %}
     {% block list %}{% endblock %}
+
+                        <div class="sonata-ba-list">
+                    <div class="span-18">
+                        {% block list_table %}{% endblock %}
+                    </div>
+                    <div class="span-6 last">
+                        {% block list_filters %}{% endblock %}
+                    </div>
+                </div>
 {% endblock %}