Throw an exception if a component property's `type` contains non-string values

Created on 17 July 2024, about 2 months ago
Updated 19 August 2024, 20 days ago

Problem/Motivation

The simple component with null type (without wrapping it in a string) produces an unhelpful PHP error.

TypeError: Drupal\Core\Theme\Component\ComponentValidator::Drupal\Core\Theme\Component\{closure}(): Argument #1 ($type) must be of type string, null given in Drupal\Core\Theme\Component\ComponentValidator::Drupal\Core\Theme\Component\{closure}() (line 278 of core/lib/Drupal/Core/Theme/Component/ComponentValidator.php).

Steps to reproduce

Create a component propert with type null:

$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: Example
status: experimental
props:
  type: object
  properties:
    foo:
      type: [null, boolean]

It should be 'null', but if you miss that part and get back to component usage later, it is hard to understand which component is the problematic one, because the error doesn't have any hints to it.

  private function getClassProps(array $props_schema): array {
    $classes_per_prop = [];
    foreach ($props_schema['properties'] ?? [] as $prop_name => $prop_def) {
      $type = $prop_def['type'] ?? 'null';
      $types = is_string($type) ? [$type] : $type;
      // For each possible type, check if it is a class.
      $class_types = array_filter($types, static fn(string $type) => !in_array(
        $type,
        ['array', 'boolean', 'integer', 'null', 'number', 'object', 'string']
      ));
      $classes_per_prop[$prop_name] = $class_types;
    }
    return array_filter($classes_per_prop);
  }

This is the current code from \Drupal\Core\Theme\Component\ComponentValidator::getClassProps. As you can see, the anonymous function expects $type to be a strictly string. But if it is NULL, this leads to a PHP error with an useless message.

$type = $prop_def['type'] ?? 'null'; β€” this part also fails, because it is an array with a NULL value. https://3v4l.org/lfJ6e

Proposed resolution

  1. Add fool's protection and fix it for the developer by casting NULL into 'null'.
  2. Validate types before it enters \Drupal\Core\Theme\Component\ComponentValidator::getClassProps and throw a meaningful exception with mention of component ID and problem.

Remaining tasks

Decide how to handle this. The loop below also expects that all props will be strings, so maybe there should be a validation before that, to ensure that all property types are actual strings?

This is an edge case, but still causing same error:

$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: Example
status: experimental
props:
  type: object
  properties:
    foo:
      type: [!!float 12.3, boolean]
πŸ“Œ Task
Status

RTBC

Version

11.0 πŸ”₯

Component
single-directory componentsΒ  β†’

Last updated 4 days ago

Created by

πŸ‡·πŸ‡ΊRussia Niklan Russia, Perm

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

Merge Requests

Comments & Activities

  • Issue created by @Niklan
  • Merge request !8807Add test with broken property type. β†’ (Open) created by Niklan
  • Status changed to Needs review about 2 months ago
  • πŸ‡·πŸ‡ΊRussia Niklan Russia, Perm

    Added the test that will fail with such definition. It is practically useless, I think, but it shows that the input and expected data are not the same. If you try to render it, a PHP error occurs. Maybe we should throw an exception in that case, I don't know.

  • Pipeline finished with Failed
    about 2 months ago
    #226998
  • Pipeline finished with Canceled
    about 2 months ago
    Total: 65s
    #227001
  • Pipeline finished with Failed
    about 2 months ago
    Total: 578s
    #227003
  • πŸ‡·πŸ‡ΊRussia Niklan Russia, Perm

    I propose to throw an exception if the types of the property contain values that are not strings, which will include floats and special YAML types. We definitely do not want to correct the value !!float 12.3 in any way. We should throw a meaningful exception, indicating the component ID and property name. Then developers can easily identify and fix the problem.

    If we are going to fix NULL for developers automatically, we still have to check for other types and throw an exception. So it's just more code with basically the same result.

  • πŸ‡·πŸ‡ΊRussia Niklan Russia, Perm

    Added check for property type definition values, and if it contains a non-string value, throws an exception. In my case, it is now clear where the problem is:

    Drupal\Core\Render\Component\Exception\InvalidComponentException: The component "foo:bar" uses non-string types for properties: required. in Drupal\Core\Theme\Component\ComponentValidator->validateDefinition() (line 96 of core/lib/Drupal/Core/Theme/Component/ComponentValidator.php).

    $schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
    name: Bar
    props:
      type: object
      properties:
        required:
          type: [null, boolean]
          title: Required
    
  • Pipeline finished with Success
    about 2 months ago
    Total: 632s
    #228072
  • πŸ‡·πŸ‡ΊRussia Niklan Russia, Perm
  • Status changed to RTBC 30 days ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Tried to get some feedback in the slack channel #components but no luck.

    Believe this is a net improvement for sure though

    Test-only feature shows that

    1) Drupal\Tests\Core\Theme\Component\ComponentValidatorTest::testValidateDefinitionInvalid with data set #3 (['https://git.drupalcode.org/pr...a.json', 'Call to Action', 'My description', ['object', ['text'], [[null, 'Title', 'The title for the cta', ['Press', 'Submit now']], ['string', 'URL', 'uri'], ['string', 'Target', ['', '_blank']], ['Drupal\Core\Template\Attribute', 'Attributes']]], 'my-cta', 'module', 'sdc_test:my-cta', [[[[]]]], '', 'sdc_test', 'my-cta.twig', 'my-group'])
    Failed asserting that exception of type "Drupal\Core\Render\Component\Exception\InvalidComponentException" is thrown.
    2) Drupal\Tests\Core\Theme\Component\ComponentValidatorTest::testValidateDefinitionInvalid with data set #4 (['https://git.drupalcode.org/pr...a.json', 'Call to Action', 'My description', ['object', ['text'], [[['string', null], 'Title', 'The title for the cta', ['Press', 'Submit now']], ['string', 'URL', 'uri'], ['string', 'Target', ['', '_blank']], ['Drupal\Core\Template\Attribute', 'Attributes']]], 'my-cta', 'module', 'sdc_test:my-cta', [[[[]]]], '', 'sdc_test', 'my-cta.twig', 'my-group'])
    Failed asserting that exception of type "TypeError" matches expected exception "Drupal\Core\Render\Component\Exception\InvalidComponentException". Message was: "Drupal\Core\Theme\Component\ComponentValidator::Drupal\Core\Theme\Component\{closure}(): Argument #1 ($type) must be of type string, null given" at
    /builds/issue/drupal-3462156/core/lib/Drupal/Core/Theme/Component/ComponentValidator.php:278
    /builds/issue/drupal-3462156/core/lib/Drupal/Core/Theme/Component/ComponentValidator.php:84
    /builds/issue/drupal-3462156/core/tests/Drupal/Tests/Core/Theme/Component/ComponentValidatorTest.php:62
    
  • Status changed to Needs work 24 days ago
  • πŸ‡³πŸ‡ΏNew Zealand quietone New Zealand

    I don't see that anyone has received the code for this issue, only that the test only feature has been used. Remember, issues do need a code review. I thought at first that this was throwing a new exception but I see that it is not. I do think a comment is needed, which I indicated in the MR, perhaps some of the detail in #4 would be useful there.

    The title here should include some indication of what this fix applies to. The title should be a description of what is being fixed or improved. The title is used as the git commit message so it should be meaningful an concise. See List of issue fields β†’ .

    So, two small things, although this still needs a review by someone familiar with this component.

  • Pipeline finished with Canceled
    24 days ago
    Total: 87s
    #254990
  • Status changed to Needs review 24 days ago
  • πŸ‡·πŸ‡ΊRussia Niklan Russia, Perm

    Added comment and adjusting issue title

  • Pipeline finished with Failed
    23 days ago
    #254991
  • Status changed to RTBC 23 days ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Believe title reflects the change so removing that tag.

    Also appears additional feedback has been addressed

  • πŸ‡§πŸ‡ͺBelgium Wim Leers Ghent πŸ‡§πŸ‡ͺπŸ‡ͺπŸ‡Ί

    I think the test could be slightly clearer (see MR comment), but I think this is ready nonetheless πŸ‘

  • Pipeline finished with Success
    20 days ago
    Total: 602s
    #258231
Production build 0.71.5 2024