/** * Loops through and displays all form errors. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ protected function displayErrorMessages(array $form, FormStateInterface $form_state) { $error_links = []; $errors = $form_state->getErrors(); // Loop through all form errors and check if we need to display a link. foreach ($errors as $name => $error) { $form_element = FormElementHelper::getElementByName($name, $form); $title = FormElementHelper::getElementTitle($form_element); // Only show links to erroneous elements that are visible. $is_visible_element = Element::isVisibleElement($form_element); // Only show links for elements that have a title themselves or have // children with a title. $has_title = !empty($title); // Only show links for elements with an ID. $has_id = !empty($form_element['#id']); // Do not show links to elements with suppressed messages. Most often // their parent element is used for inline errors. if (!empty($form_element['#error_no_message'])) { unset($errors[$name]); } elseif ($is_visible_element && $has_title && $has_id) { $error_links[] = $this->l($title, Url::fromRoute('<none>', [], ['fragment' => $form_element['#id'], 'external' => TRUE])); unset($errors[$name]); } } // Set normal error messages for all remaining errors. foreach ($errors as $error) { $this->drupalSetMessage($error, 'error'); } if (!empty($error_links)) { $render_array = [['#markup' => $this->formatPlural(count($error_links), '1 error has been found: ', '@count errors have been found: ')], ['#theme' => 'item_list', '#items' => $error_links, '#context' => ['list_style' => 'comma-list']]]; $message = $this->renderer->renderPlain($render_array); $this->drupalSetMessage($message, 'error'); } }
/** * Loops through and displays all form errors. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ protected function displayErrorMessages(array $form, FormStateInterface $form_state) { $error_links = []; $errors = $form_state->getErrors(); // Loop through all form errors and check if we need to display a link. foreach ($errors as $name => $error) { $form_element = FormElementHelper::getElementByName($name, $form); $title = FormElementHelper::getElementTitle($form_element); // Only show links to erroneous elements that are visible. $is_visible_element = Element::isVisibleElement($form_element); // Only show links for elements that have a title themselves or have // children with a title. $has_title = !empty($title); // Only show links for elements with an ID. $has_id = !empty($form_element['#id']); // Do not show links to elements with suppressed messages. Most often // their parent element is used for inline errors. if (!empty($form_element['#error_no_message'])) { unset($errors[$name]); } elseif ($is_visible_element && $has_title && $has_id) { // We need to pass this through SafeMarkup::escape() so // drupal_set_message() does not encode the links. $error_links[] = SafeMarkup::escape($this->l($title, Url::fromRoute('<none>', [], ['fragment' => $form_element['#id'], 'external' => TRUE]))); unset($errors[$name]); } } // Set normal error messages for all remaining errors. foreach ($errors as $error) { $this->drupalSetMessage($error, 'error'); } if (!empty($error_links)) { $message = $this->formatPlural(count($error_links), '1 error has been found: !errors', '@count errors have been found: !errors', ['!errors' => SafeMarkup::set(implode(', ', $error_links))]); $this->drupalSetMessage($message, 'error'); } }
/** * {@inheritdoc} */ public function flagErrors(FieldItemListInterface $items, ConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) { $field_name = $this->fieldDefinition->getName(); $field_state = static::getWidgetState($form['#parents'], $field_name, $form_state); if ($violations->count()) { // Locate the correct element in the form. $element = NestedArray::getValue($form_state->getCompleteForm(), $field_state['array_parents']); // Do not report entity-level validation errors if Form API errors have // already been reported for the field. // @todo Field validation should not be run on fields with FAPI errors to // begin with. See https://www.drupal.org/node/2070429. $element_path = implode('][', $element['#parents']); if ($reported_errors = $form_state->getErrors()) { foreach (array_keys($reported_errors) as $error_path) { if (strpos($error_path, $element_path) === 0) { return; } } } // Only set errors if the element is visible. if (Element::isVisibleElement($element)) { $handles_multiple = $this->handlesMultipleValues(); $violations_by_delta = array(); foreach ($violations as $violation) { // Separate violations by delta. $property_path = explode('.', $violation->getPropertyPath()); $delta = array_shift($property_path); $violations_by_delta[$delta][] = $violation; $violation->arrayPropertyPath = $property_path; } /** @var \Symfony\Component\Validator\ConstraintViolationInterface[] $delta_violations */ foreach ($violations_by_delta as $delta => $delta_violations) { // Pass violations to the main element: // - if this is a multiple-value widget, // - or if the violations are at the ItemList level. if ($handles_multiple || !is_numeric($delta)) { $delta_element = $element; } else { $original_delta = $field_state['original_deltas'][$delta]; $delta_element = $element[$original_delta]; } foreach ($delta_violations as $violation) { // @todo: Pass $violation->arrayPropertyPath as property path. $error_element = $this->errorElement($delta_element, $violation, $form, $form_state); if ($error_element !== FALSE) { $form_state->setError($error_element, $violation->getMessage()); } } } } } }
/** * Determines if an element is visible. * * @return bool * TRUE if the element is visible, otherwise FALSE. */ public function isVisible() { return \Drupal\Core\Render\Element::isVisibleElement($this->array); }
/** * Processes the subdivision elements, adding predefined values where found. * * @param array $element * The existing form element array. * @param array $values * An array of address values, keyed by property name. * @param \Drupal\address\Entity\AddressFormatInterface $address_format * The address format. * * @return array * The processed form element array. */ protected function processSubdivisionElements(array $element, array $values, AddressFormatInterface $address_format) { $depth = $this->subdivisionRepository->getDepth($values['country_code']); if ($depth === 0) { // No predefined data found. return $element; } $subdivision_properties = []; foreach ($address_format->getUsedSubdivisionFields() as $field) { $subdivision_properties[] = FieldHelper::getPropertyName($field); } // Load and insert the subdivisions for each parent id. $currentDepth = 1; foreach ($subdivision_properties as $index => $property) { if (!isset($element[$property]) || !Element::isVisibleElement($element[$property])) { break; } $parent_property = $index ? $subdivision_properties[$index - 1] : NULL; if ($parent_property && empty($values[$parent_property])) { break; } $parent_id = $parent_property ? $values[$parent_property] : NULL; $subdivisions = $this->subdivisionRepository->getList($values['country_code'], $parent_id); if (empty($subdivisions)) { break; } $element[$property]['#type'] = 'select'; $element[$property]['#options'] = $subdivisions; $element[$property]['#empty_value'] = ''; unset($element[$property]['#size']); if ($currentDepth < $depth) { $element[$property]['#ajax'] = ['callback' => [get_class($this), 'ajaxRefresh'], 'wrapper' => $element['#wrapper_id']]; } $currentDepth++; } return $element; }