Jak dostat komponentu do Fasady

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

Ahoj,

morim se s injektaci komponenty do fasady. Co resim: mam komponentu mailer, ktera odesle mail s vyuzitim definovane sablony.

Komponenta:

<?php
namespace App\Controls\Mailer;

class MailerControl extends Control
{
}

interface IMailerFactory
{

    /**
     * @return MailerControl
     */
    public function create();
}
?>

Base fasada:

<?php
namespace App\Model\Facades;

use Kdyby\Doctrine\EntityManager;
use App\Controls\Mailer\MailerControl;

class BaseFacade extends \Nette\Object
{

    /** @var EntityManager */
    protected $em;

    /** @var MailerControl */
    protected $mailer;

    public function __construct(EntityManager $em, MailerControl $mailer)
    {
        $this->em = $em;
        $this->mailer = $mailer;
    }

}
?>

config.neon

services:
	- App\Controls\Mailer\MailerControl
	- App\Controls\Mailer\IMailerFactory
	- App\Model\Facades\UserFacade
	router: App\RouterFactory::createRouter
	# Factories
	- App\Forms\SignFormFactory

basepresenter

<?php
abstract class BasePresenter extends Presenter
{
    /** @var IMailerFactory @inject */
    public $mailerFactory;

    /**
     *
     * @return MailerControl
     */
    protected function createComponentMailer()
    {
        $control = $this->mailerFactory->create();
        return $control;
    }
}
?>

A ted si v SingInFactory po odeslani formulare chci zavolat metodu sendPasswordRecoveryInstructions(), ktera by odeslala email.

<?php
class SignFormFactory extends Object
{

    /** @var EntityManager */
    private $em;

    /** @var UserFacade */
    private $userFacade;

    /** @var Translator */
    private $translator;

    /** @var User */
    private $user;


    /**
     *
     * @param UserFacade $userFacade
     * @param Translator $translator
     * @param User $user
     * @param EntityManager $em
     */
    public function __construct(UserFacade $userFacade, Translator $translator, User $user, EntityManager $em)
    {
        $this->userFacade = $userFacade;
        $this->translator = $translator;
        $this->user = $user;
        $this->em = $em;
    }

    /**
     *
     * @param Form $form
     * @param ArrayHash $values
     */
    public function recoverSubmitted($form, $values)
    {
        try
        {
            $this->userFacade->sendPasswordRecoveryInstructions($values->email);
		    ....
        } catch (Exception $e)
        {

        }
    }
}
?>

Proto chci do BaseFasade dostat komponentu MailerControl. No a nejak jsem se v tom ted ztratil :)

Kdyz si Mailer predam konstruktorem, Nette na me krici Component '' is not attached to ‚Nette\Application\UI\Presenter‘ kvuli

<?php
$template = $this->createTemplate();
?>

v komponente mailera.

Navic nevim, jestli nemicham dve veci (zbytecne) v configu pri registraci komponenty a interface jako sluzby
App\Controls\Mailer\MailerControl
App\Controls\Mailer\IMailerFactory

A v Base presenteru mam

<?php
createComponentMailer()
?>

Tak jsem z toho jelen :)

David Matějka
Moderator | 6445
+
0
-

Nepouzivej na to komponentu, vytvor si sluzbu a sablonu vytvor dle treba https://phpfashion.com/…-a-nette-2-3

libik
Člen | 96
+
0
-

Ok, diky, zamerim se timto smerem.

libik
Člen | 96
+
0
-

Jeste se k tomu vracim. Kdyz dle odkazu pouziju templateFactory, ladenka na me krici Circular reference detected for services: application.12, security.user, 103_App_Model_Facades_UserFacade, 104_App_Controls_Mailer_MailSender, latte.templateFactory.

S pouzitim latteFactory to ale funguje. Bojim se, aby ta kruhovita hlaska neznamenala nejakou zasadni chybu v navrhu.

Dle prvniho mailu jsem upravil

<?php
namespace App\Controls\Mailer;

use Nette\Mail\SendmailMailer;
use Nette\Mail\Message;
use Nette\Diagnostics\Debugger;
use Nette\Application\LinkGenerator;
use Kdyby\Translation\Translator;
use Nette\Bridges\ApplicationLatte\ILatteFactory;
use Nette\Bridges\ApplicationLatte\UIMacros;

class MailSender
{

    /** @var Translator */
    private $translator;

    /** @var LinkGenerator */
    private $linkGenerator;

    /** @var ILatteFactory */
    private $latteFactory;

    /** @var UserEntity */
    private $userEntity;

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

    /**
     * @param string $from
     * @param Translator $translator
     * @param LinkGenerator $linkGenerator
     * @param \Nette\Application\UI\ITemplateFactory $templateFactory
     */
    public function __construct($from, Translator $translator, LinkGenerator $linkGenerator, \Nette\Application\UI\ITemplateFactory $templateFactory)
    {
        $this->from = $from;
        $this->translator = $translator;
        $this->linkGenerator = $linkGenerator;
        $this->templateFactory = $templateFactory;
    }
...
?>

v configu jsem zaregistroval sluzbu

services:
	- App\Controls\Mailer\MailSender(%email.defaultFrom%)
	- App\Model\Facades\UserFacade

a v BaseEntity pripojuju v konstruktoru

<?php
<?php

namespace App\Model\Facades;

use Kdyby\Doctrine\EntityManager;
use App\Controls\Mailer\MailSender;

/**
 * @package App\Model\Facades
 */
class BaseFacade extends \Nette\Object
{

    /** @var EntityManager */
    protected $em;

    /** @var MailSender */
    protected $mailSender;

    /**
     *
     * @param EntityManager $em
     * @param MailSender $mailSender
     */
    public function __construct(EntityManager $em, MailSender $mailSender)
    {
        $this->em = $em;
        $this->mailSender = $mailSender;
    }

}

V BasePresenteru injectuju UserFacade (dedi od BaseFacade)

<?php
abstract class BasePresenter extends Presenter
{

    /** @persistent null|string */
    public $locale;

    /**
     * @var \Kdyby\Translation\Translator
     * @inject
     */
    public $translator;

    /**
     *
     * @var UserFacade
     * @inject
     */
    public $userFacade;
?>
David Matějka
Moderator | 6445
+
0
-

Circular reference casto opravdu znaci nejakou chybu navrhu, ale vetsinou je resitelna. V tvem pripade to vypada, ze UserFacade implementuje IAuthenticator, ze? Resenim je proste pro authenticator udelat samostatnou tridu (a tu registrovat jako sluzbu). A delat co nejmensi tridy je obvykle best practise.

A mimochodem, to vyzadovani MailSender v BaseFacade neni prilis idealni. A Base* tridam je take obvykle se lepsi vyhnout :)

A posledni poznamka, na posilani mailu apod. jsou skvele eventy, konkretne treba kdyby/events

libik
Člen | 96
+
0
-

Diky, diky!
Authenticator osamostatnen a uz to funguje.
Na kdyby/events se podivam.