BasePresenter ano nebo ne? pripadne jak spravne/nejlepe

MrAndy
Člen | 12
+
0
-

Ahoj vsem,
rad bych se zeptal jaky je nejlepsi zpusob pouzivani BasePresenteru.

Docetl jsem se ze jeho pouzivani muze vest ke Constructor hell a ze je lepsi pouzivat kompozici.
Ale jak jsem pochopil pri pouzivani kompozic je nutne v kazdem presenteru pouzit construct, coz mi prijde jako zbytecne psani navic.

V mem pripade vim ze v kazdem presenteru potrebuji $database a nekdy $translate, a v tomto pripade mi prijde BasePresenter jako idealni reseni.
A tak se chci zeptat jake je tedy idelani reseni abych se vyhnul Constructor hell ale zaroven mel vsude dostupne $database a $translate?

Muj Base

<?php declare(strict_types = 1);

namespace App;

use App\Core\Alerts;
use Nette;
use Contributte;

abstract class BasePresenter extends Nette\Application\UI\Presenter
{
    /** @persistent */
    public $locale;

    public function __construct(
        protected Nette\Database\Explorer $database,
        protected Nette\Localization\Translator $translator,
        protected Contributte\Translation\LocalesResolvers\Session $translatorSessionResolver
    )
    {
        parent::__construct();
    }

    protected function startup(): void
    {
        parent::startup();
        $this->locale = $this->translator->getLocale();
        $this->translatorSessionResolver->setLocale($this->locale);

        if (!$this->getUser()->isLoggedIn() && $this->getAction() !== 'login') {
            $this->redirect(':Auth:login', ['locale' => $this->locale]);
        }
    }

    public function beforeRender(): void
    {
        parent::beforeRender();
        $this->template->tplDir = __DIR__.'/UI/Templates/';
        $this->template->locale = $this->locale;
        $this->template->pageTitle = 'DevIOArts';
        $this->template->pageTitleSub = 'With Love <i class="fa fa-heart text-danger"></i>';

        $this->setAlerts();
    }

    private function setAlerts(): void
    {
        $alerts = new Alerts($this->database);
        $this->template->alerts = $alerts->getAlerts();
        $this->template->alertsCount = count($this->template->alerts);
    }

    public function handleChangeLocale(string $locale): void
    {
        $this->translatorSessionResolver->setLocale($locale);
        $this->redirect('this');
    }
}
Infanticide0
Člen | 103
+
+1
-

inject* metody budou fungovat líp.
Alerts jsou nějaký notifikace? Proč to není UI Control?
#[Persistent]

MrAndy
Člen | 12
+
0
-

To je presne ono, dekuji
Ano, alerts jsou notifikace a UI Control to neni protoze mne to nenapadlo, prepisu, jeste jednou diky :-)

Šaman
Člen | 2658
+
+4
-

Ohledně DI v presenterech existuje zlaté pravidlo:

  • v abstraktních používat settery (inject* metoda je setter s defaultně zapnutým injectováním závislostí)
  • v koncových presenterech používat konstruktor (přestože inject metody a properties fungují taky a spousta lidí je používá i tady)
  • doporučuji používat i keyword final u koncových presenterů – už z nich nepůjde dědit, takže nemůže existovat potomek, který si přepíše konstruktor

Proč? Inject property porušují zapouzdření (jsou public a někdo zvenku tam tu závislost předá). Inject metody jsou ok, jen je nikdy nevolej ručně (pokud sám nevíš přesně že to chceš). Jsou to settery, které z konvence DI kontejner najde a vyplní ihned po vytvoření objektu. Pak už by neměly být přesány.
Konstruktor je nejčistější, není možné vůbec vytvořit objekt bez jeho závislostí a nehrozí jejich přepsání během života objektu. Ale v abstraktních presenterech hrozí právě ten constructor hell, kde potomek musí volat konstruktor předka a předat mu závislosti.

U komponent, pokud máš také důvod k používání abstraktních předků doporučuji stejný způsob, jen je tam potřeba to automatické injectování zapnout. Většinou si u nich ale vystačíme s final třídami.

A v modelu ideálně používat jen konstruktor a případně settery, které ale zmíníme v configu (hledej decorator) a nebudeme zapínat automatické injectování pomocí metod.

Marek Znojil
Člen | 84
+
0
-

Šaman napsal(a):

  • doporučuji používat i keyword final u koncových presenterů – už z nich nepůjde dědit, takže nemůže existovat potomek, který si přepíše konstruktor

Doporučuji i u inject* metod.