Makro {link} v emailech od Nette 2.3 (hodně obsáhle)

před 4 lety

David Grudl
Nette Core | 6849
+
+19
-

Od Nette 2.3 je k dispozici nástroj LinkGenerator pro generování odkazů mimo presentery, ale se stejným komfortem.

Jak ho použít?

Mám teda nějakou třídu, která odesílá emaily, předám ji LinkGenerator do proměnné $this->linkGenerator a vytvořím si objekt Latte.

Kód emailu může vypadat nějak takto:

<title>Subject of message</title>

<p>Hello {$name} <a n:href="Homepage:">click here</a></p>

A kód třídy:

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

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

    function sendEmail()
    {
        $latte = new Latte\Engine;
        $latte->setTempDirectory(...);
        ...
    }

Nastavit temp directory je docela fajn, aby se šablona s každým emailem nemusela znovu kompilovat (pokud jich posíláte denně méně než pár set, v samostatných requestech, je to teda upřímně docela fuk), jenže kde vzít cestu k té složce? Můžeme si ji opět předat, ale chytřejší řešení je místo toho si předat objekt, tzv. továrničku, který dovede vyrobit Latte právě už s nastavenou cestou k temp dir:

/** @var Nette\Bridges\ApplicationLatte\ILatteFactory */
private $latteFactory;

// opět předáme přes konstruktor

function sendEmail()
{
    $latte = $this->latteFactory->create();

    // nainstaluji do $latte makra {link} a n:href
    Nette\Bridges\ApplicationLatte\UIMacros::install($latte->getCompiler());

    // a vygenerujeme HTML email
    $html = $latte->renderToString(__DIR__ . '/email.latte', [
        'name' => $order->getName(), // proměnné do šablony
        ....
    ]);
    ...
}

Tady ještě jednou přeruším, protože musím zmínit ještě jednu alternativu, a to nechat si vygenerovat přímo známý objekt $template, už s nakonfigurovaným Latte. Vyměním tedy latteFactory za templateFactory:

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

// opět předáme přes konstruktor případně anotací @inject

function sendEmail()
{
    $template = $this->templateFactory->createTemplate();
    $template->name = $order->getName();

    $html = (string) $template;
    ...
}

(Stejně jako templateFactory->createTemplate() funguje i $this->createTemplate() uvnitř presenteru či komponenty, ale vhodnější je odesílání emailů delegovat do samostatné třídy, protože to není zodpovědnost presenterů. Vidíte, že to používání šablon nijak neomezuje.)

Zbytek metody sendEmail bude vypadat cca takto:

    ...
    $mail = new Nette\Mail\Message;
    $mail->addTo($order->email);
    $mail->setHtmlBody($html); // nebo setHtmlBody($template)

    $mailer->send($mail);   // $mailer si opět předáme
}

A teď zbývá poslední krok! Zapojit do toho ten LinkGenerator, ke kterému jsem se dosud nedostal. Je to snadné, ale zatím ne intuitivní (intuitivní API teprve hledám).

Jednoduše generátor vložte do šablony do proměnné _control.

Tedy buď:

$params = array(
    'name' => $order->getName(),
    '_control' => $this->linkGenerator,
    ...
);

nebo

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

podle toho, kterou cestou na to jdete.

A odkazy se začnou generovat.

před 4 lety

greeny
Člen | 406
+
+3
-

Jen nápad, nějak dopodrobna jsem to nepromýšlel, ale co nějakej ILinkFactory (function link())? A pak metoda typu setLinkFactory(ILinkFactory $factory). Makro {link} by pak mohlo používat $template->_linkFactory s fallbackem na $template->_control.

před 4 lety

ic
Člen | 416
+
+1
-

Tohle by se asi pěkně hodilo v https://github.com/…r/Micro-blog -u

před 4 lety

Climber007
Člen | 104
+
+1
-

Při linku obsahujícím cestu s modulem (:Front:Homepage:) LinkGenerator selže, že prý špatný název presenteru. Chyba nebo jsem udělal někde něco špatně?

před 4 lety

Joe Kolář
Člen | 13
+
+2
-

Pro LinkGenerator neexistuji nic jako relativní nebo absolutní cesta, takže to zkus bez počáteční dvojtečky.

před 4 lety

Climber007
Člen | 104
+
0
-

Bez dvojtečky to samozřejmě jde, ale chtěl bych tu šablonu používat jak s LinkGenratorem, tak normálně v Presenteru. Jde o to, že by se to mělo chovat ve všech případech konzistentně.

před 4 lety

David Matějka
Moderator | 5880
+
+1
-

viz issue na gh: https://github.com/…on/issues/72, muzete poslat PR ;)

před 4 lety

Climber007
Člen | 104
+
0
-

Díky, jsem blbej, tam jsem se zapomněl nepodívat. PR moc rád, nevím jak budu stíhat.

Editoval Climber007 (11. 9. 2015 19:59)