entity = $entity; } /** * Groups violation offsets by field and entity level. * * Sets the $violationOffsetsByField and $entityViolationOffsets properties. */ protected function groupViolationOffsets() { if (!isset($this->violationOffsetsByField)) { $this->violationOffsetsByField = []; $this->entityViolationOffsets = []; foreach ($this as $offset => $violation) { if ($path = $violation->getPropertyPath()) { // An example of $path might be 'title.0.value'. list($field_name) = explode('.', $path, 2); if ($this->entity->hasField($field_name)) { $this->violationOffsetsByField[$field_name][$offset] = $offset; } } else { $this->entityViolationOffsets[$offset] = $offset; } } } } /** * {@inheritdoc} */ public function getEntityViolations() { $this->groupViolationOffsets(); $violations = []; foreach ($this->entityViolationOffsets as $offset) { $violations[] = $this->get($offset); } return new static($this->entity, $violations); } /** * {@inheritdoc} */ public function getByField($field_name) { return $this->getByFields([$field_name]); } /** * {@inheritdoc} */ public function getByFields(array $field_names) { $this->groupViolationOffsets(); $violations = []; foreach (array_intersect_key($this->violationOffsetsByField, array_flip($field_names)) as $field_name => $offsets) { foreach ($offsets as $offset) { $violations[] = $this->get($offset); } } return new static($this->entity, $violations); } /** * {@inheritdoc} */ public function filterByFields(array $field_names) { $this->groupViolationOffsets(); $new_violations = []; foreach (array_intersect_key($this->violationOffsetsByField, array_flip($field_names)) as $field_name => $offsets) { foreach ($offsets as $offset) { $violation = $this->get($offset); // Take care of composite field violations and re-map them to some // covered field if necessary. if ($violation->getConstraint() instanceof CompositeConstraintBase) { $covered_fields = $violation->getConstraint()->coversFields(); // Keep the composite field if it covers some remaining field and put // a violation on some other covered field instead. if ($remaining_fields = array_diff($covered_fields, $field_names)) { $message_params = ['%field_name' => $field_name]; $violation = new ConstraintViolation( $this->t('The validation failed because the value conflicts with the value in %field_name, which you cannot access.', $message_params), 'The validation failed because the value conflicts with the value in %field_name, which you cannot access.', $message_params, $violation->getRoot(), reset($remaining_fields), $violation->getInvalidValue(), $violation->getPlural(), $violation->getCode(), $violation->getConstraint(), $violation->getCause() ); $new_violations[] = $violation; } } $this->remove($offset); } } foreach ($new_violations as $violation) { $this->add($violation); } return $this; } /** * {@inheritdoc} */ public function filterByFieldAccess(AccountInterface $account = NULL) { $filtered_fields = []; foreach ($this->getFieldNames() as $field_name) { if (!$this->entity->get($field_name)->access('edit', $account)) { $filtered_fields[] = $field_name; } } return $this->filterByFields($filtered_fields); } /** * {@inheritdoc} */ public function getFieldNames() { $this->groupViolationOffsets(); return array_keys($this->violationOffsetsByField); } /** * {@inheritdoc} */ public function getEntity() { return $this->entity; } /** * {@inheritdoc} */ public function add(ConstraintViolationInterface $violation) { parent::add($violation); $this->violationOffsetsByField = NULL; $this->entityViolationOffsets = NULL; } /** * {@inheritdoc} */ public function remove($offset) { parent::remove($offset); $this->violationOffsetsByField = NULL; $this->entityViolationOffsets = NULL; } /** * {@inheritdoc} */ public function set($offset, ConstraintViolationInterface $violation) { parent::set($offset, $violation); $this->violationOffsetsByField = NULL; $this->entityViolationOffsets = NULL; } }