annotate core/modules/views/src/ViewsDataHelper.php @ 0:c75dbcec494b

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