"Fossies" - the Fresh Open Source Software Archive

Member "drupal-8.9.10/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFormatterBase.php" (26 Nov 2020, 6752 Bytes) of package /linux/www/drupal-8.9.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "EntityReferenceFormatterBase.php" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.0.8_vs_9.1.0-rc1.

    1 <?php
    2 
    3 namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
    4 
    5 use Drupal\Core\Cache\CacheableMetadata;
    6 use Drupal\Core\Entity\EntityInterface;
    7 use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
    8 use Drupal\Core\Field\FieldItemListInterface;
    9 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
   10 use Drupal\Core\Field\FormatterBase;
   11 use Drupal\Core\TypedData\TranslatableInterface;
   12 
   13 /**
   14  * Parent plugin for entity reference formatters.
   15  */
   16 abstract class EntityReferenceFormatterBase extends FormatterBase {
   17 
   18   /**
   19    * Returns the referenced entities for display.
   20    *
   21    * The method takes care of:
   22    * - checking entity access,
   23    * - placing the entities in the language expected for display.
   24    * It is thus strongly recommended that formatters use it in their
   25    * implementation of viewElements($items) rather than dealing with $items
   26    * directly.
   27    *
   28    * For each entity, the EntityReferenceItem by which the entity is referenced
   29    * is available in $entity->_referringItem. This is useful for field types
   30    * that store additional values next to the reference itself.
   31    *
   32    * @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items
   33    *   The item list.
   34    * @param string $langcode
   35    *   The language code of the referenced entities to display.
   36    *
   37    * @return \Drupal\Core\Entity\EntityInterface[]
   38    *   The array of referenced entities to display, keyed by delta.
   39    *
   40    * @see ::prepareView()
   41    */
   42   protected function getEntitiesToView(EntityReferenceFieldItemListInterface $items, $langcode) {
   43     $entities = [];
   44 
   45     foreach ($items as $delta => $item) {
   46       // Ignore items where no entity could be loaded in prepareView().
   47       if (!empty($item->_loaded)) {
   48         $entity = $item->entity;
   49 
   50         // Set the entity in the correct language for display.
   51         if ($entity instanceof TranslatableInterface) {
   52           $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $langcode);
   53         }
   54 
   55         $access = $this->checkAccess($entity);
   56         // Add the access result's cacheability, ::view() needs it.
   57         $item->_accessCacheability = CacheableMetadata::createFromObject($access);
   58         if ($access->isAllowed()) {
   59           // Add the referring item, in case the formatter needs it.
   60           $entity->_referringItem = $items[$delta];
   61           $entities[$delta] = $entity;
   62         }
   63       }
   64     }
   65 
   66     return $entities;
   67   }
   68 
   69   /**
   70    * {@inheritdoc}
   71    *
   72    * @see ::prepareView()
   73    * @see ::getEntitiestoView()
   74    */
   75   public function view(FieldItemListInterface $items, $langcode = NULL) {
   76     $elements = parent::view($items, $langcode);
   77 
   78     $field_level_access_cacheability = new CacheableMetadata();
   79 
   80     // Try to map the cacheability of the access result that was set at
   81     // _accessCacheability in getEntitiesToView() to the corresponding render
   82     // subtree. If no such subtree is found, then merge it with the field-level
   83     // access cacheability.
   84     foreach ($items as $delta => $item) {
   85       // Ignore items for which access cacheability could not be determined in
   86       // prepareView().
   87       if (!empty($item->_accessCacheability)) {
   88         if (isset($elements[$delta])) {
   89           CacheableMetadata::createFromRenderArray($elements[$delta])
   90             ->merge($item->_accessCacheability)
   91             ->applyTo($elements[$delta]);
   92         }
   93         else {
   94           $field_level_access_cacheability = $field_level_access_cacheability->merge($item->_accessCacheability);
   95         }
   96       }
   97     }
   98 
   99     // Apply the cacheability metadata for the inaccessible entities and the
  100     // entities for which the corresponding render subtree could not be found.
  101     // This causes the field to be rendered (and cached) according to the cache
  102     // contexts by which the access results vary, to ensure only users with
  103     // access to this field can view it. It also tags this field with the cache
  104     // tags on which the access results depend, to ensure users that cannot view
  105     // this field at the moment will gain access once any of those cache tags
  106     // are invalidated.
  107     $field_level_access_cacheability->merge(CacheableMetadata::createFromRenderArray($elements))
  108       ->applyTo($elements);
  109 
  110     return $elements;
  111   }
  112 
  113   /**
  114    * {@inheritdoc}
  115    *
  116    * Loads the entities referenced in that field across all the entities being
  117    * viewed.
  118    */
  119   public function prepareView(array $entities_items) {
  120     // Collect entity IDs to load. For performance, we want to use a single
  121     // "multiple entity load" to load all the entities for the multiple
  122     // "entity reference item lists" being displayed. We thus cannot use
  123     // \Drupal\Core\Field\EntityReferenceFieldItemList::referencedEntities().
  124     $ids = [];
  125     foreach ($entities_items as $items) {
  126       foreach ($items as $item) {
  127         // To avoid trying to reload non-existent entities in
  128         // getEntitiesToView(), explicitly mark the items where $item->entity
  129         // contains a valid entity ready for display. All items are initialized
  130         // at FALSE.
  131         $item->_loaded = FALSE;
  132         if ($this->needsEntityLoad($item)) {
  133           $ids[] = $item->target_id;
  134         }
  135       }
  136     }
  137     if ($ids) {
  138       $target_type = $this->getFieldSetting('target_type');
  139       $target_entities = \Drupal::entityTypeManager()->getStorage($target_type)->loadMultiple($ids);
  140     }
  141 
  142     // For each item, pre-populate the loaded entity in $item->entity, and set
  143     // the 'loaded' flag.
  144     foreach ($entities_items as $items) {
  145       foreach ($items as $item) {
  146         if (isset($target_entities[$item->target_id])) {
  147           $item->entity = $target_entities[$item->target_id];
  148           $item->_loaded = TRUE;
  149         }
  150         elseif ($item->hasNewEntity()) {
  151           $item->_loaded = TRUE;
  152         }
  153       }
  154     }
  155   }
  156 
  157   /**
  158    * Returns whether the entity referenced by an item needs to be loaded.
  159    *
  160    * @param \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $item
  161    *   The item to check.
  162    *
  163    * @return bool
  164    *   TRUE if the entity needs to be loaded.
  165    */
  166   protected function needsEntityLoad(EntityReferenceItem $item) {
  167     return !$item->hasNewEntity();
  168   }
  169 
  170   /**
  171    * Checks access to the given entity.
  172    *
  173    * By default, entity 'view' access is checked. However, a subclass can choose
  174    * to exclude certain items from entity access checking by immediately
  175    * granting access.
  176    *
  177    * @param \Drupal\Core\Entity\EntityInterface $entity
  178    *   The entity to check.
  179    *
  180    * @return \Drupal\Core\Access\AccessResult
  181    *   A cacheable access result.
  182    */
  183   protected function checkAccess(EntityInterface $entity) {
  184     return $entity->access('view', NULL, TRUE);
  185   }
  186 
  187 }