Circular reference detected for services
- Pert Jančálek
- Člen | 5
Ahojte, potřeboval bych pomoct s předáváním parametrů … všechno mi fungovalo až do té doby, než jsem přidal do DI containeru následující třídu:
use Nette\Application\LinkGenerator;
use Nette\Application\UI\ITemplateFactory;
use Nette\Mail\Message;
use Latte\Engine;
use Nette\Mail\SmtpMailer;
class Mailer
{
/** @var LinkGenerator */
private $linkGenerator;
/** @var ITemplateFactory */
private $templateFactory;
/** @var SmtpMailer */
private $sendMailer;
/**
* Mailer constructor.
* @param LinkGenerator $linkGenerator
* @param ITemplateFactory $templateFactory
*/
public function __construct(LinkGenerator $linkGenerator, ITemplateFactory $templateFactory )
{
$this->sendMailer = new SmtpMailer([
'host' => '***',
'username' => '***',
'password' => '***',
'secure' => 'ssl'
]);
$this->linkGenerator = $linkGenerator;
$this->templateFactory = $templateFactory;
}
/**
* @param array $params
*/
public function sendKey(array $params)
{
$latte = new Engine();
$template = $this->createTemplate();
$template->name = 'name';
$template->setFile(__DIR__ . '/mailTemplates/key.latte');
$mail = new Message;
$mail->setHtmlBody($latte->renderToString($template, $params));
$this->sendMailer->send($mail);
}
protected function createTemplate()
{
$template = $this->templateFactory->createTemplate();
$template->getLatte()->addProvider('uiControl', $this->linkGenerator);
return $template;
}
}
Jediná třída, která tento objekt vyžadaduje je třída userFacade.
Hned potom, co tuto třídu předám userFacadě jako parametr, tak dostanu
chybovou hlášku:
Circular reference detected for services: application.4, 71_App_Forms_StatusFormFactory, security.user, 77_App_Model_Facades_UserFacade, 78_App_Model_Utils_Mailer, latte.templateFactory
Absolutně netuším, kde by mohl být problém. Mohli byste mi prosím pomoci ?
Editoval Pert Jančálek (12. 9. 2017 19:45)
- David Matějka
- Moderator | 6445
tipuju, ze user facade implementuje authorizator? nejlepsi bude z authorizatoru udelat samotnou sluzbu (ktera nebude zavisla na user facade)
- Pert Jančálek
- Člen | 5
Třída implementuje rozhraní IAuthenticator. Příjde mi to tak logické,
protože používám Doctrine a tato třída má potřebné objekty, ale tu
entitu vytáhla.
Tak díky za odpovědi, ale škoda, že to neřeší můj problém.
Editoval Pert Jančálek (12. 9. 2017 20:55)
- Pert Jančálek
- Člen | 5
<?php
namespace App\Forms;
use App\Model\Facades\StatusFacade;
use App\Model\Facades\UserFacade;
use Czubehead\BootstrapForms\BootstrapForm as Form;
use Nette\Security\User;
use Nette\Utils\ArrayHash;
class StatusFormFactory extends BaseFormFactory
{
/** @var StatusFacade */
protected $statusFacade;
/**
* StatusFormFactory constructor.
* @param StatusFacade $statusFacade
*/
public function __construct(StatusFacade $statusFacade, User $user, UserFacade $userFacade)
{
parent::__construct($user, $userFacade);
$this->statusFacade = $statusFacade;
}
public function statusForm()
{
$form = new Form();
$form->addTextArea('content')
->setAttribute('id', 'preview')
->addRule(Form::MAX_LENGTH, 'Maximální délka statusu je %d znaků.', 3000)
->setRequired('Vyplňte prosím status před jeho odesláním.');
$form->addMultiUpload('images', 'Obrázky')
->setRequired(false)
->setOmitted(false);
$form->addSubmit('submit', 'submit');
$form->onSuccess[] = [$this, 'statusSucceeded'];
return $form;
}
public function statusSucceeded(Form $form, $vals)
{
$vals->user = $this->userFacade->getUser($this->user->getId());
$this->statusFacade->createStatus($form, $vals);
}
public function infoForm()
{
$form = $this->texyArea('content', 'Obsah');
$form->addSubmit('submit', 'odeslat');
$form->onSuccess[] = [$this, 'infoSuccess'];
return $form;
}
public function infoSuccess(Form $form, ArrayHash $vals)
{
$vals->user = $this->userFacade->getUser($this->user->getId());
$this->statusFacade->createInfo($vals);
}
}
<?php
namespace App\Model\Facades;
use App\Model\Entities\User as UserEntity;
use App\Model\Entities\UserSettings;
use App\Model\Utils\Mailer;
use App\Model\Utils\RouteParser;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Doctrine\ORM\EntityManager;
use Nette\Application\UI\Form;
use Nette\InvalidArgumentException;
use Nette\Mail\Message;
use Nette\Utils\ArrayHash;
use Nette\Security\AuthenticationException;
use Nette\Security\IAuthenticator;
use Nette\Security\Identity;
use Nette\Security\IIdentity;
use Nette\Security\Passwords;
use Nette\Mail\SmtpMailer;
class UserFacade extends BaseFacade implements IAuthenticator
{
/** @var Mailer */
private $mailer;
/**
* UserFacade constructor.
* @param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
// $this->mailer = $mailer;
$this->mailer = new SmtpMailer([
...
]);
$this->em = $entityManager;
}
/**
* @param int $id
* @return UserEntity|null
*/
public function getUser($id)
{
return $this->em->find(UserEntity::class, $id);
}
/**
* @param string $name
* @return null|UserEntity
*/
public function getUserByName($name)
{
return $this->em->getRepository(UserEntity::class)->findOneBy(array('name' => $name));
}
/**
* @param string $route
* @return UserEntity|null
*/
public function getUserByRoute($route)
{
return $this->em->getRepository(UserEntity::class)->findOneBy(['route' => $route]);
}
/**
* @param string $route
* @return UserEntity|null
*/
public function getIdByRoute($route)
{
return $this->em->createQuery('
SELECT PARTIAL u.{id}
FROM App\Model\Entities\USER u
WHERE u.route = :route
')
->setParameter('route', $route)
->setMaxResults(1)
->getOneOrNullResult();
}
/**
* Performs an authentication against e.g. database.
* and returns IIdentity on success or throws AuthenticationException
* @return IIdentity
* @throws AuthenticationException
*/
function authenticate(array $credentials)
{
list($name, $password) = $credentials;
$user = $this->getPartialUser($name);
if (!$user) throw new AuthenticationException('Špatné jméno');
if (!Passwords::verify($password, $user->password)) throw new AuthenticationException('Špatné heslo');
if($user->settings->key !== NULL) throw new KeyException();
if (Passwords::needsRehash($user->password)) {
$user->password = Passwords::hash($password);
$this->em - flush();
}
return new Identity($user->id, explode(' ', $user->role), ['route' => $user->route]);
}
function userChecked(UserEntity $user)
{
$user->settings->key = NULL;
$this->em->flush();
}
/**
* @param $name
* @return UserEntity|null
*/
private function getPartialUser($name)
{
return $this->em->createQuery('
SELECT PARTIAL u.{id, name, password, role, route}, PARTIAL s.{id,key}
FROM App\Model\Entities\User u
INNER JOIN u.settings s
WHERE u.name = :name
')
->setParameter('name', $name)
->setMaxResults(1)
->getOneOrNullResult();
}
/**
* @param ArrayHash $vals
* @throws InvalidArgumentException
* @throws UniqueConstraintViolationException
*/
public function adminEdit(Form $form, ArrayHash $vals)
{
$user = $this->getUser($vals->userId);
if (is_null($user))
throw new InvalidArgumentException('Uživatel, na kterého se snažíte dotázat, neexistuje');
if ($user->role === UserEntity::ROLE_ADMIN && $this->vals->userRoute !== $user->route)
throw new InvalidArgumentException('Nemůžeš upravovat jiného administrátora.');
$user->name = $vals->name;
$user->role = $vals->role;
if ($vals->password)
$user->password = Passwords::hash($vals->name);
if ($vals->route)
$user->route = RouteParser::parseRoute($vals->route);
if ($vals->description)
$user->settings->description = $vals->description;
$user->email = $vals->email;
$this->em->flush();
$this->filesUpload($form, $vals);
}
/**
* @param ArrayHash $vals
* @throws UniqueConstraintViolationException
*/
public function registerUser(ArrayHash $vals)
{
$user = new UserEntity();
$user->name = $vals->name;
$user->password = Passwords::hash($vals->password);
$user->email = $vals->email;
$user->points = 0;
$user->route = RouteParser::parseRoute($user->name);
$settings = new UserSettings();
$settings->key = $this->generateKey();
$user->role = UserEntity::ROLE_USER;
$user->settings = $settings;
$settings->register_at = new \DateTime();
$this->em->persist($settings);
$this->em->persist($user);
$this->em->flush();
// $this->mailer->sendKey(['name' => $vals->name, 'route' => $user->route, 'key' => $settings->key]);
$this->sendKey($vals->email, $user->route, $user->settings->key);
}
private function sendKey($email, $route, $key)
{
$mail = new Message();
$mail->setFrom('Oaza <admin@...>')
->addTo($email)
->setSubject('Potvrzení registrace')
->setHtmlBody('<h1>Registrace na webu</h1><br>
<p>Pro potvrzení tvého účtu přejdi na odkaz níže</p>
<br>
<a>odkaz ...</a>
');
$this->mailer->send($mail);
}
/**
* @return string
*/
private function generateKey()
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$length = mb_strlen($characters);
$key = '';
for ($i = 0; $i < 50; $i++)
{
$key .= $characters[rand(0, $length - 1)];
}
return $key;
}
protected function filesUpload(Form $form, ArrayHash $vals)
{
if ($vals->profile->isOk())
$vals->profile->move('images/players/profile/' . $vals->userId . '.png');
else if ($vals->profile->getName() !== null && !$vals->profile->isOk())
$form->addError('Obrázek avatara se po cestě poškodil. Nahrajte ho proísm znovu.');
if ($vals->background->isOk())
$vals->background->move('images/players/background/' . $vals->userId . '.png');
else if ($vals->background->getName() !== null && !$vals->background->isOk())
$form->addError('Backgound se po cestě poškodil. Nahrajte ho proísm znovu.');
}
public function userEdit(Form $form, ArrayHash $vals)
{
$user = $this->getUser($vals->userId);
if ($vals->password)
$user->password = Passwords::hash($vals->password);
$user->settings->description = $vals->description;
$this->em->flush();
$this->filesUpload($form, $vals);
}
}
class KeyException extends \Exception
{
}
U třídy userFacade jsem tu závislost momentálně oddělal a prozatimní funkcí.
- David Matějka
- Moderator | 6445
Tak díky za odpovědi, ale škoda, že to neřeší můj problém.
resi to tvuj problem. Nette\Security\User vyzaduje IAuthenticator, ktery mas implementovany v UserFacade. Ta pak vyzaduje ten Mailer, ten vyzaduje ITemplateFactory a to vyzaduje Nette\Security\User – a je tu circular reference.
kdyz udelas z authenticatoru samotnou sluzbu, problem zmizi