Problem/Motivation
If a field supports creating multiple bundles of given entity type (e.g. a media reference field that allows referencing Video and Image), users are normally presented a dropdown list to select which bundle they want to create. If the user only has privileges to create one of the available bundles, no dropdown is selected. This makes sense. However, when they click the button to add a new entity, the wrong bundle form can be presented, allowing them to create an entity of a bundle type they don't have access to create.
This happens because of this code in the form widget:
// Let the user select the bundle, if multiple are available.
if ($create_bundles_count > 1) {
$bundles = [];
foreach ($this->entityTypeBundleInfo->getBundleInfo($target_type) as $bundle_name => $bundle_info) {
if (in_array($bundle_name, $create_bundles)) {
$bundles[$bundle_name] = $bundle_info['label'];
}
}
asort($bundles);
$element['actions']['bundle'] = [
'#type' => 'select',
'#options' => $bundles,
];
}
else {
$element['actions']['bundle'] = [
'#type' => 'value',
'#value' => reset($create_bundles),
];
}
The else statement is hit in this scenario. It sets the bundle to a fixed value form element. However, this value is NOT sent in the Ajax request that's sent when the button to add a new item is pressed. So the logic in determineBundle
doesn't have a value to use from form state, so it defaults to instead use the first item from the list of bundles that can be referenced. Since "image" appears first in this list, it's used:
protected function determineBundle(FormStateInterface $form_state) {
$ief_settings = $form_state->get(['inline_entity_form', $this->getIefId()]);
if (!empty($ief_settings['form settings']['bundle'])) {
return $ief_settings['form settings']['bundle'];
}
elseif (!empty($ief_settings['bundle'])) {
return $ief_settings['bundle'];
}
else {
$target_bundles = $this->getTargetBundles();
return reset($target_bundles);
}
}
The last else statement is hit here.
Steps to reproduce
- Fresh Drupal install using Standard profile with Inline Entity Form (I was using rc15) and Media installed
- Add a Media reference field on Basic Page, allowing both Image and Video to be referenced
- Configure the form widget to be Inline Entity Form - Complex, all default settings
- Modify the permissions for the Content Editor role to allow it to create Video media (nothing else)
- As an admin, Visit Basic Page node form, observe you have a dropdown to select which bundle to create
- As a content editor, Visit Basic Page node form, observe you don't have a dropdown (this is good, you only have perms to create Video, so no sense in showing dropdown). Observe that when clicking the button "Add new media item" you are presented the form for creating an Image instead of Video
Proposed resolution
I think updating the last else statement in determineBundle
to pull from the list of bundles the user is allowed to create is the solution here, rather than the list the field is allowed to reference.
I'm not sure it's needed at all to set the fixed bundle value in the form. Not sure this is doing anything at all since it's not sent with the AJAX request.
Remaining tasks
User interface changes
API changes
Data model changes