commit 58bf410f027a5310f5ada67bff504346af3dc51f
Author: Filip Jani <jsem@filek.cz>
Date:   Fri Apr 19 20:10:22 2019 +0200

    Re #7337 přidán grid pro muzea a formuláře pro editaci
    - upraven base Datagrid pro podporu angličtny
    - přidán BaseUserPresenter do admin modulu pro umožnění přístupu jak Adminům tak uživatelům s právy editace

diff --git a/app/AdminModule/component/Museum/MuseumEditForm.latte b/app/AdminModule/component/Museum/MuseumEditForm.latte
new file mode 100644
index 0000000..b6a732f
--- /dev/null
+++ b/app/AdminModule/component/Museum/MuseumEditForm.latte
@@ -0,0 +1,5 @@
+<div class="row">
+    <div class="col-4">
+        {control form}
+    </div>
+</div>
\ No newline at end of file
diff --git a/app/AdminModule/component/Museum/MuseumEditForm.php b/app/AdminModule/component/Museum/MuseumEditForm.php
new file mode 100644
index 0000000..fb3e8e6
--- /dev/null
+++ b/app/AdminModule/component/Museum/MuseumEditForm.php
@@ -0,0 +1,132 @@
+<?php
+
+
+namespace App\AdminModule\Components;
+
+use App\Enum\EFlashMessage;
+use App\Model\Repository\MuseumRepository;
+use App\Utils\Form;
+use Nette\Application\UI\Control;
+
+/**
+ * Formulář pro přidávání / editaci muzeí
+ *
+ * @package App\AdminModule\Components
+ */
+class MuseumEditForm extends Control
+{
+    /**
+     * @var Form
+     */
+    private $form;
+    /**
+     * @var int ID muzea
+     */
+    private $museumId;
+
+    /**
+     * @var MuseumRepository
+     */
+    private $museumRepository;
+
+    public function __construct(MuseumRepository $museumRepository)
+    {
+        parent::__construct();
+
+        $this->museumRepository = $museumRepository;
+
+        $this->museumId = NULL;
+        $this->form = new Form;
+    }
+
+    public function render()
+    {
+        $this->template->setFile(__DIR__ . '/MuseumEditForm.latte');
+        $this->template->render();
+    }
+
+    public function createComponentForm()
+    {
+        $this->form->addText(MuseumRepository::COLUMN_NAME, 'Museum')
+            ->addRule(Form::REQUIRED, 'Pole %label je povinné.');
+        $this->form->addText(MuseumRepository::COLUMN_PLACE, 'Place')
+            ->addRule(Form::REQUIRED, 'Pole %label je povinné.');
+
+        $this->form->addSubmit('submit', 'Save');
+
+        $this->form->setDefaults($this->getDefaults());
+
+        $this->form->onValidate[] = [$this, 'formValidate'];
+        $this->form->onSuccess[] = [$this, 'formSuccess'];
+
+        return $this->form;
+    }
+
+    public function formValidate(Form $form)
+    {
+        $values = $form->getValues();
+
+        // Vkládáme nové muzeum - kontrola zda již neexistuje se stejným názvem
+        if(empty($this->museumId))
+        {
+            if ($this->museumRepository->findByName($values[MuseumRepository::COLUMN_NAME])->fetch())
+            {
+                $form->addError('Museum with the same name already exists. Please choose another name.');
+            }
+        }
+    }
+
+    public function formSuccess(Form $form)
+    {
+        $result = $this->museumRepository->save($form->getValues(TRUE), $this->museumId);
+
+        if ($result)
+        {
+            $this->presenter->flashMessage('Museum was added successfully.', EFlashMessage::SUCCESS);
+            $this->presenter->redirect('Museum:edit', ['id' => $result->{MuseumRepository::COLUMN_ID}]);
+        } else
+        {
+            $form->addError('Museum couldn\'t be added. Please try it again later.');
+        }
+    }
+
+    /**
+     * Nastavení ID muzea při editaci
+     *
+     * @param int $museumId
+     */
+    public function setMuseum(int $museumId)
+    {
+        $this->museumId = $museumId;
+    }
+
+    /**
+     * Vrací hodnoty z databáze při upravování existujícího muzea
+     *
+     * @return array
+     */
+    public function getDefaults()
+    {
+        $defaultValues = array();
+
+        if (!empty($this->museumId))
+        {
+            $museumRow = $this->museumRepository->findRow($this->museumId);
+
+            if ($museumRow)
+            {
+                $defaultValues = $museumRow->toArray();
+            }
+        }
+
+        return $defaultValues;
+    }
+}
+
+interface IMuseumEditFormFactory
+{
+    /**
+     * @return MuseumEditForm
+     */
+    public function create();
+}
\ No newline at end of file
diff --git a/app/AdminModule/component/Museum/MuseumGrid.php b/app/AdminModule/component/Museum/MuseumGrid.php
new file mode 100644
index 0000000..d418a9b
--- /dev/null
+++ b/app/AdminModule/component/Museum/MuseumGrid.php
@@ -0,0 +1,76 @@
+<?php
+
+
+namespace App\AdminModule\Components;
+
+
+use App\Model\Repository\MuseumRepository;
+use App\Utils\DataGrid\DataGrid;
+use Ublaboo\DataGrid\Exception\DataGridException;
+
+/**
+ * Grid pro seznam muzeí, je přístupný všem uživatelům s právy editace, proto textace v ENG
+ *
+ * @package App\AdminModule\Components
+ */
+class MuseumGrid extends DataGrid
+{
+    /**
+     * @var MuseumRepository
+     */
+    private $museumRepository;
+
+    public function __construct(MuseumRepository $museumRepository)
+    {
+        $this->museumRepository = $museumRepository;
+
+        parent::__construct(FALSE);
+    }
+
+    /**
+     * Abstraktní metoda, slouží k nastavení primárního klíče a nastavení datasource
+     *  1. $this->setPrimaryKey();
+     *  2. $this->setDataSource();
+     *
+     * @throws DataGridException
+     */
+    public function init()
+    {
+        $this->setPrimaryKey(MuseumRepository::COLUMN_ID);
+        $this->setDataSource($this->museumRepository->findAll());
+    }
+
+    /**
+     * Definice sloupečků, akcí, vyhledávácích filtrů gridu
+     *
+     * @throws DataGridException
+     */
+    public function define()
+    {
+        // Definice sloupečků
+        $this->addColumnNumber(MuseumRepository::COLUMN_ID, 'ID')->setDefaultHide(TRUE);
+        $this->addColumnText(MuseumRepository::COLUMN_NAME, 'Museum');
+        $this->addColumnText(MuseumRepository::COLUMN_PLACE, 'Place');
+
+        // Definice filtrů
+        $this->addFilterText(MuseumRepository::COLUMN_NAME, 'Museum');
+        $this->addFilterText(MuseumRepository::COLUMN_PLACE, 'Place');
+
+        // Definice akcí
+        $this->addAction('edit', 'edit', 'Museum:edit', ['id' => MuseumRepository::COLUMN_ID])
+            ->setTitle('Edit');
+
+        $this->addAction('delete', 'delete', 'deleteMuseum!', ['id' => MuseumRepository::COLUMN_ID])
+            ->setConfirm('Do you really want to delete museum %s.', MuseumRepository::COLUMN_NAME)
+            ->setTitle('Delete')
+            ->setClass('btn btn-xs btn-danger ajax');
+    }
+}
+
+interface IMuseumGridFactory
+{
+    /**
+     * @return MuseumGrid
+     */
+    public function create();
+}
\ No newline at end of file
diff --git a/app/AdminModule/component/User/UserEditForm.php b/app/AdminModule/component/User/UserEditForm.php
index c2526ce..f32eb59 100644
--- a/app/AdminModule/component/User/UserEditForm.php
+++ b/app/AdminModule/component/User/UserEditForm.php
@@ -128,7 +128,7 @@ class UserEditForm extends Control
             $this->presenter->redirect('User:edit', ['id' => $result->{UserRepository::COLUMN_ID}]);
         } else
         {
-            $this->presenter->flashMessage('Uživatele se nepodařilo upravit.', EFlashMessage::ERROR);
+            $form->addError('Uživatele se nepodařilo upravit.');
         }
     }
 
diff --git a/app/AdminModule/component/User/UserGrid.php b/app/AdminModule/component/User/UserGrid.php
index b48425d..5b5ea64 100644
--- a/app/AdminModule/component/User/UserGrid.php
+++ b/app/AdminModule/component/User/UserGrid.php
@@ -19,7 +19,7 @@ class UserGrid extends DataGrid
     {
         $this->userRepository = $userRepository;
 
-        parent::__construct(NULL, NULL);
+        parent::__construct();
     }
 
     /**
@@ -61,8 +61,6 @@ class UserGrid extends DataGrid
             ->setConfirm('Opravdu chcete uživatele "%s" odstranit?', UserRepository::COLUMN_LOGIN)
             ->setTitle('Odstranit')
             ->setClass('btn btn-xs btn-danger ajax');
-
-        $this->setDefaultPerPage(20);
     }
 }
 
diff --git a/app/AdminModule/presenters/BaseUserPresenter.php b/app/AdminModule/presenters/BaseUserPresenter.php
new file mode 100644
index 0000000..c0b378d
--- /dev/null
+++ b/app/AdminModule/presenters/BaseUserPresenter.php
@@ -0,0 +1,26 @@
+<?php
+
+
+namespace App\AdminModule\Presenters;
+
+use App\Enum\EUserRole;
+
+/**
+ * Presenter používaný v administraci pro uživatele s právy editace
+ *  kontroluje zda je uživatel Admin nebo uživatel s právy editace
+ *
+ * @package App\AdminModule\Presenters
+ */
+abstract class BaseUserPresenter extends BaseAdminPresenter
+{
+    /**
+     * Část přístupná i uživatelům s právy editace
+     *
+     * @return bool
+     */
+    protected function isUserAllowed()
+    {
+        return $this->user->isLoggedIn()
+            && ($this->user->isInRole(EUserRole::ADMIN) || $this->user->isInRole(EUserRole::USER));
+    }
+}
\ No newline at end of file
diff --git a/app/AdminModule/presenters/MuseumPresenter.php b/app/AdminModule/presenters/MuseumPresenter.php
new file mode 100644
index 0000000..9804235
--- /dev/null
+++ b/app/AdminModule/presenters/MuseumPresenter.php
@@ -0,0 +1,65 @@
+<?php
+
+
+namespace App\AdminModule\Presenters;
+
+use App\AdminModule\Components\IMuseumEditFormFactory;
+use App\AdminModule\Components\IMuseumGridFactory;
+use App\Model\Repository\MuseumRepository;
+
+class MuseumPresenter extends BaseUserPresenter
+{
+    /**
+     * @var IMuseumGridFactory
+     */
+    private $museumGridFactory;
+    /**
+     * @var IMuseumEditFormFactory
+     */
+    private $museumEditFormFactory;
+    /**
+     * @var MuseumRepository
+     */
+    private $museumRepository;
+
+    public function __construct(IMuseumGridFactory $museumGridFactory,
+                                IMuseumEditFormFactory $museumEditFormFactory,
+                                MuseumRepository $museumRepository
+    )
+    {
+        parent::__construct();
+
+        $this->museumGridFactory = $museumGridFactory;
+        $this->museumEditFormFactory = $museumEditFormFactory;
+        $this->museumRepository = $museumRepository;
+    }
+
+    public function actionEdit(int $id)
+    {
+        $this['museumEditForm']->setMuseum($id);
+    }
+
+    /**
+     * Handle používaný v MuseumGrid pro smazání muzea
+     *
+     * @param int $id : ID mazaného muzea
+     */
+    public function handleDeleteMuseum(int $id)
+    {
+        if ($this->isAjax())
+        {
+            $this->museumRepository->findRow($id)->delete();
+            $this['museumGrid']->reload();
+        }
+    }
+
+    public function createComponentMuseumGrid()
+    {
+        return $this->museumGridFactory->create();
+    }
+
+    public function createComponentMuseumEditForm()
+    {
+        return $this->museumEditFormFactory->create();
+    }
+}
\ No newline at end of file
diff --git a/app/AdminModule/presenters/UserPresenter.php b/app/AdminModule/presenters/UserPresenter.php
index 93e04e8..f59ad24 100644
--- a/app/AdminModule/presenters/UserPresenter.php
+++ b/app/AdminModule/presenters/UserPresenter.php
@@ -35,8 +35,6 @@ class UserPresenter extends BaseAdminPresenter
         $this->userFacade = $userFacade;
     }
 
-    public function actionAdd(){}
-
     public function actionEdit(int $id)
     {
         $this['userEditForm']->setUser($id);
diff --git a/app/AdminModule/templates/@layout.latte b/app/AdminModule/templates/@layout.latte
index 11bcddb..e8b4e07 100644
--- a/app/AdminModule/templates/@layout.latte
+++ b/app/AdminModule/templates/@layout.latte
@@ -114,7 +114,7 @@
     <li class="nav-item"><a href="#" class="nav-link" title="Surface type">
             Surface&nbsp;type </a></li>
 
-    <li class="nav-item"><a href="#" class="nav-link" title="Museum">
+    <li class="nav-item"><a n:href="Museum:default" n:class="nav-link, $presenter->isLinkCurrent('Museum:*') ? active" title="Museum">
             Museum </a></li>
     <li class="nav-item"><a href="#" class="nav-link" title="Origin">
             Origin </a></li>
diff --git a/app/AdminModule/templates/Museum/add.latte b/app/AdminModule/templates/Museum/add.latte
new file mode 100644
index 0000000..3b19565
--- /dev/null
+++ b/app/AdminModule/templates/Museum/add.latte
@@ -0,0 +1,10 @@
+{block content}
+<div class="row">
+    <div class="col-11">
+        <h4>New Museum</h4>
+    </div>
+    <div class="col-1">
+        <a n:href="Museum:default" class="btn btn-sm btn-success"><span class="fa fa-fw fa-list"></span> Museum list</a>
+    </div>
+</div>
+{control museumEditForm}
\ No newline at end of file
diff --git a/app/AdminModule/templates/Museum/default.latte b/app/AdminModule/templates/Museum/default.latte
new file mode 100644
index 0000000..b45aea8
--- /dev/null
+++ b/app/AdminModule/templates/Museum/default.latte
@@ -0,0 +1,14 @@
+{block content}
+<div class="row">
+    <div class="col-11">
+        <h4>Museum List</h4>
+    </div>
+    <div class="col-1">
+        <a n:href="Museum:add" class="btn btn-sm btn-success"><span class="fa fa-fw fa-plus"></span> New Museum</a>
+    </div>
+</div>
+<div class="row">
+    <div class="col-10 offset-1">
+        {control museumGrid}
+    </div>
+</div>
\ No newline at end of file
diff --git a/app/AdminModule/templates/Museum/edit.latte b/app/AdminModule/templates/Museum/edit.latte
new file mode 100644
index 0000000..89bc5a0
--- /dev/null
+++ b/app/AdminModule/templates/Museum/edit.latte
@@ -0,0 +1,10 @@
+{block content}
+<div class="row">
+    <div class="col-11">
+        <h4>Edit Museum</h4>
+    </div>
+    <div class="col-1">
+        <a n:href="Museum:default" class="btn btn-sm btn-success"><span class="fa fa-fw fa-list"></span> Museum list</a>
+    </div>
+</div>
+{control museumEditForm}
\ No newline at end of file
diff --git a/app/config/components.neon b/app/config/components.neon
index 6890056..6bb5683 100644
--- a/app/config/components.neon
+++ b/app/config/components.neon
@@ -2,7 +2,9 @@ services:
     # Gridy
     - App\FrontModule\Components\IExampleGirdFactory
     - App\AdminModule\Components\IUserGridFactory
+    - App\AdminModule\Components\IMuseumGridFactory
 
     # Formuláře
     - App\FrontModule\Components\ILoginFormFactory
-    - App\AdminModule\Components\IUserEditFormFactory
\ No newline at end of file
+    - App\AdminModule\Components\IUserEditFormFactory
+    - App\AdminModule\Components\IMuseumEditFormFactory
\ No newline at end of file
diff --git a/app/model/repository/MuseumRepository.php b/app/model/repository/MuseumRepository.php
index ed7efb5..b7bc490 100644
--- a/app/model/repository/MuseumRepository.php
+++ b/app/model/repository/MuseumRepository.php
@@ -15,6 +15,17 @@ class MuseumRepository extends Repository
 
     /** Sloupečky tabulky */
     const COLUMN_ID = 'id_museum';
-    const COLUMN_TITLE = 'museum';
+    const COLUMN_NAME = 'museum';
     const COLUMN_PLACE = 'place';
+
+    /**
+     * Najde muzeum podle jména v DB
+     *
+     * @param string $name
+     * @return \Nette\Database\Table\Selection
+     */
+    public function findByName(string $name)
+    {
+        return $this->findBy([self::COLUMN_NAME => $name]);
+    }
 }
\ No newline at end of file
diff --git a/app/utils/datagrid/DataGrid.php b/app/utils/datagrid/DataGrid.php
index 6fd54f3..6c1fcc8 100644
--- a/app/utils/datagrid/DataGrid.php
+++ b/app/utils/datagrid/DataGrid.php
@@ -2,7 +2,6 @@
 
 namespace App\Utils\DataGrid;
 
-use Nette\ComponentModel\IContainer;
 use Nette\Database\Table\Selection;
 use Ublaboo\DataGrid\Column\ColumnDateTime;
 use Ublaboo\DataGrid\Column\ColumnNumber;
@@ -20,37 +19,42 @@ abstract class DataGrid extends BaseDataGrid
 {
     /**
      * DataGrid konstruktor.
-     * @param IContainer|null $parent
-     * @param null $name
+     *
+     * @param bool $useCzechTranslations : určuje zda se má používat Grid s českým překladem
+     * @throws DataGridException
      */
-    public function __construct(IContainer $parent = null, $name = null)
+    public function __construct($useCzechTranslations = TRUE)
     {
-        parent::__construct($parent, $name);
-
-        $translator = new SimpleTranslator([
-            'ublaboo_datagrid.no_item_found_reset' => 'Žádné položky nenalezeny. Filtr můžete vynulovat',
-            'ublaboo_datagrid.no_item_found' => 'Žádné položky nenalezeny.',
-            'ublaboo_datagrid.here' => 'zde',
-            'ublaboo_datagrid.items' => 'Položky',
-            'ublaboo_datagrid.all' => 'všechny',
-            'ublaboo_datagrid.from' => 'z',
-            'ublaboo_datagrid.reset_filter' => 'Resetovat filtr',
-            'ublaboo_datagrid.group_actions' => 'Hromadné akce',
-            'ublaboo_datagrid.show_all_columns' => 'Zobrazit všechny sloupce',
-            'ublaboo_datagrid.hide_column' => 'Skrýt sloupec',
-            'ublaboo_datagrid.action' => 'Akce',
-            'ublaboo_datagrid.previous' => 'Předchozí',
-            'ublaboo_datagrid.next' => 'Další',
-            'ublaboo_datagrid.choose' => 'Vyberte',
-            'ublaboo_datagrid.execute' => 'Provést',
-            'ublaboo_datagrid.show_default_columns' => 'Zobrazit výchozí sloupce',
-            'ublaboo_datagrid.filter_submit_button' => 'Filtrovat',
-
-            'Name' => 'Jméno',
-            'Inserted' => 'Vloženo'
-        ]);
-
-        $this->setTranslator($translator);
+        parent::__construct(NULL, NULL);
+
+        if($useCzechTranslations)
+        {
+            $translator = new SimpleTranslator([
+                'ublaboo_datagrid.no_item_found_reset' => 'Žádné položky nenalezeny. Filtr můžete vynulovat',
+                'ublaboo_datagrid.no_item_found' => 'Žádné položky nenalezeny.',
+                'ublaboo_datagrid.here' => 'zde',
+                'ublaboo_datagrid.items' => 'Položky',
+                'ublaboo_datagrid.all' => 'všechny',
+                'ublaboo_datagrid.from' => 'z',
+                'ublaboo_datagrid.reset_filter' => 'Resetovat filtr',
+                'ublaboo_datagrid.group_actions' => 'Hromadné akce',
+                'ublaboo_datagrid.show_all_columns' => 'Zobrazit všechny sloupce',
+                'ublaboo_datagrid.hide_column' => 'Skrýt sloupec',
+                'ublaboo_datagrid.action' => 'Akce',
+                'ublaboo_datagrid.previous' => 'Předchozí',
+                'ublaboo_datagrid.next' => 'Další',
+                'ublaboo_datagrid.choose' => 'Vyberte',
+                'ublaboo_datagrid.execute' => 'Provést',
+                'ublaboo_datagrid.show_default_columns' => 'Zobrazit výchozí sloupce',
+                'ublaboo_datagrid.filter_submit_button' => 'Filtrovat',
+
+                'Name' => 'Jméno',
+                'Inserted' => 'Vloženo'
+            ]);
+
+
+            $this->setTranslator($translator);
+        }
 
         $this->setTemplateFile(__DIR__ . '/templates/datagrid.latte');
 
@@ -60,6 +64,8 @@ abstract class DataGrid extends BaseDataGrid
 
         $this->setStrictSessionFilterValues(false);
 
+        $this->setDefaultPerPage(20);
+
         $this->init();
 
         $this->define();
