annotate core/modules/views/src/ViewsDataHelper.php @ 19:fa3358dc1485 tip

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