D
D
Dmitry2017-09-19 19:14:17
Zend Framework
Dmitry, 2017-09-19 19:14:17

How to solve the problem of "Circular dependency" in Zend 2 or even competently organize dependency injection?

There are 2 services ( TableGateway ) and factories for them: Day and DaySet .

day:

- id
- date
- dayset
dayset:

- id
- title

Day is related to DaySet by field dayset .
Both TableGateways are assembled by a factory ( DayTableFactory and DaySetTableFactory ).
Since Day refers to DaySet - in the DayTableFactory factory, through the service manager, I get an instance of DaySetTable :
DayTableFactory
public function __invoke(ServiceLocatorInterface $serviceLocator) {
    // ...
    $daySetTable = $serviceLocator->get(DaySetTable::class);

    return DayTable(..., $daySetTable);
}


The DayTable has a method that "maps" the Day object by populating the dayset field with the DaySet object :
DayTable::populate($item)
$daySetId = $item->getDayset()
/** @var DaySet $daySetObject */
$daySetObject = $this->daySetTable->get($daySetId);
$item->setDayset($daySetObject);


It is necessary to implement this in DaySetTable so that this table-gate service can map its objects ( DaySet ) and fill, for example, the DaySet::days property ( @var Day[]|array $days ).
If you pull a DayTable - Circular Dependency error from the service manager ( ServiceLocator ) in the DaySetTable factory, it is understandable.
Passing a ServiceLocator (using the same ServiceLocatorAwareTrait) to the DaySetTable service is not the smartest move given that this approach is already deprecated in ZF3.
The question is how to resolve the cyclic dependency ( DaySetTable <-> DayTable) without telling the service ( DaySet ) about the service container?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
N
novrm, 2017-09-20
@novrm

Put a limit on the number of cycles.
In the class, write a certain variable that will decrease to a certain value with each iteration.

F
Fortop, 2017-09-20
@Fortop

The problem of circular dependency is solved by initializing one of the dependencies on the first call, and not when instantiating.

class a {}

class b {
    public function _construct($locator){}
    public function someOperation() {
        $this->dependency = $this->dependency ??  $this->locator->get(a::class);
        //..... 
    } 
}

With this, class "a" can still get dependency via constructor without locator injection

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question