Chris@0: $value) { Chris@0: if ($key === '' || $key[0] !== '#') { Chris@0: if (is_array($value)) { Chris@0: if (isset($value['#weight'])) { Chris@0: $weight = $value['#weight']; Chris@0: $sortable = TRUE; Chris@0: } Chris@0: else { Chris@0: $weight = 0; Chris@0: } Chris@0: // Supports weight with up to three digit precision and conserve Chris@0: // the insertion order. Chris@0: $child_weights[$key] = floor($weight * 1000) + $i / $count; Chris@0: } Chris@0: // Only trigger an error if the value is not null. Chris@0: // @see https://www.drupal.org/node/1283892 Chris@0: elseif (isset($value)) { Chris@17: trigger_error(new FormattableMarkup('"@key" is an invalid render array key', ['@key' => $key]), E_USER_ERROR); Chris@0: } Chris@0: } Chris@0: $i++; Chris@0: } Chris@0: Chris@0: // Sort the children if necessary. Chris@0: if ($sort && $sortable) { Chris@0: asort($child_weights); Chris@0: // Put the sorted children back into $elements in the correct order, to Chris@0: // preserve sorting if the same element is passed through Chris@0: // \Drupal\Core\Render\Element::children() twice. Chris@0: foreach ($child_weights as $key => $weight) { Chris@0: $value = $elements[$key]; Chris@0: unset($elements[$key]); Chris@0: $elements[$key] = $value; Chris@0: } Chris@0: $elements['#sorted'] = TRUE; Chris@0: } Chris@0: Chris@0: return array_keys($child_weights); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns the visible children of an element. Chris@0: * Chris@0: * @param array $elements Chris@0: * The parent element. Chris@0: * Chris@0: * @return array Chris@0: * The array keys of the element's visible children. Chris@0: */ Chris@0: public static function getVisibleChildren(array $elements) { Chris@0: $visible_children = []; Chris@0: Chris@0: foreach (static::children($elements) as $key) { Chris@0: $child = $elements[$key]; Chris@0: Chris@0: // Skip value and hidden elements, since they are not rendered. Chris@0: if (!static::isVisibleElement($child)) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $visible_children[$key] = $child; Chris@0: } Chris@0: Chris@0: return array_keys($visible_children); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines if an element is visible. Chris@0: * Chris@0: * @param array $element Chris@0: * The element to check for visibility. Chris@0: * Chris@0: * @return bool Chris@0: * TRUE if the element is visible, otherwise FALSE. Chris@0: */ Chris@0: public static function isVisibleElement($element) { Chris@0: return (!isset($element['#type']) || !in_array($element['#type'], ['value', 'hidden', 'token'])) Chris@0: && (!isset($element['#access']) Chris@0: || (($element['#access'] instanceof AccessResultInterface && $element['#access']->isAllowed()) || ($element['#access'] === TRUE))); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets HTML attributes based on element properties. Chris@0: * Chris@0: * @param array $element Chris@0: * The renderable element to process. Passed by reference. Chris@0: * @param array $map Chris@0: * An associative array whose keys are element property names and whose Chris@0: * values are the HTML attribute names to set on the corresponding Chris@0: * property; e.g., array('#propertyname' => 'attributename'). If both names Chris@0: * are identical except for the leading '#', then an attribute name value is Chris@0: * sufficient and no property name needs to be specified. Chris@0: */ Chris@0: public static function setAttributes(array &$element, array $map) { Chris@0: foreach ($map as $property => $attribute) { Chris@0: // If the key is numeric, the attribute name needs to be taken over. Chris@0: if (is_int($property)) { Chris@0: $property = '#' . $attribute; Chris@0: } Chris@0: // Do not overwrite already existing attributes. Chris@0: if (isset($element[$property]) && !isset($element['#attributes'][$attribute])) { Chris@0: $element['#attributes'][$attribute] = $element[$property]; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Indicates whether the given element is empty. Chris@0: * Chris@0: * An element that only has #cache set is considered empty, because it will Chris@0: * render to the empty string. Chris@0: * Chris@0: * @param array $elements Chris@0: * The element. Chris@0: * Chris@0: * @return bool Chris@0: * Whether the given element is empty. Chris@0: */ Chris@0: public static function isEmpty(array $elements) { Chris@0: return empty($elements) || (count($elements) === 1 && array_keys($elements) === ['#cache']); Chris@0: } Chris@0: Chris@0: }