Access denied to Form field: set as disabled (eca_form_field_disable)

Created on 29 March 2023, over 1 year ago
Updated 27 April 2023, over 1 year ago

Problem/Motivation

Executing the action Form field: set as disabled (eca_form_field_disable) results in an Access denied error.

The log message:

Access denied to Form field: set as disabled (eca_form_field_disable) from ECA Test (test) for event Drupal\eca_form\Event\FormBuild:
- event (DTO)
- machine-name (string "eca.form.build")
- entity (Entity node/article//)
- node (Entity node/article//)
- user (Entity user/1/admin)
- form (DTO)
- id (string "node_article_form")
- base-id (string "node_form")
- operation (string "default")
- num-errors (integer "0")

Steps to reproduce

  1. In a fresh Drupal 9.5 site, install and enable ECA and the ECA Form submodule.
  2. Create a model that includes the Form field: set as disabled action.
  3. Test the model by performing an action that triggers the event.

I tested this on a new Drupal install that I set up to learn about the ECA module and haven't been able to get the eca_form_field_disable action to run successfully.

I've tried a few different events (without conditions), like content_entity_prepareform and form_form_after_build, but haven't been able to get 'set as disabled' to execute. I've also tried this with 'Execute models with user' (with uid 1) and with the 'switch user' action.

I've also tried the same events with different actions, for example Form: set method (eca_form_set_method) has run successfully.

Here is my config:

langcode: en
status: true
dependencies:
  module:
    - eca_form
    - eca_user
id: test
modeller: core
label: Test
version: '1'
weight: null
events:
  form_form_build:
    plugin: 'form:form_build'
    label: 'Build form'
    configuration:
      form_id: node_article_form
      entity_type_id: ''
      bundle: ''
      operation: ''
    successors:
      -
        id: eca_switch_account
        condition: null
conditions: {  }
gateways: {  }
actions:
  eca_switch_account:
    plugin: eca_switch_account
    label: 'User: switch current account'
    configuration:
      user_id: '1'
    successors:
      -
        id: eca_form_field_disable
        condition: null
  eca_form_field_disable:
    plugin: eca_form_field_disable
    label: 'Form field: set as disabled'
    configuration:
      flag: true
      field_name: op
    successors: {  }
🐛 Bug report
Status

Fixed

Version

1.2

Component

Documentation

Created by

🇨🇦Canada jmee Canada

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

Comments & Activities

  • Issue created by @jmee
  • 🇩🇪Germany mxh Offenburg

    Many ECA action plugins use the access method to verify, whether the action is executable. It's a design problem of ECA that leads to this confusion. In your case, the form field named as "op" most probably doesn't exist. Guess you're trying to disable the submit button of the article form. Try using "submit" as form field name instead of "op" in your config and let me know here whether that works for you or not.

    The "Build form" event should already be the right one to react upon, when it's about manipulating submit buttons. I'm currently not sure whether "node_article_form" is the correct form ID, but could be. Otherwise, you could also try to set for entity type ID "node", bundle "article" and operation "default, edit".

  • 🇩🇪Germany mxh Offenburg

    Many ECA action plugins are using the access method to determine, whether an action is executable. That's a design problem of ECA, that leads to this confusion. In your case, the form field named as "op" most probably doesn't exist and thus leads to an access denied result.

    Guess you're trying to disable the Save button in the article form. Try using "submit" as field name instead of "op", and please let me know here whether that works or not.

    The "Build form" event should already be the right one when it's about manipulating submit buttons in an entity form. I'm not sure whether "node_article_form" is the correct form ID - maybe it is, but if not, you could also try with entity type "node", bundle "article" and operation "default, edit".

  • 🇨🇦Canada jmee Canada

    Changing the value in "Field name" on the eca_form_field_disable to `submit` worked, thanks for that tip!

    Maybe the help text could be improved, I wouldn't have thought that `op` was correct if not for a message in the ui telling me to use the name attribute.

    The current help text is:

    The input name of the form field. This is mostly found in the "name" attribute of an form element. This property supports tokens.

    And the input element is:

    <input data-drupal-selector="edit-submit" type="submit" id="edit-submit" name="op" value="Save" class="button button--primary js-form-submit form-submit">

    In this situation the type attribute was what worked. Is this always the case, or are there situations where we would need to use a different attribute value ?

    Thank you for such a quick response!

  • 🇩🇪Germany mxh Offenburg

    Agreed, the help text may not be ideal and could be improved. The keyword in the help text is "mostly" ;)

    The reason why "submit" works here is not because of the type attribute, it's because the "Save" button is identified with a "submit" array key within the form render array.

    Another possible improvement would be to additionally "autodetect" a form field element using the "#name" render array key, some kind of fallback try when it didn't manage to find a form field element yet.

    Finally another improvement could be: A text to a forbidden access result could be added to appear in the logs, and the action could add an informative text why access was forbidden. In this case it could tell something like "The targeted form field element does not exist".

    Not yet marking as fixed, as I think it makes sense to at least address one possible improvement for this.

  • 🇨🇦Canada jmee Canada

    Changing the help text / documentation seems like the minimum here. Using submit would have been my first guess, but the way it is currently written is actively misleading.

    The field label here ('Field name') is also pretty ambiguous. There's nothing here that is actually telling a user what is needed.

    If this action needs the input's #name key from the form render array, why not just say that ?

    Thanks again! I'd love to better understand this topic.

  • 🇩🇪Germany mxh Offenburg

    If this action needs the input's #name key from the form render array, why not just say that ?

    That's not how the action behaves internally. It could be added as a fallback behaviour if it didn't find a form field element otherwise, as suggested in #5. Mostly, form field elements are being identified by their array key within the form render array, prepended by their "#parents" key entries. Nevertheless, we have an obvious room for optimization here, both regarding the description and its internal behaviour.

  • 🇨🇦Canada jmee Canada

    thank you for taking the time to respond here! I thought I understood by now I'm more lost. It sounded like a user needs to enter a value from the render array, but now it seems that is wrong as well.

    Is it possible to explain what a user is supposed to enter in the Field name field on this action in order for the action to run ?

    If it's not something that can be explained, or if it's something that changes drastically depending on the situation, then there's not a field label or help text or even documentation that will solve the issue. If this is the case, I'd lean towards identifying this as a bug, rather than a documentation issue.

  • 🇩🇪Germany mxh Offenburg

    It sounded like a user needs to enter a value from the render array, but now it seems that is wrong as well.

    I just described the internal behavior above, trying to explain why the current behavior is what it is. The user of the plugin is supposed to enter the input name of a form field, as the help text describes. The internal behavior is then supposed to resolve that. However, it's not that easy, because it's not consistent how the form render array is being built up - otherwise it would already work.

    Is it possible to explain what a user is supposed to enter in the Field name field on this action in order for the action to run ?

    As said, the name which can be found in the according input element as attribute, is what mostly works. Especially when it's a textfield, options etc. or any other sort of form input. Submit buttons however are currently a bit of a special case, and that's why there not part of mostly for now. We could consider improving the behavior as mentioned above.

    I agree that we may now handle this as a bug.

  • @mxh opened merge request.
  • Status changed to Needs review over 1 year ago
  • 🇩🇪Germany mxh Offenburg

    I took a closer look into the current behavior, and it turns out that usually, all form submit buttons in a content form share the same name "op". That leads to the fact that the suggested improvement of the internal behavior doesn't make much sense, as finding an element named as "op" would then only return one (of possibly multiple) elements.

    The only aspects I could improve in a matter of justified time was by adding a descriptive text when the access result denied is being logged. I also added a sentence into the description for the form's "Field name" specifically for the labeled "Save" and "Preview" buttons, which are mostly found when working on a content form. Hope that might be helpful in the future.

  • Status changed to RTBC over 1 year ago
  • 🇩🇪Germany jurgenhaas Gottmadingen

    This looks like the best we can do for now. Thanks @mxh

  • 🇩🇪Germany jurgenhaas Gottmadingen

    Merged and back ported.

  • Status changed to Fixed over 1 year ago
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024