commit 3882f5d361b2687c7e5fdff127562c08d7aabb9e
Author: Filip Jani <jsem@filek.cz>
Date:   Tue May 28 23:35:43 2019 +0200

    Re #7505 úprava a mazání řádek

diff --git a/app/AdminModule/component/Transliteration/TransliterationDataEditForm.latte b/app/AdminModule/component/Transliteration/TransliterationDataEditForm.latte
index 0ffd040..2d3c707 100644
--- a/app/AdminModule/component/Transliteration/TransliterationDataEditForm.latte
+++ b/app/AdminModule/component/Transliteration/TransliterationDataEditForm.latte
@@ -42,7 +42,7 @@
                                     <div class="card mb-1">
                                         <h5 class="mb-0">
                                             <a class="btn btn-link" data-toggle="collapse" data-target="#{$name}"
-                                               aria-expanded="{$expanded}" onclick="return false;">
+                                               aria-expanded="{$expanded}">
                                                 <small>
                                                     <span class="fa fa-fw fa-plus"></span>
                                                     <span class="fa fa-fw fa-minus"></span>
@@ -50,7 +50,7 @@
                                             </a>
                                         </h5>
 
-                                        <div id="{$name}" class="collapse{$show}">
+                                        <div id="{$name}" class="collapse{$show}" title="multiplierContent">
                                             <div class="card-body">
                                                 <div n:multiplier="$name" n:class="row, mb-2">
                                                     <input n:name="\App\Model\Repository\LineRepository::COLUMN_ID">
@@ -85,5 +85,43 @@
                 </div>
             </div>
         {/form}
+
+        <script>
+            $(document).ready(function ()
+            {
+                showCollapse();
+            });
+
+            /**
+             * Rozbalení stromu po dynamickém přidání prvků a znovunačtení snippetu
+             */
+            function showCollapse()
+            {
+                // Pro každej multiplier content
+                $('div[title="multiplierContent"]').each(function ()
+                {
+                    // Pokud obsahuje div s třídou .row mb-2, znamená to, že je tam nějaký vstupní prvek
+                    let inputs = $(this).find(".row.mb-2");
+                    if (inputs.length > 0)
+                    {
+                        // Rozbalení seznamu
+                        let id = this.id;
+                        $(this).attr('class', 'collapse show');
+                        $('a[data-target="#' + id + '"]').attr('aria-expanded', 'true');
+
+                        // Rozbalení vrchního seznamu
+                        $(this).parents().each(function ()
+                        {
+                            let thisId = this.id.toString();
+                            if (thisId !== "" && id.toString().includes(thisId))
+                            {
+                                $(this).attr('class', 'collapse show');
+                                $('a[data-target="#' + thisId + '"]').attr('aria-expanded', 'true');
+                            }
+                        })
+                    }
+                })
+            }
+        </script>
     {/snippet}
-{/ifset}
\ No newline at end of file
+{/ifset}
diff --git a/app/AdminModule/component/Transliteration/TransliterationDataEditForm.php b/app/AdminModule/component/Transliteration/TransliterationDataEditForm.php
index 2a3fe6d..9ead9e6 100644
--- a/app/AdminModule/component/Transliteration/TransliterationDataEditForm.php
+++ b/app/AdminModule/component/Transliteration/TransliterationDataEditForm.php
@@ -4,6 +4,7 @@
 namespace App\AdminModule\Components;
 
 
+use App\Enum\EFlashMessage;
 use App\Model\Facade\TransliterationFacade;
 use App\Model\Repository\LineRepository;
 use App\Model\Repository\ObjectTypeRepository;
@@ -11,6 +12,7 @@ use App\Model\Repository\SurfaceTypeRepository;
 use App\Utils\Form;
 use Nette\Application\UI\Control;
 use Nette\Forms\Container;
+use Nette\Forms\Controls\SubmitButton;
 use WebChemistry\Forms\Controls\Multiplier;
 
 class TransliterationDataEditForm extends Control
@@ -21,9 +23,6 @@ class TransliterationDataEditForm extends Control
     /** @var array Pole objektů a typu povrch pro strom dat transliterace */
     private $containers;
 
-    /** @var array Pole s výchozími hodnotami při upravování */
-    private $defaults;
-
     /**
      * @var ObjectTypeRepository
      */
@@ -53,7 +52,7 @@ class TransliterationDataEditForm extends Control
         $containers = [];
 
         // Načtení typů objektů a typu povrchů do pole pro vykreslení v šabloně
-        foreach ($objectTypes as $oId =>$objectType)
+        foreach ($objectTypes as $oId => $objectType)
         {
             $containers[$oId]['title'] = $objectType;
 
@@ -71,7 +70,7 @@ class TransliterationDataEditForm extends Control
         $this->template->setFile(__DIR__ . '/TransliterationDataEditForm.latte');
 
         $this->template->containers = $this->containers;
-        $this->template->defaults = $this->defaults = $this->getDefaults();
+        $this->template->defaults = $this->getDefaults();
 
         $this->template->render();
     }
@@ -109,8 +108,7 @@ class TransliterationDataEditForm extends Control
             }
         }
 
-        $defaults = $this->defaults === NULL ? $this->getDefaults() : $this->defaults;
-        $form->setDefaults($defaults);
+        $form->setDefaults($this->getDefaults());
 
         $form->onSuccess[] = [$this, 'formSuccess'];
         $form->addSubmit('submit', 'Save');
@@ -120,7 +118,18 @@ class TransliterationDataEditForm extends Control
 
     public function formSuccess(Form $form)
     {
-        $result = $this->transliterationFacade->saveTransliterationData($this->id, $form->getValues());
+        $result = $this->transliterationFacade->saveTransliterationData($this->id, $form);
+
+        // Redirect musí být, jinak se v dynamických prvcích nenačtou IDčka
+        //  a vkládají se nové záznamy místo upravování stávajících
+        if ($result)
+        {
+            $this->presenter->flashMessage('Transliteration data were edited successfully.', EFlashMessage::SUCCESS);
+        } else
+        {
+            $this->presenter->flashMessage('Transliteration data were not edited.', EFlashMessage::ERROR);
+        }
+        $this->presenter->redirect('Transliteration:edit', ['id' => $this->id]);
     }
 
     /**
@@ -144,6 +153,8 @@ class TransliterationDataEditForm extends Control
         {
             return $this->transliterationFacade->getTransliterationData($this->id);
         }
+
+        return [];
     }
 }
 
diff --git a/app/model/facade/TransliterationFacade.php b/app/model/facade/TransliterationFacade.php
index 6c8c1ef..56489af 100644
--- a/app/model/facade/TransliterationFacade.php
+++ b/app/model/facade/TransliterationFacade.php
@@ -8,6 +8,8 @@ use App\Model\Repository\LineRepository;
 use App\Model\Repository\ObjectTypeRepository;
 use App\Model\Repository\SurfaceRepository;
 use App\Model\Repository\SurfaceTypeRepository;
+use Nette\Application\UI\Form;
+use Nette\Database\Context;
 use Nette\Database\Table\ActiveRow;
 use Nette\Utils\ArrayHash;
 
@@ -29,27 +31,38 @@ class TransliterationFacade
      * @var SurfaceTypeRepository
      */
     private $surfaceTypeRepository;
+    /**
+     * @var Context
+     */
+    private $context;
 
     public function __construct(SurfaceRepository $surfaceRepository,
                                 LineRepository $lineRepository,
                                 ObjectTypeRepository $objectTypeRepository,
-                                SurfaceTypeRepository $surfaceTypeRepository
+                                SurfaceTypeRepository $surfaceTypeRepository,
+                                Context $context
     )
     {
         $this->surfaceRepository = $surfaceRepository;
         $this->lineRepository = $lineRepository;
         $this->objectTypeRepository = $objectTypeRepository;
         $this->surfaceTypeRepository = $surfaceTypeRepository;
+        $this->context = $context;
     }
 
     /**
      * Uloží data transliterace
      *
      * @param int|null $id : ID transliterace
-     * @param ArrayHash $formValues
+     * @param Form $form
+     * @return bool
      */
-    public function saveTransliterationData(int $id, ArrayHash $formValues)
+    public function saveTransliterationData(int $id, Form $form): bool
     {
+        $formValues = $form->getValues();
+
+        $this->removeDeletedLines($id, $formValues);
+
         // Škaredý zanoření hodnot z formuláře v kontainerech :(
         foreach ($formValues as $objectTypeId => $surfaceContainers)
         {
@@ -57,44 +70,56 @@ class TransliterationFacade
             {
                 foreach ($inputs as $key => $values)
                 {
-                    $lineId = (int)$values->{LineRepository::COLUMN_ID};
-
-                    // Editace již existující řádky
-                    if (!empty($lineId))
+                    try
                     {
-                        $this->lineRepository->fetchById($lineId)->update($values);
+                        $lineId = (int)$values->{LineRepository::COLUMN_ID};
 
-                    } else
-                    {
-                        $surface = $this->surfaceRepository->fetchSurface($id, $objectTypeId, $surfaceTypeId);
+                        // Editace již existující řádky
+                        if (!empty($lineId))
+                        {
+                            $this->lineRepository->fetchById($lineId)->update($values);
 
-                        if ($surface === FALSE)
+                        } else
                         {
-                            // TODO: předělat do repository
-                            $surface = $this->surfaceRepository->insert(
-                                [
-                                    SurfaceRepository::COLUMN_SURFACE_TYPE_ID => $surfaceTypeId,
-                                    SurfaceRepository::COLUMN_OBJECT_TYPE_ID => $objectTypeId,
-                                    SurfaceRepository::COLUMN_TRANSLITERATION_ID => $id
-                                ]
-                            );
+                            $surface = $this->surfaceRepository->fetchSurface($id, $objectTypeId, $surfaceTypeId);
+
+                            if ($surface === FALSE)
+                            {
+                                $surface = $this->surfaceRepository->insert(
+                                    [
+                                        SurfaceRepository::COLUMN_SURFACE_TYPE_ID => $surfaceTypeId,
+                                        SurfaceRepository::COLUMN_OBJECT_TYPE_ID => $objectTypeId,
+                                        SurfaceRepository::COLUMN_TRANSLITERATION_ID => $id
+                                    ]
+                                );
+
+                                // Z nějakýho důvodu insert vrací počet vložených řádků a ne ActiveRow, i když je v tabulce PK,
+                                //  proto se ID načítá takhle zvlášť
+                                $surfaceId = $this->context->getInsertId(SurfaceRepository::COLUMN_ID);
+                            }
+
+                            $values->{LineRepository::COLUMN_SURFACE_ID} = isset($surfaceId) ? $surfaceId : $surface->{SurfaceRepository::COLUMN_ID};
+                            $this->lineRepository->insert($values);
                         }
-
-                        $values->{LineRepository::COLUMN_SURFACE_ID} = $surface->{SurfaceRepository::COLUMN_ID};
-                        $this->lineRepository->insert($values);
+                    } catch (\Exception $exception)
+                    {
+                        \Tracy\Debugger::log('Nepodařilo se uložit data transliterace. Chyba: ' . $exception->getMessage(), 'transliteration-facade');
+                        return FALSE;
                     }
                 }
             }
         }
+
+        return TRUE;
     }
 
     /**
      * Vrací data transliterace pro formulář
      *
      * @param int $id : ID transliterace
-     * @return array
+     * @return array : pole výchozích hodnot pro formulář
      */
-    public function getTransliterationData(int $id)
+    public function getTransliterationData(int $id): array
     {
         $surfaces = $this->surfaceRepository->findByTransliterationId($id)->fetchAll();
 
@@ -105,7 +130,7 @@ class TransliterationFacade
         {
             // Načtení všech řádek
             $lineRows = $surface->related(LineRepository::TABLE_NAME, SurfaceRepository::COLUMN_ID)->fetchAll();
-            if ($lineRows === FALSE)
+            if ($lineRows === FALSE || empty($lineRows))
             {
                 continue;
             }
@@ -119,13 +144,69 @@ class TransliterationFacade
         return $defaults;
     }
 
+    /**
+     * Odstraní smazané řádky z DB
+     *
+     * @param int $id : ID transliterace
+     * @param ArrayHash $formValues : hodnoty z formuláře
+     * @return int : počet smazaných řádek
+     */
+    public function removeDeletedLines(int $id, ArrayHash $formValues)
+    {
+        $deletedIds = $this->getDeletedLineIds($id, $formValues);
+
+        return $this->lineRepository->deleteLines($deletedIds);
+    }
+
+    /**
+     * Vrací ID smazaných řádek transliterace
+     *
+     * @param int $id : ID transliterace
+     * @param ArrayHash $formValues : hodnoty z formuláře
+     * @return array
+     */
+    private function getDeletedLineIds(int $id, ArrayHash $formValues)
+    {
+        $deletedIds = [];
+        $oldLines = $this->getTransliterationData($id);
+
+        // Tohle je fakt nádhera :(
+        foreach ($oldLines as $objectTypeId => $surfaceContainers)
+        {
+            foreach ($surfaceContainers as $surfaceTypeId => $activeRows)
+            {
+                foreach ($activeRows as $activeRow)
+                {
+                    if (isset($formValues[$objectTypeId][$surfaceTypeId]))
+                    {
+                        $oldLineFound = FALSE;
+                        foreach ($formValues[$objectTypeId][$surfaceTypeId] as $array)
+                        {
+                            if ($array[LineRepository::COLUMN_ID] == $activeRow->{LineRepository::COLUMN_ID})
+                            {
+                                $oldLineFound = TRUE;
+                                break;
+                            }
+                        }
+
+                        if (!$oldLineFound)
+                        {
+                            $deletedIds[] = $activeRow->{LineRepository::COLUMN_ID};
+                        }
+                    }
+                }
+            }
+        }
+
+        return $deletedIds;
+    }
     /**
      * Vrací název inputu pro formulář
      *
      * @param string|NULL $name
      * @return string
      */
-    public function getInputName(string $name)
+    public function getInputName(string $name): string
     {
         return str_replace(' ', '', $name);
     }
diff --git a/app/model/repository/LineRepository.php b/app/model/repository/LineRepository.php
index f1e8cbb..db8692f 100644
--- a/app/model/repository/LineRepository.php
+++ b/app/model/repository/LineRepository.php
@@ -86,4 +86,15 @@ class LineRepository extends Repository
         return $this->findBy([self::COLUMN_ID => $id])->fetch();
     }
 
+    /**
+     * Vrací počet smazaných řádek
+     *
+     * @param array $lineIds
+     * @return int
+     */
+    public function deleteLines(array $lineIds) : int
+    {
+        return $this->findBy([self::COLUMN_ID => $lineIds])->delete();
+    }
+
 }
\ No newline at end of file
