0

I've written a console for invoicing frontend orders

https://github.com/DominicWatts/AutoInvoice/blob/master/Console/Command/Invoice.php

If I put Magento\Sales\Model\Service\InvoiceService in the constructor and run setup:di:compile magento console throws an 'Area Code Not Set' error.

You can't set area code as part of the constructor because when you run this and other console commands you see 'Area Code Already Set' error.

I understand state and why setting the 'area' is necessary.

My workaround is to do the following

use Magento\Sales\Model\Service\InvoiceService; 

protected function execute(InputInterface $input, OutputInterface $output)
{
    $this->state->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL);
    $this->method();
}
public function method()
{
    $this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    $this->invoiceService = $this->_objectManager->create(InvoiceService::class);
    // do stuff
}

So basically using object manager at runtime instead of injecting. I'm constantly reading that using the object manager is bad. Therefore I feel like I'm not understanding a key concept.

So my questions are this:

a) Is this the right way to work around the issue?

b) If it's not - what is the correct approach?

c) Does using object manager add resource overhead? Or is it more that it will be deprecated at some stage.

1

It seems that when the class Magento\Sales\Model\Service\InvoiceService is injected, it calls some functions that cause the error. Since it doesn't happen when you use the ObjectManager directly, I suggest that you will try to inject Magento\Sales\Model\Service\InvoiceService\Proxy in the constructor. This will cause that the code will only call the functions that you use and won't call the functions that cause the error.

Read more about proxies here: https://devdocs.magento.com/guides/v2.3/extension-dev-guide/proxies.html

Regarding to your questions:

a+c) Using the object manager directly is bad for unit testing, because if you write unit tests, this code will make it impossible to inject mocks into the constructor. I don't know about any other reasons not to use the object manager directly.

b) The correct approach is to use the dependency injection - so proxy solution is the right approach (if it helps to resolve the error).

  • You have opened my eyes to proxies. I'm looking forward to trying this out. See it if works. I like the idea of lazy loading among other things to avoid dependency loop. One thing though. devdocs.magento.com/guides/v2.3/coding-standards/… says 2.5. Proxies and interceptors MUST NEVER be explicitly requested in constructors. Which has kinda blew my mind. I would have thought that's the only way to use them efficiently. – Dominic Xigen Jun 1 '19 at 23:24
  • Yep works - or at least in the context I'm using it – Dominic Xigen Jun 4 '19 at 12:00
  • Yes, you are right, but they suggest that you can inject the proxy using a di.xml file - github.com/magento/magento-coding-standard/issues/18 – tmcgrath92 Jun 10 '19 at 14:53
  • So I guess something like this will work - <type name="MyController"> <arguments> <argument name="invoiceService" xsi:type="object">Magento\Sales\Model\Service\InvoiceService\Proxy</argument> </arguments> </type> – tmcgrath92 Jun 10 '19 at 14:55
  • I think I follow what you are saying but I will happily award points if you put together an answer – Dominic Xigen Jun 11 '19 at 11:25
0

Just to clarify accepted answer the solution was indeed

public function __construct(
    \Magento\Sales\Model\Service\InvoiceService\Proxy $invoiceService
) {
    $this->invoiceService = $invoiceService;
    parent::__construct();
}

Update

However this https://devdocs.magento.com/guides/v2.3/coding-standards/technical-guidelines.html states

  • 2.5. Proxies and interceptors MUST NEVER be explicitly requested in constructors.

And sure enough I was messing around with https://github.com/magento/magento-coding-standard Magento Coding Standard rules for PHP_CodeSniffer.

Sure enough:

FOUND 1 ERROR AND 3 WARNINGS AFFECTING 4 LINES
--------------------------------------------------------------------------------
  63 | ERROR   | Proxies and interceptors MUST never be explicitly requested in
     |         | constructors.

So maybe my initial approach was correct.

  • how did you resolve this error Proxies and interceptors MUST NEVER be explicitly requested in constructors ? – Mohit Rane Jul 24 '19 at 7:02
  • @MohitRane in my opinion my original workaround is the best solution – Dominic Xigen Jul 24 '19 at 14:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.