bfda18cfd23a6b50806becac02046896c10846c8
[yaffs-website] / web / core / modules / views / src / ViewsDataHelper.php
1 <?php
2
3 namespace Drupal\views;
4
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\Component\Utility\SafeMarkup;
7
8 /**
9  * Defines a helper class for stuff related to views data.
10  */
11 class ViewsDataHelper {
12
13   /**
14    * The views data object, containing the cached information.
15    *
16    * @var \Drupal\views\ViewsData
17    */
18   protected $data;
19
20   /**
21    * A prepared list of all fields, keyed by base_table and handler type.
22    *
23    * @var array
24    */
25   protected $fields;
26
27   /**
28    * Constructs a ViewsData object.
29    *
30    * @param \Drupal\views\ViewsData $views_data
31    *   The views data object, containing the cached table information.
32    */
33   public function __construct(ViewsData $views_data) {
34     $this->data = $views_data;
35   }
36
37   /**
38    * Fetches a list of all fields available for a given base type.
39    *
40    * @param array|string $base
41    *   A list or a single base_table, for example node.
42    * @param string $type
43    *   The handler type, for example field or filter.
44    * @param bool $grouping
45    *   Should the result grouping by its 'group' label.
46    * @param string $sub_type
47    *   An optional sub type. E.g. Allows making an area plugin available for
48    *   header only, instead of header, footer, and empty regions.
49    *
50    * @return array
51    *   A keyed array of in the form of 'base_table' => 'Description'.
52    */
53   public function fetchFields($base, $type, $grouping = FALSE, $sub_type = NULL) {
54     if (!$this->fields) {
55       $data = $this->data->get();
56       // This constructs this ginormous multi dimensional array to
57       // collect the important data about fields. In the end,
58       // the structure looks a bit like this (using nid as an example)
59       // $strings['nid']['filter']['title'] = 'string'.
60       //
61       // This is constructed this way because the above referenced strings
62       // can appear in different places in the actual data structure so that
63       // the data doesn't have to be repeated a lot. This essentially lets
64       // each field have a cheap kind of inheritance.
65
66       foreach ($data as $table => $table_data) {
67         $bases = [];
68         $strings = [];
69         $skip_bases = [];
70         foreach ($table_data as $field => $info) {
71           // Collect table data from this table
72           if ($field == 'table') {
73             // calculate what tables this table can join to.
74             if (!empty($info['join'])) {
75               $bases = array_keys($info['join']);
76             }
77             // And it obviously joins to itself.
78             $bases[] = $table;
79             continue;
80           }
81           foreach (['field', 'sort', 'filter', 'argument', 'relationship', 'area'] as $key) {
82             if (!empty($info[$key])) {
83               if ($grouping && !empty($info[$key]['no group by'])) {
84                 continue;
85               }
86               if ($sub_type && isset($info[$key]['sub_type']) && (!in_array($sub_type, (array) $info[$key]['sub_type']))) {
87                 continue;
88               }
89               if (!empty($info[$key]['skip base'])) {
90                 foreach ((array) $info[$key]['skip base'] as $base_name) {
91                   $skip_bases[$field][$key][$base_name] = TRUE;
92                 }
93               }
94               elseif (!empty($info['skip base'])) {
95                 foreach ((array) $info['skip base'] as $base_name) {
96                   $skip_bases[$field][$key][$base_name] = TRUE;
97                 }
98               }
99               foreach (['title', 'group', 'help', 'base', 'aliases'] as $string) {
100                 // First, try the lowest possible level
101                 if (!empty($info[$key][$string])) {
102                   $strings[$field][$key][$string] = $info[$key][$string];
103                 }
104                 // Then try the field level
105                 elseif (!empty($info[$string])) {
106                   $strings[$field][$key][$string] = $info[$string];
107                 }
108                 // Finally, try the table level
109                 elseif (!empty($table_data['table'][$string])) {
110                   $strings[$field][$key][$string] = $table_data['table'][$string];
111                 }
112                 // We don't have any help provided for this field. If a better
113                 // description should be used for the Views UI you use
114                 // hook_views_data_alter() in module.views.inc or implement a
115                 // custom entity views_data handler.
116                 // @see hook_views_data_alter()
117                 // @see \Drupal\node\NodeViewsData
118                 elseif ($string == 'help') {
119                   $strings[$field][$key][$string] = '';
120                 }
121                 else {
122                   if ($string != 'base') {
123                     $strings[$field][$key][$string] = SafeMarkup::format("Error: missing @component", ['@component' => $string]);
124                   }
125                 }
126               }
127             }
128           }
129         }
130         foreach ($bases as $base_name) {
131           foreach ($strings as $field => $field_strings) {
132             foreach ($field_strings as $type_name => $type_strings) {
133               if (empty($skip_bases[$field][$type_name][$base_name])) {
134                 $this->fields[$base_name][$type_name]["$table.$field"] = $type_strings;
135               }
136             }
137           }
138         }
139       }
140     }
141
142     // If we have an array of base tables available, go through them
143     // all and add them together. Duplicate keys will be lost and that's
144     // Just Fine.
145     if (is_array($base)) {
146       $strings = [];
147       foreach ($base as $base_table) {
148         if (isset($this->fields[$base_table][$type])) {
149           $strings += $this->fields[$base_table][$type];
150         }
151       }
152       uasort($strings, ['self', 'fetchedFieldSort']);
153       return $strings;
154     }
155
156     if (isset($this->fields[$base][$type])) {
157       uasort($this->fields[$base][$type], [$this, 'fetchedFieldSort']);
158       return $this->fields[$base][$type];
159     }
160     return [];
161   }
162
163   /**
164    * Sort function for fetched fields.
165    *
166    * @param array $a
167    *   First item for comparison. The compared items should be associative arrays
168    *   that include a 'group' and a 'title' key.
169    * @param array $b
170    *   Second item for comparison.
171    *
172    * @return int
173    *   Returns -1 if $a comes before $b, 1 other way round and 0 if it cannot be
174    *   decided.
175    */
176   protected static function fetchedFieldSort($a, $b) {
177     $a_group = Unicode::strtolower($a['group']);
178     $b_group = Unicode::strtolower($b['group']);
179     if ($a_group != $b_group) {
180       return $a_group < $b_group ? -1 : 1;
181     }
182
183     $a_title = Unicode::strtolower($a['title']);
184     $b_title = Unicode::strtolower($b['title']);
185     if ($a_title != $b_title) {
186       return $a_title < $b_title ? -1 : 1;
187     }
188
189     return 0;
190   }
191
192 }