views.drush.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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. $args = func_get_args();
  113. // The provided views names specified in the command.
  114. $viewnames = _convert_csv_to_array($args);
  115. $views = views_get_all_views();
  116. $i = 0;
  117. // Find all overridden views.
  118. foreach ($views as $view) {
  119. if ($view->disabled) {
  120. continue;
  121. }
  122. if ($view->type == dt('Overridden')) {
  123. $overridden[$view->name] = $view->name;
  124. }
  125. }
  126. // If there are no overridden views in the system, report it.
  127. if (empty($overridden)) {
  128. drush_log(dt('There are no overridden views in the system.'), 'ok');
  129. }
  130. // If the user provided the "--all" option, revert all views.
  131. if (drush_get_option('all')) {
  132. $i = views_revert_allviews($views);
  133. }
  134. // If the user specified a list of views on the CLI, revert those.
  135. elseif (!empty($viewnames)) {
  136. foreach ($viewnames as $key => $viewname) {
  137. $is_overridden = array_key_exists($viewname, $overridden);
  138. // Check if the provided view name is in the system.
  139. if ($viewname && !array_key_exists($viewname, $views)) {
  140. drush_set_error(dt("'@viewname' view is not present in the system.", array('@viewname' => $viewname)));
  141. }
  142. // Check if the provided view is overridden.
  143. elseif (!$is_overridden) {
  144. drush_set_error(dt("The view specified '@viewname' is not overridden.", array('@viewname' => $viewname)));
  145. }
  146. // If the view is overriden, revert it.
  147. elseif ($is_overridden) {
  148. views_revert_view($views[$viewname]);
  149. $i++;
  150. }
  151. // We should never get here but well.
  152. else {
  153. drush_set_error(dt(
  154. "The view specified '@viewname' is not provided in code, and thus cannot be reverted.",
  155. array('@viewname' => $viewname)
  156. ));
  157. }
  158. }
  159. }
  160. // The user neither selected the "--all" option, nor provided a list of views
  161. // to revert. Prompt the user.
  162. else {
  163. // List of choices for the user.
  164. $overridden['all'] = dt('Revert all overridden views');
  165. // Add a choice at the end.
  166. $choice = drush_choice($overridden, 'Enter a number to choose which view to revert.', '!key');
  167. // Prompt the user.
  168. if ($choice !== FALSE) {
  169. // Revert all views option.
  170. if ($choice == 'all') {
  171. $i = views_revert_allviews($views);
  172. }
  173. // Else the user specified a single view.
  174. else {
  175. views_revert_view($views[$choice]);
  176. $i++;
  177. }
  178. }
  179. }
  180. // Final results output.
  181. if ($i == 0) {
  182. drush_log(dt('No views were reverted.'), 'ok');
  183. }
  184. else {
  185. drush_log(dt('Reverted a total of @count views.', array('@count' => $i)), 'ok');
  186. }
  187. }
  188. /**
  189. * Reverts all views.
  190. *
  191. * @param array $views
  192. * All views in the system as provided by views_get_all_views().
  193. */
  194. function views_revert_allviews($views) {
  195. $i = 0;
  196. foreach ($views as $view) {
  197. if ($view->disabled) {
  198. continue;
  199. }
  200. if ($view->type == t('Overridden')) {
  201. views_revert_view($view);
  202. $i++;
  203. }
  204. }
  205. return $i;
  206. }
  207. /**
  208. * Revert a specified view.
  209. *
  210. * Checks on wether or not the view is overridden is handled in
  211. * views_revert_views_revert(). We perform a check here anyway in case someone
  212. * somehow calls this function on their own...
  213. *
  214. * @param object $view
  215. * The view object to be reverted.
  216. */
  217. function views_revert_view($view) {
  218. // Check anyway just in case.
  219. if ($view->type == t('Overridden')) {
  220. // Revert the view.
  221. $view->delete();
  222. // Clear its cache.
  223. ctools_include('object-cache');
  224. ctools_object_cache_clear('view', $view->name);
  225. // Give feedback.
  226. $message = dt("Reverted the view '@viewname'", array('@viewname' => $view->name));
  227. drush_log($message, 'success');
  228. // Reverted one more view.
  229. }
  230. else {
  231. drush_set_error(dt("The view '@viewname' is not overridden.", array('@viewname' => $view->name)));
  232. }
  233. }
  234. /**
  235. * Change the settings to a more developer oriented value.
  236. */
  237. function views_development_settings() {
  238. variable_set('views_ui_show_listing_filters', TRUE);
  239. variable_set('views_ui_show_master_display', TRUE);
  240. variable_set('views_ui_show_advanced_column', TRUE);
  241. variable_set('views_ui_always_live_preview', FALSE);
  242. variable_set('views_ui_always_live_preview_button', TRUE);
  243. variable_set('views_ui_show_preview_information', TRUE);
  244. variable_set('views_ui_show_sql_query', TRUE);
  245. variable_set('views_ui_show_performance_statistics', TRUE);
  246. variable_set('views_show_additional_queries', TRUE);
  247. variable_set('views_devel_output', TRUE);
  248. variable_set('views_devel_region', 'message');
  249. variable_set('views_ui_display_embed', TRUE);
  250. $message = dt("Setup the new views settings.");
  251. drush_log($message, 'success');
  252. }
  253. /**
  254. * Callback function for views-list command.
  255. */
  256. function drush_views_list() {
  257. // Initialize stuff.
  258. $rows = array();
  259. $disabled_views = array();
  260. $enabled_views = array();
  261. $overridden = 0;
  262. $indb = 0;
  263. $incode = 0;
  264. $disabled = 0;
  265. $total = 0;
  266. $views = views_get_all_views();
  267. // Get the --name option.
  268. // @todo Take into account the case off a comma-separated list of names.
  269. $name = drush_get_option_list('name');
  270. $with_name = !empty($name) ? TRUE : FALSE;
  271. // Get the --tags option.
  272. $tags = drush_get_option_list('tags');
  273. $with_tags = !empty($tags) ? TRUE : FALSE;
  274. // Get the --status option. Store user input appart to reuse it after.
  275. $status_opt = drush_get_option_list('status');
  276. // Use the same logic than $view->disabled.
  277. if (in_array('disabled', $status_opt)) {
  278. $status = TRUE;
  279. $with_status = TRUE;
  280. }
  281. elseif (in_array('enabled', $status_opt)) {
  282. $status = FALSE;
  283. $with_status = TRUE;
  284. }
  285. else {
  286. $status = NULL;
  287. // Wrong or empty --status option.
  288. $with_status = FALSE;
  289. }
  290. // Get the --type option.
  291. $type = drush_get_option_list('type');
  292. // Use the same logic than $view->type.
  293. $with_type = FALSE;
  294. if (in_array('normal', $type) || in_array('default', $type)|| in_array('overridden', $type)) {
  295. $with_type = TRUE;
  296. }
  297. // Set the table headers.
  298. $header = array(
  299. dt('Machine name'),
  300. dt('Description'),
  301. dt('Type'),
  302. dt('Status'),
  303. dt('Tag'),
  304. );
  305. // Setup a row for each view.
  306. foreach ($views as $id => $view) {
  307. // If options were specified, check that first mismatch push the loop to
  308. // the next view.
  309. if ($with_tags && !in_array($view->tag, $tags)) {
  310. continue;
  311. }
  312. if ($with_status && !$view->disabled == $status) {
  313. continue;
  314. }
  315. if ($with_type && strtolower($view->type) !== $type[0]) {
  316. continue;
  317. }
  318. if ($with_name && !stristr($view->name, $name[0])) {
  319. continue;
  320. }
  321. $row = array();
  322. // Each row entry should be in the same order as the header.
  323. $row[] = $view->name;
  324. $row[] = $view->description;
  325. $row[] = $view->type;
  326. $row[] = $view->disabled ? dt('Disabled') : dt('Enabled');
  327. $row[] = $view->tag;
  328. // Place the row in the appropiate array so we can have disabled views at
  329. // the bottom.
  330. if ($view->disabled) {
  331. $disabled_views[] = $row;
  332. }
  333. else {
  334. $enabled_views[] = $row;
  335. }
  336. unset($row);
  337. // Gather some statistics.
  338. switch ($view->type) {
  339. case dt('Normal'):
  340. $indb++;
  341. break;
  342. case dt('Overridden'):
  343. $overridden++;
  344. break;
  345. case dt('Default'):
  346. $incode++;
  347. break;
  348. }
  349. $total++;
  350. }
  351. $disabled = count($disabled_views);
  352. // Sort alphabeticaly.
  353. asort($disabled_views);
  354. asort($enabled_views);
  355. // If options were used.
  356. $summary = "";
  357. if ($with_name || $with_tags || $with_status || $with_type) {
  358. $summary = "Views";
  359. if ($with_name) {
  360. $summary .= " named $name[0]";
  361. }
  362. if ($with_tags) {
  363. $tags = implode(" or ", $tags);
  364. $summary .= " tagged $tags";
  365. }
  366. if ($with_status) {
  367. $status_opt = implode("", $status_opt);
  368. $summary .= " which status is '$status_opt'";
  369. }
  370. if ($with_type) {
  371. $type = ucfirst($type[0]);
  372. $summary .= " of type '$type'";
  373. }
  374. }
  375. if (!empty($summary)) {
  376. drush_print($summary . "\n");
  377. }
  378. // Print all rows as a table.
  379. if ($total > 0) {
  380. $rows = array_merge($enabled_views, $disabled_views);
  381. // Put the headers as first row.
  382. array_unshift($rows, $header);
  383. drush_print_table($rows, TRUE);
  384. }
  385. // Print the statistics messages.
  386. drush_print(dt("A total of @total views were found in this Drupal installation:", array('@total' => $total)));
  387. drush_print(dt(" @indb views reside only in the database", array('@indb' => $indb)));
  388. drush_print(dt(" @over views are overridden", array('@over' => $overridden)));
  389. drush_print(dt(" @incode views are in their default state", array('@incode' => $incode)));
  390. drush_print(dt(" @dis views are disabled\n", array('@dis' => $disabled)));
  391. }
  392. /**
  393. * Analyze all installed views.
  394. */
  395. function drush_views_analyze() {
  396. views_include('analyze');
  397. $messages_count = 0;
  398. $total = 0;
  399. foreach (views_get_all_views() as $view_name => $view) {
  400. $total++;
  401. if ($messages = views_analyze_view($view)) {
  402. drush_print($view_name);
  403. foreach ($messages as $message) {
  404. $messages_count++;
  405. drush_print($message['type'] . ': ' . $message['message'], 2);
  406. }
  407. }
  408. }
  409. drush_log(dt('A total of @total views were analyzed and @messages problems were found.', array('@total' => $total, '@messages' => $messages_count)), 'ok');
  410. }
  411. /**
  412. * Enables views.
  413. */
  414. function drush_views_enable() {
  415. $viewnames = _convert_csv_to_array(func_get_args());
  416. // Return early if no view names were specified.
  417. if (empty($viewnames)) {
  418. return drush_set_error(dt('Please specify a space delimited list of view names to enable'));
  419. }
  420. _views_drush_changestatus($viewnames, FALSE);
  421. }
  422. /**
  423. * Disables views.
  424. */
  425. function drush_views_disable() {
  426. $viewnames = _convert_csv_to_array(func_get_args());
  427. // Return early if no view names were specified.
  428. if (empty($viewnames)) {
  429. return drush_set_error(dt('Please specify a space delimited list of view names to disable'));
  430. }
  431. _views_drush_changestatus($viewnames, TRUE);
  432. }
  433. /**
  434. * Helper function to enable / disable views.
  435. *
  436. * @param array $viewnames
  437. * Names of the views to process.
  438. * @param bool $status
  439. * TRUE to disable or FALSE to enable the view.
  440. */
  441. function _views_drush_changestatus($viewnames = array(), $status = NULL) {
  442. if ($status !== NULL && !empty($viewnames)) {
  443. $changed = FALSE;
  444. $processed = $status ? dt('disabled') : dt('enabled');
  445. $views_status = variable_get('views_defaults', array());
  446. foreach ($viewnames as $key => $viewname) {
  447. if ($views_status[$viewname] !== $status) {
  448. $views_status[$viewname] = $status;
  449. $changed = TRUE;
  450. drush_log(dt("The view '!name' has been !processed", array('!name' => $viewname, '!processed' => $processed)), 'success');
  451. }
  452. else {
  453. drush_set_error(dt("The view '!name' is already !processed", array('!name' => $viewname, '!processed' => $processed)));
  454. }
  455. }
  456. // If we made changes to views status, save them and clear caches.
  457. if ($changed) {
  458. variable_set('views_defaults', $views_status);
  459. views_invalidate_cache();
  460. drush_log(dt("Views cache was cleared"), 'ok');
  461. drush_log(dt("Menu cache is set to be rebuilt on the next request."), 'ok');
  462. }
  463. }
  464. }
  465. /**
  466. * Adds a cache clear option for views.
  467. *
  468. * @param array $types
  469. * The list of cache types that are available.
  470. */
  471. function views_drush_cache_clear(&$types) {
  472. $types['views'] = 'views_invalidate_cache';
  473. }