HookIntegrator.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. namespace ModulesGarden\Servers\ZimbraEmail\Core\Hook;
  3. use function ModulesGarden\Servers\ZimbraEmail\Core\Helper\isAdmin;
  4. use function ModulesGarden\Servers\ZimbraEmail\Core\Helper\di;
  5. use ModulesGarden\Servers\ZimbraEmail\Core\ModuleConstants;
  6. use ModulesGarden\Servers\ZimbraEmail\Core\DependencyInjection;
  7. use ModulesGarden\Servers\ZimbraEmail\Core\UI\Traits\RequestObjectHandler;
  8. use \ModulesGarden\Servers\ZimbraEmail\Core\Traits\AppParams;
  9. /**
  10. * class HookIntegrator
  11. * Prepares a views basing on /App/Integrations/Admin/ & /App/Integrations/Client controlers
  12. * to be injected on WHMCS subpages
  13. */
  14. class HookIntegrator
  15. {
  16. use RequestObjectHandler;
  17. use AppParams;
  18. /**
  19. * @var null
  20. * an array of WHMCS hook params, in which the Integrator was used
  21. */
  22. protected $hookParams = null;
  23. /**
  24. * @var bool
  25. * determines if works on admin or client area side
  26. */
  27. protected $isAdmin = false;
  28. /** @var array
  29. * avalible hook integrations list
  30. */
  31. protected $integrations = [];
  32. /** @var null|string
  33. * HTML data to be returned as a result of the integration process
  34. */
  35. protected $integrationData = [];
  36. public function __construct($hookParams)
  37. {
  38. $this->setHookParams($hookParams);
  39. $this->checkIsAdmin();
  40. $this->integrate();
  41. }
  42. public function setHookParams($hookParams)
  43. {
  44. if (is_array($hookParams))
  45. {
  46. $this->hookParams = $hookParams;
  47. }
  48. return $this;
  49. }
  50. /**
  51. * determines if works on admin or client area side
  52. */
  53. public function checkIsAdmin()
  54. {
  55. $this->isAdmin = isAdmin();
  56. }
  57. /**
  58. * returns integration output
  59. */
  60. public function getHtmlCode()
  61. {
  62. return $this->getWrapperHtml();
  63. }
  64. /**
  65. * starts whole integration process
  66. */
  67. protected function integrate()
  68. {
  69. $this->loadAvailableIntegrations();
  70. $this->loadIntegrationData();
  71. }
  72. /**
  73. * loads available integration instances for current page
  74. */
  75. protected function loadAvailableIntegrations()
  76. {
  77. $hooksPath = ModuleConstants::getModuleRootDir() . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'Integrations'
  78. . DIRECTORY_SEPARATOR . ($this->isAdmin ? 'Admin' : 'Client');
  79. if (!file_exists($hooksPath) || !is_readable($hooksPath))
  80. {
  81. return false;
  82. }
  83. $files = scandir($hooksPath, 1);
  84. if ($files)
  85. {
  86. foreach ($files as $key => $value)
  87. {
  88. if ($value === "." || $value === ".." || !(stripos($value, '.php') > 0))
  89. {
  90. unset($files[$key]);
  91. continue;
  92. }
  93. $this->addIntegration(str_replace('.php', '', $value));
  94. }
  95. }
  96. }
  97. /**
  98. * adds integration instance to the integrations list for current page
  99. * @param null|string $className
  100. * @return bool
  101. */
  102. protected function addIntegration($className = null)
  103. {
  104. //check if integration class exists
  105. $integrationClassName = '\ModulesGarden\Servers\ZimbraEmail\App\Integrations\\' . ($this->isAdmin ? 'Admin' : 'Client') . '\\' . $className;
  106. if (!class_exists($integrationClassName) || !is_subclass_of($integrationClassName, \ModulesGarden\Servers\ZimbraEmail\Core\Hook\AbstractHookIntegrationController::class))
  107. {
  108. return false;
  109. }
  110. //creates an instance of integration class
  111. $integrationInstance = DependencyInjection::create($integrationClassName);
  112. //check if integration should be added to current page
  113. if (!$this->validateIntegrationInstance($integrationInstance))
  114. {
  115. return false;
  116. }
  117. $this->integrations[] = $integrationInstance;
  118. }
  119. /**
  120. * check if the integration should be added to current page
  121. * @param null|AbstractHookIntegrationController $instance
  122. * @return bool
  123. */
  124. public function validateIntegrationInstance($instance = null)
  125. {
  126. if (!is_subclass_of($instance, \ModulesGarden\Servers\ZimbraEmail\Core\Hook\AbstractHookIntegrationController::class))
  127. {
  128. return false;
  129. }
  130. if (
  131. $instance->getJqSelector() === null ||
  132. !is_callable($instance->getControllerCallback())
  133. )
  134. {
  135. return false;
  136. }
  137. return true;
  138. }
  139. public function loadIntegrationData()
  140. {
  141. foreach ($this->integrations as $integration)
  142. {
  143. if (!$this->isIntegrationApplicable($integration))
  144. {
  145. continue;
  146. }
  147. $callbackData = $integration->getControllerCallback();
  148. $this->setAppParam('IntegrationControlerName', $callbackData[0]);
  149. $this->setAppParam('IntegrationControlerMethod', $callbackData[1]);
  150. /** @var
  151. * $integrationResult \ModulesGarden\Servers\ZimbraEmail\Core\UI\View
  152. */
  153. $integrationResult = call_user_func([di($callbackData[0]), $callbackData[1]]);
  154. if (!($integrationResult instanceof \ModulesGarden\Servers\ZimbraEmail\Core\UI\View))
  155. {
  156. $this->setAppParam('IntegrationControlerName', null);
  157. $this->setAppParam('IntegrationControlerMethod', null);
  158. continue;
  159. }
  160. $integrationResult->setIsIntegration(true);
  161. $view = new HookIntegratorView($integrationResult, $integration);
  162. $this->updateIntegrationData($integration, $view->getHTML());
  163. $this->setAppParam('IntegrationControlerName', null);
  164. $this->setAppParam('IntegrationControlerMethod', null);
  165. }
  166. }
  167. /**
  168. * check if integration params match page/request params
  169. * @param null|AbstractHookIntegrationController $integration
  170. * @return bool
  171. */
  172. public function isIntegrationApplicable($integration = null)
  173. {
  174. //check just in case, in order not to kill whole WHMCS
  175. if (!$integration)
  176. {
  177. return false;
  178. }
  179. //check if filename is correct for the integration
  180. if ($this->hookParams['filename'] !== $integration->getFileName())
  181. {
  182. return false;
  183. }
  184. //check if all provided request params are correct for the integration
  185. foreach ($integration->getRequestParams() as $rKey => $rParam)
  186. {
  187. if (is_array($rParam))
  188. {
  189. $found = false;
  190. foreach ($rParam as $irParam)
  191. {
  192. if ($this->getRequestValue($rKey) === $irParam)
  193. {
  194. $found = true;
  195. break;
  196. }
  197. }
  198. if (!$found)
  199. {
  200. return false;
  201. }
  202. }
  203. elseif ($this->getRequestValue($rKey) !== $rParam)
  204. {
  205. return false;
  206. }
  207. }
  208. //check if integration callback is correct
  209. $integrationCallback = $integration->getControllerCallback();
  210. if ((!is_subclass_of($integrationCallback[0], \ModulesGarden\Servers\ZimbraEmail\Core\Http\AbstractController::class)
  211. && !is_subclass_of($integrationCallback[0], \ModulesGarden\Servers\ZimbraEmail\Core\Http\AbstractClientController::class))
  212. || !method_exists($integrationCallback[0], $integrationCallback[1]))
  213. {
  214. return false;
  215. }
  216. return true;
  217. }
  218. protected function updateIntegrationData($integrationDetails, $htmlData)
  219. {
  220. if (!is_string($htmlData) || $htmlData === '' || !$integrationDetails || !is_object($integrationDetails))
  221. {
  222. return false;
  223. }
  224. $this->integrationData[] = [
  225. 'htmlData' => $htmlData,
  226. 'integrationDetails' =>$integrationDetails
  227. ];
  228. }
  229. protected function getWrapperHtml()
  230. {
  231. if (!$this->integrationData)
  232. {
  233. return null;
  234. }
  235. $wrapper = new HookIntegrationsWrapper($this->integrationData);
  236. return $wrapper->getHtml();
  237. }
  238. }