6a9188bee6813bdebf323d46ba6c3cea7cfde9d8
[yaffs-website] / web / core / modules / views / src / ViewsDataHelper.php
1 <?php
2
3 namespace Drupal\views;
4
5 use Drupal\Component\Render\FormattableMarkup;
6
7 /**
8  * Defines a helper class for stuff related to views data.
9  */
10 class ViewsDataHelper {
11
12   /**
13    * The views data object, containing the cached information.
14    *
15    * @var \Drupal\views\ViewsData
16    */
17   protected $data;
18
19   /**
20    * A prepared list of all fields, keyed by base_table and handler type.
21    *
22    * @var array
23    */
24   protected $fields;
25
26   /**
27    * Constructs a ViewsData object.
28    *
29    * @param \Drupal\views\ViewsData $views_data
30    *   The views data object, containing the cached table information.
31    */
32   public function __construct(ViewsData $views_data) {
33     $this->data = $views_data;
34   }
35
36   /**
37    * Fetches a list of all fields available for a given base type.
38    *
39    * @param array|string $base
40    *   A list or a single base_table, for example node.
41    * @param string $type
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.
48    *
49    * @return array
50    *   A keyed array of in the form of 'base_table' => 'Description'.
51    */
52   public function fetchFields($base, $type, $grouping = FALSE, $sub_type = NULL) {
53     if (!$this->fields) {
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'.
59       //
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.
64
65       foreach ($data as $table => $table_data) {
66         $bases = [];
67         $strings = [];
68         $skip_bases = [];
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']);
75             }
76             // And it obviously joins to itself.
77             $bases[] = $table;
78             continue;
79           }
80           foreach (['field', 'sort', 'filter', 'argument', 'relationship', 'area'] as $key) {
81             if (!empty($info[$key])) {
82               if ($grouping && !empty($info[$key]['no group by'])) {
83                 continue;
84               }
85               if ($sub_type && isset($info[$key]['sub_type']) && (!in_array($sub_type, (array) $info[$key]['sub_type']))) {
86                 continue;
87               }
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;
91                 }
92               }
93               elseif (!empty($info['skip base'])) {
94                 foreach ((array) $info['skip base'] as $base_name) {
95                   $skip_bases[$field][$key][$base_name] = TRUE;
96                 }
97               }
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];
102                 }
103                 // Then try the field level
104                 elseif (!empty($info[$string])) {
105                   $strings[$field][$key][$string] = $info[$string];
106                 }
107                 // Finally, try the table level
108                 elseif (!empty($table_data['table'][$string])) {
109                   $strings[$field][$key][$string] = $table_data['table'][$string];
110                 }
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] = '';
119                 }
120                 else {
121                   if ($string != 'base') {
122                     $strings[$field][$key][$string] = new FormattableMarkup("Error: missing @component", ['@component' => $string]);
123                   }
124                 }
125               }
126             }
127           }
128         }
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;
134               }
135             }
136           }
137         }
138       }
139     }
140
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
143     // Just Fine.
144     if (is_array($base)) {
145       $strings = [];
146       foreach ($base as $base_table) {
147         if (isset($this->fields[$base_table][$type])) {
148           $strings += $this->fields[$base_table][$type];
149         }
150       }
151       uasort($strings, ['self', 'fetchedFieldSort']);
152       return $strings;
153     }
154
155     if (isset($this->fields[$base][$type])) {
156       uasort($this->fields[$base][$type], [$this, 'fetchedFieldSort']);
157       return $this->fields[$base][$type];
158     }
159     return [];
160   }
161
162   /**
163    * Sort function for fetched fields.
164    *
165    * @param array $a
166    *   First item for comparison. The compared items should be associative arrays
167    *   that include a 'group' and a 'title' key.
168    * @param array $b
169    *   Second item for comparison.
170    *
171    * @return int
172    *   Returns -1 if $a comes before $b, 1 other way round and 0 if it cannot be
173    *   decided.
174    */
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;
180     }
181
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;
186     }
187
188     return 0;
189   }
190
191 }