Interceptor.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Interception;
  7. use Magento\Framework\App\ObjectManager;
  8. /**
  9. * Interceptor trait that contains the common logic for all interceptor classes.
  10. *
  11. * A trait is used because our interceptor classes need to extend the class that they are intercepting.
  12. *
  13. * Any class using this trait is required to implement \Magento\Framework\Interception\InterceptorInterface
  14. *
  15. * @see \Magento\Framework\Interception\InterceptorInterface
  16. */
  17. trait Interceptor
  18. {
  19. /**
  20. * List of plugins
  21. *
  22. * @var PluginListInterface
  23. */
  24. private $pluginList;
  25. /**
  26. * Subject type name
  27. *
  28. * @var string
  29. */
  30. private $subjectType;
  31. /**
  32. * Initialize the Interceptor
  33. *
  34. * @return void
  35. */
  36. public function ___init()
  37. {
  38. $this->pluginList = ObjectManager::getInstance()->get(PluginListInterface::class);
  39. $this->subjectType = get_parent_class($this);
  40. if (method_exists($this->subjectType, '___init')) {
  41. parent::___init();
  42. }
  43. }
  44. /**
  45. * Calls parent class method
  46. *
  47. * @param string $method
  48. * @param array $arguments
  49. * @return mixed
  50. */
  51. public function ___callParent($method, array $arguments)
  52. {
  53. return parent::$method(...array_values($arguments));
  54. }
  55. /**
  56. * Calls parent class sleep if defined, otherwise provides own implementation
  57. *
  58. * @return array
  59. */
  60. public function __sleep()
  61. {
  62. if (method_exists(get_parent_class($this), '__sleep')) {
  63. $properties = parent::__sleep();
  64. } else {
  65. $properties = array_keys(get_object_vars($this));
  66. }
  67. $properties = array_diff($properties, ['pluginList', 'subjectType']);
  68. return $properties;
  69. }
  70. /**
  71. * Causes Interceptor to be initialized
  72. *
  73. * @return void
  74. */
  75. public function __wakeup()
  76. {
  77. if (method_exists(get_parent_class($this), '__wakeup')) {
  78. parent::__wakeup();
  79. }
  80. $this->___init();
  81. }
  82. /**
  83. * Calls plugins for a given method.
  84. *
  85. * @param string $method
  86. * @param array $arguments
  87. * @param array $pluginInfo
  88. * @return mixed|null
  89. */
  90. protected function ___callPlugins($method, array $arguments, array $pluginInfo)
  91. {
  92. $subject = $this;
  93. $type = $this->subjectType;
  94. $pluginList = $this->pluginList;
  95. $next = function (...$arguments) use (
  96. $method,
  97. &$pluginInfo,
  98. $subject,
  99. $type,
  100. $pluginList,
  101. &$next
  102. ) {
  103. $capMethod = ucfirst($method);
  104. $currentPluginInfo = $pluginInfo;
  105. $result = null;
  106. if (isset($currentPluginInfo[DefinitionInterface::LISTENER_BEFORE])) {
  107. // Call 'before' listeners
  108. foreach ($currentPluginInfo[DefinitionInterface::LISTENER_BEFORE] as $code) {
  109. $pluginInstance = $pluginList->getPlugin($type, $code);
  110. $pluginMethod = 'before' . $capMethod;
  111. $beforeResult = $pluginInstance->$pluginMethod($this, ...array_values($arguments));
  112. if ($beforeResult !== null) {
  113. $arguments = (array)$beforeResult;
  114. }
  115. }
  116. }
  117. if (isset($currentPluginInfo[DefinitionInterface::LISTENER_AROUND])) {
  118. // Call 'around' listener
  119. $code = $currentPluginInfo[DefinitionInterface::LISTENER_AROUND];
  120. $pluginInfo = $pluginList->getNext($type, $method, $code);
  121. $pluginInstance = $pluginList->getPlugin($type, $code);
  122. $pluginMethod = 'around' . $capMethod;
  123. $result = $pluginInstance->$pluginMethod($subject, $next, ...array_values($arguments));
  124. } else {
  125. // Call original method
  126. $result = $subject->___callParent($method, $arguments);
  127. }
  128. if (isset($currentPluginInfo[DefinitionInterface::LISTENER_AFTER])) {
  129. // Call 'after' listeners
  130. foreach ($currentPluginInfo[DefinitionInterface::LISTENER_AFTER] as $code) {
  131. $pluginInstance = $pluginList->getPlugin($type, $code);
  132. $pluginMethod = 'after' . $capMethod;
  133. $result = $pluginInstance->$pluginMethod($subject, $result, ...array_values($arguments));
  134. }
  135. }
  136. return $result;
  137. };
  138. $result = $next(...array_values($arguments));
  139. $next = null;
  140. return $result;
  141. }
  142. }