PageRenderTime 22ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/code/update/SilvercartUpdate.php

https://bitbucket.org/silvercart/silvercart/
PHP | 410 lines | 166 code | 24 blank | 220 comment | 26 complexity | 91e44d9a3c9d938c4299dc789d615bb2 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright 2010, 2011 pixeltricks GmbH
  4. *
  5. * This file is part of SilverCart.
  6. *
  7. * SilverCart is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * SilverCart is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with SilverCart. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. * @package Silvercart
  21. * @subpackage Update
  22. */
  23. /**
  24. * Handles the updates of SilverCart which can't be handled by SilverStipes
  25. * default logic.
  26. * Provides the default logic and db fields for all updates.
  27. * Translations for status and status messages have to follow the convention:
  28. * <code>
  29. * $lang['en_US']['SilvercartUpdate']['STATUS_DONE'] = 'Done';
  30. * $lang['en_US']['SilvercartUpdate']['STATUSMESSAGE_DONE'] = 'This update was successfully completed.';
  31. * </code>
  32. * The key to get a translation of a status is 'STATUS_{STATUSTEXT}'.
  33. * The key to get a translation of a status message is 'STATUSMESSAGE_{STATUSTEXT}'.
  34. *
  35. * @package Silvercart
  36. * @subpackage Update
  37. * @author Sebastian Diel <sdiel@pixeltricks.de>
  38. * @copyright Pixeltricks GmbH
  39. * @since 25.03.2011
  40. * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
  41. */
  42. class SilvercartUpdate extends DataObject {
  43. public static $db = array(
  44. 'SilvercartVersion' => 'VarChar(8)',
  45. 'SilvercartUpdateVersion' => 'VarChar(8)',
  46. 'Status' => 'VarChar(16)',
  47. 'StatusMessage' => 'VarChar(255)',
  48. 'Description' => 'Text',
  49. );
  50. /**
  51. * The default status is remaining.
  52. *
  53. * @var array
  54. */
  55. public static $defaults = array(
  56. 'Status' => 'remaining',
  57. );
  58. public static $casting = array(
  59. 'TranslatedStatus' => 'VarChar',
  60. );
  61. /**
  62. * Sets the default sort order.
  63. *
  64. * @var string
  65. */
  66. public static $default_sort = 'SilvercartVersion DESC, SilvercartUpdateVersion DESC';
  67. /**
  68. * Sets the required updates for a specific update version.
  69. *
  70. * @example Update 0.9 - 7 requires specific changes done by update 0.9 - 5.
  71. * <code>
  72. * |public static $required_updates = array(
  73. * | '0.9' => '5'
  74. * |);
  75. * </code>
  76. * @example Update 0.9 - 8 requires specific changes done by update 0.9 - 5 and 0.9 - 7.
  77. * <code>
  78. * |public static $required_updates = array(
  79. * | '0.9' => array(
  80. * | '5',
  81. * | '7',
  82. * | )
  83. * |);
  84. * </code>
  85. * @example Update 1.0 - 3 requires specific changes done by update 0.9 - 8, 1.0 - 1 and 1.0 - 2.
  86. * <code>
  87. * |public static $required_updates = array(
  88. * | '0.9' => '8',
  89. * | '1.0' => array(
  90. * | '1',
  91. * | '2'
  92. * | )
  93. * |);
  94. * </code>
  95. *
  96. *
  97. * @var array
  98. */
  99. public static $required_updates = array();
  100. /**
  101. * Construct a new DataObject.
  102. *
  103. * @param array $record Array of field values.
  104. * @param bool $isSingleton This this to true if this is a singleton() object.
  105. */
  106. public function __construct($record = false, $isSingleton = false) {
  107. parent::__construct($record, $isSingleton);
  108. $className = $this->ClassName;
  109. /**
  110. * original expression
  111. * $classDefaults = $className::$defaults;
  112. * was replaced with eval call to provide compatibility to PHP 5.2
  113. */
  114. $classDefaults = eval('return ' . $className . '::$defaults;');
  115. if ($className == 'SilvercartUpdate' || $this->isInDB()) {
  116. $error = '';
  117. } elseif (!method_exists($this, 'executeUpdate')) {
  118. // method executeUpdate does not exist, trigger error
  119. $error = 'Method executeUpdate not found in class ' . $className;
  120. } elseif ($record === false) {
  121. if (!DataObject::get_one($className)) {
  122. $updateDefaults = $classDefaults;
  123. if (!array_key_exists('SilvercartVersion', $updateDefaults)
  124. || empty ($updateDefaults['SilvercartVersion'])) {
  125. // default value for SilvercartVersion is not set, trigger error
  126. $error = 'Default value for SilvercartVersion not set in class ' . $className;
  127. } elseif (!array_key_exists('SilvercartUpdateVersion', $updateDefaults)
  128. || empty ($updateDefaults['SilvercartUpdateVersion'])) {
  129. // default value for SilvercartUpdateVersion is not set, trigger error
  130. $error = 'Default value for SilvercartUpdateVersion not set in class ' . $className;
  131. } elseif (DataObject::get_one('SilvercartUpdate', sprintf("`SilvercartVersion`='%s' AND `SilvercartUpdateVersion`='%s'", $updateDefaults['SilvercartVersion'], $updateDefaults['SilvercartUpdateVersion']))) {
  132. // update already exists, trigger error
  133. $error = 'SilvercartUpdateVersion ' . $updateDefaults['SilvercartUpdateVersion'] . ' already exists for SilvercartVersion ' . $updateDefaults['SilvercartVersion'] . ' (defined in class ' . $className . ')';
  134. }
  135. }
  136. }
  137. if (!empty($error)) {
  138. trigger_error($error, E_USER_ERROR);
  139. exit();
  140. }
  141. }
  142. /**
  143. * Remove permission to edit for all members.
  144. *
  145. * @param Member $member Member
  146. *
  147. * @return bool
  148. *
  149. * @author Sebastian Diel <sdiel@pixeltricks.de>
  150. * @since 29.03.2011
  151. */
  152. public function canEdit($member = null) {
  153. return false;
  154. }
  155. /**
  156. * Remove permission to delete for all members.
  157. *
  158. * @param Member $member Member
  159. *
  160. * @return bool
  161. *
  162. * @author Sebastian Diel <sdiel@pixeltricks.de>
  163. * @since 29.03.2011
  164. */
  165. public function canDelete($member = null) {
  166. return false;
  167. }
  168. /**
  169. * Builds the default records for the update classes (singleton). The default
  170. * values should be specified in the extended update classes.
  171. *
  172. * @return void
  173. *
  174. * @author Sebastian Diel <sdiel@pixeltricks.de>
  175. * @since 29.03.2011
  176. */
  177. public function requireDefaultRecords() {
  178. if ($this->ClassName == 'SilvercartUpdate'
  179. || DataObject::get_one($this->ClassName)) {
  180. return;
  181. }
  182. parent::requireDefaultRecords();
  183. $requiredUpdate = new $this->ClassName();
  184. $requiredUpdate->StatusMessage = _t('SilvercartUpdate.STATUSMESSAGE_REMAINING');
  185. $requiredUpdate->write();
  186. $config = SilvercartConfig::getConfig();
  187. $config->SilvercartVersion;
  188. $config->SilvercartUpdateVersion;
  189. if (version_compare($config->SilvercartVersion, $requiredUpdate->SilvercartVersion, '>')
  190. || (version_compare($config->SilvercartVersion, $requiredUpdate->SilvercartVersion, '==')
  191. && $config->SilvercartUpdateVersion >= $requiredUpdate->SilvercartUpdateVersion)) {
  192. $requiredUpdate->skip();
  193. }
  194. }
  195. /**
  196. * Field labels for display in tables.
  197. *
  198. * @return array
  199. *
  200. * @author Sebastian Diel <sdiel@pixeltricks.de>
  201. * @since 29.03.2011
  202. */
  203. public function fieldLabels() {
  204. return array_merge(
  205. parent::fieldLabels(),
  206. array(
  207. 'SilvercartVersion' => _t('SilvercartUpdate.SILVERCARTVERSION'),
  208. 'SilvercartUpdateVersion' => _t('SilvercartUpdate.SILVERCARTUPDATEVERSION'),
  209. 'Status' => _t('SilvercartUpdate.STATUS'),
  210. 'StatusMessage' => _t('SilvercartUpdate.STATUSMESSAGE'),
  211. 'Description' => _t('SilvercartUpdate.DESCRIPTION'),
  212. 'TranslatedStatus' => _t('SilvercartUpdate.STATUS'),
  213. )
  214. );
  215. }
  216. /**
  217. * Summaryfields for display in tables.
  218. *
  219. * @return array
  220. *
  221. * @author Sebastian Diel <sdiel@pixeltricks.de>
  222. * @since 29.03.2011
  223. */
  224. public function summaryFields() {
  225. return array(
  226. 'SilvercartVersion' => _t('SilvercartUpdate.SILVERCARTVERSION'),
  227. 'SilvercartUpdateVersion' => _t('SilvercartUpdate.SILVERCARTUPDATEVERSION'),
  228. 'TranslatedStatus' => _t('SilvercartUpdate.STATUS'),
  229. 'StatusMessage' => _t('SilvercartUpdate.STATUSMESSAGE'),
  230. 'Description' => _t('SilvercartUpdate.DESCRIPTION'),
  231. );
  232. }
  233. /**
  234. * Returns the translation for the updates status.
  235. *
  236. * @return string
  237. */
  238. public function getTranslatedStatus() {
  239. return _t('SilvercartUpdate.STATUS_' . strtoupper($this->Status), $this->Status);
  240. }
  241. /**
  242. * Sets the update status to done.
  243. * Optionally, you can put a status message.
  244. *
  245. * @param string $statusMessage The status message to write with the status.
  246. *
  247. * @return void
  248. *
  249. * @author Sebastian Diel <sdiel@pixeltricks.de>
  250. * @since 29.03.2011
  251. */
  252. public function done($statusMessage = '') {
  253. $this->updateStatus('done', $statusMessage);
  254. $config = SilvercartConfig::getConfig();
  255. $config->SilvercartVersion = $this->SilvercartVersion;
  256. $config->SilvercartUpdateVersion = $this->SilvercartUpdateVersion;
  257. $config->write();
  258. }
  259. /**
  260. * Sets the update status to skipped.
  261. * Optionally, you can put a status message.
  262. *
  263. * @param string $statusMessage The status message to write with the status.
  264. *
  265. * @return void
  266. *
  267. * @author Sebastian Diel <sdiel@pixeltricks.de>
  268. * @since 29.03.2011
  269. */
  270. public function skip($statusMessage = '') {
  271. $this->updateStatus('skipped', $statusMessage);
  272. }
  273. /**
  274. * Sets the update status to skipped to prevent damage on existing data.
  275. * Optionally, you can put a status message.
  276. *
  277. * @param string $statusMessage The status message to write with the status.
  278. *
  279. * @return void
  280. *
  281. * @author Sebastian Diel <sdiel@pixeltricks.de>
  282. * @since 29.03.2011
  283. */
  284. public function skipToPreventDamage($statusMessage = '') {
  285. if (empty ($statusMessage)) {
  286. $statusMessage = _t('SilvercartUpdate.STATUSMESSAGE_SKIPPED_TO_PREVENT_DAMAGE');
  287. }
  288. $this->updateStatus('skipped', $statusMessage);
  289. $config = SilvercartConfig::getConfig();
  290. $config->SilvercartVersion = $this->SilvercartVersion;
  291. $config->SilvercartUpdateVersion = $this->SilvercartUpdateVersion;
  292. $config->write();
  293. }
  294. /**
  295. * Sets the update status to error.
  296. * Optionally, you can put a status message.
  297. *
  298. * @param string $statusMessage The status message to write with the status.
  299. *
  300. * @return void
  301. *
  302. * @author Sebastian Diel <sdiel@pixeltricks.de>
  303. * @since 29.03.2011
  304. */
  305. public function error($statusMessage = '') {
  306. $this->updateStatus('error', $statusMessage);
  307. }
  308. /**
  309. * Sets the update status.
  310. * Optionally, you can put a status message.
  311. *
  312. * @param string $status The status to write.
  313. * @param string $statusMessage The status message to write with the status.
  314. *
  315. * @return void
  316. *
  317. * @author Sebastian Diel <sdiel@pixeltricks.de>
  318. * @since 29.03.2011
  319. */
  320. public function updateStatus($status, $statusMessage = '') {
  321. if (empty($statusMessage)) {
  322. $statusMessage = _t('SilvercartUpdate.STATUSMESSAGE_' . strtoupper($status));
  323. }
  324. $this->Status = $status;
  325. $this->StatusMessage = $statusMessage;
  326. $this->write();
  327. }
  328. /**
  329. * Executes the update for a specific (update) version.
  330. * Base check whether the update is already done, skipped or still remaining.
  331. *
  332. * @return void
  333. *
  334. * @author Sebastian Diel <sdiel@pixeltricks.de>
  335. * @since 25.03.2011
  336. */
  337. public function doUpdate() {
  338. if (DataObject::get_one($this->ClassName, "`Status`='remaining'")) {
  339. $config = SilvercartConfig::getConfig();
  340. $config->SilvercartVersion;
  341. $config->SilvercartUpdateVersion;
  342. if (version_compare($config->SilvercartVersion, $this->SilvercartVersion, '>')
  343. || (version_compare($config->SilvercartVersion, $this->SilvercartVersion, '==')
  344. && $config->SilvercartUpdateVersion >= $this->SilvercartUpdateVersion)) {
  345. $this->skip();
  346. } elseif (!empty (self::$required_updates)) {
  347. ksort(self::$required_updates);
  348. foreach (self::$required_updates as $version => $updateVersions) {
  349. if (is_array($updateVersions)) {
  350. sort($updateVersions);
  351. } else {
  352. $updateVersions = array($updateVersions);
  353. }
  354. foreach ($updateVersions as $updateVersion) {
  355. if (is_numeric($updateVersion)) {
  356. $requiredUpdate = DataObject::get('SilvercartUpdate', sprintf("`Status`='remaining' AND `SilvercartVersion`='%s' AND `SilvercartUpdateVersion`='%s'", $version, $updateVersion));
  357. if ($requiredUpdate) {
  358. $requiredUpdate->doUpdate();
  359. }
  360. }
  361. }
  362. }
  363. if ($this->executeUpdate()) {
  364. $this->done();
  365. }
  366. } elseif ($this->executeUpdate()) {
  367. $this->done();
  368. } elseif ($this->Status == 'remaining') {
  369. $this->error();
  370. }
  371. }
  372. }
  373. /**
  374. * Executes all remaining updates.
  375. *
  376. * @return void
  377. *
  378. * @author Sebastian Diel <sdiel@pixeltricks.de>
  379. * @since 29.03.2011
  380. */
  381. public static function doAllUpdates() {
  382. foreach (DataObject::get('SilvercartUpdate', "`Status`='remaining'") as $update) {
  383. $update->doUpdate();
  384. }
  385. }
  386. }