Reputation: 1274
I have a simple class which looks like this:
<?php
namespace App\Algorithm;
use App\Dao\MatchDao;
use App\Service\MatchService;
class Calculator {
private $users;
private $matchDao;
function __construct(MatchService $matchService, MatchDao $matchDao) {
$this->users = $matchService->users;
$this->matchDao = $matchDao;
}
public function hourlyRate() {
$query = $this->matchDao->getSingleColumn('Payment', 'hourly_rate', 32);
var_dump($query);
}
}
But I get the following error message:
Circular reference detected for service "App\Algorithm\Calculator", path: "App\Algorithm\Calculator -> App\Service\MatchService -> App\Algorithm\Calculator".
MatchService.php
<?php
namespace App\Service;
use App\Algorithm\Calculator;
use App\Algorithm\Collection;
class MatchService {
public $users;
private $collection;
private $calculator;
function __construct(Collection $collection, Calculator $calculator) {
$this->collection = $collection;
$this->calculator = $calculator;
}
public function getMatch($data) {
$this->users = $this->collection->getAllUsers($data);
$this->calculator->hourlyRate();
return 1;
}
}
The problem would be MatchService
but what exactly am I doing wrong?
Upvotes: 7
Views: 13794
Reputation: 2125
It is kind of obvious that you are injecting service A into Service B, and, also, Service B into Service A . Seems kind of not logical to do so, but sometimes is needed. In my case, I have two services :
_MySesion -> Which prototypes Symfony Session
_MyClient -> Responsible for identify the client and get its DB Credentials
I use the MySession to store those credentials, as so, it will be available to the whole system, but, to get those credentials using MyClient, I need some info stored into MySession .... See, two services that need each other to work ...
I start to see this same
Circular reference detected for service
just after upgrade to Symfony 5. And, sfy5 itself suggested the solution :
composer require symfony/proxy-manager-bridge
Remember that the services may be set with
lazy : true
More info on Symfony Docs
Upvotes: 3
Reputation: 48865
As several people have pointed out, the circular dependency comes from that fact that you are trying to inject the Calculator into MatchService and at the same time, injecting MatchService into the Calculator. No way to create one before creating the other.
Looking a bit more deeply, it appears that Calculator is using the MatchService to get list of users. As a second problem, Calculator is trying to get the users before MatchService has generated them.
Here is one possible refactoring:
class Calculator
{
private $matchDao;
public function __construct(MatchDao $matchDao)
{
$this->matchDao = $matchDao;
}
public function getHourlyRate($users) // Added argument
{
$query = $this->matchDao->getSingleColumn('Payment', 'hourly_rate', 32);
}
}
class MatchService
{
private $collection;
private $calculator;
public function __construct(Collection $collection, Calculator $calculator)
{
$this->calculator = $calculator;
$this->collection = $collection;
}
public function getMatch($data)
{
$users = $this->collection->getAllUsers($data);
$this->calculator->getHourlyRate($users);
}
}
Removing MatchService from the Calculator's constructor solves the circular dependency problem. Passing $users to getHourlyRate solves the problem of trying to get users before they are available.
This is course is just one possible solution. It's not clear from your posted code if Calculator really needs $users or not.
Upvotes: 6
Reputation: 4389
This usually occurs when classes are dependency injecting each other, hence the circular reference.
Given you above example, your class MatchService
injects Collection
and Calculator
. One of these (would assume calculator as collection is probably a doctrine class) dependency injects your MatchService
.
Here is how I imagine your classes are supt:
class MatchService
{
public $users;
private $collection;
private $calculator;
public function __construct(Collection $collection, Calculator $calculator) {
$this->collection = $collection;
$this->calculator = $calculator;
}
}
class Calculator
{
private $matchService;
public function __construct(MatchService $matchService)
{
$this->matchService = $matchService;
}
}
You have a couple of options:
It's hard for us to solve for you as it's dependent on how you architect your application.
Upvotes: 3