Skip to content

Plugins/Interceptors Don't Work with Early Stage Single Instance Objects in Developer Mode #2674

Closed
@astorm

Description

@astorm

If I enable developer mode by adding the following to my .htacess file

SetEnv MAGE_MODE developer

and then add a plugin configuration

#File: app/code/Pulsestorm/Testbed/etc/di.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <type name="Magento\Framework\Logger\Monolog">
        <plugin name="namespace_vendor_magento_framework_logger_monolog" type="Pulsestorm\Testbed\Plugin\MagentoFrameworkLoggerMonolog" />
    </type>
</config>

Magento doesn't seem to see the plugin until I do a full compile

php bin/magento setup:di:compile

Expected Behavior: When Magento developer mode is enabled, all plugins are active immediately. From an end-client-programmer-user perspective the plugin system should behave the same in all Magento modes (developer, production, default, etc.) irrespective of the implementation details

Actual Behavior: Magento doesn't recognize certain plugins until the setup:di:compile command is run

Notes

I believe this problem is limited to what I'd call early stage single-instance-object instantiation. If the object manager creates an instance/singleton object (i.e. via get) before the framework loads the di configuration, that instance/singleton is cached in the object manager. Since the object manager, by definition, caches instance/singleton objects, this means these early stage objects never have a chance to be intercepted in developer mode.

That is, in

#File: vendor/magento/framework/Interception/ObjectManager/Config/Developer.php
public function getInstanceType($instanceName)
{
    $type = parent::getInstanceType($instanceName);
    if ($this->interceptionConfig && $this->interceptionConfig->hasPlugins($instanceName)) {
        return $type . '\\Interceptor';
    }
    return $type;
}

The $this->interceptionConfig is false for a time. In a quick test on the 2.0 system, that means the following classes are "un-intercept-able" by the developer mode object manager (without a compile)

Magento\Framework\App\ObjectManager\ConfigLoader
Magento\Framework\App\Cache\Type\Config
Magento\Framework\App\Cache\Type\FrontendPool
Magento\Framework\App\Cache\Frontend\Pool
Magento\Framework\App\Cache\Frontend\Factory
Magento\Framework\Filesystem
Magento\Framework\Filesystem\Directory\ReadFactory
Magento\Framework\Filesystem\Directory\WriteFactory
Magento\Framework\App\ResourceConnection\Proxy
Magento\Framework\ObjectManager\Config\Reader\DomFactory
Magento\Framework\App\ObjectManager\ConfigCache
Magento\Framework\Cache\Frontend\Adapter\Zend
Magento\Framework\Cache\Frontend\Decorator\TagScope
Magento\Framework\Cache\Frontend\Decorator\Logger
Magento\Framework\Cache\InvalidateLogger
Magento\Framework\App\Request\Http
Magento\Framework\Stdlib\Cookie\PhpCookieReader
Magento\Framework\Stdlib\StringUtils
Magento\Framework\App\Route\ConfigInterface\Proxy
Magento\Backend\App\Request\PathInfoProcessor\Proxy
Magento\Framework\Logger\Monolog
Magento\Framework\Logger\Handler\System
Magento\Framework\Filesystem\Driver\File
Magento\Framework\Logger\Handler\Exception
Magento\Framework\Logger\Handler\Debug
Magento\Framework\Cache\Frontend\Adapter\Zend
Magento\Framework\Cache\Frontend\Decorator\TagScope
Magento\Framework\Cache\Frontend\Decorator\Logger
Magento\Framework\App\Cache\Type\AccessProxy
Magento\Framework\App\Cache\State
Magento\Framework\App\DeploymentConfig\Writer
Magento\Framework\App\DeploymentConfig\Reader
Magento\Framework\Config\File\ConfigFilePool
Magento\Framework\Config\Scope
Magento\Framework\App\AreaList\Proxy
Magento\Framework\Interception\Config\Config
Magento\Framework\ObjectManager\Config\Reader\Dom\Proxy
Magento\Framework\Config\Scope

Not sure what the right fix here is. My naive approach to something like this would be to

  1. Limit the pre di configuration loading use of the object manager
  2. Formally introduce the concept of stages into the object manager (pre-di.xml, pre area-di.xml, etc.)
  3. Add tooling that warns developers if they're trying to plugin to one of these classes.

That said, as a third-part I wouldn't presume to come up with a solution myself as this is the sort of thing that will have impact system wide across multiple teams.

Right now if developers are trying to plugin to one of the above classes while working in developer mode they're going to spin their wheels for a bit before realize them need to run setup:di:compile even though developer mode is supposed, and sometimes does, make that unnecessary. That's the problem I'd be interested in seeing solved.

Metadata

Metadata

Assignees

Labels

Issue: Ready for WorkGate 4. Acknowledged. Issue is added to backlog and ready for developmentbug report

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions