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

/vtlib/Vtiger/PackageUpdate.php

https://bitbucket.org/jhunsinfotech/blue-blues
PHP | 412 lines | 249 code | 46 blank | 117 comment | 66 complexity | 3c331f0e25f2ec76b8a3168d4b5e59c2 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, LGPL-3.0
  1. <?php
  2. /*+**********************************************************************************
  3. * The contents of this file are subject to the vtiger CRM Public License Version 1.0
  4. * ("License"); You may not use this file except in compliance with the License
  5. * The Original Code is: vtiger CRM Open Source
  6. * The Initial Developer of the Original Code is vtiger.
  7. * Portions created by vtiger are Copyright (C) vtiger.
  8. * All Rights Reserved.
  9. ************************************************************************************/
  10. include_once('vtlib/Vtiger/PackageImport.php');
  11. /**
  12. * Provides API to update module into vtiger CRM
  13. * @package vtlib
  14. */
  15. class Vtiger_PackageUpdate extends Vtiger_PackageImport {
  16. var $_migrationinfo = false;
  17. /**
  18. * Constructor
  19. */
  20. function Vtiger_PackageUpdate() {
  21. parent::__construct();
  22. }
  23. /**
  24. * Initialize Update
  25. * @access private
  26. */
  27. function initUpdate($moduleInstance, $zipfile, $overwrite) {
  28. $module = $this->getModuleNameFromZip($zipfile);
  29. if(!$moduleInstance || $moduleInstance->name != $module) {
  30. self::log('Module name mismatch!');
  31. return false;
  32. }
  33. if($module != null) {
  34. $unzip = new Vtiger_Unzip($zipfile, $overwrite);
  35. // Unzip selectively
  36. $unzip->unzipAllEx( ".",
  37. Array(
  38. 'include' => Array('templates', "modules/$module"), // We don't need manifest.xml
  39. //'exclude' => Array('manifest.xml') // DEFAULT: excludes all not in include
  40. ),
  41. // Templates folder to be renamed while copying
  42. Array('templates' => "Smarty/templates/modules/$module"),
  43. // Cron folder to be renamed while copying
  44. Array('cron' => "cron/modules/$module")
  45. );
  46. // If data is not yet available
  47. if(empty($this->_modulexml)) {
  48. $this->__parseManifestFile($unzip);
  49. }
  50. if($unzip) $unzip->close();
  51. }
  52. return $module;
  53. }
  54. /**
  55. * Update Module from zip file
  56. * @param Vtiger_Module Instance of the module to update
  57. * @param String Zip file name
  58. * @param Boolean True for overwriting existing module
  59. */
  60. function update($moduleInstance, $zipfile, $overwrite=true) {
  61. $module = $this->getModuleNameFromZip($zipfile);
  62. if($module != null) {
  63. // If data is not yet available
  64. if(empty($this->_modulexml)) {
  65. $this->__parseManifestFile($unzip);
  66. }
  67. $buildModuleArray = array();
  68. $installSequenceArray = array();
  69. $moduleBundle = (boolean)$this->_modulexml->modulebundle;
  70. if($moduleBundle == true) {
  71. $moduleList = (Array)$this->_modulexml->modulelist;
  72. foreach($moduleList as $moduleInfos) {
  73. foreach($moduleInfos as $moduleInfo) {
  74. $moduleInfo = (Array)$moduleInfo;
  75. $buildModuleArray[] = $moduleInfo;
  76. $installSequenceArray[] = $moduleInfo['install_sequence'];
  77. }
  78. }
  79. sort($installSequenceArray);
  80. $unzip = new Vtiger_Unzip($zipfile);
  81. $unzip->unzipAllEx($this->getTemporaryFilePath());
  82. foreach ($installSequenceArray as $sequence) {
  83. foreach ($buildModuleArray as $moduleInfo) {
  84. if($moduleInfo['install_sequence'] == $sequence) {
  85. $moduleInstance = Vtiger_Module::getInstance($moduleInfo['name']);
  86. $this->update($moduleInstance, $this->getTemporaryFilePath($moduleInfo['filepath']), $overwrite);
  87. }
  88. }
  89. }
  90. } else {
  91. if(!$moduleInstance || $moduleInstance->name != $module) {
  92. self::log('Module name mismatch!');
  93. return false;
  94. }
  95. $module = $this->initUpdate($moduleInstance, $zipfile, $overwrite);
  96. // Call module update function
  97. $this->update_Module($moduleInstance);
  98. }
  99. }
  100. }
  101. /**
  102. * Update Module
  103. * @access private
  104. */
  105. function update_Module($moduleInstance) {
  106. $tabname = $this->_modulexml->name;
  107. $tablabel= $this->_modulexml->label;
  108. $parenttab=$this->_modulexml->parent;
  109. $tabversion=$this->_modulexml->version;
  110. $isextension= false;
  111. if(!empty($this->_modulexml->type)) {
  112. $type = strtolower($this->_modulexml->type);
  113. if($type == 'extension' || $type == 'language')
  114. $isextension = true;
  115. }
  116. Vtiger_Module::fireEvent($moduleInstance->name,
  117. Vtiger_Module::EVENT_MODULE_PREUPDATE);
  118. // TODO Handle module property changes like menu, label etc...
  119. /*if(!empty($parenttab) && $parenttab != '') {
  120. $menuInstance = Vtiger_Menu::getInstance($parenttab);
  121. $menuInstance->addModule($moduleInstance);
  122. }*/
  123. $this->handle_Migration($this->_modulexml, $moduleInstance);
  124. $this->update_Tables($this->_modulexml);
  125. $this->update_Blocks($this->_modulexml, $moduleInstance);
  126. $this->update_CustomViews($this->_modulexml, $moduleInstance);
  127. $this->update_SharingAccess($this->_modulexml, $moduleInstance);
  128. $this->update_Events($this->_modulexml, $moduleInstance);
  129. $this->update_Actions($this->_modulexml, $moduleInstance);
  130. $this->update_RelatedLists($this->_modulexml, $moduleInstance);
  131. $this->update_CustomLinks($this->_modulexml, $moduleInstance);
  132. $this->update_CronTasks($this->_modulexml);
  133. $moduleInstance->__updateVersion($tabversion);
  134. Vtiger_Module::fireEvent($moduleInstance->name,
  135. Vtiger_Module::EVENT_MODULE_POSTUPDATE);
  136. }
  137. /**
  138. * Parse migration information from manifest
  139. * @access private
  140. */
  141. function parse_Migration($modulenode) {
  142. if(!$this->_migrations) {
  143. $this->_migrations = Array();
  144. if(!empty($modulenode->migrations) &&
  145. !empty($modulenode->migrations->migration)) {
  146. foreach($modulenode->migrations->migration as $migrationnode) {
  147. $migrationattrs = $migrationnode->attributes();
  148. $migrationversion = $migrationattrs['version'];
  149. $this->_migrations["$migrationversion"] = $migrationnode;
  150. }
  151. }
  152. // Sort the migration details based on version
  153. if(count($this->_migrations) > 1) {
  154. uksort($this->_migrations, 'version_compare');
  155. }
  156. }
  157. }
  158. /**
  159. * Handle migration of the module
  160. * @access private
  161. */
  162. function handle_Migration($modulenode, $moduleInstance) {
  163. // TODO Handle module migration SQL
  164. $this->parse_Migration($modulenode);
  165. $cur_version = $moduleInstance->version;
  166. foreach($this->_migrations as $migversion=>$migrationnode) {
  167. // Perform migration only for higher version than current
  168. if(version_compare($cur_version, $migversion, '<')) {
  169. self::log("Migrating to $migversion ... STARTED");
  170. if(!empty($migrationnode->tables) && !empty($migrationnode->tables->table)) {
  171. foreach($migrationnode->tables->table as $tablenode) {
  172. $tablename = $tablenode->name;
  173. $tablesql = "$tablenode->sql"; // Convert to string
  174. // Skip SQL which are destructive
  175. if(Vtiger_Utils::IsDestructiveSql($tablesql)) {
  176. self::log("SQL: $tablesql ... SKIPPED");
  177. } else {
  178. // Supress any SQL query failures
  179. self::log("SQL: $tablesql ... ", false);
  180. Vtiger_Utils::ExecuteQuery($tablesql, true);
  181. self::log("DONE");
  182. }
  183. }
  184. }
  185. self::log("Migrating to $migversion ... DONE");
  186. }
  187. }
  188. }
  189. /**
  190. * Update Tables of the module
  191. * @access private
  192. */
  193. function update_Tables($modulenode) {
  194. $this->import_Tables($modulenode);
  195. }
  196. /**
  197. * Update Blocks of the module
  198. * @access private
  199. */
  200. function update_Blocks($modulenode, $moduleInstance) {
  201. if(empty($modulenode->blocks) || empty($modulenode->blocks->block)) return;
  202. foreach($modulenode->blocks->block as $blocknode) {
  203. $blockInstance = Vtiger_Block::getInstance($blocknode->label, $moduleInstance);
  204. if(!$blockInstance) {
  205. $blockInstance = $this->import_Block($modulenode, $moduleInstance, $blocknode);
  206. } else {
  207. $this->update_Block($modulenode, $moduleInstance, $blocknode, $blockInstance);
  208. }
  209. $this->update_Fields($blocknode, $blockInstance, $moduleInstance);
  210. }
  211. }
  212. /**
  213. * Update Block of the module
  214. * @access private
  215. */
  216. function update_Block($modulenode, $moduleInstance, $blocknode, $blockInstance) {
  217. // TODO Handle block property update
  218. }
  219. /**
  220. * Update Fields of the module
  221. * @access private
  222. */
  223. function update_Fields($blocknode, $blockInstance, $moduleInstance) {
  224. if(empty($blocknode->fields) || empty($blocknode->fields->field)) return;
  225. foreach($blocknode->fields->field as $fieldnode) {
  226. $fieldInstance = Vtiger_Field::getInstance($fieldnode->fieldname, $moduleInstance);
  227. if(!$fieldInstance) {
  228. $fieldInstance = $this->import_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode);
  229. } else {
  230. $this->update_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode, $fieldInstance);
  231. }
  232. $this->__AddModuleFieldToCache($moduleInstance, $fieldInstance->name, $fieldInstance);
  233. }
  234. }
  235. /**
  236. * Update Field of the module
  237. * @access private
  238. */
  239. function update_Field($blocknode, $blockInstance, $moduleInstance, $fieldnode, $fieldInstance) {
  240. // TODO Handle field property update
  241. if(!empty($fieldnode->helpinfo)) $fieldInstance->setHelpInfo($fieldnode->helpinfo);
  242. if(!empty($fieldnode->masseditable)) $fieldInstance->setMassEditable($fieldnode->masseditable);
  243. }
  244. /**
  245. * Import Custom views of the module
  246. * @access private
  247. */
  248. function update_CustomViews($modulenode, $moduleInstance) {
  249. if(empty($modulenode->customviews) || empty($modulenode->customviews->customview)) return;
  250. foreach($modulenode->customviews->customview as $customviewnode) {
  251. $filterInstance = Vtiger_Filter::getInstance($customviewnode->viewname, $moduleInstance);
  252. if(!$filterInstance) {
  253. $filterInstance = $this->import_CustomView($modulenode, $moduleInstance, $customviewnode);
  254. } else {
  255. $this->update_CustomView($modulenode, $moduleInstance, $customviewnode, $filterInstance);
  256. }
  257. }
  258. }
  259. /**
  260. * Update Custom View of the module
  261. * @access private
  262. */
  263. function update_CustomView($modulenode, $moduleInstance, $customviewnode, $filterInstance) {
  264. // TODO Handle filter property update
  265. }
  266. /**
  267. * Update Sharing Access of the module
  268. * @access private
  269. */
  270. function update_SharingAccess($modulenode, $moduleInstance) {
  271. if(empty($modulenode->sharingaccess)) return;
  272. // TODO Handle sharing access property update
  273. }
  274. /**
  275. * Update Events of the module
  276. * @access private
  277. */
  278. function update_Events($modulenode, $moduleInstance) {
  279. if(empty($modulenode->events) || empty($modulenode->events->event)) return;
  280. if(Vtiger_Event::hasSupport()) {
  281. foreach($modulenode->events->event as $eventnode) {
  282. $this->update_Event($modulenode, $moduleInstance, $eventnode);
  283. }
  284. }
  285. }
  286. /**
  287. * Update Event of the module
  288. * @access private
  289. */
  290. function update_Event($modulenode, $moduleInstance, $eventnode) {
  291. //Vtiger_Event::register($moduleInstance, $eventnode->eventname, $eventnode->classname, $eventnode->filename);
  292. // TODO Handle event property update
  293. }
  294. /**
  295. * Update actions of the module
  296. * @access private
  297. */
  298. function update_Actions($modulenode, $moduleInstance) {
  299. if(empty($modulenode->actions) || empty($modulenode->actions->action)) return;
  300. foreach($modulenode->actions->action as $actionnode) {
  301. $this->update_Action($modulenode, $moduleInstance, $actionnode);
  302. }
  303. }
  304. /**
  305. * Update action of the module
  306. * @access private
  307. */
  308. function update_Action($modulenode, $moduleInstance, $actionnode) {
  309. // TODO Handle action property update
  310. }
  311. /**
  312. * Update related lists of the module
  313. * @access private
  314. */
  315. function update_RelatedLists($modulenode, $moduleInstance) {
  316. if(empty($modulenode->relatedlists) || empty($modulenode->relatedlists->relatedlist)) return;
  317. $moduleInstance->deleteRelatedLists();
  318. foreach($modulenode->relatedlists->relatedlist as $relatedlistnode) {
  319. $relModuleInstance = $this->update_Relatedlist($modulenode, $moduleInstance, $relatedlistnode);
  320. }
  321. }
  322. /**
  323. * Import related list of the module.
  324. * @access private
  325. */
  326. function update_Relatedlist($modulenode, $moduleInstance, $relatedlistnode) {
  327. $relModuleInstance = Vtiger_Module::getInstance($relatedlistnode->relatedmodule);
  328. $label = $relatedlistnode->label;
  329. $actions = false;
  330. if(!empty($relatedlistnode->actions) && !empty($relatedlistnode->actions->action)) {
  331. $actions = Array();
  332. foreach($relatedlistnode->actions->action as $actionnode) {
  333. $actions[] = "$actionnode";
  334. }
  335. }
  336. if($relModuleInstance) {
  337. $moduleInstance->unsetRelatedList($relModuleInstance, "$label", "$relatedlistnode->function");
  338. $moduleInstance->setRelatedList($relModuleInstance, "$label", $actions, "$relatedlistnode->function");
  339. }
  340. return $relModuleInstance;
  341. }
  342. function update_CustomLinks($modulenode, $moduleInstance) {
  343. if(empty($modulenode->customlinks) || empty($modulenode->customlinks->customlink)) return;
  344. $moduleInstance->deleteLinks();
  345. $this->import_CustomLinks($modulenode, $moduleInstance);
  346. }
  347. function update_CronTasks($modulenode) {
  348. if(empty($modulenode->crons) || empty($modulenode->crons->cron)) return;
  349. $cronTasks = Vtiger_Cron::listAllInstancesByModule($modulenode->name);
  350. foreach ($modulenode->crons->cron as $importCronTask) {
  351. foreach($cronTasks as $cronTask) {
  352. if($cronTask->getName() == $importCronTask->name && $importCronTask->handler == $cronTask->getHandlerFile()) {
  353. Vtiger_Cron::deregister($importCronTask->name);
  354. }
  355. }
  356. if(empty($importCronTask->status)){
  357. $importCronTask->status=Vtiger_Cron::$STATUS_ENABLED;
  358. }
  359. if((empty($importCronTask->sequence))){
  360. $importCronTask->sequence=Vtiger_Cron::nextSequence();
  361. }
  362. Vtiger_Cron::register("$importCronTask->name","$importCronTask->handler", "$importCronTask->frequency", "$modulenode->name","$importCronTask->status","$importCronTask->sequence","$cronTask->description");
  363. }
  364. }
  365. }
  366. ?>