]> git.andy128k.dev Git - ipf.git/commitdiff
replace inline models with set field and set table widget
authorAndrey Kutejko <andy128k@gmail.com>
Sun, 7 Sep 2014 20:45:08 +0000 (23:45 +0300)
committerAndrey Kutejko <andy128k@gmail.com>
Sun, 7 Sep 2014 20:45:08 +0000 (23:45 +0300)
ipf/admin/legacymodel.php
ipf/admin/model.php
ipf/admin/modelinline.php
ipf/admin/static/admin/css/forms.css
ipf/admin/templates/admin/change.html

index d8baa171dfb63321e3e9bc0f4071a91a83997354..5b5027071dd247e7d5170251c9ff8b24227149db 100644 (file)
@@ -191,18 +191,14 @@ class IPF_Admin_Model extends IPF_Admin_Component
     {
         $extra = array(
             'user_fields' => $this->fields(),
+            'inlines' => $this->inlines(),
         );
+        return new IPF_Admin_ModelForm($data, $model, $this->modelName, $extra);
+    }
 
-        if ($model) {
-            // edit
-            $extra['model'] = $model;
-            $extra['initial'] = $this->getFormData($model);
-        } else {
-            // add
-            $extra['model'] = new $this->modelName;
-        }
-
-        return new IPF_Form_Model($data, $extra);
+    public function inlines()
+    {
+        return array();
     }
 
     public function saveObject($form, $model)
@@ -221,8 +217,49 @@ class IPF_Admin_Model extends IPF_Admin_Component
     {
         return null;
     }
+}
+
+class IPF_Admin_ModelForm extends IPF_Form_Model
+{
+    private $inlines = array();
 
-    public function getFormData($o)
+    function __construct($data=null, $model=null, $modelName='', $extra=array())
+    {
+        if ($model) {
+            // edit
+            $extra['model'] = $model;
+            $extra['initial'] = $this->getFormData($model);
+        } else {
+            // add
+            $extra['model'] = new $modelName;
+        }
+
+        parent::__construct($data, $extra);
+    }
+
+    function initFields($extra=array())
+    {
+        parent::initFields($extra);
+
+        if ($extra['inlines']) {
+            $this->field_groups[] = array('fields' => array_keys($this->fields));
+            foreach ($extra['inlines'] as $inlineClassName) {
+                $this->inlines[] = new $inlineClassName($extra['model']);
+            }
+        }
+
+        foreach ($this->inlines as $inline) {
+            $name = $inline->getModelName();
+            $this->fields[$name] = $inline->createField();
+
+            $this->field_groups[] = array(
+                'label' => $inline->getLegend(),
+                'fields' => array($name),
+            );
+        }
+    }
+
+    private function getFormData($o)
     {
         $data = $o->getData();
         foreach ($o->getTable()->getRelations() as $rname => $rel) {
@@ -236,8 +273,59 @@ class IPF_Admin_Model extends IPF_Admin_Component
                 }
             }
         }
+
+        foreach ($this->inlines() as $inlineName => $inlineClassName) {
+            $inlineInstance = new $inlineClassName($o, null);
+
+            $objs = array();
+            foreach ($inlineInstance->getObjects() as $io) {
+                $d = $io->getData();
+                $d['id'] = $io->pk();
+                $objs[] = $d;
+            }
+            $data[$inlineName] = $objs;
+        }
+
         return $data;
     }
+
+    function save($commit=true)
+    {
+        $model = parent::save($commit);
+
+        foreach ($this->inlines as $inline) {
+            $this->saveInlineObject($inline, $model);
+        }
+
+        return $model;
+    }
+
+    private function saveInlineObject($inline, $model)
+    {
+        $objIndex = array();
+        foreach ($inline->getObjects() as $obj)
+            $objIndex[$obj->pk()] = $obj;
+
+        $modelName = $inline->getModelName();
+        $fk_local = $inline->getFkLocal();
+
+        foreach ($this->cleaned_data[$modelName] as $objData) {
+            if (array_key_exists('id', $objData) && array_key_exists($objData['id'], $objIndex)) {
+                $obj = $objIndex[$objData['id']];
+                if (isset($objData['is_remove'])) {
+                    $obj->delete();
+                } else {
+                    $obj->synchronizeWithArray($objData);
+                    $obj->save();
+                }
+            } else {
+                $objData[$fk_local] = $model->id;
+                $obj = new $modelName;
+                $obj->synchronizeWithArray($objData);
+                $obj->save();
+            }
+        }
+    }
 }
 
 abstract class IPF_Admin_Model_Filter implements IPF_Admin_ListFilter
index 778f0f43051df1fb656417283e6cdcbf1c6a3b7b..2ada07f0ff4cebc3d1c210dffa77d2616d555d25 100644 (file)
@@ -9,9 +9,7 @@ interface IPF_Admin_ListFilter
 
 abstract class IPF_Admin_Component
 {
-    var $inlineInstances = array();
-    var $perPage = 50;
-
+    public $perPage = 50;
     public $app = null, $request = null;
 
     public function slug()
@@ -61,23 +59,6 @@ abstract class IPF_Admin_Component
         return IPF_Admin_App::RenderToResponse($template, $context, $request);
     }
 
-    protected function setInlines($model, $data=null)
-    {
-        $il = $this->inlines();
-        if (is_array($il)) {
-            foreach($il as $inlineName => $inlineClassName) {
-                $this->inlineInstances[] = new $inlineClassName($model, $data);
-            }
-        }
-    }
-
-    protected function saveInlines($obj)
-    {
-        foreach($this->inlineInstances as $inlineInstance) {
-            $inlineInstance->save($obj);
-        }
-    }
-
     protected function _setupEditForm($form)
     {
         $this->_setupForm($form);
@@ -92,19 +73,6 @@ abstract class IPF_Admin_Component
     {
     }
 
-    public function inlines()
-    {
-        return null;
-    }
-
-    public function isValidInlines()
-    {
-        foreach ($this->inlineInstances as &$il)
-            if ($il->isValid() === false)
-                return false;
-        return true;
-    }
-
     public abstract function list_display();
 
     public function list_display_links()
@@ -204,7 +172,6 @@ abstract class IPF_Admin_Component
             'form_html' => $form->renderLayout(new IPF_Admin_Form_Layout),
             'extra_js' => $extraMedia['js'],
             'extra_css' => $extraMedia['css'],
-            'inlineInstances'=>$this->inlineInstances,
             'errors' => $errors,
             'objecttools' => array(),
         );
@@ -279,7 +246,6 @@ abstract class IPF_Admin_Component
             'form_html' => $form->renderLayout(new IPF_Admin_Form_Layout),
             'extra_js' => $extraMedia['js'],
             'extra_css' => $extraMedia['css'],
-            'inlineInstances'=>$this->inlineInstances,
             'errors' => $errors,
             'objecttools' => $objecttools,
         );
index 0baf64d571096f662ee1c878e3bfbd5a1b30ba54..bb5e4dd158dc1f30bc9d0dacb30546fe7ee30adf 100644 (file)
@@ -2,19 +2,12 @@
 
 abstract class IPF_Admin_ModelInline
 {
-    var $model = null;
-    var $parentModel = null;
-    var $formset = null;
+    public $parentModel = null;
+    public $orderby = 'id';
 
-    var $orderby = 'id';
-
-    function __construct($parentModel, $data=null)
+    function __construct($parentModel)
     {
         $this->parentModel = $parentModel;
-
-        $modelName = $this->getModelName();
-        $this->model = new $modelName();
-        $this->createFormSet($data);
     }
 
     abstract function getModelName();
@@ -35,65 +28,12 @@ abstract class IPF_Admin_ModelInline
 
     function getLegend()
     {
-        return get_class($this->model);
-    }
-
-    public function listColumns()
-    {
-        if (!$this->formset || !count($this->formset))
-            return array();
-
-        $header = array();
-        foreach ($this->formset[0]->fields as $fieldname => $field) {
-            $header[] = array(
-                'fieldname' => $fieldname,
-                'label'     => $field->label,
-                'is_hidden' => $field->widget->is_hidden,
-                'is_del'    => (property_exists($field, 'is_del') && $field->is_del),
-                'has_display_method' => method_exists($this, 'column_'.$fieldname),
-            );
-        }
-        return $header;
-    }
-
-    public function displayField($fieldname, $obj)
-    {
-        $method = 'column_'.$fieldname;
-        if (!method_exists($this, $method))
-            throw new IPF_Exception('No method '.$method.' defined.');
-        return $this->$method($obj);
-    }
-
-    function isValid()
-    {
-        foreach ($this->formset as $form) {
-            if (!$form->isValid()) {
-                $empty = true;
-                foreach ($form->data as $k => $v) {
-                    if (is_array($v) && \PFF\Arr::get($v, 'error') === 4) {
-                        // empty file
-                    } elseif ($k !== $form->prefix.'is_remove' && $v) {
-                        $empty = false;
-                        break;
-                    }
-                }
-                if (!$form->isAdd || !$empty) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    protected function _getForm($model, $data, $extra)
-    {
-        $extra['model'] = $model;
-        return new IPF_Form_Model($data, $extra);
+        return $this->getModelName();
     }
 
     function getFkName()
     {
-        foreach($this->model->getTable()->getRelations() as $rel) {
+        foreach($this->getTable()->getRelations() as $rel) {
             if ($rel->getClass()==get_class($this->parentModel))
                 return $rel->getAlias();
         }
@@ -102,159 +42,69 @@ abstract class IPF_Admin_ModelInline
 
     function getFkLocal()
     {
-        foreach($this->model->getTable()->getRelations() as $rel) {
+        foreach($this->getTable()->getRelations() as $rel) {
             if ($rel->getClass() == get_class($this->parentModel))
                 return $rel->getLocal();
         }
         throw new IPF_Exception(__('Cannot get fkLocal for '.$this->getModelName()));
     }
 
-    function createFormSet($data)
+    function getObjects()
     {
-        $this->formset = array();
+        if (!$this->parentModel->exists())
+            return array();
 
-        $o = $this->_orderableColumn();
+        $query = IPF_ORM_Query::create()
+            ->from($this->getModelName())
+            ->where($this->getFkLocal().'='.$this->parentModel->id);
 
-        $form_extra = array(
-            'exclude' => array(
-                $this->getFkName(),
-                $this->getFkLocal(),
-            ),
-        );
+        $o = $this->_orderableColumn();
         if ($o)
-            $form_extra['exclude'][] = $o;
-
-        if ($this->parentModel->exists()) {
-            $query = IPF_ORM_Query::create()
-                ->from(get_class($this->model))
-                ->where($this->getFkLocal().'='.$this->parentModel->id);
-
-            if ($o)
-                $objects = $query->orderby($o)->execute();
-            else
-                $objects = $query->orderby($this->orderby)->execute();
-
-            foreach ($objects as $obj) {
-                $prefix = 'edit_'.get_class($this->model).'_'.$obj->id.'_';
-                $d = $this->extractFormData($obj, $data, $prefix);
-
-                $form = $this->_getForm($obj, $d, $form_extra);
-
-                $form->prefix = $prefix;
-
-                $del = new IPF_Form_Field_Boolean(array(
-                    'label' => __('Del'),
-                    'name' => 'is_remove',
-                ));
-                $del->is_del = true;
-                $form->fields = array_merge(array('is_remove' => $del), $form->fields);
-
-                $form->isAdd = false;
-                $this->formset[] = $form;
-            }
-        }
-
-        $n_addnum = $this->getAddNum();
-        for ($i = 0; $i < $n_addnum; $i++) {
-            $prefix = 'add_'.get_class($this->model).'_'.$i.'_';
-            $d = $data !== null ? $this->extractFormData(null, $data, $prefix) : null;
-
-            $form = $this->_getForm($this->model->copy(), $d, $form_extra);
-            $form->prefix = 'add_'.get_class($this->model).'_'.$i.'_';
-            
-            $del = new IPF_Form_Field_Boolean(array(
-                'label' => __('Del'),
-                'name' => 'is_remove',
-                'widget_attrs' => array('disabled'=>'disabled'),
-            ));
-            $del->is_del = true;
-            
-            $form->fields = array_merge(array('is_remove' => $del), $form->fields);
+            $query->orderby($o);
+        else
+            $query->orderby($this->orderby);
 
-            $form->isAdd = true;
-            $this->formset[] = $form;
-        }
+        return $query->execute();
     }
 
-    private function extractFormData($obj, $data, $prefix)
+    public function _orderable()
     {
-        $d = array();
-        if ($data === null) {
-            foreach ($obj->getData() as $k => $v) {
-                $d[$prefix.$k] = $v;
-            }
-        } else {
-            foreach ($data as $k => $v) {
-                if (strpos($k, $prefix) === 0)
-                    $d[$k] = $v;
-            }
-        }
-        return $d;
+        return $this->_orderableColumn() !== null;
     }
 
-    function save($parent_obj)
+    public function _orderableColumn()
     {
-        if (!$this->isValid())
-            throw new IPF_Exception_Form(__('Cannot save models from an invalid formset.'));
-
-        if ($this->parentModel->exists()) {
-            $objects = IPF_ORM_Query::create()
-                ->from(get_class($this->model))
-                ->orderby('id')
-                ->where($this->getFkLocal().'='.$this->parentModel->id)
-                ->execute();
-            foreach ($objects as $obj) {
-                foreach ($this->formset as $form) {
-                    if ($form->isAdd)
-                        continue;
-
-                    @list($x1,$x2,$id,$x3) = @explode('_',$form->prefix);
-                    if ($id == $obj->id) {
-                        if ($form->cleaned_data['is_remove']==true) {
-                            $obj->delete();
-                        } else {
-                            unset($form->cleaned_data[0]);
-                            foreach($form->fields as $fname=>$f) {
-                                if (is_a($f,'IPF_Form_Field_File')) {
-                                    if($form->cleaned_data[$fname]===null)
-                                        continue;
-                                    if($form->cleaned_data[$fname]=='')
-                                        unset($form->cleaned_data[$fname]);
-                                }
-
-                            }
-                            $obj->synchronizeWithArray($form->cleaned_data);
-                            $obj->save();
-                        }
-                        break;
-                    }
-                }
-            }
-        }
-
-        $fk_local = $this->getFkLocal();
-        foreach ($this->formset as $form) {
-            if ($form->isAdd) {
-                if ($form->isValid()) {
-                    unset($form->cleaned_data[0]);
-                    $form->cleaned_data[$fk_local] = $parent_obj->id;
-                    $form->save();
-                }
-            }
-        }
+        if ($this->getTable()->hasTemplate('IPF_ORM_Template_Orderable'))
+            return $this->getTable()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
+        else
+            return null;
     }
 
-    public function _orderable()
+    private function getTable()
     {
-        return $this->_orderableColumn() !== null;
+        return IPF_ORM::getTable($this->getModelName());
     }
 
-    public function _orderableColumn()
+    public function createField()
     {
-        if ($this->model->getTable()->hasTemplate('IPF_ORM_Template_Orderable'))
-            return $this->model->getTable()->getTemplate('IPF_ORM_Template_Orderable')->getColumnName();
-        else
-            return null;
+        $exclude = array(
+            $this->getFkName(),
+            $this->getFkLocal(),
+        );
+        $o = $this->_orderableColumn();
+        if ($o)
+            $exclude[] = $o;
+
+        $fields = array();
+        foreach (IPF_Form_Model::suggestFields($this->getTable(), null, $exclude, null) as $field) {
+            list($n, $f) = $field;
+            $fields[$n] = $f;
+        }
+
+        return new IPF_Form_Field_Set(array(
+            'fields' => $fields,
+            'addCount' => $this->getAddNum(),
+        ));
     }
 }
 
index 934da57393f9df68ca3f4e180142fb23514cc39d..ed59a4204e554ff8e28333e65be144259b084021 100644 (file)
@@ -168,6 +168,11 @@ fieldset.monospace textarea { font-family:"Bitstream Vera Sans Mono",Monaco,"Cou
 /* INLINE */
 .inline-related table {width: 100%;}
 
+/* SET WIDGET */
+.set-widget { border-collapse: collapse; width: 100%; }
+.set-widget th { background:#eee url(../img/nav-bg.gif) bottom left repeat-x; color:#666; }
+
+
 /* INLINE REORDER */
 .ItemsDragClass{background-color:#E3F3FE;}
 
index 05938cffc09bf355d0e5dc7bef31f7c07c05c14d..6cb00a05d4aa8af8c79c3520342c7e232f24407f 100644 (file)
                 {$form_html|safe}
               {/block}
             </fieldset>
-            {if $inlineInstances}
-            {foreach $inlineInstances as $inline}
-            <div class="inline-group">
-                <div class="tabular inline-related">
-                    <fieldset class="module">
-                    <h2>{$inline->getLegend()}</h2>
-                    <table{if $inline->_orderable()} class="orderable-inlne" data-url="{url 'IPF_Admin_Views_ListItems', array($inline->getApplication()->slug(), strtolower($inline->getModelName()))}"{/if}>
-                        <thead>
-                        <tr class="nodrop">
-                            {foreach $inline->listColumns() as $column}
-                            <th{if $column['is_del']} style="width:20px;"{elseif $column['is_hidden']} style="display:none;"{/if}>{$column['label']}</th>
-                            {/foreach}
-                        </tr>
-                        </thead>
-                        <tbody>
-                        {foreach $inline.formset as $form}
-                        <tr{if !$form.isAdd} data-id="{$form.model.pk()}"{else} class="nodrag nodrop"{/if}>
-                            {foreach $inline->listColumns() as $column}
-                            <td{if $column['is_hidden']} style="display:none;"{/if}>
-                                {assign $field = $form.field($column['fieldname'])}
-                                {if $column['has_display_method']}
-                                    {$inline->displayField($column['fieldname'], $form->model) |safe}
-                                {else}
-                                    {$field.fieldErrors()}
-                                    {$field |safe}
-                                {/if}
-                            </td>
-                            {/foreach}
-                        </tr>
-                        {/foreach}
-                        </tbody>
-                    </table>
-                    </fieldset>
-                </div>
-            </div>
-            {/foreach}
-            {/if}
             <div class="submit-row">
                 {if ($mode=='change') && $component->isAccessible(array('delete'))}<p class="float-left"><a id="id_a_delete" href="{url 'IPF_Admin_Views_DeleteItem', array($app->slug(), $component->slug(), $object_id)}" class="deletelink">{trans 'Delete'}</a></p>{/if}
                 {if ($mode=='change') && $component->isAccessible(array('change'))}<input type="submit" value="{trans 'Save'}" class="default" />{/if}