annotate core/lib/Drupal/Core/Render/Element.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\Core\Render;
Chris@0 4
Chris@17 5 use Drupal\Component\Render\FormattableMarkup;
Chris@0 6 use Drupal\Core\Access\AccessResultInterface;
Chris@0 7
Chris@0 8 /**
Chris@0 9 * Provides helper methods for Drupal render elements.
Chris@0 10 *
Chris@0 11 * @see \Drupal\Core\Render\Element\ElementInterface
Chris@0 12 *
Chris@0 13 * @ingroup theme_render
Chris@0 14 */
Chris@0 15 class Element {
Chris@0 16
Chris@0 17 /**
Chris@0 18 * Checks if the key is a property.
Chris@0 19 *
Chris@0 20 * @param string $key
Chris@0 21 * The key to check.
Chris@0 22 *
Chris@0 23 * @return bool
Chris@0 24 * TRUE of the key is a property, FALSE otherwise.
Chris@0 25 */
Chris@0 26 public static function property($key) {
Chris@0 27 return $key[0] == '#';
Chris@0 28 }
Chris@0 29
Chris@0 30 /**
Chris@0 31 * Gets properties of a structured array element (keys beginning with '#').
Chris@0 32 *
Chris@0 33 * @param array $element
Chris@0 34 * An element array to return properties for.
Chris@0 35 *
Chris@0 36 * @return array
Chris@0 37 * An array of property keys for the element.
Chris@0 38 */
Chris@0 39 public static function properties(array $element) {
Chris@0 40 return array_filter(array_keys($element), 'static::property');
Chris@0 41 }
Chris@0 42
Chris@0 43 /**
Chris@0 44 * Checks if the key is a child.
Chris@0 45 *
Chris@0 46 * @param string $key
Chris@0 47 * The key to check.
Chris@0 48 *
Chris@0 49 * @return bool
Chris@0 50 * TRUE if the element is a child, FALSE otherwise.
Chris@0 51 */
Chris@0 52 public static function child($key) {
Chris@0 53 return !isset($key[0]) || $key[0] != '#';
Chris@0 54 }
Chris@0 55
Chris@0 56 /**
Chris@0 57 * Identifies the children of an element array, optionally sorted by weight.
Chris@0 58 *
Chris@0 59 * The children of a element array are those key/value pairs whose key does
Chris@0 60 * not start with a '#'. See drupal_render() for details.
Chris@0 61 *
Chris@0 62 * @param array $elements
Chris@0 63 * The element array whose children are to be identified. Passed by
Chris@0 64 * reference.
Chris@0 65 * @param bool $sort
Chris@0 66 * Boolean to indicate whether the children should be sorted by weight.
Chris@0 67 *
Chris@0 68 * @return array
Chris@0 69 * The array keys of the element's children.
Chris@0 70 */
Chris@0 71 public static function children(array &$elements, $sort = FALSE) {
Chris@0 72 // Do not attempt to sort elements which have already been sorted.
Chris@0 73 $sort = isset($elements['#sorted']) ? !$elements['#sorted'] : $sort;
Chris@0 74
Chris@0 75 // Filter out properties from the element, leaving only children.
Chris@0 76 $count = count($elements);
Chris@0 77 $child_weights = [];
Chris@0 78 $i = 0;
Chris@0 79 $sortable = FALSE;
Chris@0 80 foreach ($elements as $key => $value) {
Chris@0 81 if ($key === '' || $key[0] !== '#') {
Chris@0 82 if (is_array($value)) {
Chris@0 83 if (isset($value['#weight'])) {
Chris@0 84 $weight = $value['#weight'];
Chris@0 85 $sortable = TRUE;
Chris@0 86 }
Chris@0 87 else {
Chris@0 88 $weight = 0;
Chris@0 89 }
Chris@0 90 // Supports weight with up to three digit precision and conserve
Chris@0 91 // the insertion order.
Chris@0 92 $child_weights[$key] = floor($weight * 1000) + $i / $count;
Chris@0 93 }
Chris@0 94 // Only trigger an error if the value is not null.
Chris@0 95 // @see https://www.drupal.org/node/1283892
Chris@0 96 elseif (isset($value)) {
Chris@17 97 trigger_error(new FormattableMarkup('"@key" is an invalid render array key', ['@key' => $key]), E_USER_ERROR);
Chris@0 98 }
Chris@0 99 }
Chris@0 100 $i++;
Chris@0 101 }
Chris@0 102
Chris@0 103 // Sort the children if necessary.
Chris@0 104 if ($sort && $sortable) {
Chris@0 105 asort($child_weights);
Chris@0 106 // Put the sorted children back into $elements in the correct order, to
Chris@0 107 // preserve sorting if the same element is passed through
Chris@0 108 // \Drupal\Core\Render\Element::children() twice.
Chris@0 109 foreach ($child_weights as $key => $weight) {
Chris@0 110 $value = $elements[$key];
Chris@0 111 unset($elements[$key]);
Chris@0 112 $elements[$key] = $value;
Chris@0 113 }
Chris@0 114 $elements['#sorted'] = TRUE;
Chris@0 115 }
Chris@0 116
Chris@0 117 return array_keys($child_weights);
Chris@0 118 }
Chris@0 119
Chris@0 120 /**
Chris@0 121 * Returns the visible children of an element.
Chris@0 122 *
Chris@0 123 * @param array $elements
Chris@0 124 * The parent element.
Chris@0 125 *
Chris@0 126 * @return array
Chris@0 127 * The array keys of the element's visible children.
Chris@0 128 */
Chris@0 129 public static function getVisibleChildren(array $elements) {
Chris@0 130 $visible_children = [];
Chris@0 131
Chris@0 132 foreach (static::children($elements) as $key) {
Chris@0 133 $child = $elements[$key];
Chris@0 134
Chris@0 135 // Skip value and hidden elements, since they are not rendered.
Chris@0 136 if (!static::isVisibleElement($child)) {
Chris@0 137 continue;
Chris@0 138 }
Chris@0 139
Chris@0 140 $visible_children[$key] = $child;
Chris@0 141 }
Chris@0 142
Chris@0 143 return array_keys($visible_children);
Chris@0 144 }
Chris@0 145
Chris@0 146 /**
Chris@0 147 * Determines if an element is visible.
Chris@0 148 *
Chris@0 149 * @param array $element
Chris@0 150 * The element to check for visibility.
Chris@0 151 *
Chris@0 152 * @return bool
Chris@0 153 * TRUE if the element is visible, otherwise FALSE.
Chris@0 154 */
Chris@0 155 public static function isVisibleElement($element) {
Chris@0 156 return (!isset($element['#type']) || !in_array($element['#type'], ['value', 'hidden', 'token']))
Chris@0 157 && (!isset($element['#access'])
Chris@0 158 || (($element['#access'] instanceof AccessResultInterface && $element['#access']->isAllowed()) || ($element['#access'] === TRUE)));
Chris@0 159 }
Chris@0 160
Chris@0 161 /**
Chris@0 162 * Sets HTML attributes based on element properties.
Chris@0 163 *
Chris@0 164 * @param array $element
Chris@0 165 * The renderable element to process. Passed by reference.
Chris@0 166 * @param array $map
Chris@0 167 * An associative array whose keys are element property names and whose
Chris@0 168 * values are the HTML attribute names to set on the corresponding
Chris@0 169 * property; e.g., array('#propertyname' => 'attributename'). If both names
Chris@0 170 * are identical except for the leading '#', then an attribute name value is
Chris@0 171 * sufficient and no property name needs to be specified.
Chris@0 172 */
Chris@0 173 public static function setAttributes(array &$element, array $map) {
Chris@0 174 foreach ($map as $property => $attribute) {
Chris@0 175 // If the key is numeric, the attribute name needs to be taken over.
Chris@0 176 if (is_int($property)) {
Chris@0 177 $property = '#' . $attribute;
Chris@0 178 }
Chris@0 179 // Do not overwrite already existing attributes.
Chris@0 180 if (isset($element[$property]) && !isset($element['#attributes'][$attribute])) {
Chris@0 181 $element['#attributes'][$attribute] = $element[$property];
Chris@0 182 }
Chris@0 183 }
Chris@0 184 }
Chris@0 185
Chris@0 186 /**
Chris@0 187 * Indicates whether the given element is empty.
Chris@0 188 *
Chris@0 189 * An element that only has #cache set is considered empty, because it will
Chris@0 190 * render to the empty string.
Chris@0 191 *
Chris@0 192 * @param array $elements
Chris@0 193 * The element.
Chris@0 194 *
Chris@0 195 * @return bool
Chris@0 196 * Whether the given element is empty.
Chris@0 197 */
Chris@0 198 public static function isEmpty(array $elements) {
Chris@0 199 return empty($elements) || (count($elements) === 1 && array_keys($elements) === ['#cache']);
Chris@0 200 }
Chris@0 201
Chris@0 202 }