Problem/Motivation
Machine names need to be unique, normally MachineName::validateMachineName takes care of this and sets form errors where required.
When creating a duplicate machine name for a MediaType entity the site crashes on form submit and throws the following error:
Uncaught PHP Exception Drupal\\Core\\Entity\\EntityStorageException: "'media_type' entity with ID 'image' already exists." at /.../core/lib/Drupal/Core/Entity/EntityStorageBase.php line 425, referer: http://example.com/admin/structure/media/add
Steps to reproduce:
1) Enable the media module, then go to /admin/structure/media/add
2) Create a type called "File Foo", click "Save".
3) Go to the same page, create another type called "File Foo", click "Save"
Proposed resolution
Figure out why MachineName::validateMachineName isn't firing for MediaType entities.
Remaining tasks
As above
User interface changes
None
API changes
None
Data model changes
None
Comment | File | Size | Author |
---|---|---|---|
#23 | interdiff-2932226-20-23.txt | 501 bytes | robpowell |
#23 | media-validate-machine-name-2932226-23-D8.patch | 3.81 KB | robpowell |
#20 | interdiff-2932226-16-20.txt | 623 bytes | robpowell |
#20 | media-validate-machine-name-2932226-20-D8.patch | 3.81 KB | robpowell |
#17 | interdiff-2932226-10-17.txt | 2.56 KB | robpowell |
Comments
Comment #2
marcoscanoThanks for reporting, this is a pretty nasty bug :)
Bumping to major because a "normal" user action on the UI shouldn't trigger a WSOD.
Added steps to reproduce to the IS.
Comment #3
marcoscanoAfter digging into this a bit, this is what I could find:
-
MachineName::validateMachineName()
is being called during the first AJAX callback (when the source select is triggered), and correctly calls$form_state->setError()
due to the machine name not being unique.- This call to
$form_state->setError()
does NOT set the error because at this point$form_state->getLimitValidationErrors()
returns an empty array.- The empty array comes from
FormValidator::determineLimitValidationErrors()
, which will set it to[]
whenever the triggering element does not execute submit callbacks and there is no explicit'#limit_validation_errors'
key on the element.Setting the element to have
'#executes_submit_callback' => TRUE,
appears to solve the problem. Also added a specific submit for this element, to prevent the whole form from being submitted on the AJAX call.I'm adding a test-only patch to demonstrate the bug.
Also, solving this has surfaced to the UI the notices reported in #2932222: Undefined index: source_configuration breaks AJAX:
Notice: Undefined index: source_configuration in Drupal\media\MediaTypeForm->validateForm() (line 289 of /var/www/html/core/modules/media/src/MediaTypeForm.php)
Because now it's on the UI, I'm including here the fix from that patch as well. If this is OK, please credit @Darvanen for the patch as well.
Comment #5
marcoscanoComment #6
BerdirFine if you found a workaround for that specific form but this is a generic problem for all forms with ajax elements, we've had #2557299: Any AJAX call disregards machine name verification when AJAX is used and leads to a fatal error open for a long time about that to fix it in general but it's complicated IIRC.
Comment #7
darvanenI think that's a solid duplication.
Comment #8
marcoscanoThank you @Berdir and @Darvanen
This one has a workaround for a specific form that affects site builders in a much more evident way. Solving it generically might take some time, so IMHO I believe it is justified to have a solution for the Media type form in the short term as its own issue.
Comment #9
phenaproximaI think I'm OK with this workaround, as long as we open a follow-up issue to remove it once #2557299: Any AJAX call disregards machine name verification when AJAX is used and leads to a fatal error lands, and a comment in the patch which points to that follow-up.
Comment #10
marcoscanoCreated follow-up: #2934154: [PP-1] Remove workaround to enforce machine name validation on MediaType forms, and included a @TODO in the patch.
Comment #12
marcoscanoComment #13
xjmMinor formatting nitpick:
@todo
should be lowercase, and the subsequent comment lines should be indented by two spaces between the//
and the text.Comment #14
xjmFWIW I am also okay with an @todo postponed on the followup, at least in principle.
Comment #15
phenaproximaLooks great! Just nits.
We can use static::class instead of get_called_class().
$form is passed by reference.
No need for TRUE here.
Let's use isset($form['source_dependent']['source_configuration']) instead.
Same here.
Comment #16
robpowellComment #17
robpowellThis should be a full code block.
Attached patch includes #13, #15 and the above code block.
Comment #18
robpowellComment #19
phenaproximaSUPERNIT! The description should begin with "Form submission handler...", and the two parameters need a description line ("The structured form array" and "The current form state" oughta do the trick).
Comment #20
robpowellupdates done
Comment #21
robpowellComment #22
phenaproximaAw man, sorry to do this, but...
1) The description needs to be indented by one more space.
2) The description should say "Current form state", not "parent".
Comment #23
robpowellupdate done
Comment #24
robpowellComment #25
phenaproximaAh yesh, this is good to go once Drupal CI passes it. Thanks, @robpowell!
Comment #27
xjmI checked with @larowlan and he also mentioned being comfortable with this workaround/hotfix for this specific issue.
Committed and pushed to 8.5.x. Thanks!