Magento 2:インタラクションの前後/前後のプラグイン


32

Magento 2で、「around」プラグインを作成するとき

public function aroundRenderResult(
    \Magento\Framework\Controller\ResultInterface $subject,
    \Closure $proceed,
    ResponseHttp $response
) {
    //...
    $proceed($response);
    //...      
}    

渡されたメソッドを呼び出し/呼び出すことで、実際の元のメソッドの呼び出しで終了するプラグインの周りの次のステップに進むことができます$proceed。これは、PHPフレームワークのミドルウェア実装でよく見られる一般的なデザインパターンです。

ただし、実装の詳細に多少の混乱があります。具体的には

場合は、に加えてaroundPlugin、オブジェクト/クラスが持っているbeforeafter、定義されたプラグインをするとき、彼らはプラグイン周りのチェーンに関連して火災のですか?

すなわち、すべてのbeforeメソッドは、Aroundプラグインメソッドが起動する前に起動しますか?または、プラグインが最終的な実際の実際メソッドが起動する前にのみ起動しますか?

私が突き止めようとしている特定の問題は、Magentoがフルページキャッシュモードのときに、Magento 2フロントコントローラーのディスパッチメソッドにプラグインを接続できないように見えることです。フルページキャッシュは、を呼び出さない aroundプラグインによって動作します$proceed($response)。私はこれらのプラグインを取り巻くコードのいくつかを掘り下げてみましたが、そのプラグインがどのように機能するかを知らずにシステムを推論することは困難であることがわかりました。

つまり、dev docsページの説明は、この1つの特定のインスタンスでは不正確であるように見えます。ドキュメントが間違っているのか、これが最近導入されたバグなのか、エッジケースなのか、プラグインの設定が間違っているのかは不明です。

この優先順位付けがどのように機能するのか、直接観察することにより、または文化的知識により、誰もが知っていますか?


アランは、あなたが使用する経験則なければならないの\closure $proceed\callable $proceed中Aプラグインを?公式ドキュメントはのみ言及\callableし、上に触れることはありません\closure
thdoan 16

回答:


38

プラグインは最初にソート順でソートされ、次にメソッドプレフィックスでソートされます。

例:次のメソッドとsortOrderを持つ3つのプラグイン(PluginA、PluginB、PluginC)を持つメソッドの場合:

  • PluginA(sortOrder = 10)
    • beforeDispatch()
    • afterDispatch()
  • PluginB(sortOrder = 20)
    • beforeDispatch()
    • aroundDispatch()
    • afterDispatch()
  • PluginC(sortOrder = 30):
    • beforeDispatch()
    • aroundDispatch()
    • afterDispatch()

実行フローは次のとおりです。

  • PluginA :: beforeDispatch()
  • PluginB :: beforeDispatch()
  • PluginB :: aroundDispatch()
    • PluginC :: beforeDispatch()
    • PluginC :: aroundDispatch()
      • Action :: dispatch()
    • PluginC :: afterDispatch()
  • PluginB :: afterDispatch()
  • PluginA :: afterDispatch()

16

Magento 2クックブックから:

同じ元の機能を拡張するプラグインが複数ある場合、それらは次の順序で実行されます。

  • 最低の前のプラグイン sortOrder
  • 最低のアラウンドプラグイン sortOrder
  • プラグインの前のその他(最低から最高までsortOrder
  • プラグインの周辺(最低から最高までsortOrder
  • 最高のアフタープラグイン sortOrder
  • プラグイン後のその他(最高のものから最低のものへsortOrder

1

私にとっては:

  • ソート順が定義されていない場合、ゼロに相当します(これは、実際の順序が未定義であることを意味します)
  • プラグインは順序でソートする必要があります

コードを\Magento\Framework\Interception\Interceptor::___callPlugins()確認すると、$pluginInfo変数に保存されている順にプラグインが呼び出されていることがわかります。この情報は、次のようなインターセプターで自動生成されたメソッドから渡されます

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

ご覧のとおり、プラグインのソートを担当する\Magento\Framework\Interception\PluginListInterfaceインターフェースと\Magento\Framework\Interception\PluginList\PluginListデフォルトの実装です。_inheritPlugins:152メソッドを参照してください

/**
 * Sort items
 *
 * @param array $itemA
 * @param array $itemB
 * @return int
 */
protected function _sort($itemA, $itemB)
{
    if (isset($itemA['sortOrder'])) {
        if (isset($itemB['sortOrder'])) {
            return $itemA['sortOrder'] - $itemB['sortOrder'];
        }
        return $itemA['sortOrder'];
    } elseif (isset($itemB['sortOrder'])) {
        return $itemB['sortOrder'];
    } else {
        return 1;
    }
} 

私にとって、この関数には2つの論理エラーがあります。

  • return $itemB['sortOrder'];する必要がありreturn - $itemB['sortOrder']ます;
  • return 1; あるべき return 0;

それがあなたを助けることを願っています。


しかし、$ pluginInfoはプラグインで完全にロードされていますか?または、動作に影響する可能性のある遅延読み込みが行われていますか?複数のプラグインのソート順はどういう意味ですか?すなわち、「プラグイン1の前、プラグイン1の周り、プラグイン1の前、プラグイン2の前、プラグイン2の周り、プラグイン2の後」または「プラグイン1の前」、「プラグイン2の前、プラグイン1の周り」などコードは後のように見えますが、「getNext」はプラグイン情報を(おそらく?)遅延ロード方法で生成し、Magentoが再帰を回避することでこれをすべて不明確にし、バグとは何か、機能とは何かを見つけにくくします。
アランストーム

プラグインメソッドではなく、Magentoのソートプラグインクラス。
カンディ

また、プラグインのリストは、たとえば新しいアリアをロードする場合など、変更できます。
カンディ

「プラグインメソッドではなくプラグインクラスをソートする」ことは、プラグインの相互作用のルールが何であるか、またはすべきであるかを明確にしないので、明らかではない暗黙の知識があります。
アランストーム

多分このリンクは役に立つでしょうmagehero.com/posts/472/magento-2-interception
KAndy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.