Podpora PHP 8.1 enumeration v Latte a Presenterech

m.brecher
Generous Backer | 774
+
+2
-

Ahoj,

PHP 8.1 přinesla enumeration které nabízejí typovou kontrolu nad parametry, kde potřebujeme několik konkrétních hodnot. Kupříkladu mám formulář, kde ve 3 po sobě jdoucích krocích provádím nějaké akce. Stav formuláře chci řídit parametrem akce v presenteru, který bude mít přesně tři string hodnoty.

Rád bych použil enum v parametrech akce stejně jako se dnes používá integer parametr $id, který Nette správně přetypuje na string do url (v odkazech) a zase zpět přetypuje na int (v metodě akce v presenteru, nebo parametrech s atributem #[Parameter] a #[Persistent]).

Zkusil jsem využít backed enum:

namespace App\Presenters\Ledger;

enum Step: string		// definice enumu:
{
    case SelectBookUnit = 'selectBookUnit';
    case SelectInvoice = 'selectInvoice';
    case SelectInvoiceItem = 'selectInvoiceItem';
}
namespace App\Presenters\Ledger;

class LedgerPresenter extends BasePresenter		// presenter
{
    public function actionCreate(?Step $step = null)   // enum Step
    {
        $this->template->Step = $step;
    }
}
{* šablona akce *}

{varType App\Presenters\Ledger\Step $Step}

{block 'content'}
	<nav class="menu">
		<a n:href=":create, step: $Step::SelectBook">vyber účetnictví</a> {* enum jako parametr odkazu *}
	</nav>

{/block}

Narazil jsem na tyto výjimky:

Po ručním zadání do url: localhost/project/ledger/create?step=selectBook Nette automaticky nepřetypuje string na enum:

Nette\Application\BadRequestException #404
Argument $step passed to App\Presenters\Ledger\LedgerPresenter::actionCreate()
       must be App\Presenters\Ledger\Step, string given.

Použití enum v odkazech v Latte dopadlo podobně:

{varType App\Presenters\Ledger\Step $Step}

<a n:href=":create, step: $Step::SelectBook">vyber účetnictví</a>

Latte vyhodí výjimku když narazí v odkaze na enum hodnotu:

Error
Class name must be a valid object or a string

Závěr: PHP enum není v Nette jako parametr odkazu podporován. Podpora enum typu je ale zajímavá nová feature, která by přinesla vyšší preciznost a snížila riziko chyb.

Jaký máte názor, využili by jste podporu enumu v Latte a presenterech ?

Editoval m.brecher (8. 1. 16:01)

nightfish
Člen | 475
+
+1
-

Jaký máte názor, využili by jste podporu enumu v Latte a presenterech ?

Tak určitě.

Enumy sice jde v klidu použít už teď, ale je k tomu holt potřeba boilerplate:

public function actionDefault(?string $stepValue = null): void
{
    $step = Step::tryFrom($stepValue);

    if ($step === null) {
        $this->error();
    }

    // práce se $step typu Step
}

Šablona

<a n:href=":create, stepValue: App\Presenters\Ledger\Step::SelectBook->value">vyber účetnictví</a>
m.brecher
Generous Backer | 774
+
0
-

@nightfish

Tak určitě.

tak super !

   <a n:href=":'create', stepValue: App\Presenters\Ledger\Step::SelectBook->value">  {* funkční ale nečitelné *}
   <a n:href=":'create', step: $Step::SelectBook">  {* čitelné, ale nefunkční :( *}
   <a n:href=":'create', step: 'selectBook'">  {* string klasika nyní nejlepší řešení *}

Smyslem enumu je zpřehlednit kód, a snížit riziko chyb. To že jde enum použít přes boilerplate to vím, ale smysl má použít jednoduchý čitelný zápis, protože boilerplate kód znepřehledňuje a naopak si myslím, že funkční, ale nečitelný zápis enumu je víc náchylný na chybu než použití normálního stringu.

Lumeriol
Generous Backer | 59
+
+1
-

Za mně používám asi trochu krkolomné řešení s definicí proměnné:

{var App\Model\Enum\Ledger $ledger = App\Model\Enum\Ledger::class}
...
<a n:href=":'create', stepValue: $ledger::SelectBook->value">

Není to ideál, ale nemusím psát stringy/čísla a nemusím psát celý namespace pokud to potřebuju na víc místech. Navíc lze případně použít i statickou funkci definovanou v daném Enumu.

David Grudl
Nette Core | 8173
+
+3
-

BTW tohle v Latte je ok, ale musíš do proměnné $Step dat jméno třídy:

{var $Step = App\Presenters\Ledger\Step::class}

<a n:href=":create, step: $Step::SelectBook">vyber účetnictví</a>