Verified Commit da5ea0ae authored by Lee Rowlands's avatar Lee Rowlands
Browse files

Issue #3057545 by acbramley, hchonov, bbrala, bradjones1, larowlan,...

Issue #3057545 by acbramley, hchonov, bbrala, bradjones1, larowlan, yogeshmpawar, Leon Kessler, gease, joachim, gabesullice, kfritsche, jibran, Wim Leers, Berdir, smustgrave, alexpott, catch: ResourceTypeRepository wrongly assumes that all entity reference fields have the setting "target_type"
parent 0733716c
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@
use Drupal\Core\Entity\TypedData\EntityDataDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldException;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface;
use Drupal\Core\Form\FormStateInterface;
@@ -42,7 +41,7 @@
 *   list_class = "\Drupal\Core\Field\EntityReferenceFieldItemList",
 * )
 */
class EntityReferenceItem extends FieldItemBase implements OptionsProviderInterface, PreconfiguredFieldUiOptionsInterface {
class EntityReferenceItem extends EntityReferenceItemBase implements OptionsProviderInterface, PreconfiguredFieldUiOptionsInterface {

  /**
   * {@inheritdoc}
@@ -778,4 +777,19 @@ public static function getPreconfiguredOptions() {
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public static function getReferenceableBundles(FieldDefinitionInterface $field_definition): array {
    $settings = $field_definition->getSettings();
    $target_type_id = $settings['target_type'];
    $handler_settings = $settings['handler_settings'];

    $has_target_bundles = isset($handler_settings['target_bundles']) && !empty($handler_settings['target_bundles']);
    $target_bundles = $has_target_bundles
      ? $handler_settings['target_bundles']
      : array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo($target_type_id));
    return [$target_type_id => $target_bundles];
  }

}
+16 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\Field\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;

/**
 * Base class for field items referencing other entities.
 *
 * Any field type that is an entity reference should extend from this class in
 * order to remain backwards compatible with any changes added in the future
 * to EntityReferenceItemInterface.
 */
abstract class EntityReferenceItemBase extends FieldItemBase implements EntityReferenceItemInterface {

}
+29 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\Field\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldDefinitionInterface;

/**
 * Interface definition for field items referencing other entities.
 *
 * Field items should extend \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItemBase.
 */
interface EntityReferenceItemInterface {

  /**
   * Returns the referenceable entity types and bundles.
   *
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   *   The field definition for which to retrieve the referenceable entity
   *   types and bundles.
   *
   * @return array
   *   An array of referenceable bundles where the array is keyed by the entity
   *   type ID, with values an array of bundle names. (It is a single-value
   *   array with the entity type ID if the entity type does not implement
   *   bundles.)
   */
  public static function getReferenceableBundles(FieldDefinitionInterface $field_definition): array;

}
+28 −6
Original line number Diff line number Diff line
@@ -6,7 +6,8 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItemInterface;
use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
use Drupal\jsonapi\Access\EntityAccessChecker;
use Drupal\jsonapi\Context\FieldResolver;
use Drupal\jsonapi\Exception\EntityAccessDeniedHttpException;
@@ -137,13 +138,34 @@ protected function resolveIncludeTree(array $include_tree, Data $data, Data $inc
          $includes = IncludedData::merge($includes, new IncludedData([$exception]));
          continue;
        }
        if (is_subclass_of($field_list->getItemDefinition()->getClass(), EntityReferenceItemInterface::class)) {
          foreach ($field_list as $field_item) {
            if (!($field_item->getDataDefinition()->getPropertyDefinition('entity') instanceof DataReferenceDefinitionInterface)) {
              continue;
            }

            if (!($field_item->entity instanceof EntityInterface)) {
              continue;
            }

            // Support entity reference fields that don't have the referenced
            // target type stored in settings.
            $references[$field_item->entity->getEntityTypeId()][] = $field_item->get($field_item::mainPropertyName())->getValue();
          }
        }
        else {
          @trigger_error(
            sprintf('Entity reference field items not implementing %s is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3279140', EntityReferenceItemInterface::class),
            E_USER_DEPRECATED
          );
          $target_type = $field_list->getFieldDefinition()->getFieldStorageDefinition()->getSetting('target_type');
        assert(!empty($target_type));
          if (!empty($target_type)) {
            foreach ($field_list as $field_item) {
          assert($field_item instanceof EntityReferenceItem);
              $references[$target_type][] = $field_item->get($field_item::mainPropertyName())->getValue();
            }
          }
        }
      }
      foreach ($references as $target_type => $ids) {
        $entity_storage = $this->entityTypeManager->getStorage($target_type);
        $targeted_entities = $entity_storage->loadMultiple(array_unique($ids));
+38 −21
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Installer\InstallerKernel;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItemInterface;
use Drupal\Core\TypedData\DataReferenceTargetDefinition;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;
@@ -439,18 +440,33 @@ protected function calculateRelatableResourceTypes(ResourceType $resource_type,
  protected function getRelatableResourceTypesFromFieldDefinition(FieldDefinitionInterface $field_definition, array $resource_types) {
    $item_definition = $field_definition->getItemDefinition();
    $entity_type_id = $item_definition->getSetting('target_type');
    $handler_settings = $item_definition->getSetting('handler_settings');
    $target_bundles = empty($handler_settings['target_bundles']) ? $this->getAllBundlesForEntityType($entity_type_id) : $handler_settings['target_bundles'];
    $relatable_resource_types = [];
    $item_class = $item_definition->getClass();
    if (is_subclass_of($item_class, EntityReferenceItemInterface::class)) {
      $target_type_bundles = $item_class::getReferenceableBundles($field_definition);
    }
    else {
      @trigger_error(
        sprintf('Entity reference field items not implementing %s is deprecated in drupal:10.2.0 and will be required in drupal:11.0.0. See https://www.drupal.org/node/3279140', EntityReferenceItemInterface::class),
        E_USER_DEPRECATED
      );
      $handler_settings = $item_definition->getSetting('handler_settings');

      $has_target_bundles = isset($handler_settings['target_bundles']) && !empty($handler_settings['target_bundles']);
      $target_bundles = $has_target_bundles ? $handler_settings['target_bundles'] : $this->getAllBundlesForEntityType($entity_type_id);
      $target_type_bundles = [$entity_type_id => $target_bundles];
    }

    foreach ($target_type_bundles as $entity_type_id => $target_bundles) {
      foreach ($target_bundles as $target_bundle) {
        if ($resource_type = static::lookupResourceType($resource_types, $entity_type_id, $target_bundle)) {
          $relatable_resource_types[] = $resource_type;
          continue;
        }
      // Do not warn during the site installation since system integrity
      // is not guaranteed in this period and the warnings may pop up falsy,
      // adding confusion to the process.
      elseif (!InstallerKernel::installationAttempted()) {
        // Do not warn during site installation since system integrity
        // is not guaranteed during this period and may cause confusing and
        // unnecessary warnings.
        if (!InstallerKernel::installationAttempted()) {
          trigger_error(
            sprintf(
              'The "%s" at "%s:%s" references the "%s:%s" entity type that does not exist. Please take action.',
@@ -464,6 +480,7 @@ protected function getRelatableResourceTypesFromFieldDefinition(FieldDefinitionI
          );
        }
      }
    }

    return $relatable_resource_types;
  }
Loading