|
21 | 21 |
|
22 | 22 | use Drupal\Core\Entity\Display\EntityFormDisplayInterface; |
23 | 23 | use Drupal\Core\Entity\Entity\EntityFormDisplay; |
| 24 | +use Drupal\Core\Entity\EntityConstraintViolationListInterface; |
24 | 25 | use Drupal\Core\Entity\EntityForm; |
25 | 26 | use Drupal\Core\Entity\EntityInterface; |
26 | 27 | use Drupal\Core\Form\FormStateInterface; |
@@ -64,18 +65,100 @@ public function form(array $form, FormStateInterface $form_state) { |
64 | 65 | /** |
65 | 66 | * {@inheritdoc} |
66 | 67 | * |
67 | | - * @see \Drupal\Core\Entity\ContentEntityForm::buildEntity() |
| 68 | + * TODO Add missing return type-hint in 2.x. |
68 | 69 | */ |
69 | | - public function buildEntity(array $form, FormStateInterface $form_state) { |
70 | | - /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ |
71 | | - $entity = parent::buildEntity($form, $form_state); |
| 70 | + public function validateForm(array &$form, FormStateInterface $form_state) { |
| 71 | + parent::validateForm($form, $form_state); |
| 72 | + /** @var \Drupal\apigee_edge\Entity\FieldableEdgeEntityInterface $entity */ |
| 73 | + $entity = $this->buildEntity($form, $form_state); |
| 74 | + |
| 75 | + $violations = $entity->validate(); |
| 76 | + |
| 77 | + // Remove violations of inaccessible fields. |
| 78 | + $violations->filterByFieldAccess($this->currentUser()); |
| 79 | + |
| 80 | + // In case a field-level submit button is clicked, for example the 'Add |
| 81 | + // another item' button for multi-value fields or the 'Upload' button for a |
| 82 | + // File or an Image field, make sure that we only keep violations for that |
| 83 | + // specific field. |
| 84 | + $edited_fields = []; |
| 85 | + if ($limit_validation_errors = $form_state->getLimitValidationErrors()) { |
| 86 | + foreach ($limit_validation_errors as $section) { |
| 87 | + $field_name = reset($section); |
| 88 | + if ($entity->hasField($field_name)) { |
| 89 | + $edited_fields[] = $field_name; |
| 90 | + } |
| 91 | + } |
| 92 | + $edited_fields = array_unique($edited_fields); |
| 93 | + } |
| 94 | + else { |
| 95 | + $edited_fields = $this->getEditedFieldNames($form_state); |
| 96 | + } |
| 97 | + |
| 98 | + // Remove violations for fields that are not edited. |
| 99 | + $violations->filterByFields(array_diff(array_keys($entity->getFieldDefinitions()), $edited_fields)); |
| 100 | + |
| 101 | + $this->flagViolations($violations, $form, $form_state); |
72 | 102 |
|
73 | | - // Mark the entity as requiring validation. |
74 | | - $entity->setValidationRequired(!$form_state->getTemporaryValue('entity_validated')); |
| 103 | + // The entity was validated. |
| 104 | + $entity->setValidationRequired(FALSE); |
| 105 | + $form_state->setTemporaryValue('entity_validated', TRUE); |
75 | 106 |
|
76 | 107 | return $entity; |
77 | 108 | } |
78 | 109 |
|
| 110 | + /** |
| 111 | + * Gets the names of all fields edited in the form. |
| 112 | + * |
| 113 | + * If the entity form customly adds some fields to the form (i.e. without |
| 114 | + * using the form display), it needs to add its fields here and override |
| 115 | + * flagViolations() for displaying the violations. |
| 116 | + * |
| 117 | + * @param \Drupal\Core\Form\FormStateInterface $form_state |
| 118 | + * The current state of the form. |
| 119 | + * |
| 120 | + * @return string[] |
| 121 | + * An array of field names. |
| 122 | + * |
| 123 | + * @todo Add missing return type-hint in 2.x. |
| 124 | + */ |
| 125 | + protected function getEditedFieldNames(FormStateInterface $form_state) { |
| 126 | + return array_keys($this->getFormDisplay($form_state)->getComponents()); |
| 127 | + } |
| 128 | + |
| 129 | + /** |
| 130 | + * Flags violations for the current form. |
| 131 | + * |
| 132 | + * If the entity form customly adds some fields to the form (i.e. without |
| 133 | + * using the form display), it needs to add its fields to array returned by |
| 134 | + * getEditedFieldNames() and overwrite this method in order to show any |
| 135 | + * violations for those fields; e.g.: |
| 136 | + * @code |
| 137 | + * foreach ($violations->getByField('name') as $violation) { |
| 138 | + * $form_state->setErrorByName('name', $violation->getMessage()); |
| 139 | + * } |
| 140 | + * parent::flagViolations($violations, $form, $form_state); |
| 141 | + * @endcode |
| 142 | + * |
| 143 | + * @param \Drupal\Core\Entity\EntityConstraintViolationListInterface $violations |
| 144 | + * The violations to flag. |
| 145 | + * @param array $form |
| 146 | + * A nested array of form elements comprising the form. |
| 147 | + * @param \Drupal\Core\Form\FormStateInterface $form_state |
| 148 | + * The current state of the form. |
| 149 | + * |
| 150 | + * @todo Add missing return type-hint in 2.x. |
| 151 | + */ |
| 152 | + protected function flagViolations(EntityConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) { |
| 153 | + // Flag entity level violations. |
| 154 | + foreach ($violations->getEntityViolations() as $violation) { |
| 155 | + /** @var \Symfony\Component\Validator\ConstraintViolationInterface $violation */ |
| 156 | + $form_state->setErrorByName(str_replace('.', '][', $violation->getPropertyPath()), $violation->getMessage()); |
| 157 | + } |
| 158 | + // Let the form display flag violations of its fields. |
| 159 | + $this->getFormDisplay($form_state)->flagWidgetsErrorsFromViolations($violations, $form, $form_state); |
| 160 | + } |
| 161 | + |
79 | 162 | /** |
80 | 163 | * {@inheritdoc} |
81 | 164 | */ |
|
0 commit comments