Posílání emailů, Nette\Mail\IMailer pomocí DI, TypeError

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
ludek
Člen | 83
+
0
-

Zdravím,

dokumentaci se píše, že se mailer nemá vytvářet ručně, ale přes DI, tak jsem si do presenteru napsal:

class MailingPresenter extends BasePresenter {

    use Nette\Mail\Message;

    /** @var Nette\Mail\IMailer Mailer */
    private $mailer;

    public function __construct(Nette\Mail\IMailer $mailer) {
        parent::__construct();
        $this->mailer = $mailer;
    }

// a někde později by bylo:
$mailer->send($mail);
}

Ale dostanu chybu:

TypeError: Argument 1 passed to App\Presenters\BasePresenter::__construct() must implement interface Nette\Http\IRequest, none given

V BasePresenter je

abstract class BasePresenter extends Nette\Application\UI\Presenter {

    /** @var Nette\Http\IRequest Pro zjištění IP adresy */
    public $httpRequest;

    public function __construct(Nette\Http\IRequest $httpRequest) {
        parent::__construct();
        $this->httpRequest = $httpRequest;
    }

    protected function startup() {
        parent::startup();
        $this->ipaddress = $this->template->ipaddress = $this->httpRequest->getRemoteAddress();
    }
}

A doteď to fungovalo normálně. Můžete mi prosím poradit, co dělám špatně? Díky.

JZechy
Člen | 161
+
0
-

Když potomek (MailingPresenter) přepíše metodu rodiče (BasePresenter), tak ta metoda dělá to, co si nadefinoval v potomkovi.

Děláš sice správně, že voláš parent::__construct(), ale už mu nepředáváš IRequest jako parametr, který očekává.

iNviNho
Člen | 352
+
+2
-

Nette\Mail\Message nie je traita, ale class, takže by mala byť definovaná mimo triedy.
Nepoužíval by som constructor v presentery, ale zjednodušil si život anotáciou @inject
To isté by som spravil pre IRequest.

<?php
use Nette\Mail\Message,
	Nette\Mail\IMailer,
	Nette\Http\IRequest;

class MailingPresenter extends BasePresenter {

    /** @var IMailer Mailer @inject */
    private $mailer;

	/** @var IRequest @inject */
    public $httpRequest;

	protected function startup() {
        parent::startup();
        $this->ipaddress = $this->template->ipaddress = $this->httpRequest->getRemoteAddress();
    }

}
?>

** spojil som to všetko do jedného presentra pre prehľad

Editoval iNviNho (25. 10. 2016 12:38)

iNviNho
Člen | 352
+
0
-

@JZechy konštruktormi v presenteroch sa pri väčšom projekte môže zblázniť (constructor hell), preto odporúčam anotáciu @inject

JZechy
Člen | 161
+
+1
-

@iNviNho Tak já mu to taky nijak nedoporučoval, jen jsem mu psal, proč mu ta chyba vzniká :).

ludek
Člen | 83
+
0
-

Díky moc za odpovědi. Teď tam mám inject metodu a je to zdá se v pořádku:

/** @var Nette\Mail\IMailer Mailer */
private $mailer;

public function injectMailer(Nette\Mail\IMailer $mailer)
{
    $this->mailer = $mailer;
}

Do konstruktoru jsem to původně nacpal pro jistotu, protože je to povinná závislost. Také jsem párkrát četl, že „závislosti jedině konstruktorem a nikdy jinak“.

iNviNho
Člen | 352
+
0
-

Kde vidíš menej písania? :)

<?php
/** @var Nette\Mail\IMailer Mailer @inject */
private $mailer;
?>

alebo

<?php
/** @var Nette\Mail\IMailer Mailer */
private $mailer;

public function injectMailer(Nette\Mail\IMailer $mailer)
{
    $this->mailer = $mailer;
}
?>

Akonáhle používaš @injecty(iba v presenteri), tak hned za class si vždy definuješ všetky závislosti(premenné) a hotovka…

Ak máš napr. 10 závislosti, tak budeš písať 10 funkcií? Troška sa upíšeš a znížiš prehľadnosť :-\

abc
Člen | 92
+
+2
-

@iNviNho
v první ukázce má být property public
a nemusíš psát 10 funkcí, ale můžeš to dát všechno do jedné

nicméně nejlepší řešení je používat inject v base presenterech a ve final presenterech construct, jelikož tak třída definuje závislosti, bez kterých nemůže existovat

CZechBoY
Člen | 3608
+
+1
-

To sou vždycky dohady jestli použít anotaci nebo metody …
Metody maj výhodu, že může mít BasePresenter svoje vlastní závislosti a nikdo jinej k nim nemá přístup (private property).
Anotace má zas výhodu že je kratší zápis, ale přístup maj všichni (public property).

Něco mezi může bejt Kdyby\Autowired kdy může bejt property i private… ale to už je hodně magie (kudy se tam vlastně ta instance dostane).

ViPEr*CZ*
Člen | 818
+
0
-

Do konstruktoru jsem to původně nacpal pro jistotu, protože je to povinná závislost.

To je vlastně pravda, jen to moc neplatí u Presenterů, protože instance vytváří nějak v pozadí Nette. Dokonce s instancema i samo pracuje. Těžko někde voláš členskou metodu Presenteru, maximálně někde uvnitř objektu přes this. Takže inject je jakási speciální syntaxe/vlastnost.

a je to přesně jak píše @CZechBoY