Falešný User Warning Invalid link

m.brecher
Generous Backer | 758
+
0
-

Ahoj,

předem se omlouvám za případný falešný poplach, ale s 90% jistotou si myslím, že jsem narazil na chybu v LinkGenerátoru.

Router.php:

$router->addRoute('[<lang en>/][<slug (?!admin).*>]', [
    'presenter' => [ Route::VALUE => 'Front'],
    'action' => [ Route::VALUE => 'article'],
    'lang' => [ Route::VALUE => 'cs'],
    'slug' => [ Route::VALUE => '@homepage'],
]);
$router->addRoute('admin[/<presenter>/<action>[/<id \d+>]]', 'AdminEntry:default');

FrontPresenter.php:

public function renderArticle(string $slug)
{
    $article = $this->articleModel->getOne($slug);
    .....
}

Česká homepage (url /) – Nette hlásí chybu:

User Warning
Invalid link: Missing parameter $slug required by App\Presenters\FrontPresenter::renderArticle()

Jedná se o tento link v menu.latte:

<a n:href="Front:article" class="button">Homepage</a>

Hodnota parametru $slug ve FrontPresenteru:

public function renderArticle(string $slug)
{
    bdump($slug)	// '$homepage' - to je správně
    .....
}

Parametr $slug má správnou hodnotu, link je funkční – ověřeno kliknutím, ale Nette hlásí User Warning – FALEŠNÝ.

Zkusím obejít předání parametru $slug do akce – FrontPresenter.php:

public function renderArticle()
{
    $slug = $this->getParameter('slug');
    $article = $this->articleModel->getOne($slug);
    .....
}

Funguje stejně jako v první variantě, ale User Warning NENÍ.

Bezpochyby je chyba v Nette – Třída vyhazující User Warning nebere v potaz defaultní hodnoty definované v routeru.

Editoval m.brecher (13. 1. 2023 2:57)

David Grudl
Nette Core | 8129
+
0
-

Je to tak, hodnoty v routeru se neberou v potaz.

MajklNajt
Člen | 471
+
0
-

renderArticle(?string $slug = null)

Toto si skúšal?

m.brecher
Generous Backer | 758
+
0
-

@DavidGrudl

Je to tak, hodnoty v routeru se neberou v potaz.

A je to vlastně dobře. „Falešný“ warning je totiž užitečné upozornění na chybějící parametr v odkazu do akce. Ono je totiž dobrou praxí parametry v odkazech explicitně uvádět, i když mají v routeru definovanou hodnotu.

Takže vlastně správný postup je uvést v odkazu hodnotu parametru i když ta hodnota je defaultní.


<a n:href="Front:article" class="button">Homepage</a>    // není zřejmé, že odkaz má parametr

<a n:href="Front:article, slug: '@homepage'" class="button">Homepage</a>  // tenhle kód je srozumitelný

Editoval m.brecher (13. 1. 2023 17:20)

m.brecher
Generous Backer | 758
+
0
-

@MajklNajt

renderArticle(?string $slug = null)

V tomhle chyba nebyla, parametr $slug nebyl null, měl defaultní hodnotu '@homepage'. Chyba byla v tom, že v odkazu nebyl uveden:

<a n:href="Front:article" class="button">Homepage</a>    // chybí parametr
MajklNajt
Člen | 471
+
0
-

Ale presenter nie je závislý na routeri, a teda volať tu metódu bez argumentu, ak je vyžadovaný, je IMHO chyba návrhu, nie chyba routera

Editoval MajklNajt (13. 1. 2023 18:27)

MajklNajt
Člen | 471
+
0
-

…a teda aj chcem volať metódu bez argumentu, musí mať parameter default hodnotu v definícii

Editoval MajklNajt (13. 1. 2023 18:27)

m.brecher
Generous Backer | 758
+
0
-

@MajklNajt

Ale presenter nie je závislý na routeri, a teda volať tu metódu bez argumentu, ak je vyžadovaný, je IMHO chyba návrhu, nie chyba routera

Ono je to přesně naopak, když jsem volal metodu BEZ argumentu tak to fungovalo bez Warningu Nette:

public function renderArticle()
{
    $slug = $this->getParameter('slug');
    $article = $this->articleModel->getOne($slug);
    .....
}

Naproti tomu, když jsem volal metodu S UVEDENÍM argumentu, tak to sice fungovalo také, ale Nette vyhodilo ten Warning:

public function renderArticle(string $slug)
{
    $article = $this->articleModel->getOne($slug);
    .....
}

Je to v Nette udělané tak (jak píše v tomto vlákně @DavidGrudl), že pokud je metoda akce volána s parametrem, potom Nette kontroluje, zda ve všech odkazech do té akce je ten parametr uvedený, pokud není vyhazuje Warning. Nette přitom NEKONTROLUJE, zda Router má nastavenu defaultní hodnotu parametru, pokud ji má, tak odkazy jsou funkční i když ten parametr chybí a přesto se vyhodí Warning.

Zpočátku mě přišlo, že ten Warning když odkazy fungují je vlastně chyba, ale teď si myslím, že je to správně, protože parametry by se v odkazech do akcí měly uvádět vždycky. Navíc by to bylo zbytečně složité, aby se vedle odkazů kontrolovaly i defaultní hodnoty v Routeru.

MajklNajt
Člen | 471
+
0
-

@m.brecher asi sa nechápeme :) Zhodneme sa na tom, že správanie routera a teda aj ten warning má opodstatnenie, a práve to sa snažím vysvetliť, že sa nemôžem spoliehať na niekoho ďalšieho, že mi niekde nejakú default hodnotu dosadí sám.

A teda že mám metódu:

<?php
public function renderArticle(string $slug)
{
	if($slug === "@homepage") { /* do anything special */ }
    $article = $this->articleModel->getOne($slug);
	...
}
?>

tak link musím vytvárať vždy s uvedením slugu a skutočnosť, že metóda akceptuje hodnotu slugu @homepage ako nejakú default hodnotu a podľa nej sa správa ináč ako obvykle, to nie je súčasťou jej verejného rozhrania. V tomto prípade teda link musím tvoriť vždy <a n:href="Front:article, slug: '@homepage'" class="button">Homepage</a>

Avšak ak chcem už v definícii metódy povedať, že má nejakú default hodnotu (bez toho aby som niečo písal do routra), mala by byť zapísaná takto:

<?php
public function renderArticle(string $slug = "@homepage")
{
	if($slug === "@homepage") { /* do anything special */ }
    $article = $this->articleModel->getOne($slug);
	...
}
?>

V tomto prípade môžem link tvoriť tak, ako si to skúšal na začiatku príspevku bez uvedenia slugu <a n:href="Front:article" class="button">Homepage</a>.

A toto mi z hľadiska čitateľnosti, zrozumiteľnosti a predvídateľsnosti správania príde vhodnejšie, toť vsio :)

MajklNajt
Člen | 471
+
0
-

A ešte pre úplnosť, osobne preferujem používať ako default null, príde mi to IMHO čistejšie, lebo to hovorí, že $slug môže byť null (inými slovami undefined), ale to už je len taká slovná hračka:

<?php
public function renderArticle(?string $slug = null)
{
	if($slug === null) { /* do anything special */ }
    $article = $this->articleModel->getOne($slug);
	...
}
?>
m.brecher
Generous Backer | 758
+
0
-

@MajklNajt

osobne preferujem používať ako default null

Ano, obecně souhlasím – null jako default hodnotu jakéhokoliv parametru je ideální. Url je ale specifická záležitost, chceme mít cool url – mimo jiné aby homepage neměla žádný slug. Hodnota null se pro slug homepage ale nehodí, třeba když bych chtěl v databázi mít ve sloupci slug unikátní index, tak hodnota null se do unikátního indexu nepočítá. Proto v případě slug je lepší null výjimečně nepoužívat.

m.brecher
Generous Backer | 758
+
0
-

@MajklNajt

asi sa nechápeme :)

Já to celkem chápu, co myslíš, víceméně proti tomu nic nenamítám.

Defaultní hodnotu mohu parametru nastavit i v metodě akce – jak píšeš. Potom ale musím být opatrný, protože ten parametr pak má v různých místech presenteru různou hodnotu:

Příklad z presenteru – parametr není v url:

public renderArticle(?string $param = 'homepage')
{
     dump($param);	// 'homepage'

	// ale:

	dump($this->getParameter('param'));    //  null
}

Naproti tomu, když definuji defaultní hodnotu v Routeru, tak to nejde obejít.