Odeslání emailu z Modelu, zpřístupnění presenter z Modelu pro LiveTranslator

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

Ahoj,
prosím o radu jak mohu správně udělat následující chování.
Nějak se s tím peru a nedaří se mi.

Používám Model (nejen) pro přístup k datům z databáze. Rád bych aby aplikace posílala emaily právě z Modelu, což mi přijde dobré umístění pro odesílání emailů.

V aplikaci ještě používám LiveTranslator.

Takto se obdobně snažím o emaily:

<?php
$latte = new Latte\Engine;
$params = array(
    'orderId' => 123,
);

$mail = new Message;
$mail->setFrom('Franta <franta@example.com>')
    ->addTo('petr@example.com')
    ->setHtmlBody($latte->renderToString('email.latte', $params));`
?>

Nette mi napíše že „Filter ‚translate‘ is not defined.“
Nevím jak si do Modelu mohu přidat Presenter abych mohl použít něco jako

<?php
$template->setTranslator($this->getPresenter->translator);
?>

Moc díky

ViPEr*CZ*
Člen | 809
+
0
-

Pár postřehů… Už bych tomu neříkal model, ale nějaká business třída. Používáš MVC architektůru… ? Tak co je modelu po Presenteru? Model si nechte prostě modelem. Translátor je jen nějaká services, tak proč cpát business třídě celej Presenter? Přes DI si předejte do business třídy objekt translatoru.

akadlec
Člen | 1326
+
0
-

No osobně bych to zpracování mailů oddělil do vlastní služby, předal ji translator a vše ostatní potřebné. Do modelu pak předat jen službu a na ní zavolat nějaké sendMail s potřebnými parametry.

ViPEr*CZ*
Člen | 809
+
0
-

No a já bych právě ten holý model předal té oddělené třídě :-)

kralik
Člen | 230
+
0
-

Díky,
ale prosím ještě jednou pro ty vzadu.
Ano používám MVC architekturu.

Mužete někdo poskytnou přímo kód jak vytvořit samostatnou třídu a předat si do ni translator?
S OOP ještě nejsem uplně kamarád.

Také nepotřebuji celý presenter, ale líbí se mi toto „Přes DI si předejte do business třídy objekt translatoru.“
Ale nevím jak s tím.

Moc díky

ViPEr*CZ*
Člen | 809
+
0
-

Zkuste: https://doc.nette.org/…dependencies

Jednoduše vytvoříte-li třídu a v jejím konstruktoru uvedente nějakou závislost (musíte uvést type hint závislosti), pak pokud takovou třídu zaregistrujete v konfiguraci, tak Nette se Vám postará o vytvoření objektu a v systémovém kontejneru vyhledá právě podle type hintu onu závislost a použije ji.
Nadmíru je jasné, že ona závislost musí také existovat v systémovém kontejneru. Buď si jí tedy musíte také registrovat v konfiguraci a nebo to je nějaká služba, kterou interně vytváří automaticky samo Nette.
Váš translátor by měl mít type hint nějaký interface ITranslator.
Tuto koncovou službu (business třídu) už si injectnete do Presenteru a použijete v příslušném obslužném kódu.

David Matějka
Moderator | 6445
+
+2
-

Template, ktery znas z presenteru, je jednoduchy wapper kolem Latte\Engine. Pokud chces pouzivat primo Latte\Engine, tak tam translator dostanes pridanim filteru, viz implementace v Template

Ale Latte\Engine nevytvarej rucne, pouzij ILatteFactory, pripadne muzes rovnou pouzit ITemplateFactory, ktery ti prave vytvori onu znamou template z presenteru. Precti si https://phpfashion.com/…-a-nette-2-3, sice je to o odkazech, ale velmi se to prave dotyka pouziti sablon v emailech.

kralik
Člen | 230
+
0
-

Ahoj,
tak jsem se pokoušel z „Generování odkazů v emailech“, ale moc jsem to nepochopil.

Zkouším to takto:

<?php
<?php
class MailSender
{
    /** @var Nette\Application\LinkGenerator */
    private $linkGenerator;

    /** @var Nette\Application\UI\ITemplateFactory */
    private $templateFactory;


    function construct(Nette\Application\LinkGenerator $generator)
    {
        $this->linkGenerator = $generator;
    }

    function sendEmail()
    {
        $template = $this->templateFactory->createTemplate();
        $template->name = 'Test';
        $template->setFile(WWW_DIR.'/../app/templates/Home/notif.latte');

        Tracy\Debugger::barDump($template,'sablonaEmailu');

        $template->_control = $this->linkGenerator;

        $mail = new Nette\Mail\Message;
        $mail->addTo('test@test.com');
        $mail->setHtmlBody($template); // nebo setHtmlBody($template)

    //$mailer->send($mail);

    }

}
?>

A samotný email poslat takto:

<?php
\MailSender::sendEmail();
?>

Zatím jsem to zkoušel s tím LinkGenerátor.
Nette mi hlásí Non-static method MailSender::sendEmail() should not be called statically, assuming $this from incompatible context

Místo toho function construct(Nette\Application\LinkGenerator $generator) si předám function construct(\LiveTranslator\Translator $translator)?

Dostanu se nějak ke svému modelu abych dotáhl data z DB?
$dM = $this->mainModel->getMailData()

Kdybyste mi prosím poradili na zcela konkrétní třídě viz. výše.

Moc díky

ViPEr*CZ*
Člen | 809
+
0
-
  1. sendMail() nemůžete volat staticky, když jste si ji jako statickou nedefinoval :-)
  2. ano přes konstruktor si přidáte závislost na \LiveTranslator\Translator
  3. pokud je potřeba model mainModel, tak si ho přidejte jako další parametr konstruktoru stejně jako translator..
kralik
Člen | 230
+
0
-

Jak vyvolat sendEmail() ze třídy MailSender?
Musím vždy když ji chci zavolat funkci (sendEmail) vytvářet novou instanci?

Prosím o ucelené informace, toto je pro mne pouze kusé.

Prakticky v tomto OOP nemám žádné zkušenosti, tak se omlouvám za tyto mé LAMA otázky.

Díky

David Matějka
Moderator | 6445
+
0
-

Registrujes to jako sluzbu, kterou si vyzadas, viz treba: https://doc.nette.org/…dependencies

a jeste treba video z posoboty

ViPEr*CZ*
Člen | 809
+
0
-

Bude nutné se naučit nějaké základy. Btw funkci sendMail() ani staticky zavolat nemůže jak jste to naznačil.

<?php
\MailSender::sendEmail();
?>

Toto je špatně!!!! A proč???
Protože $template->_control = $this->linkGenerator;
$this->linkGenerator bude null a to jste zajisté nezamýšlel :-)

Jak píše David. Musíte to registrovat jako službu. Tím zajistíte v případě potřeby zavolání konstruktoru a díky DI splnění závislostí.

kralik
Člen | 230
+
0
-

Ahoj,
tak jsem zhlédl nějaká videa o DI a přečetl odkazované články a bohužel je to nad mé síly.
Dostal jsem se do bodu, kdy mám následující.

Samostatnou třídu:

<?php
use Nette\Mail\SendmailMailer;

class PosliMailFactory
{
    protected $defaultFrom;

    /** @var Nette\Application\UI\ITemplateFactory */
    protected $templateFactory;

    protected $translator;

    public function __construct($defaultFrom, Nette\Application\UI\ITemplateFactory $templateFactory, \LiveTranslator\Translator $translator) {
        $this->defaultFrom = $defaultFrom;
        $this->templateFactory = $templateFactory;
        $this->translator = $translator;
    }


    public function sendEmail()
    {
        $template = $this->templateFactory->createTemplate();

        $template->name = 'Test';
        $template->setFile(WWW_DIR.'/../app/templates/Home/notif.latte');
    //
        Tracy\Debugger::barDump($template,'sablonaEmailu');
    //
    //        //$template->_control = $this->translator;
    //
    //        $mail = new Nette\Mail\Message;
    //        $mail->addTo('test@test.com');
    //        $mail->setHtmlBody($template); // nebo setHtmlBody($template)
    //
    //        $mailer = new SendmailMailer;
    //        $mailer->send($mail);
    }
}
?>

V config.neon

<?php
parameters:
	mailFrom: "test@test.cz"
...
services:
	- PosliMailFactory(%mailFrom%)
...
?>

V BasePresenteru:

<?php
/** @var \PosliMailFactory */
    protected $posliMail;
...
public function injectPosliMail(\PosliMailFactory $posliMail) {
        $this->posliMail = $posliMail;
    }
?>

A nakonec v Presenteru

<?php
...
$this->posliMail->sendEmail();
...
?>

Nette mi vyhazuje chybu:
Argument 1 passed to Nette\Bridges\ApplicationLatte\TemplateFactory::createTemplate() must be an instance of Nette\Application\UI\Control, none given, called in D:\wamp5416\www\gap\app\model\PosliMail.php on line 32 and defined
je to u $template = $this->templateFactory->createTemplate();

Vůbec netuším zda jdu správnou cestou a je tam jen něco málo špatně, nebo je to úplně z cesty?
Prosím poraďte.
Díky

ViPEr*CZ*
Člen | 809
+
0
-

Chyba vychází z dokumentace:
https://api.nette.org/…Factory.html#…

Ta metoda chce 1 parametr. Vy jste ji nepředal nic. Navíc to má být Control.
Ku příkladu presenter vytváří template takto:

/**
* @return ITemplate
*/
protected function createTemplate()
{
  return $this->getTemplateFactory()->createTemplate($this);
}

Takže třeba přes Vaší sendEmail udělejte také nutnost 1× parametru typu Control a ten pak předejte createTemplate(…). Jinak takhle asi ok.

David Matějka
Moderator | 6445
+
0
-

@kralik @ViPEr*CZ* parametr to vyzaduje v 2.2, v 2.3 neni povinny

ViPEr*CZ*
Člen | 809
+
0
-

David Matějka napsal(a):

@kralik @ViPEr*CZ* parametr to vyzaduje v 2.2, v 2.3 neni povinny

Dík za doplnění. Nějak jsem to ani vzhledem k hlášce z chyby neuvedl. Dotyčný má asi nižší verzi Nette.
Takže jak píše David další možností je nejspíše upgrade Nette.

kralik
Člen | 230
+
0
-

ViPErCZ napsal(a):

Chyba vychází z dokumentace:
https://api.nette.org/…Factory.html#…

Ta metoda chce 1 parametr. Vy jste ji nepředal nic. Navíc to má být Control.
Ku příkladu presenter vytváří template takto:

/**
* @return ITemplate
*/
protected function createTemplate()
{
  return $this->getTemplateFactory()->createTemplate($this);
}

Takže třeba přes Vaší sendEmail udělejte také nutnost 1× parametru typu Control a ten pak předejte createTemplate(…). Jinak takhle asi ok.

Používám Nette 2.2.10

Můžete prosím uvést jak konkrétně udělat to předávání Control přes sendEmail().
Resp. Jaký přesně Control předávat?
Mám vytvořit nějaký vymyšlený Control?

Vím, že jsou to blbé otázky, ale tohle zatím netuším jak provedu.
Potřebuji, a poprosím, zcela o konkrétní příklad.

Moc díky

ViPEr*CZ*
Člen | 809
+
0
-
sendMail(Nette\Application\UI\Control $control) {
   $template = $this->templateFactory->createTemplate($control);
   ...
}

v presenteru pak

$this->posliMail->sendEmail($this);

jak prosté. Kdyby jste si to přečetl co jsem psal. Presenter vytváří šablonu tak, že factory latte předá sám sebe. Presenter je taky Control :-) No a přes parametr sendMail ho předáte do objektu a dál také té samé factory.
Pokud aktualizujete na 2.3.x tak už nic předávat nebudete nejspíše muset (viz. co psal David).

kralik
Člen | 230
+
0
-

Super, jste skvělí.
Mooc děkuji.

Doufám, že jednout také budu na vaší nynější Nette úrovni.

Pro lidi jako jsem já, přikládám kompletní plně funkční třídu:

<?php
use Nette\Mail\SendmailMailer;

class PosliMailFactory extends Nette\Object
{
    protected $defaultFrom;

    /** @var Nette\Application\UI\ITemplateFactory */
    protected $templateFactory;

     /** @var App\Model\Main */
    protected $mainModel;

    protected $translator;

    public function __construct($defaultFrom, Nette\Application\UI\ITemplateFactory $templateFactory, \LiveTranslator\Translator $translator,App\Model\Main $mainModel) {
        $this->defaultFrom = $defaultFrom;
        $this->templateFactory = $templateFactory;
        $this->translator = $translator;
        $this->mainModel = $mainModel;
    }

    public function sendEmail($co,$aid,$RecipEmail,Nette\Application\UI\Control $control)
    {

        if($RecipEmail){
            $ukol = $this->mainModel->getActionNotif($aid);

            $params = array(
                'co' => $co,
                'maction' => $ukol['Action'],
                'msubject' => $ukol['Subject']
            );

            $template = $this->templateFactory->createTemplate($control);
            $template->params = $params;
            $template->setTranslator($this->translator);

            if($control->lang == 'cs'){
                $template->setFile(WWW_DIR.'/../app/templates/Home/notifCS.latte');
            }elseif($control->lang == 'en'){
                $template->setFile(WWW_DIR.'/../app/templates/Home/notifEN.latte');
            }else{
                $template->setFile(WWW_DIR.'/../app/templates/Home/notifEN.latte');
            }

            $template->setTranslator($this->translator);

            $mailer = new Nette\Mail\SendmailMailer(array(
                          'host' => 'mujserver.domena.cz'
            ));

            $mail = new Nette\Mail\Message;

            $mail->setHtmlBody($template);

            if(is_array($RecipEmail)){
                foreach ($RecipEmail as $k => $re) {
                     $mail->addTo($re);
                }
            }else{
                $mail->addTo($RecipEmail);
            }

            $mail->setFrom($this->defaultFrom)
                ->setSubject('Předmět');

            $mailer->send($mail);



           return $res;


        }
    }

}
?>

V Presenteru:

<?php
$this->posliMail->sendEmail('new',$aid,$RecipEmail,$this);
?>

Ještě jednou díky