Problem with: Filter violations based on the given fields.

Created on 10 January 2024, 12 months ago
Updated 11 January 2024, 12 months ago

Problem/Motivation

I use a Vue3 frontend to display nodes and other entities. Think about it like an issue tracker. The thing is, that a normal user shall not fully edit a node type, but shall be able to edit a few fields. For example I do have a JSON field, which the user can be fill with the given UI. This will be saved by executing a button.

BUT (now the discovered problem), the button to set an node issue to state "done" is another button. The thing is, when I use the Drupal UI it works as expected, my custom validations catch the error in the missing JSON field and display the error. When I use JSON:API and PATCH only the field_issue_state field (which is a Workflow field), the JSON:API returns without problems.

After some digging I found _my_ problem.

  protected static function validate(EntityInterface $entity, array $field_names = NULL) {
    if (!$entity instanceof FieldableEntityInterface) {
      return;
    }

    $violations = $entity->validate();

    // Remove violations of inaccessible fields as they cannot stem from our
    // changes.
    $violations->filterByFieldAccess();

    // Filter violations based on the given fields.
    if ($field_names !== NULL) { 
      $violations->filterByFields( // <------------------ HERE
        array_diff(array_keys($entity->getFieldDefinitions()), $field_names)
      );
    }

In the EntityValidationTrait the validation of the whole entity happens AND successfully finds the errors, but because I decided to only send the `field_issue_state` field to the server the function removes the errors and treats the problem as non existend. This is strange and I guess it must be a relict of old Drupal HTML form thinking, when you can only show errors of fields you have send to the server.

But regardless the entity I have is still in a wrong state. Even if I only send a field to be changed.

In my case the idea is to deny the change from "open" to "done" because another field (the JSON field in this example) is missing informations from the user.

With the Drupal Forms were always every field is send this error will not happen often, but with JSON:API which has the PATCH endpoint where I send only the things I want to change, this problem could occur more often.

Steps to reproduce

You need an entity with a contraint on one field, but in conjunction with another (for example status). Let the field in a wrong state and only update the status field to 1 with the JSON:API call.

Proposed resolution

Not sure. Either it will be mandatory to keep track of all "validation wise connected" fields, thus you have to send them over the wire when using JSON:API or have a HTTP header to disable the code shown above.

When I comment this:

    // Filter violations based on the given fields.
//    if ($field_names !== NULL) {
//      $violations->filterByFields(
//        array_diff(array_keys($entity->getFieldDefinitions()), $field_names)
//      );
//    }

it works as expected in my case. The errors are piped to the frontend via an JSON:API 422.

Remaining tasks

User interface changes

none (because it works in the drupal ui)

API changes

Data model changes

Release notes snippet

Workaround

Just send all involved fields with their data - even if nothing changed there.

Feature request
Status

Closed: works as designed

Version

10.2

Component
JSON API 

Last updated 3 days ago

Created by

🇩🇪Germany ro-no-lo

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024