2

Is there any chance to add a plugin to all public methods of a type without writing a separate method for all of them?

I would like to use that to log method calls. The original method is always called with unmodified parameters.

As it is intended for development/debugging, any dirty hack is appreciated.

  • 1
    if it's for a controller, you might use preDispatch, if it's something else, I don't think so, but I will look further. – Marius Aug 2 '16 at 8:05
1

I don't know if this works, but it's an idea.
The Interceptor class is generated containing all the original class public methods and all interceptor methods look like this:

public function doSomething(parameters list here)
{
    $pluginInfo = $this->pluginList->getNext($this->subjectType, 'doSomething');
    if (!$pluginInfo) {
        return parent::doSomething($object);
    } else {
        return $this->___callPlugins('doSomething', func_get_args(), $pluginInfo);
    }
}

where $this->subjectType is the name of the original class and $this->pluginList is an implementation of Magento\Framework\Interception\PluginListInterface (most probably Magento\Framework\Interception\PluginList\PluginList).
Now you can try something sneaky.
(Here is where my idea may fail.)
Since $this->pluginList->getNext() is a public method, it can be pluginized.
So create a (before or around) plugin for getNext and if the value of the first parameter of getNext (second parameter in your plugin) is your intended class name, then do your logging.

  • Interesting idea, but it failed indeed, looks like I am running into infinite recursion – Fabian Schmengler Aug 2 '16 at 14:27
  • aha...but something works. Maybe you can stop the recursion somehow. Or you can just ignore my answer and start from scratch. :) – Marius Aug 2 '16 at 14:36
  • That seemed too complicated. I started from scratch, but using getNext() was a good approach, thanks and upvote for that! – Fabian Schmengler Aug 2 '16 at 15:25
1

Here's a dirty hack I came up with: The generated interceptor classes contain all methods of the original class, if there are plugins or not. In every method, PluginList::getNext() is called to get the first plugin.

Unfortunately I cannot create a plugin for the plugin list itself because it will run into infinite recursion during initialization.

But with a one line edit in the generated interceptor file, I could replace the PluginList. This is added at the end of the constructor:

$this->pluginList = new PluginListDecorator($this->pluginList, $this->_logger);

Note: If you change generated files, be prepared to loose the changes any time! This is just a temporary addition!

And the decorator class looks as follows:

class PluginListDecorator implements PluginListInterface
{
    /**
     * @var PluginListInterface
     */
    private $pluginList;
    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(PluginListInterface $pluginList, LoggerInterface $logger)
    {
        $this->pluginList = $pluginList;
        $this->logger = $logger;
    }
    public function getNext($type, $method, $code = null)
    {
        $callee = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];
        if ($callee['class'] == Interceptor::class) {
            $this->logger->info('METHOD CALLED: ' . $method);
        }
        return $this->pluginList->getNext($type, $method, $code);
    }

    public function getPlugin($type, $code)
    {
        return $this->pluginList->getPlugin($type, $code);
    }
}

If getNext() is called from the interceptor itself, I do my logging, then pass the call along to the original PluginList.

  • 1
    ha. good catch. I can add something else, since this is temporary. The interceptor is generated only if it does not exist. So how about generating it once, then copy it from var/generation to your module, keeping the correct file path and doing your modifications there. this way you can safely delete var/generation when needed. – Marius Aug 2 '16 at 15:28

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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