I've stumbled into this problem again today and it's important to know that this problem is thrown whenever a dependency down the chain initiates an instance that needs to know the state of the application.
In many cases this error is session-bound (since the session needs to know the state of the application (frontend or adminhtml)).
In my case I needed to have Magento\Tax\Api\TaxCalculationInterface
in a CLI command, but this requires at some point in it's dependency chain the customer session (probably to get the customer group).
Edit: I found a better solution using proxies. But for histories' sake, here's my previous answer:
To solve this I did not include this interface in my constructor, but rather it's factory:
/**
* @var \Magento\Tax\Api\TaxCalculationInterfaceFactory
*/
protected $taxCalculationFactory;
/**
* @param \Magento\Tax\Api\TaxCalculationInterfaceFactory $taxCalculationFactory
*/
public function __construct(
\Magento\Tax\Api\TaxCalculationInterfaceFactory $taxCalculationFactory
) {
$this->taxCalculationFactory = $taxCalculationFactory;
}
This way, the class is only instantiated in the one method where I needed it, and no longer in the constructor:
$taxCalculation = $this->taxCalculationFactory->create();
This solved the problem for me in this particular case.
And now the answer using a proxy:
If you don't want to trigger all the dependencies down the chain, you should use a proxy in your constructor. According to the original documentation:
... constructor injection also means that a chain reaction of object instantiation is often the result when you create an object.
and:
... Proxies extend other classes to become lazy-loaded versions of them. That is, a real instance of the class a proxy extends created only after one of the class’s methods is actually called.
So in my situation, with the TaxCalculationInterface
, all I had to do was instantiate my tax calculation as a proxy in my constructor:
/**
* @var \Magento\Tax\Api\TaxCalculationInterface\Proxy
*/
protected $taxCalculation;
/**
* @param \Magento\Tax\Api\TaxCalculationInterface\Proxy $taxCalculation
*/
public function __construct(
\Magento\Tax\Api\TaxCalculationInterface\Proxy $taxCalculation
) {
$this->taxCalculation = $taxCalculation;
}
This way, my class is lazy loaded. That is: it's only instantiated as soon as I call one of it's methods. For example:
$rate = $this->taxCalculation->getCalculatedRate($productRateId);