Filter bundles when filtering entity references with a view

Created on 21 May 2021, over 3 years ago
Updated 1 February 2023, almost 2 years ago

Problem/Motivation

I am using the patch in ✨ Autocreate for Entity Reference selection handlers that extend ViewsSelection Needs work comment #69 ✨ Autocreate for Entity Reference selection handlers that extend ViewsSelection Needs work , which introduces a field setting key when using filter by entity reference view, . The patch I am using is for 8.9.x, slightly different from the 9.1.x version, but both use 'auto_create_bundle'.

With the patch installed, you can limit the bundles that can be created when filtering by an entity reference view. However, IEF doesn't know to check these settings. Therefore, the IEF add widget displays a list of all possible bundles for the entity type. If you have 2 or more bundles, but have chosen to limit the bundles in the field settings, IEF will let you attempt to create entities of bundles not allowed by the field.

The referenced issue is not committed yet, so I am marking this issue postponed until it's committed, but the last couple of patches look really good, and I feel like it addresses a pretty significant issue, so I am optimistic. Once it's in the way IEF allows for creating bundles that are not configured will be a problem.

Steps to reproduce

Install one of the patches in 2800875 ✨ Autocreate for Entity Reference selection handlers that extend ViewsSelection Needs work , I am using #69, but if a newer, more appropriate patch comes along, my suspicion is that it will use the same keys.
You need 2 entity types, one with 2 or more bundles.

You need an entity reference view ( it should filter to the bundle you want to allow IEF to reference / create ).

  1. Create an entity reference field to the entity type with multiple bundles.
  2. Select filter by entity reference view and choose your view.
  3. Make sure you have "Create referenced entities if they don't already exist" checked, which should present a form to select the bundle types you want to create.
  4. Configure the form widget for the er field to use IEF - Complex ( I haven't tested with Simple ).
  5. Create an entity of the type which has the IEF field. You will notice a select widget will ALL of the bundles for the entity reference field, not just the one you configured in the field settings.

If you choose a bundle which is not configured, you will receive a notice that the selected entity can not be referenced.

Proposed resolution

To address this, I think we'd need to make the following changes:
Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormBase

  /**
   * Gets the target bundles for the current field.
   *
   * @return string[]
   *   A list of bundles.
   */
  protected function getTargetBundles() {
    $settings = $this->getFieldSettings();
    if (!empty($settings['handler_settings']['target_bundles'])) {
      $target_bundles = array_values($settings['handler_settings']['target_bundles']);
      // Filter out target bundles which no longer exist.
      $existing_bundles = array_keys($this->entityTypeBundleInfo->getBundleInfo($settings['target_type']));
      $target_bundles = array_intersect($target_bundles, $existing_bundles);
    }
    else {
      // If no target bundles have been specified then all are available.
      $target_bundles = array_keys($this->entityTypeBundleInfo->getBundleInfo($settings['target_type']));
    }

    return $target_bundles;
  }

to this:

  /**
   * Gets the target bundles for the current field.
   *
   * @return string[]
   *   A list of bundles.
   */
  protected function getTargetBundles() {
    $settings = $this->getFieldSettings();
    if (!empty($settings['handler_settings']['target_bundles'])) {
      $target_bundles = array_values($settings['handler_settings']['target_bundles']);
      // Filter out target bundles which no longer exist.
      $existing_bundles = array_keys($this->entityTypeBundleInfo->getBundleInfo($settings['target_type']));
      $target_bundles = array_intersect($target_bundles, $existing_bundles);
    }
    // Check for auto_create_bundle.
    else if (isset($settings['handler_settings']['auto_create_bundle']) && !empty($settings['handler_settings']['auto_create_bundle']) {
      $target_bundles = array_values($settings['handler_settings']['target_bundles']);
      // Filter out target bundles which no longer exist.
      $existing_bundles = array_keys($this->entityTypeBundleInfo->getBundleInfo($settings['target_type']));
      $target_bundles = array_intersect($target_bundles, $existing_bundles);      
    }
    else {
      // If no target bundles have been specified then all are available.
      $target_bundles = array_keys($this->entityTypeBundleInfo->getBundleInfo($settings['target_type']));
    }

    return $target_bundles;
  }

Remaining tasks

  1. The parent issue needs to be completed
  2. Create a patch for IEF

User interface changes

The only UI change would be an appropriately filtered list of bundles in the IEF widget.

API changes

n/a

Data model changes

n/a

πŸ› Bug report
Status

Closed: works as designed

Version

1.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States scottsawyer Atlanta

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

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡ΊπŸ‡ΈUnited States lisagodare@gmail.com

    With the patch in the parent issue, I've done the following. It's not necessary to use the autocreate bundle feature, but is necessary to use the views_with_autocreate reference method.

    /**
     * Implements function hook_field_widget_complete_form_alter().
     */
    function MY_MODULE_field_widget_complete_form_alter(&$field_widget_complete_form, FormStateInterface $form_state, $context) {
      if (isset($field_widget_complete_form['widget']['#ief_root'])) {
        $ief_id = $field_widget_complete_form['widget']['#ief_id'];
        $storage = $form_state->getStorage();
    
        if (isset($storage['inline_entity_form'][$ief_id]['instance'])) {
          $field_instance = $storage['inline_entity_form'][$ief_id]['instance'];
          $settings = $field_instance->getSettings();
    
          if (isset($settings['handler']) && in_array($settings['handler'], [
            'views',
            'views_with_autocreate',
          ])) {
            $storage = \Drupal::entityTypeManager()
              ->getStorage('view')
              ->load($settings['handler_settings']['view']['view_name']);
    
            /** @var \Drupal\views\ViewExecutable $view */
            $view = $storage->getExecutable();
            $view->setDisplay($settings['handler_settings']['view']['display_name']);
            $filters = $view->display_handler->getOption('filters');
            $type_filter = ['value' => [], 'entity_type' => 'node'];
            if (isset($filters['type'])) {
              $type_filter = array_merge($type_filter, $filters['type']);
            }
            $bundles = $type_filter['value'];
            $bundle_info = \Drupal::service('entity_type.bundle.info')
              ->getBundleInfo($type_filter['entity_type']);
            foreach ($bundles as &$bundle) {
              if (isset($bundle_info[$bundle])) {
                $bundle = $bundle_info[$bundle]['label'];
              }
            }
    
            $field_widget_complete_form['widget']['actions']['bundle']['#options'] = $bundles;
          }
        }
      }
    }
    
Production build 0.71.5 2024