PageRenderTime 25ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/OX/Extension/deliveryLog/Setup.php

https://bitbucket.org/blackriver/openx
PHP | 416 lines | 205 code | 32 blank | 179 comment | 15 complexity | cf5461ca5e4f631b77ba4e4a6be779a4 MD5 | raw file
  1. <?php
  2. /*
  3. +---------------------------------------------------------------------------+
  4. | OpenX v2.8 |
  5. | ========== |
  6. | |
  7. | Copyright (c) 2003-2009 OpenX Limited |
  8. | For contact details, see: http://www.openx.org/ |
  9. | |
  10. | This program is free software; you can redistribute it and/or modify |
  11. | it under the terms of the GNU General Public License as published by |
  12. | the Free Software Foundation; either version 2 of the License, or |
  13. | (at your option) any later version. |
  14. | |
  15. | This program is distributed in the hope that it will be useful, |
  16. | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  17. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  18. | GNU General Public License for more details. |
  19. | |
  20. | You should have received a copy of the GNU General Public License |
  21. | along with this program; if not, write to the Free Software |
  22. | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
  23. +---------------------------------------------------------------------------+
  24. $Id: Setup.php 81772 2012-09-11 00:07:29Z chris.nutting $
  25. */
  26. require_once LIB_PATH . '/Plugin/Component.php';
  27. require_once LIB_PATH . '/Plugin/ComponentGroupManager.php';
  28. require_once LIB_PATH . '/Util/CodeMunger.php';
  29. require_once MAX_PATH . '/lib/OA/Algorithm/Dependency/Ordered.php';
  30. require_once MAX_PATH . '/lib/OA/Algorithm/Dependency/Source/HoA.php';
  31. /**
  32. * Global location for storing merged plugins files code
  33. */
  34. define('OX_BUCKETS_COMPILED_FILE', MAX_PATH.'/var/cache/' . OX_getHostName() . '_mergedDeliveryFunctions.php');
  35. /**
  36. * Generates delivery log plugins cache and order the dependencies
  37. * between components per each delivery log hook.
  38. *
  39. * @package OpenXExtension
  40. * @subpackage DeliveryLog
  41. * @author Radek Maciaszek <radek.maciaszek@openx.org>
  42. */
  43. class OX_Extension_DeliveryLog_Setup extends OX_Component
  44. {
  45. const DATA_EXTENSION = 'deliveryDataPrepare';
  46. const LOG_EXTENSION = 'deliveryLog';
  47. public $aDeliveryLogHooks = array(
  48. 'preLog',
  49. 'logRequest',
  50. 'logImpression',
  51. 'logClick',
  52. 'logConversion',
  53. 'logConversionVariable',
  54. );
  55. /**
  56. * Delivery logging related extension types
  57. *
  58. * @var array
  59. */
  60. private $extensionTypes = array(
  61. self::DATA_EXTENSION,
  62. self::LOG_EXTENSION
  63. );
  64. /**
  65. * Template for generating delivery cache
  66. *
  67. * @var string
  68. */
  69. public $header = "<?php\n\n{TEMPLATE}\n\n?>";
  70. /**
  71. * Code generator
  72. *
  73. * @var OX_Util_CodeMunger
  74. */
  75. private $oCodeMunger;
  76. /**
  77. * Keeps the reference to already installed components, so it
  78. * can perform uninstall in case of any error.
  79. *
  80. * @var array
  81. */
  82. private $aInstalledComponents = array();
  83. /**
  84. * Check the dependencies for active delivery log components and
  85. * sort the in the correct order so each dependency is resolved.
  86. *
  87. * @param array $aComponentsToSchedule Array of components Ids which need to be schedules
  88. * format: array(hook name => array(components Ids))
  89. * @param array $aAllComponentIdsByHooks Array of all components identifiers
  90. * @return array Array of components ids schedules in order of dependency
  91. */
  92. function getDependencyOrderedPlugins($aComponentsToSchedule, $aAllComponentIdsByHooks)
  93. {
  94. $aDeliveryComponentsHooks = $this->filterDeliveryHooks($aAllComponentIdsByHooks);
  95. $pluginsDependencies = $this->getComponentsDependencies($aDeliveryComponentsHooks);
  96. if (!$pluginsDependencies) {
  97. $this->_logError('No dependencies are defined');
  98. return false;
  99. }
  100. $source = new OA_Algorithm_Dependency_Source_HoA($pluginsDependencies);
  101. // should we update this value only if the result of sorting is positive?
  102. $dep = new OA_Algorithm_Dependency_Ordered($source, array(), $ignoreOrphans = true);
  103. return array_values($dep->schedule($aComponentsToSchedule));
  104. }
  105. /**
  106. * Filter out components by delivery hooks
  107. *
  108. * @param array $aAllComponentsIds Array of components per hooks keys
  109. * @return array Filtered array of components per delivery hooks keys
  110. */
  111. function filterDeliveryHooks($aAllComponentsIds)
  112. {
  113. $aDeliveryHooksComponents = array();
  114. foreach ($aAllComponentsIds as $hook => &$aComponents) {
  115. if (in_array($hook, $this->aDeliveryLogHooks)) {
  116. $aDeliveryHooksComponents[$hook] = $aComponents;
  117. }
  118. }
  119. return $aDeliveryHooksComponents;
  120. }
  121. /**
  122. * Returns array of dependencies - array contains merged dependencies.
  123. *
  124. * @param array $aComponents array(hook name => array(hook components names))
  125. * @return array Dependencies array(
  126. * 'extensionType:group:plugin' => array(
  127. * 'extensionType:group:plugin',
  128. * 'extensionType:group:plugin',
  129. * ...
  130. * ),
  131. * ....;
  132. */
  133. function getComponentsDependencies($aComponents)
  134. {
  135. $dependencies = array();
  136. static $aCacheComponents = array(); // static in-memory caching
  137. foreach ($aComponents as $hook => $hookComponents) {
  138. foreach ($hookComponents as $componentId) {
  139. if (!isset($aCacheComponents[$componentId])) {
  140. $component = $this->_factoryComponentById($componentId);
  141. if (!$component) {
  142. $this->_logError('Error when creating component: '.$componentId);
  143. } else {
  144. $aCacheComponents[$componentId] = $component->getDependencies();
  145. }
  146. }
  147. $dependencies = array_merge($dependencies, $aCacheComponents[$componentId]);
  148. }
  149. }
  150. return $dependencies;
  151. }
  152. /**
  153. * Factory component by its Id
  154. *
  155. * @param string $componentId Component Id, for example: ExtensionName:GroupName:ComponentName
  156. * @return OX_Component Returns OX_Component or false on error
  157. */
  158. function _factoryComponentById($componentId)
  159. {
  160. return OX_Component::factoryByComponentIdentifier($componentId);
  161. }
  162. /**
  163. * Change the component id code into array:
  164. * input: extension:group:component name
  165. * returns: array('extension', 'group', 'component name')
  166. *
  167. * @param string $componentId
  168. * @return array
  169. */
  170. function getExtensionGroupComponentFromId($componentId)
  171. {
  172. return explode(':', $componentId);
  173. }
  174. /**
  175. * Generated delivery component cache and save it into plugins cache
  176. * folder.
  177. *
  178. * @param array $aComponentsByHooks
  179. * @return boolean True on success, false on error
  180. */
  181. function regenerateDeliveryPluginsCodeCache($aComponentsByHooks)
  182. {
  183. // Only attempt to create the merged functions file if required
  184. if (empty($GLOBALS['_MAX']['CONF']['pluginSettings']['useMergedFunctions'])) {
  185. return true;
  186. }
  187. $aDeliveryComponentsHooks = $this->filterDeliveryHooks($aComponentsByHooks);
  188. $mergedDelivery = $this->generatePluginsCode($aDeliveryComponentsHooks);
  189. if (!$mergedDelivery) {
  190. return false;
  191. }
  192. if(!$this->saveMergedDelivery($mergedDelivery)) {
  193. $this->_logError('Error when saving delivery cache, file: '.OX_BUCKETS_COMPILED_FILE);
  194. return false;
  195. }
  196. return true;
  197. }
  198. /**
  199. * Generated delivery component cache
  200. *
  201. * @param array $aComponentsByHooks
  202. * @return string Merged delivery code or false on any error
  203. */
  204. function generatePluginsCode($aComponentsByHooks)
  205. {
  206. $componentsFiles = array();
  207. $mergedDelivery = '';
  208. foreach ($aComponentsByHooks as $hookName => &$hookComponents) {
  209. foreach ($hookComponents as $componentId) {
  210. list($extension, $group, $componentName)
  211. = $this->getExtensionGroupComponentFromId($componentId);
  212. $componentFile = $this->getFilePathToPlugin($extension, $group, $componentName);
  213. if (!$componentFile) {
  214. $this->_logError('Error while generating delivery cache, file doesn\'t exist: '
  215. .$componentFile);
  216. return false;
  217. }
  218. $mungedComponent = $this->mungeFile($componentFile);
  219. if (!$mungedComponent) {
  220. $this->_logError('Error while generating delivery cache, file: '.$componentFile);
  221. return false;
  222. }
  223. $mergedDelivery .= $mungedComponent;
  224. }
  225. }
  226. return $this->templateCode($mergedDelivery);
  227. }
  228. /**
  229. * Saves merged source code into output merged delivery cache
  230. *
  231. * @param string $mergedDelivery
  232. * @return boolean True on success, else false
  233. */
  234. function saveMergedDelivery($mergedDelivery)
  235. {
  236. return @file_put_contents(OX_BUCKETS_COMPILED_FILE, $mergedDelivery);
  237. }
  238. /**
  239. * Replaces the {TEMPLATE} mark with generated code
  240. *
  241. * @param string $sourceCode
  242. * @return string
  243. */
  244. function templateCode($sourceCode)
  245. {
  246. return str_replace('{TEMPLATE}', $sourceCode, $this->header);
  247. }
  248. /**
  249. * Cleans up (munge) the delivery file. For more info see OX_Util_CodeMunger
  250. *
  251. * @param string $file Delivery file path
  252. * @return string Generated source code
  253. */
  254. function mungeFile($file)
  255. {
  256. $oCodeMunger = $this->_getCodeMunger();
  257. $code = $oCodeMunger->flattenFile($file);
  258. return preg_replace(array('/^<\?php/', '/\?>$/'), array('', ''), $code);
  259. }
  260. /**
  261. * Calls onInstall method on every component which is installed groups.
  262. * If for any reason the installation failed it uninstall already installed
  263. * components.
  264. *
  265. * @param string $extension Extension in which we are gonna to install components
  266. * @param array $aComponentGroups Component groups - component groups to install
  267. * @return boolean True on success, false otherwise
  268. */
  269. function installComponents($extension, $aComponentGroups)
  270. {
  271. /*require_once MAX_PATH.'/lib/OA.php';
  272. OA::logMem('enter deliveryLog/Setup::installComponents');*/
  273. foreach ($aComponentGroups as $group)
  274. {
  275. //OA::logMem('installing group '.$group);
  276. $aComponents = $this->_getComponents($extension, $group);
  277. foreach ($aComponents as &$oComponent)
  278. {
  279. //OA::logMem('installing component '.$oComponent->component);
  280. if (!$oComponent->onInstall()) {
  281. $this->_logError('Error when installing component: ' . get_class($oComponent));
  282. $this->recoverUninstallComponents();
  283. return false;
  284. }
  285. $this->markComponentAsInstalled($oComponent);
  286. }
  287. }
  288. //OA::logMemPeak('exit installComponents');
  289. return true;
  290. }
  291. /**
  292. * Recovery on failed installation. Calls onUninstall method
  293. * on every component from components groups.
  294. */
  295. function recoverUninstallComponents()
  296. {
  297. foreach ($this->aInstalledComponents as $componentId) {
  298. $oComponent = $this->_factoryComponentById($componentId);
  299. if (!$oComponent) {
  300. $this->_logError('Error when creating component: '.$componentId);
  301. continue;
  302. }
  303. if (!$oComponent->onUninstall()) {
  304. $this->_logError('Error when uninstalling component: '.$componentId);
  305. }
  306. }
  307. }
  308. /**
  309. * Keeps the reference of already installed components. In case
  310. * a recovery uninstall will need to be performed.
  311. *
  312. * @param Plugins_DeliveryLog $oComponent
  313. */
  314. function markComponentAsInstalled(Plugins_DeliveryLog $oComponent)
  315. {
  316. $this->aInstalledComponents[] = $oComponent->getComponentIdentifier();
  317. }
  318. /**
  319. * Returns OX_Util_CodeMunger.
  320. * This method can be used for mocking in delivery.
  321. *
  322. * @return OX_Util_CodeMunger
  323. */
  324. function _getCodeMunger()
  325. {
  326. if (!$this->oCodeMunger) {
  327. $this->oCodeMunger = new OX_Util_CodeMunger();
  328. }
  329. return $this->oCodeMunger;
  330. }
  331. /**
  332. * Returns the file path to generate component based on its extension,
  333. * group and plugin names.
  334. *
  335. * @param string $extensionType
  336. * @param string $plugin
  337. * @param string $postfix
  338. * @return string File name or false if such file do not exist
  339. */
  340. function getFilePathToPlugin($extensionType, $group, $component, $postfix = '.delivery.php')
  341. {
  342. $oPluginMgr = $this->_getComponentGroupManager();
  343. $dirPath = MAX_PATH . $oPluginMgr->pathPlugins .
  344. $extensionType . '/' . $group.'/';
  345. $file = $dirPath . $component . $postfix;
  346. if (!file_exists($file)) {
  347. return false;
  348. }
  349. return $file;
  350. }
  351. /**
  352. * Required for mocking OX_Component::getComponents
  353. *
  354. * @return array Array of components in chosen extension, group
  355. */
  356. function _getComponents($extension, $group, $recursive = 1, $enabledOnly = false)
  357. {
  358. return OX_Component::getComponents($extension, $group, $recursive, $enabledOnly);
  359. }
  360. /**
  361. * Required for mocking OX_ManagerPlugin
  362. *
  363. * @return OX_ManagerPlugin
  364. */
  365. function _getComponentGroupManager()
  366. {
  367. return new OX_Plugin_ComponentGroupManager();
  368. }
  369. function _logMessage($msg, $err=PEAR_LOG_INFO)
  370. {
  371. OA::debug($msg, $err);
  372. }
  373. function _logWarning($msg)
  374. {
  375. $this->aWarnings[] = $msg;
  376. $this->_logMessage($msg, PEAR_LOG_WARNING);
  377. }
  378. function _logError($msg)
  379. {
  380. $this->aErrors[] = $msg;
  381. $this->_logMessage($msg, PEAR_LOG_ERR);
  382. }
  383. }
  384. ?>