2 namespace Drush\Drupal\Commands\core;
4 use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
5 use Drupal\Core\Config\ConfigFactoryInterface;
6 use Drupal\Core\Entity\EntityTypeManagerInterface;
7 use Drupal\Core\Extension\ModuleHandlerInterface;
8 use Drupal\Core\Render\RendererInterface;
9 use Drush\Commands\DrushCommands;
10 use Drupal\views\Views;
11 use Drush\Utils\StringUtils;
13 class ViewsCommands extends DrushCommands
16 protected $configFactory;
18 protected $moduleHandler;
20 protected $entityTypeManager;
25 * ViewsCommands constructor.
26 * @param $moduleHandler
27 * @param $entityTypeManager
30 public function __construct(ConfigFactoryInterface $configFactory, ModuleHandlerInterface $moduleHandler, EntityTypeManagerInterface $entityTypeManager, RendererInterface $renderer)
32 $this->moduleHandler = $moduleHandler;
33 $this->entityTypeManager = $entityTypeManager;
34 $this->renderer = $renderer;
35 $this->configFactory = $configFactory;
39 * @return \Drupal\Core\Config\ConfigFactoryInterface
41 public function getConfigFactory()
43 return $this->configFactory;
47 * @return \Drupal\Core\Extension\ModuleHandlerInterface
49 public function getModuleHandler()
51 return $this->moduleHandler;
55 * @return \Drupal\Core\Entity\EntityTypeManagerInterface
57 public function getEntityTypeManager()
59 return $this->entityTypeManager;
63 * @return \Drupal\Core\Render\RendererInterface
65 public function getRenderer()
67 return $this->renderer;
71 * Set several Views settings to more developer-oriented values.
75 * @validate-module-enabled views
76 * @aliases vd,views-dev
81 'ui.show.listing_filters' => true,
82 'ui.show.master_display' => true,
83 'ui.show.advanced_column' => true,
84 'ui.always_live_preview' => false,
85 'ui.always_live_preview_button' => true,
86 'ui.show.preview_information' => true,
87 'ui.show.sql_query.enabled' => true,
88 'ui.show.sql_query.where' => 'above',
89 'ui.show.performance_statistics' => true,
90 'ui.show.additional_queries' => true,
93 $config = $this->getConfigFactory()->getEditable('views.settings');
95 foreach ($settings as $setting => $value) {
96 $config->set($setting, $value);
97 // Convert boolean values into a string to print.
98 if (is_bool($value)) {
99 $value = $value ? 'TRUE' : 'FALSE';
100 } // Wrap string values in quotes.
101 elseif (is_string($value)) {
102 $value = "\"$value\"";
104 $this->logger()->success(dt('!setting set to !value', [
105 '!setting' => $setting,
110 // Save the new config.
113 $this->logger()->success(dt('New views configuration saved.'));
117 * Get a list of all views in the system.
119 * @command views:list
121 * @option name A string contained in the view's name to filter the results with.
122 * @option tags A comma-separated list of views tags by which to filter the results.
123 * @option status Filter views by status. Choices: enabled, disabled.
125 * Show a list of all available views.
126 * @usage drush vl --name=blog
127 * Show a list of views which names contain 'blog'.
128 * @usage drush vl --tags=tag1,tag2
129 * Show a list of views tagged with 'tag1' or 'tag2'.
130 * @usage drush vl --status=enabled
131 * Show a list of enabled views.
132 * @table-style default
134 * machine-name: Machine name
136 * description: Description
139 * @default-fields machine-name,label,description,status
140 * @aliases vl,views-list
141 * @validate-module-enabled views
143 * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
145 public function vlist($options = ['name' => self::REQ, 'tags' => self::REQ, 'status' => self::REQ, 'format' => 'table'])
147 $disabled_views = [];
150 $views = $this->getEntityTypeManager()->getStorage('view')->loadMultiple();
152 // Get the --name option.
153 $name = StringUtils::csvToArray($options['name']);
154 $with_name = !empty($name) ? true : false;
156 // Get the --tags option.
157 $tags = \_convert_csv_to_array($options['tags']);
158 $with_tags = !empty($tags) ? true : false;
160 // Get the --status option. Store user input apart to reuse it after.
161 $status = $options['status'];
163 // @todo See https://github.com/consolidation/annotated-command/issues/53
164 if ($status && !in_array($status, ['enabled', 'disabled'])) {
165 throw new \Exception(dt('Invalid status: @status. Available options are "enabled" or "disabled"', ['@status' => $status]));
168 // Setup a row for each view.
169 foreach ($views as $view) {
170 // If options were specified, check that first mismatch push the loop to the
172 if ($with_name && !stristr($view->id(), $name[0])) {
175 if ($with_tags && !in_array($view->get('tag'), $tags)) {
179 $status_bool = $status == 'enabled';
180 if ($status && ($view->status() !== $status_bool)) {
185 'machine-name' => $view->id(),
186 'label' => $view->label(),
187 'description' => $view->get('description'),
188 'status' => $view->status() ? dt('Enabled') : dt('Disabled'),
189 'tag' => $view->get('tag'),
192 // Place the row in the appropriate array, so we can have disabled views at
194 if ($view->status()) {
195 $enabled_views[] = $row;
197 $disabled_views[] = $row;
201 // Sort alphabetically.
202 asort($disabled_views);
203 asort($enabled_views);
205 if (count($enabled_views) || count($disabled_views)) {
206 $rows = array_merge($enabled_views, $disabled_views);
207 return new RowsOfFields($rows);
209 $this->logger()->notice(dt('No views found.'));
214 * Execute a view and show a count of the results, or the rendered HTML.
216 * @command views:execute
218 * @param string $view_name The name of the view to execute.
219 * @param string $display The display ID to execute. If none specified, the default display will be used.
220 * @param string $view_args A comma delimited list of values, corresponding to contextual filters.
221 * @option count Display a count of the results instead of each row.
222 * @option show-admin-links Show contextual admin links in the rendered markup.
223 * @usage drush views:execute my_view
224 * Show the rendered HTML for the default display for the my_view View.
225 * @usage drush views:execute my_view page_1 3 --count
226 * Show a count of my_view:page_1 where the first contextual filter value is 3.
227 * @usage drush views:execute my_view page_1 3,foo
228 * Show the rendered HTML of my_view:page_1 where the first two contextual filter values are 3 and 'foo' respectively.
229 * @validate-entity-load view view_name
230 * @aliases vex,views-execute
231 * @validate-module-enabled views
235 public function execute($view_name, $display = null, $view_args = null, $options = ['count' => 0, 'show-admin-links' => false])
238 $view = Views::getView($view_name);
240 // Set the display and execute the view.
241 $view->setDisplay($display);
242 $view->preExecute(StringUtils::csvToArray($view_args));
245 if (empty($view->result)) {
246 $this->logger()->success(dt('No results returned for this View.'));
248 } elseif ($options['count']) {
249 drush_backend_set_result(count($view->result));
250 drush_print(count($view->result));
253 // Don't show admin links in markup by default.
254 $view->hide_admin_links = !$options['show-admin-links'];
255 $build = $view->preview();
256 return (string) $this->getRenderer()->renderPlain($build);
261 * Get a list of all Views and analyze warnings.
263 * @command views:analyze
264 * @todo Command has not been fully tested. How to generate a message?
268 * @aliases va,views-analyze
269 * @validate-module-enabled views
271 * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
273 public function analyze()
279 $views = $this->getEntityTypeManager()->getStorage('view')->loadMultiple();
281 if (!empty($views)) {
282 $analyzer = \Drupal::service('views.analyzer');
283 foreach ($views as $view_name => $view) {
284 $view = $view->getExecutable();
286 if ($messages = $analyzer->getMessages($view)) {
287 $rows[] = [$messages['type'], $messages['message']];
291 $this->logger()->success(dt('A total of @total views were analyzed and @messages problems were found.', ['@total' => count($views), '@messages' => $messages_count]));
292 return new RowsOfFields($rows);
294 $this->logger()->success(dt('There are no views to analyze'));
299 * Enable the specified views.
301 * @command views:enable
302 * @param string $views A comma delimited list of view names.
303 * @validate-entity-load view views
304 * @usage drush ven frontpage,taxonomy_term
305 * Enable the frontpage and taxonomy_term views.
306 * @aliases ven,views-enable
308 public function enable($views)
310 $view_names = StringUtils::csvToArray($views);
311 if ($views = $this->getEntityTypeManager()->getStorage('view')->loadMultiple($view_names)) {
312 foreach ($views as $view) {
317 $this->logger()->success(dt('!str enabled.', ['!str' => implode(', ', $view_names)]));
321 * Disable the specified views.
323 * @command views:disable
324 * @validate-entity-load view views
325 * @param string $views A comma delimited list of view names.
326 * @usage drush vdis frontpage taxonomy_term
327 * Disable the frontpage and taxonomy_term views.
328 * @aliases vdis,views-disable
330 public function disable($views)
332 $view_names = StringUtils::csvToArray($views);
333 if ($views = $this->getEntityTypeManager()->getStorage('view')->loadMultiple($view_names)) {
334 foreach ($views as $view) {
339 $this->logger()->success(dt('!str disabled.', ['!str' => implode(', ', $view_names)]));
343 * Adds a cache clear option for views.
345 * @hook on-event cache-clear
347 public function cacheClear(&$types, $include_bootstrapped_types)
349 if ($include_bootstrapped_types && $this->getModuleHandler()->moduleExists('views')) {
350 $types['views'] = 'views_invalidate_cache';