PageRenderTime 65ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/vtlib/Vtiger/PackageUpdate.php

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