PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/php/lib/content_object_updater.class.php

https://bitbucket.org/chamilo/chamilo-repository-dev/
PHP | 380 lines | 300 code | 50 blank | 30 comment | 21 complexity | 62affc1e14295d9405552d14599c3750 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('default' => $event->getAttribute('default'),
  229. 'user_setting' => $event->getAttribute('user_setting'), 'type' => $event->getAttribute('type'));
  230. }
  231. return $settings;
  232. }
  233. function configure_content_object()
  234. {
  235. $content_object = $this->get_content_object();
  236. $namespace = ContentObject :: get_content_object_type_namespace($content_object);
  237. $settings_file = $this->get_path() . 'settings.xml';
  238. if (file_exists($settings_file))
  239. {
  240. $xml = $this->parse_content_object_settings($settings_file);
  241. foreach ($xml as $name => $parameters)
  242. {
  243. $type = $parameters['type'];
  244. if ($type == 1)
  245. {
  246. $setting = new Setting();
  247. $setting->set_context($namespace);
  248. $setting->set_variable($name);
  249. $setting->set_value($parameters['default']);
  250. $user_setting = $parameters['user_setting'];
  251. if ($user_setting)
  252. $setting->set_user_setting($user_setting);
  253. else
  254. $setting->set_user_setting(0);
  255. if (! $setting->create())
  256. {
  257. $message = Translation :: get('ApplicationConfigurationFailed');
  258. $this->update_failed($message);
  259. }
  260. }
  261. else
  262. {
  263. $conditions = array();
  264. $conditions[] = new EqualityCondition(Setting :: PROPERTY_CONTEXT, $namespace);
  265. $conditions[] = new EqualityCondition(Setting :: PROPERTY_VARIABLE, $name);
  266. $condition = new AndCondition($conditions);
  267. $settings = AdminDataManager :: get_instance()->retrieve_settings($condition);
  268. while ($setting = $settings->next_result())
  269. {
  270. if (! $setting->delete())
  271. {
  272. return false;
  273. }
  274. }
  275. }
  276. }
  277. $this->add_message(self :: TYPE_NORMAL, Translation :: get('SettingsAdded'));
  278. }
  279. return true;
  280. }
  281. function storage_unit_exist($file)
  282. {
  283. $storage_unit_info = self :: parse_xml_file($file);
  284. $this->add_message(self :: TYPE_NORMAL, Translation :: get('StorageUnitExist') . ': <em>' . $storage_unit_info['name'] . '</em>');
  285. if (! $this->data_manager->storage_unit_exist($storage_unit_info['name']))
  286. {
  287. return false;
  288. //return $this->update_failed(Translation :: get('StorageUnitCreationFailed') . ': <em>' . $storage_unit_info['name'] . '</em>');
  289. }
  290. else
  291. {
  292. return true;
  293. }
  294. }
  295. function update_failed($error_message)
  296. {
  297. $this->add_message(self :: TYPE_ERROR, $error_message);
  298. $this->add_message(self :: TYPE_ERROR, Translation :: get('ContentObjectInstallFailed'));
  299. $this->add_message(self :: TYPE_ERROR, Translation :: get('PlatformInstallFailed'));
  300. return false;
  301. }
  302. function update_successful()
  303. {
  304. $this->add_message(self :: TYPE_CONFIRM, Translation :: get('InstallSuccess'));
  305. return true;
  306. }
  307. /**
  308. * Creates an application-specific installer.
  309. * @param string $application The application for which we want to start the installer.
  310. * @param string $values The form values passed on by the wizard.
  311. */
  312. static function factory($type, $version)
  313. {
  314. $version_string = str_replace('.', '', $version);
  315. $class = ContentObject :: type_to_class($type) . $version_string . 'ContentObjectUpdater';
  316. $file = Path :: get_repository_path() . 'lib/content_object/' . $type . '/update/' . $version . '/' . $type . '_' . $version_string . '_updater.class.php';
  317. if (file_exists($file))
  318. {
  319. require_once $file;
  320. return new $class($type);
  321. }
  322. else
  323. {
  324. return false;
  325. }
  326. }
  327. abstract function get_path();
  328. abstract function get_install_path();
  329. }
  330. ?>