commit c08e8326b4577e615f8a1a89c601d384e84ea3a9
Author: Filip Jani <jsem@filek.cz>
Date:   Tue Apr 23 20:14:29 2019 +0200

    Re #7333 Vytvoření gridu pro správu transliterací

diff --git a/app/AdminModule/component/Transliteration/TransliterationGrid.php b/app/AdminModule/component/Transliteration/TransliterationGrid.php
new file mode 100644
index 0000000..138ed13
--- /dev/null
+++ b/app/AdminModule/component/Transliteration/TransliterationGrid.php
@@ -0,0 +1,173 @@
+<?php
+
+
+namespace App\AdminModule\Components;
+
+
+use App\Model\Repository\BookRepository;
+use App\Model\Repository\BookTypeRepository;
+use App\Model\Repository\MuseumRepository;
+use App\Model\Repository\OriginRepository;
+use App\Model\Repository\TransliterationRepository;
+use App\Utils\DataGrid\DataGrid;
+use Nette\Database\Table\ActiveRow;
+use Nette\Database\Table\Selection;
+use Ublaboo\DataGrid\Exception\DataGridException;
+
+class TransliterationGrid extends DataGrid
+{
+    /**
+     * @var TransliterationRepository
+     */
+    private $transliterationRepository;
+    /**
+     * @var BookRepository
+     */
+    private $bookRepository;
+    /**
+     * @var MuseumRepository
+     */
+    private $museumRepository;
+    /**
+     * @var OriginRepository
+     */
+    private $originRepository;
+    /**
+     * @var BookTypeRepository
+     */
+    private $bookTypeRepository;
+
+    public function __construct(TransliterationRepository $transliterationRepository,
+                                BookRepository $bookRepository,
+                                MuseumRepository $museumRepository,
+                                OriginRepository $originRepository,
+                                BookTypeRepository $bookTypeRepository
+    )
+    {
+        $this->transliterationRepository = $transliterationRepository;
+        $this->bookRepository = $bookRepository;
+        $this->museumRepository = $museumRepository;
+        $this->originRepository = $originRepository;
+        $this->bookTypeRepository = $bookTypeRepository;
+
+        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(TransliterationRepository::COLUMN_ID);
+        $this->setDataSource($this->transliterationRepository->findAll());
+    }
+
+    /**
+     * Definice sloupečků, akcí, vyhledávácích filtrů gridu
+     *
+     * @throws DataGridException
+     */
+    public function define()
+    {
+        $bookRepository = $this->bookRepository;
+        $museumRepository = $this->museumRepository;
+        $originRepository = $this->originRepository;
+        $bookTypeRepository = $this->bookTypeRepository;
+
+        // ==================
+        // Definice sloupečků
+        // ==================
+        $this->addColumnNumber(TransliterationRepository::COLUMN_ID, 'ID')->setDefaultHide(TRUE);
+        $this->addColumnLink(TransliterationRepository::COLUMN_BOOK_ID, 'Book')
+            ->setRenderer(function (ActiveRow $activeRow)
+            {
+                $title = $activeRow->ref(BookRepository::TABLE_NAME, BookRepository::COLUMN_ID)->{BookRepository::COLUMN_BOOK_ABREV};
+                return $this->getRendererWithLink($activeRow, $title, 'Book:edit', $activeRow->{TransliterationRepository::COLUMN_BOOK_ID});
+            });
+        $this->addColumnNumber(TransliterationRepository::COLUMN_CHAPTER, 'Chapter');
+        $this->addColumnLink(TransliterationRepository::COLUMN_MUSEUM_ID, 'Museum')
+            ->setRenderer(function (ActiveRow $activeRow)
+            {
+                $title = $activeRow->ref(MuseumRepository::TABLE_NAME, MuseumRepository::COLUMN_ID)->{MuseumRepository::COLUMN_NAME};
+                return $this->getRendererWithLink($activeRow, $title, 'Museum:edit', $activeRow->{TransliterationRepository::COLUMN_MUSEUM_ID});
+            });
+        $this->addColumnText(TransliterationRepository::COLUMN_MUSEUM_NO, 'Museum No');
+        $this->addColumnLink(TransliterationRepository::COLUMN_ORIGIN_ID, 'Origin')
+            ->setRenderer(function (ActiveRow $activeRow)
+            {
+                $title = $activeRow->ref(OriginRepository::TABLE_NAME, OriginRepository::COLUMN_ID)->{OriginRepository::COLUMN_ORIGIN};
+                return $this->getRendererWithLink($activeRow, $title, 'Origin:edit', $activeRow->{TransliterationRepository::COLUMN_ORIGIN_ID});
+            });
+        $this->addColumnLink(TransliterationRepository::COLUMN_BOOK_TYPE_ID, 'Book Type')
+            ->setRenderer(function (ActiveRow $activeRow)
+            {
+                $title = $activeRow->ref(BookTypeRepository::TABLE_NAME, BookTypeRepository::COLUMN_ID)->{BookTypeRepository::COLUMN_BOOK_TYPE};
+                return $this->getRendererWithLink($activeRow, $title, 'BookType:edit', $activeRow->{TransliterationRepository::COLUMN_BOOK_TYPE_ID});
+            });
+        $this->addColumnText(TransliterationRepository::COLUMN_REG_NO, 'Reg No');
+        $this->addColumnText(TransliterationRepository::COLUMN_DATE, 'Date');
+
+        // ===============
+        // Definice filtrů
+        // ===============
+        $this->addFilterText(TransliterationRepository::COLUMN_BOOK_ID, 'Book')
+            ->setCondition(function (Selection $selection, $value) use ($bookRepository)
+            {
+                $bookIds = $bookRepository->getBooksLikeBookAbbrev($value)->fetchField(BookRepository::COLUMN_ID);
+                $bookIds = $bookIds ? $bookIds : NULL;
+
+                $selection->where(BookRepository::COLUMN_ID, $bookIds);
+            });
+        $this->addFilterText(TransliterationRepository::COLUMN_CHAPTER, 'Chapter');
+        $this->addFilterText(TransliterationRepository::COLUMN_MUSEUM_ID, 'Museum')
+            ->setCondition(function (Selection $selection, $value) use ($museumRepository)
+            {
+                $museumIds = $museumRepository->getMuseumsLikeName($value)->fetchField(MuseumRepository::COLUMN_ID);
+                $museumIds = $museumIds ? $museumIds : NULL;
+
+                $selection->where(MuseumRepository::COLUMN_ID, $museumIds);
+            });
+        $this->addFilterText(TransliterationRepository::COLUMN_MUSEUM_NO, 'Museum No');
+        $this->addFilterText(TransliterationRepository::COLUMN_ORIGIN_ID, 'Origin')
+            ->setCondition(function (Selection $selection, $value) use ($originRepository)
+            {
+                $originIds = $originRepository->getOriginsLikeName($value)->fetchField(OriginRepository::COLUMN_ID);
+                $originIds = $originIds ? $originIds : NULL;
+
+                $selection->where(OriginRepository::COLUMN_ID, $originIds);
+            });
+        $this->addFilterText(TransliterationRepository::COLUMN_BOOK_TYPE_ID, 'Book Type')
+            ->setCondition(function (Selection $selection, $value) use ($bookTypeRepository)
+            {
+                $bookTypeIds = $bookTypeRepository->getBookTypesLikeType($value)->fetchField(BookTypeRepository::COLUMN_ID);
+                $bookTypeIds = $bookTypeIds ? $bookTypeIds : NULL;
+
+                $selection->where(BookTypeRepository::COLUMN_ID, $bookTypeIds);
+            });
+        $this->addFilterText(TransliterationRepository::COLUMN_REG_NO, 'Reg No');
+        $this->addFilterText(TransliterationRepository::COLUMN_DATE, 'Date');
+
+        // =============
+        // Definice akcí
+        // =============
+//        $this->addAction('edit', 'edit', 'Transliteration:edit', ['id' => TransliterationRepository::COLUMN_ID])
+//            ->setTitle('Edit');
+
+        $this->addAction('delete', 'delete', 'deleteTransliteration!', ['id' => TransliterationRepository::COLUMN_ID])
+            ->setConfirm('Do you really want to delete transliteration?')
+            ->setTitle('Delete')
+            ->setClass('btn btn-xs btn-danger ajax');
+    }
+}
+
+interface ITransliterationGridFactory
+{
+    /**
+     * @return TransliterationGrid
+     */
+    public function create();
+}
\ No newline at end of file
diff --git a/app/AdminModule/presenters/TransliterationPresenter.php b/app/AdminModule/presenters/TransliterationPresenter.php
new file mode 100644
index 0000000..5c78dc8
--- /dev/null
+++ b/app/AdminModule/presenters/TransliterationPresenter.php
@@ -0,0 +1,42 @@
+<?php
+
+
+namespace App\AdminModule\Presenters;
+
+
+use App\AdminModule\Components\ITransliterationGridFactory;
+use App\Model\Repository\TransliterationRepository;
+
+class TransliterationPresenter extends BaseUserPresenter
+{
+    /**
+     * @var ITransliterationGridFactory
+     */
+    private $transliterationGridFactory;
+
+    public function __construct(ITransliterationGridFactory $transliterationGridFactory,
+                                TransliterationRepository $transliterationRepository)
+    {
+        parent::__construct();
+        $this->transliterationGridFactory = $transliterationGridFactory;
+    }
+
+    /**
+     * Handle používaný v TransliterationGrid pro smazání transliterace
+     *
+     * @param int $id : ID transliterace
+     */
+    public function handleDeleteTransliteration(int $id)
+    {
+        if ($this->isAjax())
+        {
+            $this->transliterationGridFactory->findRow($id)->delete();
+            $this['transliterationGrid']->reload();
+        }
+    }
+
+    public function createComponentTransliterationGrid()
+    {
+        return $this->transliterationGridFactory->create();
+    }
+}
\ No newline at end of file
diff --git a/app/AdminModule/templates/@layout.latte b/app/AdminModule/templates/@layout.latte
index dce76c2..8b2c6da 100644
--- a/app/AdminModule/templates/@layout.latte
+++ b/app/AdminModule/templates/@layout.latte
@@ -101,7 +101,7 @@
 
     <li class="nav-item"><a n:href="Book:default" n:class="nav-link, $presenter->isLinkCurrent('Book:*') ? active" title="Book">
             Book </a></li>
-    <li class="nav-item"><a href="#" class="nav-link" title="Transliteration">
+    <li class="nav-item"><a n:href="Transliteration:default" n:class="nav-link, $presenter->isLinkCurrent('Transliteration:*') ? active" title="Transliteration">
             Transliteration </a></li>
     <li class="nav-item"><a n:href="BookType:default" n:class="nav-link, $presenter->isLinkCurrent('BookType:*') ? active" title="Book type">
             Book type </a></li>
diff --git a/app/AdminModule/templates/Transliteration/default.latte b/app/AdminModule/templates/Transliteration/default.latte
new file mode 100644
index 0000000..2a972b8
--- /dev/null
+++ b/app/AdminModule/templates/Transliteration/default.latte
@@ -0,0 +1,16 @@
+{block content}
+    <div class="row">
+        <div class="col-10">
+            <div class="display-5">Transliteration List</div>
+        </div>
+        <div class="col-2 text-right">
+{*            <a n:href="Transliteration:addType" class="btn btn-sm btn-success"><span class="fa fa-fw fa-plus"></span> New Surface Type</a>*}
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-10 offset-1">
+            {control transliterationGrid}
+        </div>
+    </div>
+
+{/block}
\ No newline at end of file
diff --git a/app/config/components.neon b/app/config/components.neon
index 29e36e6..8d4fed8 100644
--- a/app/config/components.neon
+++ b/app/config/components.neon
@@ -8,6 +8,7 @@ services:
     - App\AdminModule\Components\ISurfaceTypeGridFactory
     - App\AdminModule\Components\IBookTypeGridFactory
     - App\AdminModule\Components\IBookGridFactory
+    - App\AdminModule\Components\ITransliterationGridFactory
 
     # Formuláře
     - App\FrontModule\Components\ILoginFormFactory
diff --git a/app/model/repository/BookRepository.php b/app/model/repository/BookRepository.php
index 200cb4d..e9a14d4 100644
--- a/app/model/repository/BookRepository.php
+++ b/app/model/repository/BookRepository.php
@@ -26,4 +26,15 @@ class BookRepository extends Repository
     const COLUMN_VOLUME = 'volume';
     const COLUMN_VOLUME_NO = 'volume_no';
     const COLUMN_REVISION_HISTORY = 'revision_history';
+
+    /**
+     * Vrací knihy se zkratkou LIKE % $bookName %
+     *
+     * @param string $bookName
+     * @return \Nette\Database\Table\Selection
+     */
+    public function getBooksLikeBookAbbrev(string $bookName)
+    {
+        return $this->findAll()->where(self::COLUMN_BOOK_ABREV . ' LIKE', '%' . $bookName . '%');
+    }
 }
\ No newline at end of file
diff --git a/app/model/repository/BookTypeRepository.php b/app/model/repository/BookTypeRepository.php
index a23b571..fc704ba 100644
--- a/app/model/repository/BookTypeRepository.php
+++ b/app/model/repository/BookTypeRepository.php
@@ -28,4 +28,14 @@ class BookTypeRepository extends Repository
         return $this->findBy([self::COLUMN_BOOK_TYPE => $bookType]);
     }
 
+    /**
+     * Vrací typ knihy LIKE % $name %
+     *
+     * @param string $name
+     * @return \Nette\Database\Table\Selection
+     */
+    public function getBookTypesLikeType(string $name)
+    {
+        return $this->findAll()->where(self::COLUMN_BOOK_TYPE . ' LIKE', '%' . $name . '%');
+    }
 }
\ No newline at end of file
diff --git a/app/model/repository/MuseumRepository.php b/app/model/repository/MuseumRepository.php
index b7bc490..e8a5f04 100644
--- a/app/model/repository/MuseumRepository.php
+++ b/app/model/repository/MuseumRepository.php
@@ -28,4 +28,15 @@ class MuseumRepository extends Repository
     {
         return $this->findBy([self::COLUMN_NAME => $name]);
     }
+
+    /**
+     * Vrací muzea podle názvu LIKE % $name %
+     *
+     * @param string $name
+     * @return \Nette\Database\Table\Selection
+     */
+    public function getMuseumsLikeName(string $name)
+    {
+        return $this->findAll()->where(self::COLUMN_NAME . ' LIKE', '%' . $name . '%');
+    }
 }
\ No newline at end of file
diff --git a/app/model/repository/OriginRepository.php b/app/model/repository/OriginRepository.php
index cdbf508..2c325f7 100644
--- a/app/model/repository/OriginRepository.php
+++ b/app/model/repository/OriginRepository.php
@@ -17,4 +17,15 @@ class OriginRepository extends Repository
     const COLUMN_ID = 'id_origin';
     const COLUMN_ORIGIN = 'origin';
     const COLUMN_OLD_NAME = 'old_name';
+
+    /**
+     * Vrací místa původu se názvem LIKE % $name %
+     *
+     * @param string $name
+     * @return \Nette\Database\Table\Selection
+     */
+    public function getOriginsLikeName(string $name)
+    {
+        return $this->findAll()->where(self::COLUMN_ORIGIN . ' LIKE', '%' . $name . '%');
+    }
 }
\ No newline at end of file
diff --git a/app/utils/datagrid/DataGrid.php b/app/utils/datagrid/DataGrid.php
index e074537..713f965 100644
--- a/app/utils/datagrid/DataGrid.php
+++ b/app/utils/datagrid/DataGrid.php
@@ -2,6 +2,8 @@
 
 namespace App\Utils\DataGrid;
 
+use App\Model\Repository\BookRepository;
+use Nette\Database\Table\ActiveRow;
 use Nette\Database\Table\Selection;
 use Ublaboo\DataGrid\Column\ColumnDateTime;
 use Ublaboo\DataGrid\Column\ColumnNumber;
@@ -171,6 +173,43 @@ abstract class DataGrid extends BaseDataGrid
         return $filterText;
     }
 
+    /**
+     * Umožnění filtrování sloupečků s odkazem
+     *
+     * @param string $key
+     * @param string $name
+     * @param null $href
+     * @param null $column
+     * @param array|null $params
+     * @return \Ublaboo\DataGrid\Column\ColumnLink|null
+     */
+    public function addColumnLink($key, $name, $href = null, $column = null, array $params = null)
+    {
+        $column = parent::addColumnLink($key, $name, $href, $column, $params);
+        $column->setSortable();
+        $column->setTemplateEscaping(FALSE);
+
+        return $column;
+    }
+
+    /**
+     * Generování odkazu pro tabulky, které jsou přes cizí klíč
+     *
+     * @param ActiveRow $activeRow
+     * @param string $title
+     * @param string $destination
+     * @param int $id
+     * @return string
+     * @throws \Nette\Application\UI\InvalidLinkException
+     */
+    public function getRendererWithLink(ActiveRow $activeRow, string $title, string $destination, int $id): string
+    {
+        $link = $this->presenter->link($destination, ['id' => $id]);
+
+        $title = !empty($title) ? $title : 'empty';
+        return '<a href="' . $link . '">' . $title . '</a>';
+    }
+
     /**
      * Fixnutí zobrazování všech záznamů v českém překladu gridu
      *
