Předávání tříd – chyba Circular reference detected for services
- Andre
- Člen | 24
Mám problém s vzájemným předáváním závislostí mezi prezentery a třídami v modelu. Vzhledem k tomu, že třídy se používají v různých metodách po celé aplikaci, nerad bych vytvářel přes new. Nevím, ale jak vyřešit chybovou hlášku Circular reference detected for services, kterou dostávám kvůli tomu, že se třídy vzájemně odkazují na sebe. Fórum jsem procházel, vláken je hodně, ale nikde jsem odpověď nenašel. Pokud místo konstruktorů injectu přes metodu inject*, výsledná chyba je stejná.
Presenter vypadá takto:
abstract class BasePresenter extends Nette\Application\UI\Presenter {
/** @persistent */
public $backlink;
/** @inject @var Nette\Database\Context */
public $db;
/** @inject @var \App\Model\OrderManager */
public $OrderManager;
/** @inject @var \App\Model\ServiceManager */
public $ServiceManager;
...
ServiceManager:
class ServiceManager extends Nette\Object {
/** @var Nette\Database\Context */
private $db;
/** @var \App\Model\OrderManager */
public $OrderManager;
/** @var Nette\Application\UI\ITemplateFactory */
private $templateFactory;
/** @var Nette\Bridges\ApplicationLatte\ILatteFactory */
private $latteFactory;
public function __construct(Nette\Database\Context $db, \App\Model\OrderManager $OrderManager, Nette\Application\UI\ITemplateFactory $templateFactory, Nette\Bridges\ApplicationLatte\ILatteFactory $latteFactory) {
$this->db = $db;
$this->OrderManager = $OrderManager;
$this->templateFactory = $templateFactory;
$this->latteFactory = $latteFactory;
}
...
}
OrderManager:
class OrderManager extends Nette\Object {
/** @var Nette\Database\Context */
private $db;
/** @var \App\Model\ServiceManager */
public $ServiceManager;
public function __construct(Nette\Database\Context $db, \App\Model\ServiceManager $ServiceManager) {
$this->db = $db;
$this->ServiceManager = $ServiceManager;
}
Editoval Andre (28. 3. 2015 16:31)
- Filip Klimeš
- Nette Blogger | 156
Tuhle chybu asi nepůjde vyřešit jinak, než předěláním návrhu aplikace.
Polož si otázku – nešlo by to udělat jinak? Proč má jedna třída závislost na druhé, která má zpětně závislost na té první? Je to nutné?
Pokud dodržuješ klasické vrstvení aplikace, upřímně si nedokážu představit reálný use-case pro Tvůj případ. Zkus ho sem napsat, možná vymyslíme lepší řešení.
Editoval Filip Klimeš (28. 3. 2015 23:41)
- piler
- Člen | 111
V mojom pripade som natrafil na pripad pri Event dispatcher. Do neho som si zaregistroval subscibers a jeden subscriber dostane ako dependency zase Event dispatcher aby v istej situacii mohol dispatchnut event dalej.
Tu nastava probem, ze Dispatcher ma Subscriber1 a Subscriber1 potrebuje Dispatcher aby mohol dispatchnut event.
Mozno to nie je spravne riesenie, ale nevidim v tom zatial nejaky problem.
- piler
- Člen | 111
Povedzme je tam command ktory stiahne recent events a prechadza ich po jednom a dispatchuje na zaklade resource type a action nieco ako
<?php
$dispatcher->dispatch(
sprintf('gc_event_%s_%s', $resourceEvent->resource_type(), $resourceEvent->action()),
$resourceEvent
);
?>
Povedzme, ze dispatchujem event gc_event_payments_failed na ktory pocuva FailedSubscriber. Tam nastane dalsi check. Ak je to z dovodu nedostatku penazi, tak sa dispatchne event gc_event_payments_insufficient_funds inak sa dipatchne gc_event_payments_unknown.
Tato logika sa zamozrejme da presunut od vlastneho event dispatcheru a mat tam tie podmienky, ale takto mi to pride cistejsie.
Pouzivame symfony dispatcher, pretoze vyuzivame aj priority, co kdyby nema/nemalo. Ako Kdyby/Events circular reference vyriesi, netusim.
Dakujem.
Dik za pomoc.
- David Matějka
- Moderator | 6445
@piler kdyby/events ma priority uz pres dva roky: https://github.com/…28464e558e78
Circular reference je tam vyreseny diky Lazy event manageru. Coz ti doporucuju si implementovat i u symfony event dispatcheru, aby se ti vzdy nemusel inicializovat cely graf zavislosti a navic ti to vyresi i ty circular reference :). Symfony samotne pouziva ContainerAwareEventDispatcher, takze bude stacit to naportovat na nette di
- piler
- Člen | 111
@DavidMatějka myslim, ze sme dispatcher implementovali pred menej ako 2 rokmi, tak som to musel prehliadnut.
Pozeram na ten ContainerAwareEventDispatcher a tu sa v konstruktore zadava container. Pozeram do nasej implementacie a EventDispatcher vytvaram cez DI. Je teda mozme vytvorit Dispatcher cez DI a zaroven mu dat DIC ako zavislost?
Vdaka za rady ;)