PageRenderTime 34ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/Croogo/Console/Command/Task/UpgradeTask.php

https://github.com/kareypowell/croogo
PHP | 352 lines | 277 code | 24 blank | 51 comment | 36 complexity | 25e98c697c44b5e2cc8428c2ceb3f36c MD5 | raw file
  1. <?php
  2. /**
  3. * UpgradeTask
  4. *
  5. * @package Croogo.Croogo.Console.Command.Task
  6. * @since 1.5
  7. * @author Fahad Ibnay Heylaal <contact@fahad19.com>
  8. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  9. * @link http://www.croogo.org
  10. */
  11. class UpgradeTask extends AppShell {
  12. /**
  13. * maps 1.4 controllers to the current plugin
  14. */
  15. protected $_controllerMap = array(
  16. 'attachments' => 'file_manager',
  17. 'filemanager' => 'file_manager',
  18. 'contacts' => 'contacts',
  19. 'messages' => 'contacts',
  20. 'terms' => 'taxonomy',
  21. 'vocabularies' => 'taxonomy',
  22. 'types' => 'taxonomy',
  23. 'comments' => 'comments',
  24. 'acl_actions' => 'acl',
  25. 'acl_permissions' => 'acl',
  26. 'roles' => 'users',
  27. 'users' => 'users',
  28. 'nodes' => 'nodes',
  29. 'regions' => 'blocks',
  30. 'blocks' => 'blocks',
  31. 'languages' => 'settings',
  32. 'settings' => 'settings',
  33. 'menus' => 'menus',
  34. 'links' => 'menus',
  35. );
  36. /**
  37. * Setting instance
  38. */
  39. public $Setting = null;
  40. /**
  41. * Load Settings plugin and model
  42. */
  43. protected function _loadSettingsPlugin() {
  44. if (!CakePlugin::loaded('Settings')) {
  45. CakePlugin::load('Settings');
  46. }
  47. if (!$this->Setting) {
  48. $this->Setting = ClassRegistry::init('Settings.Setting');
  49. }
  50. }
  51. /**
  52. * getOptionParser
  53. */
  54. public function getOptionParser() {
  55. return parent::getOptionParser()
  56. ->addSubCommand('acl', array(
  57. 'help' => __d('croogo', 'Upgrade ACL database for core controllers.'),
  58. 'parser' => array(
  59. 'description' => __d('croogo',
  60. 'Upgrades the ACO hierarchy from 1.3/1.4 so it follows the default ' .
  61. 'behavior in normal CakePHP applications. The primary difference is ' .
  62. 'plugin controllers now are stored underneath its own Plugin ACO record, ' .
  63. 'whereas previous version assumes all Controllers belongs to the root ' .
  64. '\'controllers\' node.%s' .
  65. '<warning>Ensure that you have a backup of your aros, acos, and aros_acos table ' .
  66. 'before upgrading.</warning>', $this->nl(2)
  67. ),
  68. ),
  69. ))
  70. ->addSubCommand('settings', array(
  71. 'help' => __d('croogo', 'Create settings.json from database'),
  72. ))
  73. ->addSubCommand('bootstraps', array(
  74. 'help' => __d('croogo', 'Update Hook.bootstrap settings'),
  75. ))
  76. ->addSubCommand('links', array(
  77. 'help' => __d('croogo', 'Update Links in database'),
  78. ))
  79. ->addSubCommand('first_migrations', array(
  80. 'help' => __d('croogo', 'Create first migration records'),
  81. ))
  82. ->addSubCommand('migrations', array(
  83. 'help' => __d('croogo', 'Run all pending migrations for core plugins'),
  84. ))
  85. ->addSubCommand('all', array(
  86. 'help' => __d('croogo', 'Run all upgrade tasks'),
  87. ));
  88. }
  89. /**
  90. * convert settings.yml to settings.json
  91. */
  92. public function settings($keys = array()) {
  93. $this->_loadSettingsPlugin();
  94. if (file_exists(APP . 'Config' . DS . 'settings.json')) {
  95. $this->err(__d('croogo', '<warning>Config/settings.json already exist</warning>'));
  96. } else {
  97. $defaultPlugins = array(
  98. 'Settings', 'Comments', 'Contacts', 'Nodes', 'Meta', 'Menus',
  99. 'Users', 'Blocks', 'Taxonomy', 'FileManager', 'Ckeditor',
  100. );
  101. $Setting = $this->Setting;
  102. $setting = $Setting->findByKey('Hook.bootstraps');
  103. $plugins = explode(',', $setting['Setting']['value']);
  104. if (is_array($plugins)) {
  105. foreach ($plugins as $plugin) {
  106. if (!in_array($plugin, $defaultPlugins)) {
  107. $defaultPlugins[] = $plugin;
  108. }
  109. }
  110. }
  111. $Setting->write('Hook.bootstraps', join(',', $defaultPlugins));
  112. if ($version = file_get_contents(APP . 'VERSION.txt')) {
  113. $Setting->write('Croogo.version', $version);
  114. }
  115. $Setting->write('Access Control.multiColumn', '', array(
  116. 'title' => 'Allow login by username or email',
  117. 'input_type' => 'checkbox',
  118. 'editable' => true,
  119. ));
  120. $Setting->write('Access Control.multiRole', 0, array(
  121. 'title' => 'Enable Multiple Roles',
  122. 'input_type' => 'checkbox',
  123. 'editable' => true,
  124. ));
  125. $Setting->write('Access Control.rowLevel', 0, array(
  126. 'title' => 'Row Level Access Control',
  127. 'input_type' => 'checkbox',
  128. 'editable' => true,
  129. ));
  130. $Setting->write('Access Control.autoLoginDuration', '+1 week', array(
  131. 'title' => '"Remember Me" Cookie Lifetime',
  132. 'description' => 'Eg: +1 day, +1 week',
  133. 'input_type' => 'text',
  134. 'editable' => true,
  135. ));
  136. $this->out(__d('croogo', '<success>Config/settings.yml created based on `settings` table</success>'));
  137. }
  138. }
  139. /**
  140. * Upgrade ACL database
  141. */
  142. public function acl() {
  143. App::uses('AclUpgrade', 'Acl.Lib');
  144. if (!CakePlugin::loaded('Acl') || !class_exists('AclUpgrade')) {
  145. $this->err('AclUpgrade class not found or Acl plugin not loaded');
  146. $this->_stop();
  147. }
  148. $Upgrade = new AclUpgrade();
  149. if (($result = $Upgrade->upgrade()) !== true) {
  150. $this->err($result);
  151. } else {
  152. $this->out('<success>ACL Upgrade completed successfully</success>');
  153. }
  154. }
  155. public function links() {
  156. if (!CakePlugin::loaded('Menus')) {
  157. CakePlugin::load('Menus');
  158. }
  159. App::uses('View', 'View');
  160. App::uses('AppHelper', 'View/Helper');
  161. App::uses('MenusHelper', 'Menus.View/Helper');
  162. $Menus = new MenusHelper(new View());
  163. $Link = ClassRegistry::init('Menus.Link');
  164. $links = $Link->find('all', array('fields' => array('id', 'title', 'link')));
  165. $count = 0;
  166. foreach ($links as $link) {
  167. if (!strstr($link['Link']['link'], 'controller:')) {
  168. continue;
  169. }
  170. if (strstr($link['Link']['link'], 'plugin:')) {
  171. continue;
  172. }
  173. $url = $Menus->linkStringToArray($link['Link']['link']);
  174. if (isset($this->_controllerMap[$url['controller']])) {
  175. $url['plugin'] = $this->_controllerMap[$url['controller']];
  176. $linkString = $Menus->urlToLinkString($url);
  177. $Link->id = $link['Link']['id'];
  178. $this->out(__d('croogo', 'Updating Link %s', $Link->id));
  179. $this->warn(__d('croogo', '- %s', $link['Link']['link']));
  180. $this->success(__d('croogo', '+ %s', $linkString), 2);
  181. $Link->saveField('link', $linkString, false);
  182. $count++;
  183. }
  184. }
  185. $this->out(__d('croogo', 'Links updated: %d rows', $count));
  186. }
  187. /**
  188. * Upgrade Hook.bootstraps
  189. */
  190. public function bootstraps() {
  191. $this->_loadSettingsPlugin();
  192. $bootstraps = Configure::read('Hook.bootstraps');
  193. $plugins = explode(',', $bootstraps);
  194. $plugins = $this->_bootstrapReorderByDependency($plugins);
  195. $plugins = $this->_bootstrapSetupEditor($plugins);
  196. $this->Setting->write('Hook.bootstraps', join(',', $plugins));
  197. $this->out(__d('croogo', 'Hook.bootstraps updated'));
  198. }
  199. /**
  200. * Activate/move Wysiwyg before Ckeditor/Tinymce when appropriate
  201. */
  202. protected function _bootstrapSetupEditor($plugins) {
  203. $plugins = array_flip($plugins);
  204. if (empty($plugins['Ckeditor']) && empty($plugins['Tinymce'])) {
  205. return;
  206. }
  207. foreach ($plugins as $plugin => &$value) {
  208. $value *= 10;
  209. }
  210. if (!empty($plugins['Ckeditor']) && !empty($plugins['Tinymce'])) {
  211. $editor = ($plugins['Ckeditor'] < $plugins['Tinymce']) ? $plugins['Ckeditor'] : $plugins['Tinymce'];
  212. } elseif (!empty($plugins['Ckeditor'])) {
  213. $editor = $plugins['Ckeditor'];
  214. } else {
  215. $editor = $plugins['Tinymce'];
  216. }
  217. if (empty($plugins['Wysiwyg'])) {
  218. $plugins['Wysiwyg'] = $editor - 1;
  219. } else {
  220. if ($plugins['Wysiwyg'] >= $editor) {
  221. $plugins['Wysiwyg'] = $editor - 1;
  222. }
  223. }
  224. asort($plugins);
  225. $plugins = array_flip($plugins);
  226. return $plugins;
  227. }
  228. /**
  229. * Re-order plugins based on dependencies:
  230. * for e.g, Ckeditor depends on Wysiwyg
  231. * if in Hook.bootstraps Ckeditor appears before Wysiwyg,
  232. * we will reorder it so that it loads right after Wysiwyg
  233. */
  234. protected function _bootstrapReorderByDependency($plugins) {
  235. $pluginsOrdered = $plugins;
  236. foreach ($plugins as $p) {
  237. $jsonPath = APP . 'Plugin' . DS . $p . DS . 'Config' . DS . 'plugin.json';
  238. if (file_exists($jsonPath)) {
  239. $pluginData = json_decode(file_get_contents($jsonPath), true);
  240. if (isset($pluginData['dependencies']['plugins'])) {
  241. foreach ($pluginData['dependencies']['plugins'] as $d) {
  242. $k = array_search($p, $pluginsOrdered);
  243. $dk = array_search($d, $pluginsOrdered);
  244. if ($dk > $k) {
  245. unset($pluginsOrdered[$k]);
  246. $pluginsOrdered = array_slice($pluginsOrdered, 0, $k + 1, true) +
  247. array($p => $p) +
  248. array_slice($pluginsOrdered, $k + 1, count($pluginsOrdered) - 1, true);
  249. $pluginsOrdered = array_values($pluginsOrdered);
  250. }
  251. }
  252. }
  253. }
  254. }
  255. return $pluginsOrdered;
  256. }
  257. /**
  258. * create schema_migrations record for $plugin
  259. */
  260. protected function _createFirstMigration($plugin) {
  261. static $Migration;
  262. if (empty($Migration)) {
  263. $Migration = ClassRegistry::init(array(
  264. 'class' => 'AppModel',
  265. 'table' => 'schema_migrations',
  266. ));
  267. }
  268. $className = 'FirstMigration' . $plugin;
  269. $migration = $Migration->findByClass($className);
  270. if (!empty($migration)) {
  271. return true;
  272. }
  273. $Migration->create();
  274. return $Migration->save(array(
  275. 'class' => $className,
  276. 'type' => $plugin,
  277. ));
  278. }
  279. /**
  280. * Create default FirstMigration records for installations using croogo_data.sql
  281. */
  282. public function first_migrations() {
  283. foreach ((array)Configure::read('Core.corePlugins') as $plugin) {
  284. $result = $this->_createFirstMigration($plugin);
  285. if (!$result) {
  286. $this->error(sprintf('Unable to setup FirstMigration records for %s', $plugin));
  287. }
  288. }
  289. $this->success('FirstMigration default records created');
  290. }
  291. /**
  292. * Runs all available pending migrations for core plugins
  293. */
  294. public function migrations() {
  295. $CroogoPlugin = new CroogoPlugin();
  296. foreach ((array)Configure::read('Core.corePlugins') as $plugin) {
  297. $result = $CroogoPlugin->migrate($plugin);
  298. if (!$result) {
  299. $this->out($CroogoPlugin->migrationErrors);
  300. }
  301. }
  302. }
  303. /**
  304. * Runs all available subcommands
  305. */
  306. public function all() {
  307. foreach ($this->OptionParser->subcommands() as $command) {
  308. $name = $command->name();
  309. if ($name === 'all') {
  310. continue;
  311. }
  312. $this->out(__d('croogo', 'Upgrade "%s"', $name));
  313. $this->$name();
  314. }
  315. }
  316. public function execute() {
  317. if (empty($this->args)) {
  318. return $this->out($this->OptionParser->help());
  319. }
  320. $commands = array_keys($this->OptionParser->subcommands('croogo'));
  321. $command = $this->args[0];
  322. if ($command[0] != '_' && in_array($command, $commands)) {
  323. return $this->{$command}();
  324. } else {
  325. $this->out(__d('croogo', 'Command not recognized'));
  326. }
  327. }
  328. }