Invalid argument supplied for foreach() when generating link

2 years ago

ydenda
Member | 21
+
0
-

Hello together,

What am I missing?

when I attempt to produce the account activation link in presenter:

$template->link = $this->link('Front:Sign:verify', $token);

or in template:

<a href="{link //Front:Sign:verify, $token}">activate account</a>

TRACY complains on /nette/application/src/Application/UI/Presenter.php:1143
with warning: Invalid argument supplied for foreach()

First I thought the problem could be I haven't used FQDN on my test bench to reach the web app, nevertheless even after change to FQDN, I got the same error.

Unfortunately I cannot show you the TRACY output, since currently I have unsupported php version on production site.

Ubuntu 16/04, Apache 2.4.18, php 7.0, Nette 2.4

2 years ago

idiox
Member | 14
+
0
-

Hi,

try to delete the comma after “:verify”

<?php

<a href="{link //Front:Sign:verify, $token}">activate account</a>

?>
<?php

<a href="{link //Front:Sign:verify $token}">activate account</a>

?>

Latte links

<?php
{link Product:show $productId}
?>

Last edited by idiox (2016-11-12 15:24)

2 years ago

ydenda
Member | 21
+
0
-

Hi idiox,

the comma is needed to split the url and arguments (GET parameters) according Docu;
Link generation does not work even without argument $token, so I expect the problem is anywhere else.

2 years ago

ydenda
Member | 21
+
0
-

I tried to isolate the problem a bit more…

When I place following code:

$template->link = $this->link('Front:Sign:verify', $token);

in renderDefault method, the link is successfully generated.

Problem occurs, when I place the line in some other method. For better imagination, please see the code of corresponding presenter:

<?php

namespace FrontModule;

use \Nette;
use \Nette\Mail\Message;
use \Nette\Mail\SendmailMailer;

class MailPresenter extends BasePresenter
{
    public function sendActivationMail($username, $email, $token) {

        $mail = new Message;
        $mail->setSubject('Aktivační email');
        $mail->setFrom('nobody@nobody.cz', 'Registrace');
        $mail->addTo($email, $username);

        $template = $this->createTemplate();
        $template->setFile(__DIR__ . '/templates/newUser.phtml');

        $template->token = $token;
        $template->username = $username;
        $template->email = $email;
        $template->link = $this->link('//:Front:Sign:verify' , $token);

        $mail->setHtmlBody($template);

        $mailer = new SendmailMailer;
        $mailer->send($mail);

        return;
    }
}

Does anyone have an idea what I've done wrong?

2 years ago

David Matějka
Moderator | 5702
+
0
-

From where do you call this method?

2 years ago

ydenda
Member | 21
+
0
-

Hi David,

method is called from onSuccess method of app/forms/SignUpFormFactory.php which is the generic file (except the needed changes to call method from MailPresenter class)

2 years ago

CZechBoY
Member | 3212
+
0
-

How do you create the “MailPresenter” class? or how you attach it to the onSucces event?

2 years ago

ydenda
Member | 21
+
0
-

Beside others, it is passed in constructor to the SignUpFormFactory:

/** @var \FrontModule\MailPresenter  @inject */
    protected $mailPresenter;

    public function __construct(FormFactory $factory, Model\UserManager $userManager, \FrontModule\MailPresenter $mailPresenter)
    {
        $this->factory = $factory;
        $this->userManager = $userManager;
        $this->mailPresenter = $mailPresenter;
    }

and then reached via

$this->mailPresenter->sendActivationMail($values->username, $values->email, $token);

Obviously it is not the best practice – any hints on this?

2 years ago

CZechBoY
Member | 3212
+
0
-

Extend some Nette\Object or make from that plain class without parent.

2 years ago

CZechBoY
Member | 3212
+
0
-

Btw inject doesnt work on protected properties, only on public.

2 years ago

idiox
Member | 14
+
0
-

Ok, sry. I never used comma after action name in n:href so I thought that is superfluous and causing the problem.. :)

Last edited by idiox (2016-11-13 14:34)

2 years ago

ydenda
Member | 21
+
0
-

Well, I made things working a bit.

After some time I've found article Link generation in emails with Nette 2.3

So I created /app/model/MailManager.php with following content:

<?php

namespace App\Model;

use \Nette;

use \Nette\Mail\Message;
use \Nette\Mail\SendmailMailer;

class MailSender
{


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

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

    function __construct(\Nette\Application\LinkGenerator $generator, \Nette\Application\UI\ITemplateFactory $tf)
    {
        $this->linkGenerator = $generator;
        $this->templateFactory = $tf;
    }

    public function sendActivationMail($username, $email, $token) {
        $mail = new Message;
        $mail->setSubject('Account activation');
        $mail->setFrom('nobody@nobody.cz', 'SignUp - myProject');
        $mail->addTo($email, $username);

        $template = $this->templateFactory->createTemplate();
        $template->setFile(__DIR__ . '/MailTemplates/newUser.phtml');

        $template->getLatte()->addProvider('uiControl', $this->linkGenerator); // for Latte 2.4 allows {link} in template

        $template->token = $token;
        $template->username = $username;
        $template->email = $email;

        $mail->setHtmlBody($template);

        $mailer = new SendmailMailer;
        $mailer->send($mail);

        return;
    }

}

It made the {link} working in the template, nevertheless $this->link is not available.
For my needs it is sufficient so far.

Thank you guys for spent effort trying to help me.
Hope this helps others…

2 years ago

CZechBoY
Member | 3212
+
0
-

btw. it is better to inject interface Nette\Mail\IMailer instead of creating SendMailer by yourself.

Last edited by CZechBoY (2016-11-16 18:55)