Problem/Motivation

Entity browsers do not have an entity type or set of bundles. They are entity type and entity bundle agnostic. Their widgets are often specific to a certain type, such as the file upload widget, or a view widget where there is a certain entity type. Users often think they can use the file upload widget for media and the media upload widget for files. Or they might select an entity browser with a view for users on a node field, and everything works until you go to save and you get an "This entity cannot be referenced" error.

Proposed resolution

Where possible, widgets should expose their entity type and bundle type so that it can be validated against the widget context.

The widgets should be validated on the field widget settings form. If they do not match, a useful error should display to the user.

Additionally, since there may be existing configs, or someone might copy and past within a config, we should have validation when the widget loads to check that it matches the widget context. If it does not match the current context, display to the user a useful error.

A possible follow up would be to get this working on entity embed config form, for example, and inline entity form field widget config form.

Remaining tasks

- review

User interface changes

- additional error messages on the field widget config settings
- replacement of widget with error message if misconfigured within entity browser

API changes

- WidgetBase implements new interface WidgetEntityInfoInterface
- if Widgets implement its methods to expose the widget's entity type or bundle types, additional validation of the widget will take place on the field widget settings and within the entity browser.

Data model changes

- In order to add test coverage of the media_image_upload widget, adding a schema for it (which was missing).
- One thing to note on this is that the 'multiple' parameter is being set to a string even though it *should* be a boolean. This is for backwards compatibility, so as not to break existing implementations.

Original issue summary

Using Drupal 8.4.3 with the new core media module, entity_browser 2.x and media_entity_browser 2.x, when I use the 'Upload images as media items' widget and upload a new image file I get the following error:

The website encountered an unexpected error. Please try again later.
Recoverable fatal error: Argument 1 passed to file_validate() must implement interface Drupal\file\FileInterface, instance of Drupal\media\Entity\Media given, called in modules/contrib/entity_browser/src/Plugin/EntityBrowser/WidgetValidation/File.php on line 31 and defined in file_validate() (line 286 of core/modules/file/file.module).

For example: #2875209: TypeError: Argument 1 passed to file_validate() must implement interface Drupal\file\FileInterface, instance of Drupal\media_entity\Entity\Media given mentions the fix as changing the type of field, however that is not a solution to this problem since the module allows the entity browser to be used for these field types.

CommentFileSizeAuthor
#71 2930677-71.patch67.81 KBwaropd
#68 2930677-n68.patch67.88 KBhanoii
#67 2930677-n67.patch68.85 KBhanoii
#55 entity-browser-widget-entity-validation-2930677-55.patch69.56 KBoknate
#51 entity-browser-widget-entity-validation-2930677-50.patch65.14 KBoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-7.patch19.17 KBoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-6.patch24.19 KBoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-5.patch3.27 KBoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-5.patch3.27 KBoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-4.patch969 bytesoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-3.patch7.63 KBoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-2.patch4.13 KBoknate
#50 entity-browser-widget-entity-validation-2930677--44-PART-1.patch6.82 KBoknate
#40 entity-browser-widget-entity-validation-2930677-40.patch65.14 KBoknate
#38 entity-browser-widget-entity-validation-2930677-38.patch64.95 KBoknate
#36 entity-browser-widget-entity-validation-2930677-36.patch64.95 KBoknate
#30 entity-browser-widget-entity-validation-2930677-30-combined-with-2807873-38.patch70.38 KBoknate
#30 entity-browser-widget-entity-validation-2930677-30.patch64.96 KBoknate
#30 2930677–280787--interdiff-27-30.txt26.58 KBoknate
#28 entity-browser-widget-entity-validation-2930677-28-combined-with-2807873-38.patch70.38 KBoknate
#28 entity-browser-widget-entity-validation-2930677-28.patch64.96 KBoknate
#28 2930677–280787--interdiff-27-28.txt26.58 KBoknate
#26 entity-browser-widget-entity-validation-2930677-24-reroll.patch56.17 KBoknate
#25 2930677–280787--interdiff-21-24.txt27.17 KBoknate
#24 2930677–280787--interdiff-21-24.txt27.17 KBoknate
#24 entity-browser-widget-entity-validation-2930677-24-combined-with-2807873-38.patch61.59 KBoknate
#24 entity-browser-widget-entity-validation-2930677-24.patch57.81 KBoknate
#21 entity-browser-widget-entity-validation-2930677-21.patch34.19 KBoknate
#21 entity-browser-widget-entity-validation-2930677-21-combined-with-2807873-38.patch39.81 KBoknate
#19 entity-browser-widget-entity-validation-2930677-19-combined-with-2807873-38.patch29.39 KBoknate
#19 entity-browser-widget-entity-validation-2930677-19.patch19.75 KBoknate
#18 entity-browser-widget-entity-validation-2930677-18.patch11.93 KBoknate
#16 entity-browser-widget-entity-validation-2930677-16.patch6.16 KBoknate
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

rooby created an issue. See original summary.

rooby’s picture

Title: Error when uploading a new file into an image field via the media_entity_browser module » Error when uploading a new file into an image field using 'Upload images as media items'
rooby’s picture

I know there are a couple of other issues open for the same/similar error however they have been closed and IMO their solutions/workarounds are not sufficient because it is supposed to work with file fields. See:

 * @FieldWidget(
 *   id = "entity_browser_file",
 *   label = @Translation("Entity browser"),
 *   provider = "entity_browser",
 *   multiple_values = TRUE,
 *   field_types = {
 *     "file",
 *     "image"
 *   }
 * )
rooby’s picture

As a proof of concept, if I was to change the validate function to do this:
(excuse the potentially bad choice of functions, I'm just hacking stuff out)

        // Get the file entity from a media entity.
        if ($entity->getEntityType()->id() == 'media') {
          $source = $entity->getSource();
          $file = $entity->get($source->configuration['source_field'])->entity;
        }
        else {
          $file = $entity;
        }

        if ($errors = file_validate($file, $options['validators'])) {

Then I get around this issue but then I get "The entity must be of type file. "

That issue has also been reported elsewhere and was fobbed off with the same misconfiguration explanation, however again, if it shouldn't be configured like that we shouldn't be allowing it to be configured like that.

justinlevi’s picture

I'm also experiencing this issue. Any solution yet?

rooby’s picture

Issue summary: View changes
mandavya’s picture

same problem here

Any thoughts!

juliakoelsch’s picture

I migrated to Core Media, and did not alter the config generated during the migration. I have the config as it was generated, and lots of content already, so changing the field type is not an option. Any help would be appreciated!

lias’s picture

This is still an issue with core Media and Entity Browser.

Drupal 8.6.1
Entity Browser 8x-2.0
Inline Entity Form 8x-1.0-rc1
Paragraphs 8x-1.3

Unable to upload/replace image using Entity Browser. Clicking on upload does in fact upload the image to sites/default/files/media but doesn't display as uploaded and results instead in "The entity must be of type media." error.

The file displays in the Files content overview section but doesn't register as Media content. The file also shows that it is not used in 0 places.

When switched from Entity Browser widget to Inline entity form - simple/advanced the image is correctly uploaded and displayed.

Similar and unresolved issues:

https://www.drupal.org/project/entity_browser/issues/2822354 - there is a suggested solution to make sure that the field is a Media reference field but I am using entity reference > media > image for the field and still get the "..must be of type.." error
https://www.drupal.org/project/entity_browser/issues/2685029
https://www.drupal.org/project/entity_browser/issues/2948839

------EDIT

I've decide to move to Media Library which is currently experimental in Drupal 8.6.1 core. It seems to be functioning well for selecting media images for reuse and for uploading.

stijndmd’s picture

You need to add a reference field instead.

Reference group => Other
Next step: Content group => Media
Next step: in the field setup you can pick one of your created media bundles

oknate’s picture

removed comment, I realized it wasn't relevant.

no74h’s picture

Changing field type is not a solution nor a workaround for sites with uploaded medias. Any ideas?

oknate’s picture

Status: Active » Closed (cannot reproduce)

I believe the bug here is user error. You must use the "Upload" widget for file/image fields and the "Upload as media items" widget for media entity fields.

In order to recreate the bug, I had to use the "Upload as media items" widget on an image field. I don't think this is happening with media entity reference fields.

Feel free to reopen it if you are seeing this using a media entity reference field.

I opened another issue, which is that entity browsers should have an assigned entity type. That way, you could only show relevant widgets for the entity type on the widgets form, and prevent entity browsers for other entity types from showing as options on field widgets.

#3041830: Entity Browsers should be assigned an entity type

rooby’s picture

Priority: Major » Normal
Status: Closed (cannot reproduce) » Active

I don't really understand why this bug report would be closed and a feature request opened.

This is a bug (a PHP error), which is caused by allowing users to set a broken configuration. Although probably not major since it is not something that happens with the usual configuration.
We should not allow users to do that if it's going to cause errors. At the least we should show a message to say this is an incorrect configuration.

Also, you marked as "Closed (cannot reproduce) in the same comment where you said you reproduced it. If it's going to be closed it should probably be "Closed (won't fix)" or "Closed (works as designed)". Or even "Closed (duplicate)" of that newly created ticket.

oknate’s picture

Good point, "cannot reproduce" was the wrong designation. We can leave this one open too.

oknate’s picture

Status: Active » Needs review
StatusFileSize
new6.16 KB

Here's an initial patch that will replace the widget with a warning if wrong entity type widget used on field. Implemented on Upload, MediaImageUpload and View widget.

Status: Needs review » Needs work
oknate’s picture

Status: Needs work » Needs review
StatusFileSize
new11.93 KB

Fixing test and adding entity check and bundle check to EntityForm widget.

Still needs to be done:

  • copy validation over to field widget settings validation When field widget settings are updated, the validation should check each widget against the target entity type of the field set form error on entity browser field if the mismatch.
  • Add test coverage
oknate’s picture

Adding validation on the field widget settings form. Since I have another patch that has added some unrelated validation, I worked off a combined patch (with 2807873 #38) . I'm adding a combined patch to test against testbot, and patch that has just the changes for this issue, which could be committed after that one is committed.

- Adds interface WidgetEntityInfoInterface with two methods, ::getTargetEntityTypeId and ::getTargetBundles. I added it to a new interface to avoid breaking BC.
- Adds interface to WidgetBase with default implementations. This way all widgets that extend this class, which should be all of them have default implementations that return NULL or an empty array (for the getTargetBundles()) method. Since the validation checks if these are set before validating, so that contrib modules that extend WidgetBase but haven't implemented the two methods will just not be validated. After this is merged we can create tickets on those other modules issue queues to implement the two methods in their widget classes.
- Updates all four widgets included with module to implement these two methods.
- Add validation to the field widget when settings updated to iterate through the widgets and if the widget has methods that return entity type or bundles, validate them against the field widget settings and set form errors if there is a mismatch.

There are some nice features, such as if a view implements the 'type' filter it will validate that the bundles set in the type filter are within the allowed bundles on the field. This should stop an annoying problem where entity browser allows you to use a view that selects bundles that aren't allowed on field and you get a vague error. See #3035741: Vague error on submit in field widget when invalid item selected.

Still to do:
- add test coverage

Status: Needs review » Needs work

The last submitted patch, 19: entity-browser-widget-entity-validation-2930677-19-combined-with-2807873-38.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

oknate’s picture

Adding test coverage for field widget settings form.

It could still use more test coverage. This covers the functionality, but only tests the view widget. It would be good to test the upload, media upload and entity form widgets.

The last submitted patch, 21: entity-browser-widget-entity-validation-2930677-21-combined-with-2807873-38.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

oknate’s picture

Requeuing test. It was a random failure.

oknate’s picture

- Adds test coverage for field widget settings form validation for upload, media upload and entity form.
- Adds schema for MediaUploadWidget, as it was missing, and trying to add it to a test was giving me schema errors. When adding it, I noticed that my configs had been exported with strings for the multiple field, so I changed that one to be a string, so as not to break BC.
- Fixes a bug in my previous patches where the target entity was incorrectly sourced in the validation method.

There is still some test coverage to do. There should be validation for all four widgets when they are misconfigured, it shows the Drupal warning instead of loading the form.

oknate’s picture

StatusFileSize
new27.17 KB

Fixing interdiff on the last comment. One of the branches didn't have latest commit.

oknate’s picture

Reroll of patch #24 (as I hadn't merged in changed to one of the branches, so it shows the last commit as part of patch.

The last submitted patch, 24: entity-browser-widget-entity-validation-2930677-24-combined-with-2807873-38.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

oknate’s picture

- Adds test coverage for all four widgets when misconfigured (which can happen despite field widget validation if they change entity browser after the fact).
- Move similar functionality into widget base, adds new interface for the validation.

To do:
Mostly review. I ran out of time tonight so I might need to fix the tests a little. There might be some cleanup, coding standards. Will look at it with fresh eyes later.

Status: Needs review » Needs work
oknate’s picture

oknate’s picture

Random failures on #32, requeuing tests.

rooby’s picture

Awesome, thanks. I'll try to review ASAP.

oknate’s picture

rooby’s picture

Thanks @oknate.

I've got some Drupal contrib time planned for this weekend so I'll review then.

oknate’s picture

StatusFileSize
new64.95 KB

reroll

kellyimagined’s picture

Status: Needs review » Reviewed & tested by the community

I went through and tested, and unable to see the error post applying patch from #38.

oknate’s picture

Reroll, as patch wasn't applying any more.

oknate’s picture

Status: Reviewed & tested by the community » Needs review
kellyimagined’s picture

Status: Needs review » Reviewed & tested by the community

This patches with the latest dev from 4/20, as well as removes the error.

berdir’s picture

An issue summary update would be very helpful, explain what exactly the problem is and what the patch is doing. If I understand this correctly, this is basically just about validating which widget can be used in the current context, but it is a pretty massive patch.

oknate’s picture

Title: Error when uploading a new file into an image field using 'Upload images as media items' » Validate Widget entity type and widget type
Issue summary: View changes
oknate’s picture

Title: Validate Widget entity type and widget type » Validate Widget entity type and bundles
oknate’s picture

Title: Validate Widget entity type and bundles » Validate widget entity type and bundles
oknate’s picture

Issue summary: View changes
oknate’s picture

Issue summary: View changes
oknate’s picture

Issue summary: View changes
oknate’s picture

Since it's such a massive patch, I broke it up so it can reviewed in parts:

  • part 1: changes to widgets to support exposing entity type and entity bundle
  • part 2: validation added to field widgets that come with the module, entity_browser_entity_reference and entity_browser_file on the field widget config form.
  • part 3: changes to widget getForm methods to validate based on the changes in part 1. If a widget doesn't implement it's own validation as in this part 3, the validation doesn't happen. This means contrib modules that implement this will need to add some validation to their getForm methods if they would like to get this validation on their widgets.
  • part 4: add schema for media_image_upload, it was missing and I received a schema error adding this to an entity browser for the tests. We could possibly avoid adding this by changing the way the tests work.
  • part 5: changes to EntityBrowserTest. There was a validation problem where an entity browser with a file entity widget was being used on a node field in the test. I update the test to use a different field that isn't misconfigured.
  • part 6: adds a bunch of validation tests to cover the widgets shipping with the module.
  • part 7: new configs to simplify the tests, so I don't need to write out the creation of fields and field widget configs on each test.

We could possibly break this into 3 patches, if that helps:

  1. Add validation on field widget config form on entity form settings page.
  2. Add validation on widgets within the entity browser when using a field widget, entity_embed or inline entity form widget.
  3. Add missing schema for media_image_upload.

They're all interconnected and I feel the changes are relatively low risk, so I think as long it's reviewable, one large patch isn't unworkable.

oknate’s picture

Issue summary: View changes
mmbk’s picture

Great work, this patch is working fine and really helpful.

While working with the patch, I was wondering whether it is possible to expose only valid entity browsers inside the configuration form. This would make it even easier to configure the form display.

As this patch is already that huge, I don't want to extend it. Nevertheless I tried to implement this functionality and came up with this patch

--- a/src/Plugin/Field/FieldWidget/EntityReferenceBrowserWidget.php
+++ b/src/Plugin/Field/FieldWidget/EntityReferenceBrowserWidget.php
@@ -153,9 +153,16 @@ class EntityReferenceBrowserWidget extends WidgetBase implements ContainerFactor
     $element = parent::settingsForm($form, $form_state);
 
     $browsers = [];
+    $target_entity_type = $this->getFieldSetting('target_type');
     /** @var \Drupal\entity_browser\EntityBrowserInterface $browser */
     foreach ($this->entityTypeManager->getStorage('entity_browser')->loadMultiple() as $browser) {
-      $browsers[$browser->id()] = $browser->label();
+      $widgets = $browser->getWidgets();
+      foreach ($widgets as $widget) {
+        if ( $widget->getTargetEntityTypeId() == $target_entity_type) {
+          $browsers[$browser->id()] = $browser->label();
+          continue;
+        }
+      }
     }
 
     $element['entity_browser'] = [

which might be the base for a possible follow-up?

oknate’s picture

@mmbk, thanks for the review. I considered limiting the entity browsers in the select, but I was concerned we would get tickets from users concerned that entity browsers are missing from the select. It's too bad drupal core doesn't support greying out select elements. I think we should make a separate issue for this, as a follow up. Perhaps we could add a note under the select. "The following entity browsers are not available to select because they are not applicable to this field widget, @list_of_browsers". We'd also have to handle the case where there are no available entity browsers.

oknate’s picture

StatusFileSize
new69.56 KB

Reroll

stewest’s picture

Confirmed RTBC - Thanks

oknate’s picture

Tested that this still applies against current head. 👍

It will need a reroll against 8.x-1.x branch, as there is a test dependency on drupal:media (>= 8.4)

plato1123’s picture

So for fields that were set up as image (migrated from D7) there's not much hope for ever converting those fields to entity-browser/media, is there?

Maybe we could have some twig trickery where we have a migrated image field AND a new media entity field. If the new media entity field is filled in then the twig just skips rendering the old field. If the new field doesn't exist and the old migrated one does, it shows the old one.

I suppose we could even hide input for the old migrated field so that editors aren't confused by it, if it had content from the migration great, if not nobody would ever know it's even still there.

Or put another way:

field_featured_image_migrated old image field migrated from d7

field_featured_image_media_entity new image field that is entity reference that goes to our media library

If the second one exists then rendering of the first one is ignored, allowing editors to change images for migrated content as they need to (but really they're adding to the new field and the twig is skipping the old one). Maybe a convoluted solution but seems like it would work...

a.dmitriiev’s picture

I was also thinking how to improve the widget's appearance and found that WidgetBase has access() method. Maybe as another approach it would be better to pass widget_context from form_state (['entity_browser', 'widget_context']) to this access method and then each instance of the widget can decide if it is allowed to be shown or not according to field settings the browser is used in?

Widget Context has 'target_bundles', 'target_entity_type' and 'cardinality'. If widget has restriction by type or bundle it will react on that and restrict access to widget, what do you think?

This will definitely bring some breaking changes to WidgetInterface that doesn't have any arguments for access method.

a.dmitriiev’s picture

I checked it a bit more and found that it is also possible to not change the access() method definition, because the widget context can be retrieved from entity_browser.selection_storage the same way it is done in src/Plugin/views/filter/ContextualBundle.php starting from line 89 (I am talking about version 2.x)

a.dmitriiev’s picture

Another advantage of having this in access() method - when having multiple tabs in the form - the tabs, that should not be there, will not be there, instead of having the message from the patch.

Actually I did the override of the plugin class and extend the access method and it works pretty nice. Maybe this idea could be a part of the existing approved patch?

botanic_spark’s picture

@a.dmitriiev Would you mind sharing your solution? How did you manage to use access method?
I really like the idea of using access() method. It looks much cleaner and natural.

a.dmitriiev’s picture

First I have overriden the widgets:

/**
 * Implements hook_entity_browser_widget_info_alter().
 */
function my_module_entity_browser_widget_info_alter(array &$widgets) {
  $overrides = [
    'dropzonejs_media_entity_inline_entity_form' => '\Drupal\my_module\Plugin\EntityBrowser\Widget\InlineEntityFormMediaWidgetOverride',
    'dropzonejs_media_entity' => '\Drupal\my_module\Plugin\EntityBrowser\Widget\MediaEntityDropzoneJsEbWidgetOverride',
    'entity_form' => '\Drupal\my_module\Plugin\EntityBrowser\Widget\EntityFormOverride'
  ];
  foreach ($overrides as $plugin_id => $class) {
    if (!empty($widgets[$plugin_id])) {
      $widgets[$plugin_id]['class'] = $class;
    }
  }
}

And then extended the widget classes from entity browser module with the classes listed in the hook above.

EntityFormOverride:



namespace Drupal\my_module\Plugin\EntityBrowser\Widget;


use Drupal\Core\Access\AccessResult;
use Drupal\entity_browser_entity_form\Plugin\EntityBrowser\Widget\EntityForm;
use Symfony\Component\DependencyInjection\ContainerInterface;

class EntityFormOverride extends EntityForm {

  use WidgetContextTrait;

  /**
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   * @param array $configuration
   * @param string $plugin_id
   * @param mixed $plugin_definition
   *
   * @return \Drupal\Core\Plugin\ContainerFactoryPluginInterface|\Drupal\entity_browser\WidgetBase|\Drupal\entity_browser_entity_form\Plugin\EntityBrowser\Widget\EntityForm
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $widget = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $widget->setRequestStack($container->get('request_stack'));
    $widget->setStorage($container->get('entity_browser.selection_storage'));
    return $widget;
  }

  /**
   * {@inheritdoc}
   */
  protected function contextAccess() {
    $widget_context = $this->getWidgetContext();
    if (!empty($widget_context)) {
      if ($widget_context['target_entity_type'] !== $this->configuration['entity_type'] || !in_array($this->configuration['bundle'], $widget_context['target_bundles'])) {
        return AccessResult::forbidden('This field does not support ' . $this->configuration['entity_type'] . ' of type ' . $this->configuration['bundle']);
      }
    }
    return AccessResult::allowed();
  }

  /**
   * Overrides access to widget.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   */
  public function access() {
    if (parent::access()) {
      return $this->contextAccess();
    }
  }
}

InlineEntityFormMediaWidgetOverride:



namespace Drupal\my_module\Plugin\EntityBrowser\Widget;


use Drupal\Core\Access\AccessResult;
use Drupal\dropzonejs_eb_widget\Plugin\EntityBrowser\Widget\InlineEntityFormMediaWidget;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class InlineEntityFormMediaWidgetOverride
 *
 * @package Drupal\my_module\Plugin\EntityBrowser\Widget
 */
class InlineEntityFormMediaWidgetOverride extends InlineEntityFormMediaWidget {

  use WidgetContextTrait;

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $widget = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $widget->setRequestStack($container->get('request_stack'));
    $widget->setStorage($container->get('entity_browser.selection_storage'));
    return $widget;
  }

  /**
   * {@inheritdoc}
   */
  protected function contextAccess() {
    $widget_context = $this->getWidgetContext();
    if (!empty($widget_context)) {
      if ($widget_context['target_entity_type'] !== 'media' || !in_array($this->configuration['media_type'], $widget_context['target_bundles'])) {
        return AccessResult::forbidden('This field does not support media of type ' . $this->configuration['media_type']);
      }
    }
    return AccessResult::allowed();
  }

  /**
   * Overrides access to widget.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   */
  public function access() {
    if (parent::access()) {
      return $this->contextAccess();
    }
  }

}

MediaEntityDropzoneJsEbWidgetOverride:



namespace Drupal\my_module\Plugin\EntityBrowser\Widget;


use Drupal\Core\Access\AccessResult;
use Drupal\dropzonejs_eb_widget\Plugin\EntityBrowser\Widget\MediaEntityDropzoneJsEbWidget;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class MediaEntityDropzoneJsEbWidgetOverride
 *
 * @package Drupal\my_module\Plugin\EntityBrowser\Widget
 */
class MediaEntityDropzoneJsEbWidgetOverride extends MediaEntityDropzoneJsEbWidget {

  use WidgetContextTrait;

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $widget = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $widget->setRequestStack($container->get('request_stack'));
    $widget->setStorage($container->get('entity_browser.selection_storage'));
    return $widget;
  }

  /**
   * {@inheritdoc}
   */
  protected function contextAccess() {
    $widget_context = $this->getWidgetContext();
    if (!empty($widget_context)) {
      if ($widget_context['target_entity_type'] != 'media' || !in_array($this->configuration['media_type'], $widget_context['target_bundles'])) {
        return AccessResult::forbidden('This field does not support media of type ' . $this->configuration['media_type']);
      }
    }
    return AccessResult::allowed();
  }

  /**
   * Overrides access to widget.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   */
  public function access() {
    if (parent::access()) {
      return $this->contextAccess();
    }
  }

}

WidgetContextTrait:



namespace Drupal\my_module\Plugin\EntityBrowser\Widget;


use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Symfony\Component\HttpFoundation\RequestStack;

trait WidgetContextTrait {

  /**
   * A request stack symfony instance.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The entity browser selection storage.
   *
   * @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
   */
  protected $selectionStorage;

  /**
   * Sets Request Stack dependency injection.
   *
   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
   */
  protected function setRequestStack(RequestStack $requestStack) {
    $this->requestStack = $requestStack;
  }

  /**
   * Sets storage dependency injection.
   *
   * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $storage
   */
  protected function setStorage(KeyValueStoreExpirableInterface $storage) {
    $this->selectionStorage = $storage;
  }

  /**
   * Gets widget context.
   *
   * @return array
   */
  protected function getWidgetContext() {
    // Pull $this->value from entity browser storage.
    $current_request = $this->requestStack->getCurrentRequest();
    if ($current_request->query->has('uuid')) {
      $uuid = $current_request->query->get('uuid');
      if ($storage = $this->selectionStorage->get($uuid)) {
        if (isset($storage['widget_context'])) {
          return $storage['widget_context'];
        }
      }
    }
    return [];
  }

  /**
   * Checks context access.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  abstract protected function contextAccess();

}
a.dmitriiev’s picture

And now I have only 1 entity browser that has widgets for all media types, but the tabs are displayed only when they are allowed to be displayed.

botanic_spark’s picture

@a.dmitriiev Nice approach. I ended up patching the access() methods to expose a hook that I can use in other modules.
Then I used my custom module to add logic about widget context, and now I also have a single browser that respects field settings :)

I also like the use of WidgetContextTrait.

Anyway - I think this approach should be considered for this issue as it feels much more user friendly and less misleading then throwing errors and warnings to users.

tobiasb’s picture

Status: Reviewed & tested by the community » Needs work

Patch does not apply anymore to latest release https://www.drupal.org/project/entity_browser/releases/8.x-2.10.

hanoii’s picture

Status: Needs work » Needs review
StatusFileSize
new68.85 KB

Re-roll against 2.x

hanoii’s picture

StatusFileSize
new67.88 KB

Fix on the previous re-roll as schema was already there.

nelo_drup’s picture

@hanoii I'm getting this error in drupal 10.2.6 and using paragraphs with an image field with Entity browser widget and use media directories

TypeError: file_validate(): Argument #1 ($file) must be of type Drupal\file\FileInterface, Drupal\media\Entity\Media given, called in /var/www/example.com/modules/contrib/entity_browser/src/Plugin/EntityBrowser/WidgetValidation/File.php on line 31 in file_validate() (line 101 of core/modules/file/file.module).

for some reason the patch doesn't do anything in my case

chris matthews’s picture

2930677-n68.patch in #68 is not working for me either.

waropd’s picture

StatusFileSize
new67.81 KB

Patch on 2.15.0

benstallings’s picture

Status: Needs review » Needs work

Claude Code says:

Issues found:

1. Bug: MediaImageUpload::getForm() breaks the media_type validation. The new if (!empty($widget_context)) wraps the early return, and the existing media_type check is changed to elseif. This means when widget_context IS set but the entity type matches (normal case), the elseif doesn't execute, and media_type validation is completely skipped. The user could have a NULL/invalid media type and the code would fall through without catching it. The existing if for media_type should remain independent, not be chained as elseif.
2. Bug: View widget alter hook receives wrong object. The original code had $view as a ViewExecutable. The refactored code splits it into $view (config entity) and $view_executable, but the alter hook call still passes $view: $this->moduleHandler->alter('entity_browser_view_executable', $view, ...) This is a breaking change — hook implementations expecting a ViewExecutable now receive a View config entity. Should be $view_executable.
3. Unused variable in View widget getForm(). $entity_browser is loaded but never referenced — dead code / wasted query.
4. View loaded 3 times. getForm() loads the view, then getTargetEntityTypeId() and getTargetBundles() each load it again independently. The view object from getForm() should be reused or the results cached.
5. Missing $defaultTheme in WidgetFormValidationTest. All other WebDriverTestBase tests in the module set protected $defaultTheme = 'stark';. This will cause a deprecation warning or test failure on newer Drupal.
6. Missing use statements in EntityReferenceBrowserWidget. The validateSettingsForm references WidgetEntityInfoInterface and FieldConfig, but neither is imported. This would be a fatal error.
7. getTargetBundles() in View widget is fragile but acceptable. It reads $filters['type']['value'] which assumes a specific filter name. Returns [] for unrecognized configurations (fails open), so it won't cause false positives — just missed validations for non-standard views.
8. Bundle validation logic inconsistency. In View widget's getForm(), the bundle check iterates $widget_target_bundles and returns an error if ANY widget bundle is missing from $widget_context['target_bundles']. But this means a view showing articles AND pages would fail validation on a field targeting only articles — even though the view includes articles. Depending on intent, you might want to check for zero overlap rather than requiring all widget bundles to match.
9. Test duplication. testEntityBrowserWidgetContext, testContextualBundle, and testContextualBundleExposed all have identical field setup blocks (creating field_galaxy with the same config). This could use a shared helper like WidgetFormValidationTest::setUpField().

Summary: The feature concept is valuable — catching entity type mismatches at config time saves users from confusing runtime failures. But the patch has two clear bugs (#1 media_type validation bypass, #2 alter hook regression) and a fatal error (#6 missing imports) that need fixing before merge. The performance concern (#4) is secondary but worth addressing.

benstallings’s picture

Assigned: Unassigned » benstallings

benstallings’s picture

Assigned: benstallings » Unassigned
Status: Needs work » Needs review

anybody made their first commit to this issue’s fork.

berdir’s picture

Status: Needs review » Needs work

This has merge conflicts.

hanoii’s picture

Status: Needs work » Needs review

I've rebased !142 onto upstream