Generovaná navigace z URL do základní šablony
- Allconius
- Člen | 317
Ahoj, jde nějak jednoduše vytvořit dynamickou navigaci pro stránky,
např. z URL ? Aby třeba https://projekt.cz/…re/zivotopis vytvorilo v sablone
zivotopis navigaci :
→ home (https://projekt.cz)
→ dokumenty (https://projekt.cz/dokumenty) → formulare (https://projekt.cz/…ty/formulare)
- Kamil Valenta
- Člen | 822
explode(‚/‘, $url)
Ačkoliv si myslím, že v praxi bude vždy lépe zohledňovat strukturu např. z DB.
- m.brecher
- Generous Backer | 873
Generovat navigaci z url ne. Normálně z databáze. Web s několika stránkami může mít takhle jednoduchou navigaci:
Tabulka pro navigaci
SET NAMES utf8;
SET time_zone = '+00:00';
SET foreign_key_checks = 0;
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
SET NAMES utf8mb4;
DROP TABLE IF EXISTS `node`;
CREATE TABLE `node` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`slug` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_czech_ci DEFAULT NULL,
`caption` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_czech_ci NOT NULL,
`published` tinyint(4) NOT NULL DEFAULT '1',
`sort` smallint(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `caption` (`caption`),
UNIQUE KEY `sort` (`sort`),
UNIQUE KEY `slug` (`slug`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_czech_ci;
INSERT INTO `node` (`id`, `slug`, `caption`, `published`, `sort`) VALUES
(1, '@homepage', 'Homepage', 1, 1),
(2, 'sluzby', 'Služby', 1, 2),
(3, 'ukazky', 'Ukázky', 1, 3),
(4, 'reference', 'Reference', 1, 4);
Komponenta menu:
use App\Model\MenuModel;
use Nette\Application\UI\Control;
class MainMenu extends Control
{
public function __construct(
private MenuModel $menuModel,
private string $currSlug,
)
{}
public function render()
{
$this->template->currSlug = $this->currSlug;
$this->template->items = $this->menuModel->getMenuItems();
$this->template->render(__DIR__.'/templates/mainMenu.latte');
}
}
Interface factory komponenty:
use App\Components\MainMenu;
interface MainMenuFactory
{
public function create(?string $currSlug): MainMenu;
}
Šablona komponenty mainMenu.latte, položka menu aktuální stránky má css třídu selected
<div class="menu-container">
<nav class="menu">
{foreach $items as $item}
{var $selected = $item->slug === $currSlug ? 'selected'}
<a n:class="'button', $selected" href="{plink ':Article:default', slug: $item->slug}">{$item->caption}</a>
{/foreach}
</nav>
</div>
Vykreslení komponenty v layoutu:
{control 'mainMenu'}
Model:
use Nette\Database\Explorer;
use Nette\Database\Table\Selection;
class MenuModel
{
public function __construct(private Explorer $database)
{}
public function getMenuItems(): Selection
{
return $this->database->table('node')->where('published', true)->order('sort');
}
}
Router – presenter Article pro stránky webu + možnost presenterů administrace, stránky jsou indexovány pomocí parametru slug, což odpovídá url za lomítkem, ale homepage nemá slug '' ale @homepage.
use Nette;
use Nette\Application\Routers\RouteList;
use Nette\Application\Routers\Route;
final class RouterFactory
{
use Nette\StaticClass;
public static function createRouter(): RouteList
{
$router = new RouteList;
$router->addRoute('[<slug (?!admin).*>]', [
'presenter' => [Route::Value => 'Article'],
'action' => [Route::Value => 'default'],
'slug' => [Route::Value => '@homepage'],
]);
$router->addRoute('admin[/<presenter>/<action>[/<id>]]');
return $router;
}
}
Použití menu v presenteru:
use Nette\Application\UI\Presenter;
final class ArticlePresenter extends Presenter
{
public function __construct(private MainMenuFactory $mainMenuFactory)
public function renderDefault(string $slug)
{
# zde zpracujeme $slug pro vykreslení příslušné stránky
}
public function createComponentMainMenu(): MainMenu
{
return $this->mainMenuFactory->create(currSlug: $this->getParameter('slug'));
}
}
Editoval m.brecher (29. 5. 2023 23:01)
- Allconius
- Člen | 317
Ahoj, díky za návod, nějak jsem se zase nějak zasekl na předávání
proměnné z továrny komponenty, nechápu co tam mám špatně.
Továrna:
declare(strict_types=1);
namespace App\Components\News;
interface NewsControlFactory
{
public function create(string $url): NewsControl;
}
Komponenta:
class NewsControl extends Control {
function __construct(
private DbManager $dbManager,
private string $url,
)
{
}
A vypíše se:
Nette\DI\ServiceCreationException
Service of type App\Components\News\NewsControl: Parameter $url in NewsControl::__construct() has no class type or default value, so its value must be specified.
nechápu co ještě potřebuje kromě „private string $url“ ?
- m.brecher
- Generous Backer | 873
@Allconius
has no … default value, so its value must be specified.
Nemá předanou hodnotu $url z presenteru do metody create() viz:
public function createComponentMainMenu(): MainMenu
{
return $this->mainMenuFactory->create(currSlug: $this->getParameter('slug'));
}
otestuj si, jestli se předává nenulová hodnota, to zajišťuje Router, který jsem Ti poslal, kde je <slug> v routě sice nepovinný, ale má defaultní nenulovou hodnotu, takže nikdy není null!
'slug' => [Route::Value => '@homepage'],
Doporučuji místo $url používat $slug, je to tak zvykem, jako url je zvykem označovat celé url, slug je jenom jeden segment url, který adresuje článek/produkt !
- m.brecher
- Generous Backer | 873
@Allconius
Chyba bude ale pravděpodobně v tom jak píše @MarekBartoš že nebude správně registrovaná služba. Takhle to vypadá, že je registrovaná jako služba komponenta NewsControl ta ale službou být nesmí, naopak je potřeba registrovat jako službu factory NewsControlFactory. Podívej se do Tracy panel DIC, kde jsou červeně aktivní vytvořené služby, kterou službu tam reálně máš ;)