Views.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. <?php
  2. namespace Drupal\views;
  3. /**
  4. * Static service container wrapper for views.
  5. */
  6. class Views {
  7. /**
  8. * The translation manager.
  9. *
  10. * @var \Drupal\Core\StringTranslation\TranslationInterface
  11. */
  12. protected static $translationManager;
  13. /**
  14. * A static cache for handler types data.
  15. *
  16. * @var array
  17. */
  18. protected static $handlerTypes;
  19. /**
  20. * A list of all available views plugin types.
  21. *
  22. * @var array
  23. */
  24. protected static $plugins = [
  25. 'access' => 'plugin',
  26. 'area' => 'handler',
  27. 'argument' => 'handler',
  28. 'argument_default' => 'plugin',
  29. 'argument_validator' => 'plugin',
  30. 'cache' => 'plugin',
  31. 'display_extender' => 'plugin',
  32. 'display' => 'plugin',
  33. 'exposed_form' => 'plugin',
  34. 'field' => 'handler',
  35. 'filter' => 'handler',
  36. 'join' => 'plugin',
  37. 'pager' => 'plugin',
  38. 'query' => 'plugin',
  39. 'relationship' => 'handler',
  40. 'row' => 'plugin',
  41. 'sort' => 'handler',
  42. 'style' => 'plugin',
  43. 'wizard' => 'plugin',
  44. ];
  45. /**
  46. * Returns the views data service.
  47. *
  48. * @return \Drupal\views\ViewsData
  49. * Returns a views data cache object.
  50. */
  51. public static function viewsData() {
  52. return \Drupal::service('views.views_data');
  53. }
  54. /**
  55. * Returns the views data helper service.
  56. *
  57. * @return \Drupal\views\ViewsDataHelper
  58. * Returns a views data helper object.
  59. */
  60. public static function viewsDataHelper() {
  61. return \Drupal::service('views.views_data_helper');
  62. }
  63. /**
  64. * Returns the view executable factory service.
  65. *
  66. * @return \Drupal\views\ViewExecutableFactory
  67. * Returns a views executable factory.
  68. */
  69. public static function executableFactory() {
  70. return \Drupal::service('views.executable');
  71. }
  72. /**
  73. * Returns the view analyzer.
  74. *
  75. * @return \Drupal\views\Analyzer
  76. * Returns a view analyzer object.
  77. */
  78. public static function analyzer() {
  79. return \Drupal::service('views.analyzer');
  80. }
  81. /**
  82. * Returns the plugin manager for a certain views plugin type.
  83. *
  84. * @param string $type
  85. * The plugin type, for example filter.
  86. *
  87. * @return \Drupal\views\Plugin\ViewsPluginManager
  88. */
  89. public static function pluginManager($type) {
  90. return \Drupal::service('plugin.manager.views.' . $type);
  91. }
  92. /**
  93. * Returns the plugin manager for a certain views handler type.
  94. *
  95. * @return \Drupal\views\Plugin\ViewsHandlerManager
  96. */
  97. public static function handlerManager($type) {
  98. return \Drupal::service('plugin.manager.views.' . $type);
  99. }
  100. /**
  101. * Loads a view from configuration and returns its executable object.
  102. *
  103. * @param string $id
  104. * The view ID to load.
  105. *
  106. * @return \Drupal\views\ViewExecutable
  107. * A view executable instance, from the loaded entity.
  108. */
  109. public static function getView($id) {
  110. $view = \Drupal::service('entity.manager')->getStorage('view')->load($id);
  111. if ($view) {
  112. return static::executableFactory()->get($view);
  113. }
  114. }
  115. /**
  116. * Fetches a list of all base tables available
  117. *
  118. * @param string $type
  119. * Either 'display', 'style' or 'row'.
  120. * @param string $key
  121. * For style plugins, this is an optional type to restrict to. May be
  122. * 'normal', 'summary', 'feed' or others based on the needs of the display.
  123. * @param array $base
  124. * An array of possible base tables.
  125. *
  126. * @return
  127. * A keyed array of in the form of 'base_table' => 'Description'.
  128. */
  129. public static function fetchPluginNames($type, $key = NULL, array $base = []) {
  130. $definitions = static::pluginManager($type)->getDefinitions();
  131. $plugins = [];
  132. foreach ($definitions as $id => $plugin) {
  133. // Skip plugins that don't conform to our key, if they have one.
  134. if ($key && isset($plugin['display_types']) && !in_array($key, $plugin['display_types'])) {
  135. continue;
  136. }
  137. if (empty($plugin['no_ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) {
  138. $plugins[$id] = $plugin['title'];
  139. }
  140. }
  141. if (!empty($plugins)) {
  142. asort($plugins);
  143. return $plugins;
  144. }
  145. return $plugins;
  146. }
  147. /**
  148. * Gets all the views plugin definitions.
  149. *
  150. * @return array
  151. * An array of plugin definitions for all types.
  152. */
  153. public static function getPluginDefinitions() {
  154. $plugins = [];
  155. foreach (ViewExecutable::getPluginTypes() as $plugin_type) {
  156. $plugins[$plugin_type] = static::pluginManager($plugin_type)->getDefinitions();
  157. }
  158. return $plugins;
  159. }
  160. /**
  161. * Gets enabled display extenders.
  162. */
  163. public static function getEnabledDisplayExtenders() {
  164. $enabled = array_filter((array) \Drupal::config('views.settings')->get('display_extenders'));
  165. return array_combine($enabled, $enabled);
  166. }
  167. /**
  168. * Return a list of all view IDs and display IDs that have a particular
  169. * setting in their display's plugin settings.
  170. *
  171. * @param string $type
  172. * A flag from the display plugin definitions (e.g, 'uses_menu_links').
  173. *
  174. * @return array
  175. * A list of arrays containing the $view_id and $display_id.
  176. * @code
  177. * array(
  178. * array($view_id, $display_id),
  179. * array($view_id, $display_id),
  180. * );
  181. * @endcode
  182. */
  183. public static function getApplicableViews($type) {
  184. // Get all display plugins which provides the type.
  185. $display_plugins = static::pluginManager('display')->getDefinitions();
  186. $plugin_ids = [];
  187. foreach ($display_plugins as $id => $definition) {
  188. if (!empty($definition[$type])) {
  189. $plugin_ids[$id] = $id;
  190. }
  191. }
  192. $entity_ids = \Drupal::entityQuery('view')
  193. ->condition('status', TRUE)
  194. ->condition("display.*.display_plugin", $plugin_ids, 'IN')
  195. ->execute();
  196. $result = [];
  197. foreach (\Drupal::entityTypeManager()->getStorage('view')->loadMultiple($entity_ids) as $view) {
  198. // Check each display to see if it meets the criteria and is enabled.
  199. foreach ($view->get('display') as $id => $display) {
  200. // If the key doesn't exist, enabled is assumed.
  201. $enabled = !empty($display['display_options']['enabled']) || !array_key_exists('enabled', $display['display_options']);
  202. if ($enabled && in_array($display['display_plugin'], $plugin_ids)) {
  203. $result[] = [$view->id(), $id];
  204. }
  205. }
  206. }
  207. return $result;
  208. }
  209. /**
  210. * Returns an array of all views as fully loaded $view objects.
  211. *
  212. * @return \Drupal\views\Entity\View[]
  213. * An array of loaded view entities.
  214. */
  215. public static function getAllViews() {
  216. return \Drupal::entityManager()->getStorage('view')->loadMultiple();
  217. }
  218. /**
  219. * Returns an array of all enabled views.
  220. *
  221. * @return \Drupal\views\Entity\View[]
  222. * An array of loaded enabled view entities.
  223. */
  224. public static function getEnabledViews() {
  225. $query = \Drupal::entityQuery('view')
  226. ->condition('status', TRUE)
  227. ->execute();
  228. return \Drupal::entityManager()->getStorage('view')->loadMultiple($query);
  229. }
  230. /**
  231. * Returns an array of all disabled views.
  232. *
  233. * @return \Drupal\views\Entity\View[]
  234. * An array of loaded disabled view entities.
  235. */
  236. public static function getDisabledViews() {
  237. $query = \Drupal::entityQuery('view')
  238. ->condition('status', FALSE)
  239. ->execute();
  240. return \Drupal::entityManager()->getStorage('view')->loadMultiple($query);
  241. }
  242. /**
  243. * Returns an array of view as options array, that can be used by select,
  244. * checkboxes and radios as #options.
  245. *
  246. * @param bool $views_only
  247. * If TRUE, only return views, not displays.
  248. * @param string $filter
  249. * Filters the views on status. Can either be 'all' (default), 'enabled' or
  250. * 'disabled'
  251. * @param mixed $exclude_view
  252. * View or current display to exclude.
  253. * Either a:
  254. * - views object (containing $exclude_view->storage->name and $exclude_view->current_display)
  255. * - views name as string: e.g. my_view
  256. * - views name and display id (separated by ':'): e.g. my_view:default
  257. * @param bool $optgroup
  258. * If TRUE, returns an array with optgroups for each view (will be ignored for
  259. * $views_only = TRUE). Can be used by select
  260. * @param bool $sort
  261. * If TRUE, the list of views is sorted ascending.
  262. *
  263. * @return array
  264. * An associative array for use in select.
  265. * - key: view name and display id separated by ':', or the view name only.
  266. */
  267. public static function getViewsAsOptions($views_only = FALSE, $filter = 'all', $exclude_view = NULL, $optgroup = FALSE, $sort = FALSE) {
  268. // Filter the big views array.
  269. switch ($filter) {
  270. case 'all':
  271. case 'disabled':
  272. case 'enabled':
  273. $filter = ucfirst($filter);
  274. $views = call_user_func("static::get{$filter}Views");
  275. break;
  276. default:
  277. return [];
  278. }
  279. // Prepare exclude view strings for comparison.
  280. if (empty($exclude_view)) {
  281. $exclude_view_name = '';
  282. $exclude_view_display = '';
  283. }
  284. elseif (is_object($exclude_view)) {
  285. $exclude_view_name = $exclude_view->storage->id();
  286. $exclude_view_display = $exclude_view->current_display;
  287. }
  288. else {
  289. // Append a ':' to the $exclude_view string so we always have more than one
  290. // item to explode.
  291. list($exclude_view_name, $exclude_view_display) = explode(':', "$exclude_view:");
  292. }
  293. $options = [];
  294. foreach ($views as $view) {
  295. $id = $view->id();
  296. // Return only views.
  297. if ($views_only && $id != $exclude_view_name) {
  298. $options[$id] = $view->label();
  299. }
  300. // Return views with display ids.
  301. else {
  302. foreach ($view->get('display') as $display_id => $display) {
  303. if (!($id == $exclude_view_name && $display_id == $exclude_view_display)) {
  304. if ($optgroup) {
  305. $options[$id][$id . ':' . $display['id']] = t('@view : @display', ['@view' => $id, '@display' => $display['id']]);
  306. }
  307. else {
  308. $options[$id . ':' . $display['id']] = t('View: @view - Display: @display', ['@view' => $id, '@display' => $display['id']]);
  309. }
  310. }
  311. }
  312. }
  313. }
  314. if ($sort) {
  315. ksort($options);
  316. }
  317. return $options;
  318. }
  319. /**
  320. * Returns a list of plugins and metadata about them.
  321. *
  322. * @return array
  323. * An array keyed by PLUGIN_TYPE:PLUGIN_NAME, like 'display:page' or
  324. * 'pager:full', containing an array with the following keys:
  325. * - title: The plugin's title.
  326. * - type: The plugin type.
  327. * - module: The module providing the plugin.
  328. * - views: An array of enabled Views that are currently using this plugin,
  329. * keyed by machine name.
  330. */
  331. public static function pluginList() {
  332. $plugin_data = static::getPluginDefinitions();
  333. $plugins = [];
  334. foreach (static::getEnabledViews() as $view) {
  335. foreach ($view->get('display') as $display) {
  336. foreach ($plugin_data as $type => $info) {
  337. if ($type == 'display' && isset($display['display_plugin'])) {
  338. $name = $display['display_plugin'];
  339. }
  340. elseif (isset($display['display_options']["{$type}_plugin"])) {
  341. $name = $display['display_options']["{$type}_plugin"];
  342. }
  343. elseif (isset($display['display_options'][$type]['type'])) {
  344. $name = $display['display_options'][$type]['type'];
  345. }
  346. else {
  347. continue;
  348. }
  349. // Key first by the plugin type, then the name.
  350. $key = $type . ':' . $name;
  351. // Add info for this plugin.
  352. if (!isset($plugins[$key])) {
  353. $plugins[$key] = [
  354. 'type' => $type,
  355. 'title' => $info[$name]['title'],
  356. 'provider' => $info[$name]['provider'],
  357. 'views' => [],
  358. ];
  359. }
  360. // Add this view to the list for this plugin.
  361. $plugins[$key]['views'][$view->id()] = $view->id();
  362. }
  363. }
  364. }
  365. return $plugins;
  366. }
  367. /**
  368. * Provide a list of views handler types used in a view, with some information
  369. * about them.
  370. *
  371. * @return array
  372. * An array of associative arrays containing:
  373. * - title: The title of the handler type.
  374. * - ltitle: The lowercase title of the handler type.
  375. * - stitle: A singular title of the handler type.
  376. * - lstitle: A singular lowercase title of the handler type.
  377. * - plural: Plural version of the handler type.
  378. * - (optional) type: The actual internal used handler type. This key is
  379. * just used for header,footer,empty to link to the internal type: area.
  380. */
  381. public static function getHandlerTypes() {
  382. // Statically cache this so translation only occurs once per request for all
  383. // of these values.
  384. if (!isset(static::$handlerTypes)) {
  385. static::$handlerTypes = [
  386. 'field' => [
  387. // title
  388. 'title' => static::t('Fields'),
  389. // Lowercase title for mid-sentence.
  390. 'ltitle' => static::t('fields'),
  391. // Singular title.
  392. 'stitle' => static::t('Field'),
  393. // Singular lowercase title for mid sentence
  394. 'lstitle' => static::t('field'),
  395. 'plural' => 'fields',
  396. ],
  397. 'argument' => [
  398. 'title' => static::t('Contextual filters'),
  399. 'ltitle' => static::t('contextual filters'),
  400. 'stitle' => static::t('Contextual filter'),
  401. 'lstitle' => static::t('contextual filter'),
  402. 'plural' => 'arguments',
  403. ],
  404. 'sort' => [
  405. 'title' => static::t('Sort criteria'),
  406. 'ltitle' => static::t('sort criteria'),
  407. 'stitle' => static::t('Sort criterion'),
  408. 'lstitle' => static::t('sort criterion'),
  409. 'plural' => 'sorts',
  410. ],
  411. 'filter' => [
  412. 'title' => static::t('Filter criteria'),
  413. 'ltitle' => static::t('filter criteria'),
  414. 'stitle' => static::t('Filter criterion'),
  415. 'lstitle' => static::t('filter criterion'),
  416. 'plural' => 'filters',
  417. ],
  418. 'relationship' => [
  419. 'title' => static::t('Relationships'),
  420. 'ltitle' => static::t('relationships'),
  421. 'stitle' => static::t('Relationship'),
  422. 'lstitle' => static::t('Relationship'),
  423. 'plural' => 'relationships',
  424. ],
  425. 'header' => [
  426. 'title' => static::t('Header'),
  427. 'ltitle' => static::t('header'),
  428. 'stitle' => static::t('Header'),
  429. 'lstitle' => static::t('Header'),
  430. 'plural' => 'header',
  431. 'type' => 'area',
  432. ],
  433. 'footer' => [
  434. 'title' => static::t('Footer'),
  435. 'ltitle' => static::t('footer'),
  436. 'stitle' => static::t('Footer'),
  437. 'lstitle' => static::t('Footer'),
  438. 'plural' => 'footer',
  439. 'type' => 'area',
  440. ],
  441. 'empty' => [
  442. 'title' => static::t('No results behavior'),
  443. 'ltitle' => static::t('no results behavior'),
  444. 'stitle' => static::t('No results behavior'),
  445. 'lstitle' => static::t('No results behavior'),
  446. 'plural' => 'empty',
  447. 'type' => 'area',
  448. ],
  449. ];
  450. }
  451. return static::$handlerTypes;
  452. }
  453. /**
  454. * Returns a list of plugin types.
  455. *
  456. * @param string $type
  457. * (optional) filter the list of plugins by type. Available options are
  458. * 'plugin' or 'handler'.
  459. *
  460. * @return array
  461. * An array of plugin types.
  462. */
  463. public static function getPluginTypes($type = NULL) {
  464. if ($type === NULL) {
  465. return array_keys(static::$plugins);
  466. }
  467. if (!in_array($type, ['plugin', 'handler'])) {
  468. throw new \Exception('Invalid plugin type used. Valid types are "plugin" or "handler".');
  469. }
  470. return array_keys(array_filter(static::$plugins, function ($plugin_type) use ($type) {
  471. return $plugin_type == $type;
  472. }));
  473. }
  474. /**
  475. * Translates a string to the current language or to a given language.
  476. *
  477. * See the t() documentation for details.
  478. */
  479. protected static function t($string, array $args = [], array $options = []) {
  480. if (empty(static::$translationManager)) {
  481. static::$translationManager = \Drupal::service('string_translation');
  482. }
  483. return static::$translationManager->translate($string, $args, $options);
  484. }
  485. }