Skip to content

An AD0-E702 certification exercise module: see the execution order of plugins via a custom log.

License

Notifications You must be signed in to change notification settings

denal05/Ad0e702ExerciseSeePluginExecOrderViaLog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ad0e702ExerciseSeePluginExecOrderViaLog

An AD0-E702 certification exercise module: see the execution order of plugins via the debug log.

Usage:

> bin/magento ad0e702:trigger:plugins
The demo plugins have been triggerred successfully. 
Please inspect var/log/Denal05_Ad0e702ExerciseSeePluginExecOrderViaLog/debug.log

Mark Shust has written an excellent article on this topic:
The Unexpected Behavior of Magento Plugin Execution Order

According to the devdocs there are three scenarios:
https://developer.adobe.com/commerce/php/development/components/plugins/#examples


SCENARIO A

Plugin A Plugin B Plugin C
sortOrder 10 20 30
before beforeExecute() beforeExecute() beforeExecute()
around
after afterExecute() afterExecute() afterExecute()

The following equivalent results are expected for Scenario A:

Plugin A (sort order 10): beforeExecute()
Plugin B (sort order 20): beforeExecute()
Plugin C (sort order 30): beforeExecute()
::execute()
Plugin A (sort order 10): afterExecute()
Plugin B (sort order 20): afterExecute()
Plugin C (sort order 30): afterExecute()

The following is a relevant excerpt from var/log/Denal05_Ad0e702ExerciseSeePluginExecOrderViaLog/debug.log

[2025-02-15T20:16:09.013425+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginASortOrder10::beforeExecute [] []
[2025-02-15T20:16:09.013787+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginBSortOrder20::beforeExecute [] []
[2025-02-15T20:16:09.013985+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginCSortOrder30::beforeExecute [] []
[2025-02-15T20:16:09.014372+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginASortOrder10::afterExecute [] []
[2025-02-15T20:16:09.014638+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginBSortOrder20::afterExecute [] []
[2025-02-15T20:16:09.014795+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginCSortOrder30::afterExecute [] []

SCENARIO B (with a callable around)

Plugin A Plugin D Plugin C
sortOrder 10 20 30
before beforeExecute() beforeExecute() beforeExecute()
around aroundExecute()
after afterExecute() afterExecute() afterExecute()

The following equivalent results are expected for Scenario B:

Plugin A (sort order 10): beforeExecute()
Plugin D (sort order 20): beforeExecute()
Plugin D (sort order 20): aroundExecute() - 1st half before callable
  Plugin C (sort order 30): beforeExecute()
    ::execute()
  Plugin C (sort order 30): afterExecute()
Plugin D (sort order 20): aroundExecute() - 2nd half after callable
Plugin A (sort order 10): afterExecute()
Plugin D (sort order 20): afterExecute()

The following is a relevant excerpt from var/log/Denal05_Ad0e702ExerciseSeePluginExecOrderViaLog/debug.log

[2025-02-15T20:47:33.881321+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginASortOrder10::beforeExecute [] []
[2025-02-15T20:47:33.881672+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginDSortOrder20AroundWithCallable::beforeExecute [] []
[2025-02-15T20:47:33.881807+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginDSortOrder20AroundWithCallable::aroundExecute first half [] []
[2025-02-15T20:47:33.881982+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginCSortOrder30::beforeExecute [] []
[2025-02-15T20:47:33.882340+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginCSortOrder30::afterExecute [] []
[2025-02-15T20:47:33.882571+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginDSortOrder20AroundWithCallable::aroundExecute second half [] []
[2025-02-15T20:47:33.882766+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginASortOrder10::afterExecute [] []
[2025-02-15T20:47:33.882981+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginDSortOrder20AroundWithCallable::afterExecute [] []

SCENARIO B (without a callable around)

Plugin A Plugin E Plugin C
sortOrder 10 20 30
before beforeExecute() beforeExecute() beforeExecute()
around aroundExecute() - no callable
after afterExecute() afterExecute() afterExecute()

At the present I'm getting an error that I'm passing it something unexpected:

There is an error in /var/www/ad0-e702/generated/code/Denal05/Ad0e702ExerciseSeePluginExecOrderViaLog/Console/Command/TriggerPluginsCommand/Interceptor.php at line: 23 Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Console\Command\TriggerPluginsCommand\Interceptor::execute(): Return value must be of type int, Symfony\Component\Console\Input\ArgvInput returned#0 /var/www/ad0-e702/vendor/symfony/console/Command/Command.php(326): Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Console\Command\TriggerPluginsCommand\Interceptor->execute()


SCENARIO C

Plugin F Plugin B Plugin G
sortOrder 10 20 30
before beforeExecute() beforeExecute() beforeExecute()
around aroundExecute() aroundExecute()
after afterExecute() afterExecute() afterExecute()

The following equivalent results are expected for Scenario C:

Plugin F (sort order 10): beforeExecute()
Plugin F (sort order 10): aroundExecute() - 1st half before callable
  Plugin B (sort order 20): beforeExecute()
  Plugin G (sort order 30): beforeExecute()
  Plugin G (sort order 30): aroundExecute() - 1st half before callable
    ::execute()
  Plugin G (sort order 30): aroundExecute() - 2nd half after callable
  Plugin B (sort order 20): afterExecute()
  Plugin G (sort order 30): afterExecute()
Plugin F (sort order 10): aroundExecute() - 2nd half after callable
Plugin F (sort order 10): afterExecute()

The following is a relevant excerpt from var/log/Denal05_Ad0e702ExerciseSeePluginExecOrderViaLog/debug.log

[2025-02-17T10:47:01.941232+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginFSortOrder10AroundWithCallable::beforeExecute [] []
[2025-02-17T10:47:01.941499+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginFSortOrder10AroundWithCallable::aroundExecute first half [] []
[2025-02-17T10:47:01.941658+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginBSortOrder20::beforeExecute [] []
[2025-02-17T10:47:01.941815+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginGSortOrder30AroundWithCallable::beforeExecute [] []
[2025-02-17T10:47:01.941918+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginGSortOrder30AroundWithCallable::aroundExecute first half [] []
[2025-02-17T10:47:01.947531+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginGSortOrder30AroundWithCallable::aroundExecute second half [] []
[2025-02-17T10:47:01.947806+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginBSortOrder20::afterExecute [] []
[2025-02-17T10:47:01.947975+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginGSortOrder30AroundWithCallable::afterExecute [] []
[2025-02-17T10:47:01.948133+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginFSortOrder10AroundWithCallable::aroundExecute second half [] []
[2025-02-17T10:47:01.948290+00:00] main.DEBUG: Denal05\Ad0e702ExerciseSeePluginExecOrderViaLog\Plugin\PluginFSortOrder10AroundWithCallable::afterExecute [] []

Now, why is that? What governs this weird plugin execution order?
After some careful observation, it seems that three rules emerge, in the following order of importance:

  1. The lower the sort order, the higher the priority.
  2. The "before" methods come first, then the "around", and finally the "after" methods
  3. The "around" methods encapsulate the rest of the plugins

This explains all three scenarios. Let's take a look at scenarios A and B with callable:

Scenario A

Plugin A (sort order 10): beforeExecute()
Plugin B (sort order 20): beforeExecute()
Plugin C (sort order 30): beforeExecute()
::execute()
Plugin A (sort order 10): afterExecute()
Plugin B (sort order 20): afterExecute()
Plugin C (sort order 30): afterExecute()
  • Since the most important rule is that the plugin with the lowest sort order number has the highest priority, Plugin A executes first.
  • Furthermore, since "before" comes, well, before the "after", the "before" method of Plugin A executes first.
  • The rest is history.

Scenario B

Plugin A (sort order 10): beforeExecute()
Plugin D (sort order 20): beforeExecute()
Plugin D (sort order 20): aroundExecute() - 1st half before callable
  Plugin C (sort order 30): beforeExecute()
    ::execute()
  Plugin C (sort order 30): afterExecute()
Plugin D (sort order 20): aroundExecute() - 2nd half after callable
Plugin A (sort order 10): afterExecute()
Plugin D (sort order 20): afterExecute()
  • Plugin A has the lowest sort order number, i.e., the highest priority, so it executes first. Furthermore, the "before" method of Plugin A executes first.
  • The next priority is Plugin D's "before" method.
  • Next comes the first half of Plugin D's "around" method, which encapsulates the rest of the plugins (in this case only Plugin C).
  • Then Plugin C's "before" method executes, and afterwards its "after" method.
  • Now the plugin stack starts to pop: Plugin C is done, and the second half of Plugin D's "around" method finishes.
  • Lastly, the "after" methods execute, but according to priority, Plugin A's "after" method comes before Plugin D's "after" method.

About

An AD0-E702 certification exercise module: see the execution order of plugins via a custom log.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages