Magento 2: Plugin trước / xung quanh / sau khi tương tác


32

Trong Magento 2, khi bạn tạo một plugin "xung quanh"

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

bạn có thể tiến hành plugin tiếp theo xung quanh, kết thúc bằng cách gọi phương thức gốc thực tế, bằng cách gọi / gọi $proceedphương thức đã truyền trong phương thức. Đây là một mẫu thiết kế phổ biến, thường thấy trong các triển khai phần mềm trung gian của PHP Frameworks.

Tuy nhiên - nó hiện một số nhầm lẫn w / r / t với các chi tiết thực hiện. Đặc biệt

Nếu, ngoài một aroundPlugin, một đối tượng / lớp có một beforehoặc một afterplugin được xác định, khi nào chúng bắn liên quan đến chuỗi các plugin xung quanh?

tức là tất cả các phương thức trước sẽ kích hoạt trước khi bất kỳ phương thức plugin nào kích hoạt? Hoặc trước khi các plugin chỉ bắn trước khi phương thức thực sự cuối cùng thực hiện ?

Vấn đề cụ thể mà tôi đang cố gắng theo dõi là, dường như tôi không thể có một plugin được gắn vào phương thức điều phối bộ điều khiển phía trước Magento 2 khi Magento ở chế độ bộ đệm toàn trang . Bộ đệm toàn bộ trang hoạt động bởi một plugin xung quanh không gọi $proceed($response). Tôi đã thử đào sâu vào một số mã xung quanh các plugin này và nhận thấy hệ thống khó lý do mà không biết các plugin đó hoạt động như thế nào.

tức là - mô tả trên trang dev docs xuất hiện, trong trường hợp cụ thể này, là không chính xác. Không rõ liệu tài liệu này có sai hay không, nếu đây là một lỗi được giới thiệu gần đây, nếu đó là một trường hợp cạnh hoặc nếu cấu hình plugin của tôi sai.

Có ai biết, bằng cách quan sát trực tiếp, hoặc bằng kiến ​​thức văn hóa, làm thế nào ưu tiên này được cho là hoạt động?


Alan, bạn có một quy tắc khi sử dụng \closure $proceedso với \callable $proceedtrong một plugin không? Các tài liệu chính thức chỉ đề cập \callablevà không bao giờ chạm vào \closure.
thdoan

Câu trả lời:


38

Các plugin được sắp xếp theo thứ tự sắp xếp trước, và sau đó theo tiền tố phương thức.

Ví dụ: cho phương thức có 3 plugin (PluginA, PluginB, PluginC) với các phương thức và sortOrder sau:

  • PluginA (sortOrder = 10)
    • trướcDispatch ()
    • afterDispatch ()
  • PluginB (sortOrder = 20)
    • trướcDispatch ()
    • quanhDispatch ()
    • afterDispatch ()
  • PluginC (sortOrder = 30):
    • trướcDispatch ()
    • quanhDispatch ()
    • afterDispatch ()

Lưu lượng thực hiện phải như sau:

  • PluginA :: beforeDispatch ()
  • PluginB :: beforeDispatch ()
  • PluginB :: aroundDispatch ()
    • PluginC :: beforeDispatch ()
    • PluginC :: quanhDispatch ()
      • Hành động :: công văn ()
    • PluginC :: afterDispatch ()
  • PluginB :: afterDispatch ()
  • PluginA :: afterDispatch ()

16

Từ sách dạy nấu ăn Magento 2:

Nếu có nhiều plugin mở rộng cùng chức năng ban đầu, chúng sẽ được thực thi theo trình tự sau:

  • plugin trước với mức thấp nhất sortOrder
  • các plugin xung quanh với mức thấp nhất sortOrder
  • khác trước các plugin (từ thấp nhất đến cao nhất sortOrder)
  • khác xung quanh các plugin (từ thấp nhất đến cao nhất sortOrder)
  • plugin sau cao nhất sortOrder
  • khác sau các plugin (từ cao nhất đến thấp nhất sortOrder)

1

Đối với tôi nó nên hoạt động như:

  • nếu thứ tự sắp xếp không được xác định tương đương bằng 0 (và điều này có nghĩa là thứ tự thực không được xác định)
  • các plugin nên được sắp xếp theo thứ tự

Nếu bạn xem lại mã của \Magento\Framework\Interception\Interceptor::___callPlugins()bạn, bạn có thể thấy các plugin được gọi theo thứ tự được lưu trữ trong $pluginInfobiến. Thông tin này thông qua phương thức tự động tạo mẫu trong các bộ chặn như

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

Như bạn thấy \Magento\Framework\Interception\PluginListInterfacegiao diện và \Magento\Framework\Interception\PluginList\PluginListcài đặt mặc định chịu trách nhiệm sắp xếp plugin. Xem phương thức _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;
    }
} 

Đối với tôi chức năng này có hai lỗi logic:

  • return $itemB['sortOrder'];nên được return - $itemB['sortOrder'];
  • return 1; nên là return 0;

Hy vọng nó sẽ giúp bạn.


nhưng $ pluginInfo có được tải đầy đủ với các plugin không? Hoặc có một số tải lười biếng đang diễn ra có thể ảnh hưởng đến hành vi? Thứ tự sắp xếp có ý nghĩa gì đối với nhiều plugin? tức là "trước plugin 1, xung quanh plugin 1, sau plugin 1, trước plugin 2, xung quanh plugin 2, sau plugin 2" hoặc "trước plugin 1", "trước plugin 2, xung quanh plugin 1, xung quanh plugin 2", v.v. Mã trông giống như sau này, nhưng thông tin plugin phổ biến "getNext" theo cách tải lười biếng (có thể?), Và làm thế nào Magento tránh đệ quy xung quanh làm cho tất cả không rõ ràng và khó phát hiện ra lỗi là gì, tính năng là gì.
Alan Storm

Magento sắp xếp lớp plugin không phải phương thức plugin.
KAndy

Và danh sách các plugin có thể được thay đổi, ví dụ, nếu aria mới chúng tôi được tải.
KAndy

Có một số kiến ​​thức tiềm ẩn mà bạn có không rõ ràng, bởi vì "sắp xếp lớp plugin và không phải phương thức plugin" không làm rõ quy tắc tương tác của plugin là gì hoặc nên như thế nào.
Alan Storm

có thể liên kết này sẽ hữu ích magehero.com/posts/472/magento-2-interception
KAndy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.