Rozdělení částí prseneteru do více souborů
- Michwuanquana
- Člen | 22
Zdravím,
chtěl bych rozdělit např. SignPresenter do více souborů. Zkusil jsem k tomu použít trait, následovně to pak vypadá takto:
SignPresenter.php
<?php declare(strict_types = 1);
namespace App\Modules\Front\Sign;
use App\Modules\Front\BaseFrontPresenter;
use Nette\Application\Attributes\Persistent;
final class SignPresenter extends BaseFrontPresenter
{
#[Persistent]
public string $backlink;
use Pages\Register;
use Pages\Login;
use Pages\Verify;
}
Pages/Register.php
<?php declare(strict_types = 1);
namespace App\Modules\Front\Sign\Pages;
use App\Model\App;
use App\Model\Account\Exceptions\RegistererException;
use App\UI\Form\BaseForm;
use App\Modules\Front\Sign\Services;
trait Register
{
use Services\FormFactory;
use Services\UserManager;
use Services\Mailer;
protected function createComponentRegisterForm(): BaseForm
{
$form = $this->formFactory->forBackend();
$form->addEmail('email')
->setRequired(true);
$form->addPassword('password')
->setRequired(true);
$form->addPassword('password_verify')
->setRequired(true);
$form->addSubmit('submit');
$form->onSuccess[] = [$this, 'processRegisterForm'];
return $form;
}
public function processRegisterForm(BaseForm $form): void
{
try {
if($form->values->password != $form->values->password_verify)
throw new RegistererException ("Passwords are not same.");
$user = $this->userManagerService->register($form->values->email, $form->values->password);
$this->mailer
->create('verification', $this->lang)
->to($user->getEmail())
->body($user->getVerificationToken())
->send();
$this->flashMessage("Registration was successful, please check email for verification.");
$this->redirect(App::DESTINATION_AFTER_REGISTER);
} catch (RegistererException $e) {
$form->addError($this->translator->translate($e->getMessage()));
return;
}
}
}
a třeba Services\FormFactory.php
<?php declare(strict_types = 1);
namespace App\Modules\Front\Sign\Services;
use Nette\DI\Attributes\Inject;
use App\UI\Form\FormFactory as ServiceFormFactory;
trait FormFactory {
#[Inject]
public ServiceFormFactory $formFactory;
}
Otázka zní, zda-li by nebylo vhodnější to řešit jinak, popř. jak např. v Pages/Register.php zajistit, aby mi IDE našeptávalo $this->user apod.?
Editoval Michwuanquana (7. 5. 2022 11:33)
- Marek Bartoš
- Nette Blogger | 1280
Chytré IDE (phpstorm) umí v traitách napovídat podle toho, v jakých třídách je použité.
Používat traity je ale hrozně špatný nápad. Na pozadí nedělají
víceméně nic jiného, než že zkopírují kód a pastnou ho do třídy kde
se traita používá. Výsledkem je obří, pomalá třída s desítkami a
více metodami.
Stanov si pravidlo jeden presenter = jedna akce.
Presenter se stará jen o získání parametrů z requestu a o jejich
předání do komponenty.
Komponenta definuje a zpracovává formulář.
Pokud má formulář po odeslání přesměrovat, tak si předej z presenteru
skrze konstruktor callback, ve kterém presenter přesměruje a komponenta jen
zavolá callback, nesahá na nadřazený presenter.
Je to víc psaní, ale nezamotáš se v tom. Třída neroste do obludných rozměrů a je snadné ji upravit.
- Polki
- Člen | 553
Marek Bartoš napsal(a):
K tomuhle mám Marku 2 dotazy:
- Jednoakční presentery se řinou ze všech stran a mám ohledně toho otázku, jaký máte obecně systém na nazývání takovýchto jednoakčních presenterů, aby jste se v tom nezamotali? V našich aplikacích je obecně kolem 50 presenterů a každý má ± 4 akce. Když to rozdělíme do jednoakčních presenterů, tak nám sice odpadnou starosti s checkováním práv pro jednotlivé akce (které se však přesunou na úroveň konkrétních presenterů, takže žádná změna) a stane se presenter třídou, která opravdu ctí zásady SingleResponsibility, ale zase zhruba 4× vzroste počet souborů, které budou ve složce presenters a stejně tak počet souborů ve složce templates (složky s šablonami pro jednotlivé presentery se promění na konkrétní šablony pro daný presenter s akcí default.), takže místo 50 presenterů a 50 složek v templates najednou budu mít celkem 400 souborů pod sebou. Už tak se nám zdá o čertech když musíme rolovat v ide v seznamu souborů jako diví a snažíme se to nějak logicky dělit aspoň do modulů, natož tak se v tom vyznat po rozdělení na jednoakční presentery. Jak toto řešíte vy?
- Stejně jako s tím, že má být na každou akci jeden presenter se už
dlouho řine to, že by Presentery měly mít jen 1 úroveň a tedy by neměl
existovat nějaký BasePresenter. Jako důvody se uvádějí špatné použití
dědičnosti, konstruktor hell a podobné srandy. Pokud ale udělám
jednoakční presentery, které nebudou mít tedy předka, jelikož kód by se
opakoval v různých presenterech a to tak, že by se duplicity kódu
křížily, že by nestačilo dědění z 1 třídy, tak nastává obří
duplicita kódu. Například v aplikaci chceš na všech stránkách zobrazovat
komponentu s menu. Tím se ti v rámci všech presenterů pomocí CTRL+C a
CTRL+V zduplikuje injectnutí
componentFactory
a metodacreateComponent
… No a pokud jsem se to správně naučil od kolegů, co tvoří Symfony, tak přesně pro tyto účely byla traita zavedena. V příkladu od kolegy v dotazu, kdyby chtěl použít ve více presenterech přihlašovací formulář, tak by prostě jen tu danou traitu hodil do dalšího presenteru. Ty ale píšeš ‚Používat traity je ale hrozně špatný nápad.‘ Takže je lepší mít tu duplicitu kódu, nebo kde je pravda?
Editoval Polki (7. 5. 2022 16:54)
- Marek Bartoš
- Nette Blogger | 1280
@Polki
1.Já mám appku strukturovanou podle features a povedlo se mi z Nette
vykopat mapování, abych se mohl odkazovat rovnou na třídu, takže je to
třeba App\GuardedObject\Admin\Create\CreateGuardedObjectPresenter
.
Též presentery mají své šablony u sebe a nesou stejný název jako třída
(CreateGuardedObjectPresenter.php, CreateGuardedObjectTemplate.php,
CreateGuardedObject.latte). Množství souborů vůbec neroste. Mám v plánu
(ne)mapování dostat přímo do Nette, pak o tom napíšu článek.
2.Hele já nevím. BasePresenter mám ve dvou úrovních. Obecný
BasePresenter a pak Base(Admin|Public)Presenter a víc jsem nepotřeboval.
Jestliže se ve dvou presenterech týkajících se stejných dat (např.
článku) vyskytuje stejný kód pracující s tím článkem, tak je třeba se
ptát, jestli nejde přesunout do nějaké služby. A zda se verze kódu pro
vytvoření a editaci článku nebudou měnit a nebudou se časem lišit, to pak
mít duplikát dává smysl.
Zrovna login komponentu mám v BasePublicPresenter, protože je jen zlomek
webů, na kterých bych ji neměl v layoutu a v LoginPresenteru pro
administraci, protože administrace je vždy za heslem.
Jiné obecné komponenty lze udělat globální a registrovat je na úrovni DI,
v BasePresenter je to celkem snadná úprava.
Editoval Marek Bartoš (7. 5. 2022 17:41)