<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Der Magento Experte</title>
	<atom:link href="https://www.der-mage-experte.de/tag/plugin/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.der-mage-experte.de</link>
	<description>Ihr Magento Experte &#38; Entwickler</description>
	<lastBuildDate>Fri, 09 Oct 2026 21:26:19 +0000</lastBuildDate>
	<language>de-DE</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8.6</generator>
	<item>
		<title>Plugin Chain einer Methode per CLI anzeigen</title>
		<link>https://www.der-mage-experte.de/3175/magento2-plugin-chain-einer-methode-per-cli-anzeigen/</link>
		<comments>https://www.der-mage-experte.de/3175/magento2-plugin-chain-einer-methode-per-cli-anzeigen/#comments</comments>
		<pubDate>Fri, 09 Oct 2026 21:02:54 +0000</pubDate>
		<dc:creator><![CDATA[Mex]]></dc:creator>
				<category><![CDATA[Magento Lösungen]]></category>
		<category><![CDATA[Magento 2]]></category>
		<category><![CDATA[Plugin]]></category>

		<guid isPermaLink="false">https://www.der-mage-experte.de/?p=3175</guid>
		<description><![CDATA[Magento bringt mit dev:di:info bereits einen hilfreichen Befehl für Dependency Injection mit. Eine komplette Plugin Kette für eine bestimmte Methode lässt sich damit allerdings nicht anzeigen. Mit einem kleinen eigenen CLI Command kann man sich genau diese Information direkt aus&#8230;]]></description>
				<content:encoded><![CDATA[<p>Magento bringt mit <strong>dev:di:info</strong> bereits einen hilfreichen Befehl für Dependency Injection mit. Eine komplette Plugin Kette für eine bestimmte Methode lässt sich damit allerdings nicht anzeigen. Mit einem kleinen eigenen CLI Command kann man sich genau diese Information direkt aus Magentos Interception Konfiguration holen.</p>
<p>Der folgende Befehl ist also <strong>kein Magento Standardbefehl</strong>, sondern wird durch das nachfolgende Beispiel implementiert:</p><pre class="crayon-plain-tag">bin/magento dev:plugin-chain \
'Magento\Catalog\Api\ProductRepositoryInterface' \
save</pre><p>Der Command wird zunächst in der <strong>etc/di.xml</strong> des eigenen Moduls registriert:</p><pre class="crayon-plain-tag">&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;config xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
        xsi:noNamespaceSchemaLocation=&quot;urn:magento:framework:ObjectManager/etc/config.xsd&quot;&gt;

    &lt;type name=&quot;Magento\Framework\Console\CommandListInterface&quot;&gt;
        &lt;arguments&gt;
            &lt;argument name=&quot;commands&quot; xsi:type=&quot;array&quot;&gt;
                &lt;item name=&quot;plugin_chain&quot; xsi:type=&quot;object&quot;&gt;
                    Vendor\Module\Console\Command\PluginChain
                &lt;/item&gt;
            &lt;/argument&gt;
        &lt;/arguments&gt;
    &lt;/type&gt;

&lt;/config&gt;</pre><p>Die eigentliche Command Klasse greift anschließend direkt auf Magentos <strong>PluginListInterface</strong> zu:</p><pre class="crayon-plain-tag">&lt;?php

declare(strict_types=1);

namespace Vendor\Module\Console\Command;

use Magento\Framework\Config\ScopeInterface;
use Magento\Framework\Interception\DefinitionInterface;
use Magento\Framework\Interception\PluginListInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class PluginChain extends Command
{
    private const ARG_TYPE = 'type';
    private const ARG_METHOD = 'method';
    private const OPT_AREA = 'area';

    public function __construct(
        private readonly PluginListInterface $pluginList,
        private readonly ScopeInterface $configScope
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this-&gt;setName('dev:plugin-chain')
            -&gt;setDescription('Shows the effective Magento plugin chain')
            -&gt;addArgument(
                self::ARG_TYPE,
                InputArgument::REQUIRED,
                'Class or interface'
            )
            -&gt;addArgument(
                self::ARG_METHOD,
                InputArgument::REQUIRED,
                'Method name'
            )
            -&gt;addOption(
                self::OPT_AREA,
                null,
                InputOption::VALUE_REQUIRED,
                'Magento area',
                'frontend'
            );

        parent::configure();
    }

    protected function execute(
        InputInterface $input,
        OutputInterface $output
    ): int {
        $type = ltrim(
            (string) $input-&gt;getArgument(self::ARG_TYPE),
            '\\'
        );

        $method = (string) $input-&gt;getArgument(self::ARG_METHOD);
        $area = (string) $input-&gt;getOption(self::OPT_AREA);

        $this-&gt;configScope-&gt;setCurrentScope($area);

        $pluginInfo = $this-&gt;pluginList-&gt;getNext(
            $type,
            $method
        );

        if (!$pluginInfo) {
            $output-&gt;writeln('&lt;comment&gt;No plugins found.&lt;/comment&gt;');

            return Command::SUCCESS;
        }

        $output-&gt;writeln(
            sprintf(
                '&lt;info&gt;%s::%s() [%s]&lt;/info&gt;',
                $type,
                $method,
                $area
            )
        );

        $this-&gt;renderChain(
            $output,
            $type,
            $method,
            $pluginInfo
        );

        return Command::SUCCESS;
    }

    private function renderChain(
        OutputInterface $output,
        string $type,
        string $method,
        array $pluginInfo,
        int $level = 0
    ): void {
        $indent = str_repeat('  ', $level);

        foreach (
            $pluginInfo[DefinitionInterface::LISTENER_BEFORE] ?? []
            as $code
        ) {
            $this-&gt;writePlugin(
                $output,
                $type,
                $code,
                'BEFORE',
                $indent
            );
        }

        $around = $pluginInfo[
            DefinitionInterface::LISTENER_AROUND
        ] ?? null;

        if ($around) {
            $this-&gt;writePlugin(
                $output,
                $type,
                $around,
                'AROUND',
                $indent
            );

            $next = $this-&gt;pluginList-&gt;getNext(
                $type,
                $method,
                $around
            );

            if ($next) {
                $this-&gt;renderChain(
                    $output,
                    $type,
                    $method,
                    $next,
                    $level + 1
                );
            }
        }

        foreach (
            $pluginInfo[DefinitionInterface::LISTENER_AFTER] ?? []
            as $code
        ) {
            $this-&gt;writePlugin(
                $output,
                $type,
                $code,
                'AFTER',
                $indent
            );
        }
    }

    private function writePlugin(
        OutputInterface $output,
        string $type,
        string $code,
        string $position,
        string $indent
    ): void {
        $plugin = $this-&gt;pluginList-&gt;getPlugin(
            $type,
            $code
        );

        $output-&gt;writeln(
            sprintf(
                '%s%-6s %s =&gt; %s',
                $indent,
                $position,
                $code,
                get_class($plugin)
            )
        );
    }
}</pre><p>Nach Einbau des Commands lässt sich beispielsweise die Plugin Kette für <strong>ProductRepositoryInterface::save()</strong> ausgeben:</p><pre class="crayon-plain-tag">bin/magento dev:plugin-chain \
'Magento\Catalog\Api\ProductRepositoryInterface' \
save</pre><p>Auch der Magento Admin Bereich kann berücksichtigt werden:</p><pre class="crayon-plain-tag">bin/magento dev:plugin-chain \
'Magento\Catalog\Api\ProductRepositoryInterface' \
save \
--area=adminhtml</pre><p>Interessant wird die Ausgabe vor allem bei mehreren Extensions, die dieselbe Methode verändern. Besonders <strong>around Plugins</strong> können die Ausführung beeinflussen, da ein Plugin durch den Aufruf oder eben Nichtaufruf des nächsten Callables bestimmt, ob die weitere Plugin Kette und die eigentliche Methode noch erreicht werden.</p>
<p>Damit lässt sich ziemlich genau nachvollziehen, <strong>welche Plugins Magento für eine bestimmte Methode tatsächlich hintereinander ausführt</strong>.</p>]]></content:encoded>
			<wfw:commentRss>https://www.der-mage-experte.de/3175/magento2-plugin-chain-einer-methode-per-cli-anzeigen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
