PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/php/lib/content_object_updater.class.php

https://bitbucket.org/chamilo/chamilo-repository/
PHP | 382 lines | 302 code | 50 blank | 30 comment | 21 complexity | 66dff7a798b3e6afb1000036d70a05c5 MD5 | raw file
  1. <?php
  2. namespace repository;
  3. use admin\AdminDataManager;
  4. use admin\Setting;
  5. use common\libraries\DatabaseBackup;
  6. use common\libraries\Filesystem;
  7. use common\libraries\Translation;
  8. use common\libraries\Path;
  9. use common\libraries\Configuration;
  10. use common\libraries\Utilities;
  11. use common\libraries\EqualityCondition;
  12. use common\libraries\AndCondition;
  13. use user\UserDataManager;
  14. use user\User;
  15. use DomDocument;
  16. abstract class ContentObjectUpdater
  17. {
  18. const TYPE_NORMAL = '1';
  19. const TYPE_CONFIRM = '2';
  20. const TYPE_WARNING = '3';
  21. const TYPE_ERROR = '4';
  22. const UPDATE_SUCCESS = 'success';
  23. const UPDATE_MESSAGE = 'message';
  24. /**
  25. * The datamanager which can be used by the installer of the application
  26. */
  27. private $data_manager;
  28. /**
  29. * Message to be displayed upon completion of the update procedure
  30. */
  31. private $message;
  32. private $type;
  33. /**
  34. * Constructor
  35. */
  36. function __construct($type)
  37. {
  38. $this->data_manager = RepositoryDataManager :: get_instance();
  39. $this->message = array();
  40. $this->type = $type;
  41. }
  42. function update()
  43. {
  44. $dir = $this->get_install_path();
  45. $files = Filesystem :: get_directory_content($dir, Filesystem :: LIST_FILES);
  46. foreach ($files as $file)
  47. {
  48. if ((substr($file, - 3) == 'xml'))
  49. {
  50. if (! $this->storage_unit_exist($file))
  51. {
  52. if (! $this->create_storage_unit($file))
  53. {
  54. return false;
  55. }
  56. }
  57. else
  58. {
  59. $storage_unit = self :: parse_xml_file($file);
  60. $backup = DatabaseBackup :: factory('mysql', array($storage_unit['name']), $this->get_data_manager());
  61. $output = $backup->backup();
  62. $file = Path :: get_temp_path() . 'backup/repository_' . $this->get_content_object() . '_' . time() . '.backup';
  63. Filesystem :: write_to_file($file, $output, true);
  64. $this->add_message(self :: TYPE_WARNING, 'Xml file needed with changes');
  65. }
  66. }
  67. }
  68. if (! $this->configure_content_object())
  69. {
  70. return false;
  71. }
  72. if (method_exists($this, 'update_extra'))
  73. {
  74. if (! $this->update_extra())
  75. {
  76. return false;
  77. }
  78. }
  79. return $this->update_successful();
  80. }
  81. public function import_content_object()
  82. {
  83. $type = $this->get_content_object();
  84. $file = Path :: get_repository_path() . 'lib/content_object/' . $type . '/install/example.zip';
  85. if (file_exists($file))
  86. {
  87. $condition = new EqualityCondition(User :: PROPERTY_PLATFORMADMIN, 1);
  88. $user = UserDataManager :: get_instance()->retrieve_users($condition)->next_result();
  89. $category = RepositoryDataManager :: get_instance();
  90. $import = ContentObjectImport :: factory('cpo', array('tmp_name' => $file), $user, 0);
  91. if (! $import->import_content_object())
  92. {
  93. $message = Translation :: get('ContentObjectImportFailed');
  94. $this->update_failed($message);
  95. return false;
  96. }
  97. else
  98. {
  99. $this->add_message(self :: TYPE_NORMAL, Translation :: get('ImportSuccessfull'));
  100. }
  101. }
  102. return true;
  103. }
  104. function get_content_object()
  105. {
  106. return $this->type;
  107. }
  108. function get_content_object_name()
  109. {
  110. return Utilities :: underscores_to_camelcase($this->type);
  111. }
  112. /**
  113. * Parses an XML file describing a storage unit.
  114. * For defining the 'type' of the field, the same definition is used as the
  115. * PEAR::MDB2 package. See http://pear.php.net/manual/en/package.database.
  116. * mdb2.datatypes.php
  117. * @param string $file The complete path to the XML-file from which the
  118. * storage unit definition should be read.
  119. * @return array An with values for the keys 'name','properties' and
  120. * 'indexes'
  121. */
  122. public static function parse_xml_file($file)
  123. {
  124. $name = '';
  125. $properties = array();
  126. $indexes = array();
  127. $doc = new DOMDocument();
  128. $doc->load($file);
  129. $object = $doc->getElementsByTagname('object')->item(0);
  130. $name = $object->getAttribute('name');
  131. $xml_properties = $doc->getElementsByTagname('property');
  132. $attributes = array('type', 'length', 'unsigned', 'notnull', 'default', 'autoincrement', 'fixed');
  133. foreach ($xml_properties as $index => $property)
  134. {
  135. $property_info = array();
  136. foreach ($attributes as $index => $attribute)
  137. {
  138. if ($property->hasAttribute($attribute))
  139. {
  140. $property_info[$attribute] = $property->getAttribute($attribute);
  141. }
  142. }
  143. $properties[$property->getAttribute('name')] = $property_info;
  144. }
  145. $xml_indexes = $doc->getElementsByTagname('index');
  146. foreach ($xml_indexes as $key => $index)
  147. {
  148. $index_info = array();
  149. $index_info['type'] = $index->getAttribute('type');
  150. $index_properties = $index->getElementsByTagname('indexproperty');
  151. foreach ($index_properties as $subkey => $index_property)
  152. {
  153. $index_info['fields'][$index_property->getAttribute('name')] = array(
  154. 'length' => $index_property->getAttribute('length'));
  155. }
  156. $indexes[$index->getAttribute('name')] = $index_info;
  157. }
  158. $result = array();
  159. $result['name'] = $name;
  160. $result['properties'] = $properties;
  161. $result['indexes'] = $indexes;
  162. return $result;
  163. }
  164. function add_message($type = self :: TYPE_NORMAL, $message)
  165. {
  166. switch ($type)
  167. {
  168. case self :: TYPE_NORMAL :
  169. $this->message[] = $message;
  170. break;
  171. case self :: TYPE_CONFIRM :
  172. $this->message[] = '<span style="color: green; font-weight: bold;">' . $message . '</span>';
  173. break;
  174. case self :: TYPE_WARNING :
  175. $this->message[] = '<span style="color: orange; font-weight: bold;">' . $message . '</span>';
  176. break;
  177. case self :: TYPE_ERROR :
  178. $this->message[] = '<span style="color: red; font-weight: bold;">' . $message . '</span>';
  179. break;
  180. default :
  181. $this->message[] = $message;
  182. break;
  183. }
  184. }
  185. function set_message($message)
  186. {
  187. $this->message = $message;
  188. }
  189. function get_message()
  190. {
  191. return $this->message;
  192. }
  193. function get_data_manager()
  194. {
  195. return $this->data_manager;
  196. }
  197. function retrieve_message()
  198. {
  199. return implode('<br />' . "\n", $this->get_message());
  200. }
  201. /**
  202. * Parses an XML file and sends the request to the database manager
  203. * @param String $path
  204. */
  205. function create_storage_unit($path)
  206. { //print_r($path);
  207. $storage_unit_info = self :: parse_xml_file($path);
  208. $this->add_message(self :: TYPE_NORMAL, Translation :: get('StorageUnitCreation') . ': <em>' . $storage_unit_info['name'] . '</em>');
  209. if (! $this->data_manager->create_storage_unit($storage_unit_info['name'], $storage_unit_info['properties'], $storage_unit_info['indexes']))
  210. {
  211. return $this->update_failed(Translation :: get('StorageUnitCreationFailed') . ': <em>' . $storage_unit_info['name'] . '</em>');
  212. }
  213. else
  214. {
  215. return true;
  216. }
  217. }
  218. function parse_content_object_settings($file)
  219. {
  220. $doc = new DOMDocument();
  221. $doc->load($file);
  222. $object = $doc->getElementsByTagname('application')->item(0);
  223. // Get events
  224. $events = $doc->getElementsByTagname('setting');
  225. $settings = array();
  226. foreach ($events as $index => $event)
  227. {
  228. $settings[$event->getAttribute('name')] = array(
  229. 'default' => $event->getAttribute('default'),
  230. 'user_setting' => $event->getAttribute('user_setting'),
  231. 'type' => $event->getAttribute('type'));
  232. }
  233. return $settings;
  234. }
  235. function configure_content_object()
  236. {
  237. $content_object = $this->get_content_object();
  238. $namespace = ContentObject :: get_content_object_type_namespace($content_object);
  239. $settings_file = $this->get_path() . 'settings.xml';
  240. if (file_exists($settings_file))
  241. {
  242. $xml = $this->parse_content_object_settings($settings_file);
  243. foreach ($xml as $name => $parameters)
  244. {
  245. $type = $parameters['type'];
  246. if ($type == 1)
  247. {
  248. $setting = new Setting();
  249. $setting->set_context($namespace);
  250. $setting->set_variable($name);
  251. $setting->set_value($parameters['default']);
  252. $user_setting = $parameters['user_setting'];
  253. if ($user_setting)
  254. $setting->set_user_setting($user_setting);
  255. else
  256. $setting->set_user_setting(0);
  257. if (! $setting->create())
  258. {
  259. $message = Translation :: get('ApplicationConfigurationFailed');
  260. $this->update_failed($message);
  261. }
  262. }
  263. else
  264. {
  265. $conditions = array();
  266. $conditions[] = new EqualityCondition(Setting :: PROPERTY_CONTEXT, $namespace);
  267. $conditions[] = new EqualityCondition(Setting :: PROPERTY_VARIABLE, $name);
  268. $condition = new AndCondition($conditions);
  269. $settings = AdminDataManager :: get_instance()->retrieve_settings($condition);
  270. while ($setting = $settings->next_result())
  271. {
  272. if (! $setting->delete())
  273. {
  274. return false;
  275. }
  276. }
  277. }
  278. }
  279. $this->add_message(self :: TYPE_NORMAL, Translation :: get('SettingsAdded'));
  280. }
  281. return true;
  282. }
  283. function storage_unit_exist($file)
  284. {
  285. $storage_unit_info = self :: parse_xml_file($file);
  286. $this->add_message(self :: TYPE_NORMAL, Translation :: get('StorageUnitExist') . ': <em>' . $storage_unit_info['name'] . '</em>');
  287. if (! $this->data_manager->storage_unit_exist($storage_unit_info['name']))
  288. {
  289. return false;
  290. //return $this->update_failed(Translation :: get('StorageUnitCreationFailed') . ': <em>' . $storage_unit_info['name'] . '</em>');
  291. }
  292. else
  293. {
  294. return true;
  295. }
  296. }
  297. function update_failed($error_message)
  298. {
  299. $this->add_message(self :: TYPE_ERROR, $error_message);
  300. $this->add_message(self :: TYPE_ERROR, Translation :: get('ContentObjectInstallFailed'));
  301. $this->add_message(self :: TYPE_ERROR, Translation :: get('PlatformInstallFailed'));
  302. return false;
  303. }
  304. function update_successful()
  305. {
  306. $this->add_message(self :: TYPE_CONFIRM, Translation :: get('InstallSuccess'));
  307. return true;
  308. }
  309. /**
  310. * Creates an application-specific installer.
  311. * @param string $application The application for which we want to start the installer.
  312. * @param string $values The form values passed on by the wizard.
  313. */
  314. static function factory($type, $version)
  315. {
  316. $version_string = str_replace('.', '', $version);
  317. $class = ContentObject :: type_to_class($type) . $version_string . 'ContentObjectUpdater';
  318. $file = Path :: get_repository_path() . 'lib/content_object/' . $type . '/update/' . $version . '/' . $type . '_' . $version_string . '_updater.class.php';
  319. if (file_exists($file))
  320. {
  321. require_once $file;
  322. return new $class($type);
  323. }
  324. else
  325. {
  326. return false;
  327. }
  328. }
  329. abstract function get_path();
  330. abstract function get_install_path();
  331. }
  332. ?>