views.drush.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. <?php
  2. /**
  3. * @file
  4. * Drush integration for Views.
  5. *
  6. * Useful commands:
  7. * - drush cache-clear views - Clears the views specific caches.
  8. * - views-revert - Drush command to revert views overridden in the system.
  9. */
  10. /**
  11. * Implements hook_drush_help().
  12. */
  13. function views_drush_help($section) {
  14. switch ($section) {
  15. case 'drush:views-revert':
  16. $help = dt('Reverts views in the drupal installation that have been overriden. ');
  17. $help .= dt('If no view names are specified, you will be presented with a list of overridden views to choose from. ');
  18. $help .= dt('To revert all views, do not specify any view names, and choose the option "All" from the options presented.');
  19. return $help;
  20. case 'drush:views-list':
  21. return dt('Show a list of available views with information about them.');
  22. case 'drush:views-enable':
  23. return dt('Enable the specified views. Follow the command with a space delimited list of view names');
  24. case 'drush:views-disable':
  25. return dt('Disable the specified views. Follow the command with a space delimited list of view names');
  26. }
  27. }
  28. /**
  29. * Implements hook_drush_command().
  30. */
  31. function views_drush_command() {
  32. $items = array();
  33. $items['views-revert'] = array(
  34. 'callback' => 'views_revert_views',
  35. 'drupal dependencies' => array('views'),
  36. 'description' => 'Revert overridden views to their default state. Make sure to backup first.',
  37. 'arguments' => array(
  38. 'views' => 'A space delimited list of view names.',
  39. ),
  40. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
  41. 'aliases' => array('vr'),
  42. 'options' => array(
  43. 'all' => 'If provided, all views will be reverted.',
  44. ),
  45. 'examples' => array(
  46. 'drush vr archive' => 'Reverts the "archive" view.',
  47. 'drush rln archive frontpage' => 'Reverts the "archive" and "frontpage" view.',
  48. 'drush vr' => 'Will present you with a list of overridden views to choose from, and an option to revert all overridden views.',
  49. 'drush vr --all' => 'Will revert all overridden views.',
  50. ),
  51. );
  52. $items['views-dev'] = array(
  53. 'callback' => 'views_development_settings',
  54. 'drupal dependencies' => array('views'),
  55. 'description' => 'Set the Views settings to more developer-oriented values.',
  56. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
  57. 'aliases' => array('vd'),
  58. );
  59. $items['views-list'] = array(
  60. 'drupal dependencies' => array('views'),
  61. 'description' => 'Get a list of all views in the system.',
  62. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
  63. 'aliases' => array('vl'),
  64. 'options' => array(
  65. 'name' => 'String contained in view\'s name by which filter the results.',
  66. 'tags' => 'A comma-separated list of views tags by which to filter the results.',
  67. 'status' => 'Status of the views by which to filter the results. Choices: enabled, disabled.',
  68. 'type' => 'Type of the views by which to filter the results. Choices: normal, default or overridden.',
  69. ),
  70. 'examples' => array(
  71. 'drush vl' => 'Show a list of all available views.',
  72. 'drush vl --name=blog' => 'Show a list of views which names contain "blog".',
  73. 'drush vl --tags=tag1,tag2' => 'Show a list of views tagged with "tag1" or "tag2".',
  74. 'drush vl --status=enabled' => 'Show a list of enabled views.',
  75. 'drush vl --type=overridden' => 'Show a list of overridden views.',
  76. ),
  77. );
  78. $items['views-analyze'] = array(
  79. 'drupal dependencies' => array('views', 'views_ui'),
  80. 'description' => 'Get a list of all Views analyze warnings',
  81. 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
  82. 'aliases' => array('va'),
  83. );
  84. $items['views-enable'] = array(
  85. 'drupal dependencies' => array('views'),
  86. 'description' => 'Enable the specified views.',
  87. 'arguments' => array(
  88. 'views' => 'A space delimited list of view names.',
  89. ),
  90. 'aliases' => array('ven'),
  91. 'examples' => array(
  92. 'drush ven frontpage taxonomy_term' => 'Enable the frontpage and taxonomy_term views.',
  93. ),
  94. );
  95. $items['views-disable'] = array(
  96. 'drupal dependencies' => array('views'),
  97. 'description' => 'Disable the specified views.',
  98. 'arguments' => array(
  99. 'views' => 'A space delimited list of view names.',
  100. ),
  101. 'aliases' => array('vdis'),
  102. 'examples' => array(
  103. 'drush vdis frontpage taxonomy_term' => 'Disable the frontpage and taxonomy_term views.',
  104. ),
  105. );
  106. return $items;
  107. }
  108. /**
  109. * Callback function for views-revert command.
  110. */
  111. function views_revert_views() {
  112. $views = views_get_all_views();
  113. $i = 0;
  114. // The provided views names specified in the command.
  115. $viewnames = _convert_csv_to_array(func_get_args());
  116. // Find all overridden views.
  117. foreach ($views as $view) {
  118. if ($view->disabled) {
  119. continue;
  120. }
  121. if ($view->type == dt('Overridden')) {
  122. $overridden[$view->name] = $view->name;
  123. }
  124. }
  125. // If there are no overridden views in the system, report it.
  126. if (empty($overridden)) {
  127. drush_log(dt('There are no overridden views in the system.'), 'ok');
  128. }
  129. // If the user provided the "--all" option, revert all views.
  130. if (drush_get_option('all')) {
  131. $i = views_revert_allviews($views);
  132. }
  133. // If the user specified a list of views on the CLI, revert those.
  134. elseif (!empty($viewnames)) {
  135. foreach ($viewnames as $key => $viewname) {
  136. $is_overridden = array_key_exists($viewname, $overridden);
  137. // Check if the provided view name is in the system.
  138. if ($viewname && !array_key_exists($viewname, $views)) {
  139. drush_set_error(dt("'@viewname' view is not present in the system.", array('@viewname' => $viewname)));
  140. }
  141. // Check if the provided view is overridden.
  142. elseif (!$is_overridden) {
  143. drush_set_error(dt("The view specified '@viewname' is not overridden.", array('@viewname' => $viewname)));
  144. }
  145. // If the view is overriden, revert it.
  146. elseif ($is_overridden) {
  147. views_revert_view($views[$viewname]);
  148. $i++;
  149. }
  150. // We should never get here but well.
  151. else {
  152. drush_set_error(dt(
  153. "The view specified '@viewname' is not provided in code, and thus cannot be reverted.",
  154. array('@viewname' => $viewname)
  155. ));
  156. }
  157. }
  158. }
  159. // The user neither selected the "--all" option, nor provided a list of views
  160. // to revert. Prompt the user.
  161. else {
  162. // List of choices for the user.
  163. $overridden['all'] = dt('Revert all overridden views');
  164. // Add a choice at the end.
  165. $choice = drush_choice($overridden, 'Enter a number to choose which view to revert.', '!key');
  166. // Prompt the user.
  167. if ($choice !== FALSE) {
  168. // Revert all views option.
  169. if ($choice == 'all') {
  170. $i = views_revert_allviews($views);
  171. }
  172. // Else the user specified a single view.
  173. else {
  174. views_revert_view($views[$choice]);
  175. $i++;
  176. }
  177. }
  178. }
  179. // Final results output.
  180. if ($i == 0) {
  181. drush_log(dt('No views were reverted.'), 'ok');
  182. }
  183. else {
  184. drush_log(dt('Reverted a total of @count views.', array('@count' => $i)), 'ok');
  185. }
  186. }
  187. /**
  188. * Reverts all views.
  189. *
  190. * @param array $views
  191. * All views in the system as provided by views_get_all_views().
  192. */
  193. function views_revert_allviews($views) {
  194. $i = 0;
  195. foreach ($views as $view) {
  196. if ($view->disabled) {
  197. continue;
  198. }
  199. if ($view->type == t('Overridden')) {
  200. views_revert_view($view);
  201. $i++;
  202. }
  203. }
  204. return $i;
  205. }
  206. /**
  207. * Revert a specified view.
  208. *
  209. * Checks on wether or not the view is overridden is handled in
  210. * views_revert_views_revert(). We perform a check here anyway in case someone
  211. * somehow calls this function on their own...
  212. *
  213. * @param object $view
  214. * The view object to be reverted.
  215. */
  216. function views_revert_view($view) {
  217. // Check anyway just in case.
  218. if ($view->type == t('Overridden')) {
  219. // Revert the view.
  220. $view->delete();
  221. // Clear its cache.
  222. ctools_include('object-cache');
  223. ctools_object_cache_clear('view', $view->name);
  224. // Give feedback.
  225. $message = dt("Reverted the view '@viewname'", array('@viewname' => $view->name));
  226. drush_log($message, 'success');
  227. // Reverted one more view.
  228. }
  229. else {
  230. drush_set_error(dt("The view '@viewname' is not overridden.", array('@viewname' => $view->name)));
  231. }
  232. }
  233. /**
  234. * Change the settings to a more developer oriented value.
  235. */
  236. function views_development_settings() {
  237. variable_set('views_ui_show_listing_filters', TRUE);
  238. variable_set('views_ui_show_master_display', TRUE);
  239. variable_set('views_ui_show_advanced_column', TRUE);
  240. variable_set('views_ui_always_live_preview', FALSE);
  241. variable_set('views_ui_always_live_preview_button', TRUE);
  242. variable_set('views_ui_show_preview_information', TRUE);
  243. variable_set('views_ui_show_sql_query', TRUE);
  244. variable_set('views_ui_show_performance_statistics', TRUE);
  245. variable_set('views_show_additional_queries', TRUE);
  246. variable_set('views_devel_output', TRUE);
  247. variable_set('views_devel_region', 'message');
  248. variable_set('views_ui_display_embed', TRUE);
  249. $message = dt("Setup the new views settings.");
  250. drush_log($message, 'success');
  251. }
  252. /**
  253. * Callback function for views-list command.
  254. */
  255. function drush_views_list() {
  256. // Initialize stuff.
  257. $rows = array();
  258. $disabled_views = array();
  259. $enabled_views = array();
  260. $overridden = 0;
  261. $indb = 0;
  262. $incode = 0;
  263. $disabled = 0;
  264. $total = 0;
  265. $views = views_get_all_views();
  266. // Get the --name option.
  267. // @todo Take into account the case off a comma-separated list of names.
  268. $name = drush_get_option_list('name');
  269. $with_name = !empty($name) ? TRUE : FALSE;
  270. // Get the --tags option.
  271. $tags = drush_get_option_list('tags');
  272. $with_tags = !empty($tags) ? TRUE : FALSE;
  273. // Get the --status option. Store user input appart to reuse it after.
  274. $status_opt = drush_get_option_list('status');
  275. // Use the same logic than $view->disabled.
  276. if (in_array('disabled', $status_opt)) {
  277. $status = TRUE;
  278. $with_status = TRUE;
  279. }
  280. elseif (in_array('enabled', $status_opt)) {
  281. $status = FALSE;
  282. $with_status = TRUE;
  283. }
  284. else {
  285. $status = NULL;
  286. // Wrong or empty --status option.
  287. $with_status = FALSE;
  288. }
  289. // Get the --type option.
  290. $type = drush_get_option_list('type');
  291. // Use the same logic than $view->type.
  292. $with_type = FALSE;
  293. if (in_array('normal', $type) || in_array('default', $type)|| in_array('overridden', $type)) {
  294. $with_type = TRUE;
  295. }
  296. // Set the table headers.
  297. $header = array(
  298. dt('Machine name'),
  299. dt('Description'),
  300. dt('Type'),
  301. dt('Status'),
  302. dt('Tag'),
  303. );
  304. // Setup a row for each view.
  305. foreach ($views as $id => $view) {
  306. // If options were specified, check that first mismatch push the loop to
  307. // the next view.
  308. if ($with_tags && !in_array($view->tag, $tags)) {
  309. continue;
  310. }
  311. if ($with_status && !$view->disabled == $status) {
  312. continue;
  313. }
  314. if ($with_type && strtolower($view->type) !== $type[0]) {
  315. continue;
  316. }
  317. if ($with_name && !stristr($view->name, $name[0])) {
  318. continue;
  319. }
  320. $row = array();
  321. // Each row entry should be in the same order as the header.
  322. $row[] = $view->name;
  323. $row[] = $view->description;
  324. $row[] = $view->type;
  325. $row[] = $view->disabled ? dt('Disabled') : dt('Enabled');
  326. $row[] = $view->tag;
  327. // Place the row in the appropiate array so we can have disabled views at
  328. // the bottom.
  329. if ($view->disabled) {
  330. $disabled_views[] = $row;
  331. }
  332. else {
  333. $enabled_views[] = $row;
  334. }
  335. unset($row);
  336. // Gather some statistics.
  337. switch ($view->type) {
  338. case dt('Normal'):
  339. $indb++;
  340. break;
  341. case dt('Overridden'):
  342. $overridden++;
  343. break;
  344. case dt('Default'):
  345. $incode++;
  346. break;
  347. }
  348. $total++;
  349. }
  350. $disabled = count($disabled_views);
  351. // Sort alphabeticaly.
  352. asort($disabled_views);
  353. asort($enabled_views);
  354. // If options were used.
  355. $summary = "";
  356. if ($with_name || $with_tags || $with_status || $with_type) {
  357. $summary = "Views";
  358. if ($with_name) {
  359. $summary .= " named $name[0]";
  360. }
  361. if ($with_tags) {
  362. $tags = implode(" or ", $tags);
  363. $summary .= " tagged $tags";
  364. }
  365. if ($with_status) {
  366. $status_opt = implode("", $status_opt);
  367. $summary .= " which status is '$status_opt'";
  368. }
  369. if ($with_type) {
  370. $type = ucfirst($type[0]);
  371. $summary .= " of type '$type'";
  372. }
  373. }
  374. if (!empty($summary)) {
  375. drush_print($summary . "\n");
  376. }
  377. // Print all rows as a table.
  378. if ($total > 0) {
  379. $rows = array_merge($enabled_views, $disabled_views);
  380. // Put the headers as first row.
  381. array_unshift($rows, $header);
  382. drush_print_table($rows, TRUE);
  383. }
  384. // Print the statistics messages.
  385. drush_print(dt("A total of @total views were found in this Drupal installation:", array('@total' => $total)));
  386. drush_print(dt(" @indb views reside only in the database", array('@indb' => $indb)));
  387. drush_print(dt(" @over views are overridden", array('@over' => $overridden)));
  388. drush_print(dt(" @incode views are in their default state", array('@incode' => $incode)));
  389. drush_print(dt(" @dis views are disabled\n", array('@dis' => $disabled)));
  390. }
  391. /**
  392. * Analyze all installed views.
  393. */
  394. function drush_views_analyze() {
  395. views_include('analyze');
  396. $messages_count = 0;
  397. $total = 0;
  398. foreach (views_get_all_views() as $view_name => $view) {
  399. $total++;
  400. if ($messages = views_analyze_view($view)) {
  401. drush_print($view_name);
  402. foreach ($messages as $message) {
  403. $messages_count++;
  404. drush_print($message['type'] . ': ' . $message['message'], 2);
  405. }
  406. }
  407. }
  408. drush_log(dt('A total of @total views were analyzed and @messages problems were found.', array('@total' => $total, '@messages' => $messages_count)), 'ok');
  409. }
  410. /**
  411. * Enables views.
  412. */
  413. function drush_views_enable() {
  414. $viewnames = _convert_csv_to_array(func_get_args());
  415. // Return early if no view names were specified.
  416. if (empty($viewnames)) {
  417. return drush_set_error(dt('Please specify a space delimited list of view names to enable'));
  418. }
  419. _views_drush_changestatus($viewnames, FALSE);
  420. }
  421. /**
  422. * Disables views.
  423. */
  424. function drush_views_disable() {
  425. $viewnames = _convert_csv_to_array(func_get_args());
  426. // Return early if no view names were specified.
  427. if (empty($viewnames)) {
  428. return drush_set_error(dt('Please specify a space delimited list of view names to disable'));
  429. }
  430. _views_drush_changestatus($viewnames, TRUE);
  431. }
  432. /**
  433. * Helper function to enable / disable views.
  434. *
  435. * @param array $viewnames
  436. * Names of the views to process.
  437. * @param bool $status
  438. * TRUE to disable or FALSE to enable the view.
  439. */
  440. function _views_drush_changestatus($viewnames = array(), $status = NULL) {
  441. if ($status !== NULL && !empty($viewnames)) {
  442. $changed = FALSE;
  443. $processed = $status ? dt('disabled') : dt('enabled');
  444. $views_status = variable_get('views_defaults', array());
  445. foreach ($viewnames as $key => $viewname) {
  446. if ($views_status[$viewname] !== $status) {
  447. $views_status[$viewname] = $status;
  448. $changed = TRUE;
  449. drush_log(dt("The view '!name' has been !processed", array('!name' => $viewname, '!processed' => $processed)), 'success');
  450. }
  451. else {
  452. drush_set_error(dt("The view '!name' is already !processed", array('!name' => $viewname, '!processed' => $processed)));
  453. }
  454. }
  455. // If we made changes to views status, save them and clear caches.
  456. if ($changed) {
  457. variable_set('views_defaults', $views_status);
  458. views_invalidate_cache();
  459. drush_log(dt("Views cache was cleared"), 'ok');
  460. drush_log(dt("Menu cache is set to be rebuilt on the next request."), 'ok');
  461. }
  462. }
  463. }
  464. /**
  465. * Adds a cache clear option for views.
  466. *
  467. * @param array $types
  468. * The list of cache types that are available.
  469. */
  470. function views_drush_cache_clear(&$types) {
  471. $types['views'] = 'views_invalidate_cache';
  472. }