1

We are reading the Magento configurable configuration inside an API call:

   private function getSpConfig($product)
    {
        if ($product->getTypeId() != 'configurable') {
            return null;
        }

        /**
         * @var ConfigurableBlock
         */
        $configurableBlock = $this->_layoutInterface->createBlock(ConfigurableBlock::class);
        $configurableBlock->setData('product', $product);
        $spConfig = json_decode($configurableBlock->getJsonConfig(), true);

        usort($spConfig['attributes'], function ($a, $b) {
            return $a['position'] <=> $b['position'];
        });

        return $spConfig;
    }

It turns out that the sku field is missing, which is set in Magento\InventoryConfigurableProductFrontendUi\Plugin\ConfigurableProduct\Block\Product\View\Type\AddAdditionalInfo::afterGetJsonConfig

It is defined in the frontend's di.xml

The call is wrapped into emulation:

        $storeId = $this->_storeManager->getStore()->getId();
        $this->_appEmulation->startEnvironmentEmulation($storeId, \Magento\Framework\App\Area::AREA_FRONTEND, true);

        $this->state->emulateAreaCode(\Magento\Framework\App\Area::AREA_FRONTEND, function() use ($productCollection, $customerId, $field, &$response) {
   
//              ... getSpConfig ...

        });

        $this->_appEmulation->stopEnvironmentEmulation();

Should this work or does the app emulation not cover DI ?

1 Answer 1

2

You are correct, area emulation just sets the area, while the compiled config for DI is still loaded from the GLOBAL area. If you want to fully leverage di.xml declarations from a different area, you need to use the \Magento\Framework\ObjectManager\ObjectManager::configure method and then use the Object Manager to get the needed classes. For the configure method you will first need to obtain the compiled config for the desired area, using \Magento\Framework\App\ObjectManager\ConfigLoader\Compiled::load. Something like this:

$compiledConfigForFrontendArea = $this->compiledConfigLoader->load(\Magento\Framework\App\Area::AREA_FRONTEND);

$this->state->emulateAreaCode(\Magento\Framework\App\Area::AREA_FRONTEND, function () use ($compiledConfigForFrontendArea) {
     //re-configure object manager with frontend area di compiled config
     ObjectManager::getInstance()->configure($compiledConfigForFrontendArea);

     //use the new context to get the class, otherwise di from global area is used and it breaks
     $desiredObject = ObjectManager::getInstance()->get(DesiredObject::class);
});

For my specific use-case (CLI command that needed to run in the GRAPHQL area), I had to use the configure method inside the emulateAreaCode callback. It might work outside of that for your case. Also, for frontend area the system might attempt to set a theme, keep that in mind.

Hope this helps

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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