3 namespace Drupal\views;
5 use Drupal\Component\Render\FormattableMarkup;
8 * Defines a helper class for stuff related to views data.
10 class ViewsDataHelper {
13 * The views data object, containing the cached information.
15 * @var \Drupal\views\ViewsData
20 * A prepared list of all fields, keyed by base_table and handler type.
27 * Constructs a ViewsData object.
29 * @param \Drupal\views\ViewsData $views_data
30 * The views data object, containing the cached table information.
32 public function __construct(ViewsData $views_data) {
33 $this->data = $views_data;
37 * Fetches a list of all fields available for a given base type.
39 * @param array|string $base
40 * A list or a single base_table, for example node.
42 * The handler type, for example field or filter.
43 * @param bool $grouping
44 * Should the result grouping by its 'group' label.
45 * @param string $sub_type
46 * An optional sub type. E.g. Allows making an area plugin available for
47 * header only, instead of header, footer, and empty regions.
50 * A keyed array of in the form of 'base_table' => 'Description'.
52 public function fetchFields($base, $type, $grouping = FALSE, $sub_type = NULL) {
54 $data = $this->data->get();
55 // This constructs this ginormous multi dimensional array to
56 // collect the important data about fields. In the end,
57 // the structure looks a bit like this (using nid as an example)
58 // $strings['nid']['filter']['title'] = 'string'.
60 // This is constructed this way because the above referenced strings
61 // can appear in different places in the actual data structure so that
62 // the data doesn't have to be repeated a lot. This essentially lets
63 // each field have a cheap kind of inheritance.
65 foreach ($data as $table => $table_data) {
69 foreach ($table_data as $field => $info) {
70 // Collect table data from this table
71 if ($field == 'table') {
72 // calculate what tables this table can join to.
73 if (!empty($info['join'])) {
74 $bases = array_keys($info['join']);
76 // And it obviously joins to itself.
80 foreach (['field', 'sort', 'filter', 'argument', 'relationship', 'area'] as $key) {
81 if (!empty($info[$key])) {
82 if ($grouping && !empty($info[$key]['no group by'])) {
85 if ($sub_type && isset($info[$key]['sub_type']) && (!in_array($sub_type, (array) $info[$key]['sub_type']))) {
88 if (!empty($info[$key]['skip base'])) {
89 foreach ((array) $info[$key]['skip base'] as $base_name) {
90 $skip_bases[$field][$key][$base_name] = TRUE;
93 elseif (!empty($info['skip base'])) {
94 foreach ((array) $info['skip base'] as $base_name) {
95 $skip_bases[$field][$key][$base_name] = TRUE;
98 foreach (['title', 'group', 'help', 'base', 'aliases'] as $string) {
99 // First, try the lowest possible level
100 if (!empty($info[$key][$string])) {
101 $strings[$field][$key][$string] = $info[$key][$string];
103 // Then try the field level
104 elseif (!empty($info[$string])) {
105 $strings[$field][$key][$string] = $info[$string];
107 // Finally, try the table level
108 elseif (!empty($table_data['table'][$string])) {
109 $strings[$field][$key][$string] = $table_data['table'][$string];
111 // We don't have any help provided for this field. If a better
112 // description should be used for the Views UI you use
113 // hook_views_data_alter() in module.views.inc or implement a
114 // custom entity views_data handler.
115 // @see hook_views_data_alter()
116 // @see \Drupal\node\NodeViewsData
117 elseif ($string == 'help') {
118 $strings[$field][$key][$string] = '';
121 if ($string != 'base') {
122 $strings[$field][$key][$string] = new FormattableMarkup("Error: missing @component", ['@component' => $string]);
129 foreach ($bases as $base_name) {
130 foreach ($strings as $field => $field_strings) {
131 foreach ($field_strings as $type_name => $type_strings) {
132 if (empty($skip_bases[$field][$type_name][$base_name])) {
133 $this->fields[$base_name][$type_name]["$table.$field"] = $type_strings;
141 // If we have an array of base tables available, go through them
142 // all and add them together. Duplicate keys will be lost and that's
144 if (is_array($base)) {
146 foreach ($base as $base_table) {
147 if (isset($this->fields[$base_table][$type])) {
148 $strings += $this->fields[$base_table][$type];
151 uasort($strings, ['self', 'fetchedFieldSort']);
155 if (isset($this->fields[$base][$type])) {
156 uasort($this->fields[$base][$type], [$this, 'fetchedFieldSort']);
157 return $this->fields[$base][$type];
163 * Sort function for fetched fields.
166 * First item for comparison. The compared items should be associative arrays
167 * that include a 'group' and a 'title' key.
169 * Second item for comparison.
172 * Returns -1 if $a comes before $b, 1 other way round and 0 if it cannot be
175 protected static function fetchedFieldSort($a, $b) {
176 $a_group = mb_strtolower($a['group']);
177 $b_group = mb_strtolower($b['group']);
178 if ($a_group != $b_group) {
179 return $a_group < $b_group ? -1 : 1;
182 $a_title = mb_strtolower($a['title']);
183 $b_title = mb_strtolower($b['title']);
184 if ($a_title != $b_title) {
185 return $a_title < $b_title ? -1 : 1;