Commit 48d5cd75 authored by catch's avatar catch
Browse files

Issue #3231503 by mdupont, kiseleva.t, donquixote, akalam, larowlan, joachim,...

Issue #3231503 by mdupont, kiseleva.t, donquixote, akalam, larowlan, joachim, longwave, mglaman: hook_entity_extra_field_info() is called unnecessarily often, hurting performance

(cherry picked from commit 525dcd84)
parent 74fcd731
Loading
Loading
Loading
Loading
+37 −19
Original line number Diff line number Diff line
@@ -25,11 +25,14 @@ class EntityFieldManager implements EntityFieldManagerInterface {
  use StringTranslationTrait;

  /**
   * Extra fields by bundle.
   * Extra fields info, if initialized.
   *
   * @var array
   * The fields are keyed by entity type, bundle, type ('form' or 'display'),
   * and the extra field name.
   *
   * @var array[][][][]|null
   */
  protected $extraFields = [];
  protected ?array $extraFields = NULL;

  /**
   * Static cache of base field definitions.
@@ -619,7 +622,7 @@ public function clearCachedFieldDefinitions() {
    $this->fieldMap = [];
    $this->fieldMapByFieldType = [];
    $this->entityDisplayRepository->clearDisplayModeInfo();
    $this->extraFields = [];
    $this->extraFields = NULL;
    Cache::invalidateTags(['entity_field_info']);
    // The typed data manager statically caches prototype objects with injected
    // definitions, clear those as well.
@@ -643,36 +646,51 @@ public function useCaches($use_caches = FALSE) {
   * {@inheritdoc}
   */
  public function getExtraFields($entity_type_id, $bundle) {
    $this->extraFields ??= $this->loadExtraFields();

    // Read from the "static" cache.
    if (isset($this->extraFields[$entity_type_id][$bundle])) {
      return $this->extraFields[$entity_type_id][$bundle];
    // Return an empty fallback if the bundle has no extra fields.
    return $this->extraFields[$entity_type_id][$bundle] ?? [
      'form' => [],
      'display' => [],
    ];
  }

  /**
   * Loads extra fields from cache, or rebuilds them.
   *
   * @return array[][][][]
   *   Extra fields by entity type, bundle name, type (form/display) and
   *   extra field name.
   */
  protected function loadExtraFields(): array {
    // Read from the persistent cache. Since hook_entity_extra_field_info() and
    // hook_entity_extra_field_info_alter() might contain t() calls, we cache
    // per language.
    $cache_id = 'entity_bundle_extra_fields:' . $entity_type_id . ':' . $bundle . ':' . $this->languageManager->getCurrentLanguage()->getId();
    $cache_id = 'entity_extra_field_info:' . $this->languageManager->getCurrentLanguage()->getId();
    $cached = $this->cacheGet($cache_id);
    if ($cached) {
      $this->extraFields[$entity_type_id][$bundle] = $cached->data;
      return $this->extraFields[$entity_type_id][$bundle];
      return $cached->data;
    }

    $extra = $this->moduleHandler->invokeAll('entity_extra_field_info');
    $this->moduleHandler->alter('entity_extra_field_info', $extra);
    $info = $extra[$entity_type_id][$bundle] ?? [];
    $info += [

    // Apply default values to each bundle.
    foreach ($extra as $entity_type_id => $extra_fields_by_bundle) {
      foreach ($extra_fields_by_bundle as $bundle => $bundle_extra_fields) {
        $extra[$entity_type_id][$bundle] += [
          'form' => [],
          'display' => [],
        ];
      }
    }

    // Store in the 'static' and persistent caches.
    $this->extraFields[$entity_type_id][$bundle] = $info;
    $this->cacheSet($cache_id, $info, Cache::PERMANENT, [
    $this->cacheSet($cache_id, $extra, Cache::PERMANENT, [
      'entity_field_info',
    ]);

    return $this->extraFields[$entity_type_id][$bundle];
    return $extra;
  }

}
+2 −2
Original line number Diff line number Diff line
@@ -684,7 +684,7 @@ public function testGetExtraFields() {
    $processed_hook_bundle_extra_fields[$entity_type_id][$bundle] += [
      'display' => [],
    ];
    $cache_id = 'entity_bundle_extra_fields:' . $entity_type_id . ':' . $bundle . ':' . $language_code;
    $cache_id = 'entity_extra_field_info:' . $language_code;

    $language = new Language(['id' => $language_code]);
    $this->languageManager->getCurrentLanguage()
@@ -696,7 +696,7 @@ public function testGetExtraFields() {
    $this->moduleHandler->invokeAll('entity_extra_field_info')->willReturn($hook_bundle_extra_fields);
    $this->moduleHandler->alter('entity_extra_field_info', $hook_bundle_extra_fields)->shouldBeCalled();

    $this->cacheBackend->set($cache_id, $processed_hook_bundle_extra_fields[$entity_type_id][$bundle], Cache::PERMANENT, ['entity_field_info'])->shouldBeCalled();
    $this->cacheBackend->set($cache_id, $processed_hook_bundle_extra_fields, Cache::PERMANENT, ['entity_field_info'])->shouldBeCalled();

    $this->assertSame($processed_hook_bundle_extra_fields[$entity_type_id][$bundle], $this->entityFieldManager->getExtraFields($entity_type_id, $bundle));
  }