Problem/Motivation

#2300677: JSON:API POST/PATCH support for fully validatable config entities allows to seriously expand the REST test coverage for config entity types.

Proposed resolution

Let's get ready for this!

Remaining tasks

The aim of the issue is to prepare for the massive removal of @todo in rest coverage. The final decision on the implementation of support POST/PATCH/DELETE validation has not yet been made. Therefore, participation in this issue - at your own risk ;)

User interface changes

API changes

Data model changes

CommentFileSizeAuthor
#2 2912976-2-208_additional.txt85.98 KBAnonymous (not verified)
#2 2912976-2.patch124.05 KBAnonymous (not verified)

Comments

Anonymous’s picture

vaplas created an issue. See original summary.

Anonymous’s picture

Status: Active » Needs review
StatusFileSize
new124.05 KB
new85.98 KB

This patch is based on #208 patch.

Anonymous’s picture

Review:

  1. +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
    @@ -17,12 +19,14 @@
    -abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface {
    +abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface, ValidatableInterface {
    ...
    +  use ConfigValidatableTrait;
    

    To test the all config entities (I hope).

  2. +++ b/core/modules/rest/tests/modules/rest_test_access_helper/rest_test_access_helper.module
    @@ -0,0 +1,18 @@
    +function rest_test_access_helper_entity_type_alter(&$entity_info) {
    +  $entity_info['base_field_override']->setHandlerClass("access", BaseFieldOverrideAccessControlHandlerHelper::class);
    +  $entity_info['editor']->setHandlerClass("access", EditorAccessControlHandlerHelper::class);
    +  $entity_info['field_config']->setHandlerClass("access", FieldConfigAccessControlHandlerHelper::class);
    +  $entity_info['field_storage_config']->setHandlerClass("access", FieldStorageConfigAccessControlHandlerHelper::class);
    +  $entity_info['filter_format']->setHandlerClass("access", FilterFormatAccessControlHandlerHelper::class);
    +}
    

    Most entities are porting like a charm, but these have access problems. In patch, all access controllers are changed via this helper module.

  3. +++ b/core/modules/rest/tests/modules/rest_test_access_helper/src/BaseFieldOverrideAccessControlHandlerHelper.php
    @@ -0,0 +1,20 @@
    +    return AccessResult::allowedIfHasPermission($account, 'administer node fields');
    
    +++ b/core/modules/rest/tests/modules/rest_test_access_helper/src/FieldConfigAccessControlHandlerHelper.php
    @@ -0,0 +1,21 @@
    +    return AccessResult::allowedIfHasPermissions($account, ['administer node fields']);
    
    +++ b/core/modules/rest/tests/modules/rest_test_access_helper/src/FieldStorageConfigAccessControlHandlerHelper.php
    @@ -0,0 +1,20 @@
    +    return AccessResult::allowedIfHasPermission($account, 'administer node fields');
    

    Of course, this is stupid permissions. We should not check only specific 'node' type. But just to demonstrate the passing of the tests :)

  4. +++ b/core/modules/rest/tests/modules/rest_test_base_field_override_helper/rest_test_base_field_override_helper.module
    @@ -0,0 +1,22 @@
    +function rest_test_base_field_override_helper_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
    

    Additional module for stamping the definitions, for the BaseFieldOverride test.

  5. +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
    @@ -798,12 +798,13 @@ public function testPost() {
    -      $label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
    +      $label_field = static::$labelFieldName ?: $this->entity->getEntityType()->getKey('label');
    ...
    @@ -1042,7 +1043,7 @@ public function testPatch() {
    -    $label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
    +    $label_field = static::$labelFieldName ?: $this->entity->getEntityType()->getKey('label');
    ...
    @@ -1327,7 +1328,7 @@ protected function getEntityResourcePostUrl() {
    -    $label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName;
    +    $label_field = static::$labelFieldName ?: $this->entity->getEntityType()->getKey('label');
    

    In some cases, we need the ability to redefine the label, even if the entity has it defined. Example FieldStorageConfig use id for label:

     * @ConfigEntityType(
    ...
     *   entity_keys = {
     *     "id" = "id",
     *     "label" = "id"
     *   },
  6. +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php
    @@ -798,12 +798,13 @@ public function testPost() {
    -      $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nlabel: This value should be of the correct primitive type.\n", $response);
    
    +      $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\n$label: This value should be of the correct primitive type.\n", $response);
    

    use $label instead of 'label', because now it can be different.

  7. +++ b/core/modules/rest/tests/src/Functional/EntityResource/Vocabulary/VocabularyJsonAnonTest.php
    @@ -21,12 +21,4 @@ class VocabularyJsonAnonTest extends VocabularyResourceTestBase {
    -  /**
    -   * Disable the GET test coverage due to bug in taxonomy module.
    -   * @todo Fix in https://www.drupal.org/node/2805281: remove this override.
    -   */
    -  public function testGet() {
    -    $this->markTestSkipped();
    -  }
    -
    

    A pleasant surprise + few other nit typos.

I also forgot about assertNormalizationEdgeCases part of porting.

wim leers’s picture

Issue tags: +API-First Initiative

Love the enthusiasm! 😀 👏

So the aim of this issue is to add PATCH + POST test coverage for all config entity types?

But #2300677: JSON:API POST/PATCH support for fully validatable config entities won't actually enable PATCH + POST support for all config entity types — each of the config entity types will first need to have validation logic added before they can get PATCH + POST support.

So I'm a bit confused :)

Anonymous’s picture

Well, fair question) Maybe I was wrong, and I'm ready close this issue without problems. I just thought that if we add basic support for POST/PATCH/DELETE testing to our tests after:

+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -392,9 +401,8 @@ protected function getBaseRoute($canonical_path, $method) {
-    if ($this->isConfigEntityResource()) {
-      // Currently only GET is supported for Config Entities.
-      // @todo Remove when supported https://www.drupal.org/node/2300677
+    // Without validation, it's impossible to support creation or modification.
+    if (!$this->entityType->entityClassImplements(ValidatableInterface::class)) {
       $unsupported_methods = ['POST', 'PUT', 'DELETE', 'PATCH'];

it will allow us to introduce ValidatableInterface on a more global level, like:

+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -17,12 +19,14 @@
-abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface {
+abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface, ValidatableInterface {

In any case, I was interested to check our config entities on base operations.

wim leers’s picture

Status: Needs review » Closed (works as designed)
-abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface {
+abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface, ValidatableInterface {

This will never happen (at least not during Drupal 8.x, it might in 9.x), for exactly the reasons given in #4. It'll be up to each concrete config entity class to implement ValidatableInterface.

And it's only thanks to that change that this patch can work. So I'm afraid you wasted your time this once :( That being said, every config entity type will need to add its own validation constraints, and then it can implement ValidatableInterface, and then it'll be able to add the test coverage that you already wrote here. So all those issues will be able to come to this issue/patch and get some helpful pointers/inspiration :) So, your effort won't entirely go to waste!

P.S.: if you're looking for issues to help out with — would love to hook you up with some! :D