Avoid config form field type "machine_name"

Created on 5 May 2025, 3 months ago

Problem/Motivation

This is a follow-up issue on ๐Ÿ› Token name in RenderElementActionBase cannot be specified as nested token Active and we should consistently avoid the usage of machine_name as a form field type.

Proposed resolution

  • There are 11 other cases where the field type machine_name is being used, most of them allow tokens as well and could run into the same problem. We should replace them all for consistency.
  • Most of those cases support tokens or require a token reference, both of which not being declared in the form field configuration. That should be added.
  • Form field validation: those fields that get the token reference attribute will still be validated. But others won't. We may consider our own validation as a replacement for the machine name validation that we've then lost.
๐Ÿ› Bug report
Status

Active

Version

3.0

Component

Code

Created by

๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

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

Merge Requests

Comments & Activities

  • Issue created by @jurgenhaas
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia Ishani Patel

    ishani patel โ†’ made their first commit to this issueโ€™s fork.

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia Ishani Patel

    Hello @jurgenhaas,
    I've created MR.
    Please check and review.

    Thank you!

  • Pipeline finished with Success
    3 months ago
    Total: 435s
    #494775
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

    @ishani patel this is looking good for the first item in the proposed solution. We also need to look into the other two.

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia Ishani Patel

    Hello @jurgenhaas,
    Sure,Can I go with the below changes:

    For point 2. (#token_type)
    For point 3. (#element_validate)

    Update the field definition like this:
    2. Add Token Support to the Field Configuration:

    $form['name'] = [
      '#type' => 'textfield',
      '#maxlength' => 1024,
      '#title' => $this->t('Machine name'),
      '#description' => $this->t('Specify the machine name / key of the render element. Tokens are allowed.'),
      '#default_value' => $this->configuration['name'],
      '#element_validate' => [[$this, 'validateName']],
      '#token_types' => ['node', 'user', 'custom'], // Based on your context
    ];

    3. Add Custom Validation

    public function validateName(array &$element, FormStateInterface $form_state, array &$complete_form) {
      $value = $element['#value'];
    
      // Allow token patterns like [entity:property]
      if (preg_match('/^\[.*:.*\]$/', $value)) {
        return;
      }
    
      // Otherwise, validate as a machine name.
      if (!preg_match('/^[a-z0-9_]+$/', $value)) {
        $form_state->setError($element, $this->t('The name must be a machine-readable name (lowercase letters, numbers, and underscores only) or a valid token like [node:title].'));
      }
    }

    Let me know your thoughts.
    Thank you!

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

    As for the token support, there are 2 ECA-specific attributes that we're using for the form fields:

    '#eca_token_replacement' => TRUE,
    '#eca_token_reference' => TRUE,
    

    The first one indicates that tokens are allowed in the input field and the plugin will replace tokens with their value. The second one tells the user that a token name should be provided without the brackets.

    As for the machine name replacement, we always need the eca_token_reference to be turned on. In some cases, this can also support eca_token_replacement, we need to check the code in detail if the access and execute methods do call token replacement on that config value.

    We don't need to add anything to the description, though, as ECA takes care of it according to those two properties I described.

    And then, the #token_types property is not required here, either.

    When it comes to validation, it may be a bit more complex than this. Following the token properties above, we may or may not have brackets around the "machine name", and the content itself can contain strings and a few extra characters like colons, but e.g. no spaces (I guess). But it can certainly be more than one colon, e.g. for something like node:body:value.

    In any case, the validator should go into a service or a trait, so that we don't end up with redundant code everywhere.

  • Pipeline finished with Failed
    about 2 months ago
    Total: 261s
    #513404
  • Assigned to jurgenhaas
  • Status changed to Needs work 17 days ago
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen
  • Pipeline finished with Success
    17 days ago
    Total: 494s
    #549140
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

    I've now added a field validation to the former machine name fields and also verified the token attributes for each of them.

  • Pipeline finished with Success
    17 days ago
    Total: 641s
    #549195
  • ๐Ÿ‡จ๐Ÿ‡ญSwitzerland boromino

    If I add one of the changed actions in a bpmn model and click the save button, I get the error in the modeler, that something went wrong (the model is not saved) and in the console:

    "\nAn AJAX HTTP error occurred.\nHTTP Result Code: 500\nDebugging information follows.\nPath: /admin/modeler_api/eca/bpmn_io/save\nStatusText: error\nResponseText: The website encountered an unexpected error. Try again later.TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback, class Drupal\\modeler_api\\Form\\RuntimePluginForm does not have a method "validateElementsMachineName" in call_user_func_array() (line 282 of core/lib/Drupal/Core/Form/FormValidator.php). Drupal\\Core\\Form\\FormValidator->doValidateForm() (Line: 239)\nDrupal\\Core\\Form\\FormValidator->doValidateForm() (Line: 239)\nDrupal\\Core\\Form\\FormValidator->doValidateForm() (Line: 118)\nDrupal\\Core\\Form\\FormValidator->validateForm() (Line: 585)\nDrupal\\Core\\Form\\FormBuilder->processForm() (Line: 321)\nDrupal\\Core\\Form\\FormBuilder->buildForm() (Line: 295)\nDrupal\\modeler_api\\Component->validate() (Line: 395)\nDrupal\\modeler_api\\Api->prepareModelFromData() (Line: 241)\nDrupal\\modeler_api\\Controller\\ModelerApi->save()\ncall_user_func_array() (Line: 123)\nDrupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}() (Line: 622)\nDrupal\\Core\\Render\\Renderer->executeInRenderContext() (Line: 121)\nDrupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)\nDrupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}() (Line: 183)\nSymfony\\Component\\HttpKernel\\HttpKernel->handleRaw() (Line: 76)\nSymfony\\Component\\HttpKernel\\HttpKernel->handle() (Line: 53)\nDrupal\\Core\\StackMiddleware\\Session->handle() (Line: 48)\nDrupal\\Core\\StackMiddleware\\KernelPreHandle->handle() (Line: 28)\nDrupal\\Core\\StackMiddleware\\ContentLength->handle() (Line: 32)\nDrupal\\big_pipe\\StackMiddleware\\ContentLength->handle() (Line: 116)\nDrupal\\page_cache\\StackMiddleware\\PageCache->pass() (Line: 90)\nDrupal\\page_cache\\StackMiddleware\\PageCache->handle() (Line: 48)\nDrupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle() (Line: 51)\nDrupal\\Core\\StackMiddleware\\NegotiationMiddleware->handle() (Line: 53)\nDrupal\\Core\\StackMiddleware\\AjaxPageState->handle() (Line: 51)\nDrupal\\Core\\StackMiddleware\\StackedHttpKernel->handle() (Line: 715)\nDrupal\\Core\\DrupalKernel->handle() (Line: 19)\n"

  • Pipeline finished with Canceled
    10 days ago
    #555122
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

    Ah, the validation happens in a pseudo form and not directly in the plugin, so that the trait is not available at that point. I've replaced that with a static class method now.

  • Pipeline finished with Success
    10 days ago
    #555123
  • ๐Ÿ‡จ๐Ÿ‡ญSwitzerland boromino
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

    I've addressed all topics.

  • Pipeline finished with Success
    9 days ago
    #555898
  • ๐Ÿ‡จ๐Ÿ‡ญSwitzerland boromino
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

    @boromino that's not correct. See the original issue that started all this at ๐Ÿ› Token name in RenderElementActionBase cannot be specified as nested token Active which uses mytoken:nested as a token reference, e.g. in RenderElementActionBase. So, for token references, colons are allowed.

  • ๐Ÿ‡จ๐Ÿ‡ญSwitzerland boromino

    I was only referring to token replacements, but I have tested it with a machine name with colon and it works. I thought it had to comply with Drupal's machine_name form element, but that doesn't seem to be the case.

  • Pipeline finished with Skipped
    7 days ago
    #557474
  • Pipeline finished with Success
    7 days ago
    Total: 617s
    #557472
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany jurgenhaas Gottmadingen

    Merged and back ported, thank you so much for all the tests and reviews.

Production build 0.71.5 2024