Commit c0016122 authored by Nia Kathoni's avatar Nia Kathoni Committed by Youri van Koppen
Browse files

Issue #3105322 by nikathone, sker101, MegaChriz, andileco: Added multivalue...

Issue #3105322 by nikathone, sker101, MegaChriz, andileco: Added multivalue support for the Feeds item field so entities can be updated by multiple feeds without hashes getting overwritten.
parent f383149c
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -6,8 +6,10 @@
 */

use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\feeds\FeedTypeInterface;
use Drupal\feeds\Feeds\Parser\CsvParser;
use Drupal\field\FieldStorageConfigInterface;

/**
 * Replace deprecated action ID's for 'update_non_existent' setting.
@@ -62,3 +64,18 @@ function feeds_post_update_custom_sources(&$sandbox = NULL) {
      return TRUE;
    });
}

/**
 * The feeds_item field storage config is updated to unlimited cardinality.
 */
function feeds_post_update_ensure_feeds_item_storage_config_cardinality_is_unlimited(&$sandbox = NULL) {
  \Drupal::classResolver(ConfigEntityUpdater::class)
    ->update($sandbox, 'field_storage_config', function (FieldStorageConfigInterface $field_storage_config) {
      if ($field_storage_config->getType() !== 'feeds_item') {
        return FALSE;
      }

      $field_storage_config->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
      return TRUE;
    });
}
+11 −8
Original line number Diff line number Diff line
@@ -89,14 +89,15 @@ class ItemListController extends ControllerBase {
    }

    $entity_ids = $this->entityTypeManager()->getStorage($processor->entityType())->getQuery()
      ->condition('feeds_item.target_id', $feeds_feed->id())
      ->condition('feeds_item', [$feeds_feed->id()], 'IN')
      ->pager(50)
      ->sort('feeds_item.imported', 'DESC')
      ->execute();

    $storage = $this->entityTypeManager()->getStorage($processor->entityType());
    foreach ($storage->loadMultiple($entity_ids) as $entity) {
      $ago = $this->dateFormatter->formatInterval($this->time->getRequestTime() - $entity->get('feeds_item')->imported);
      $feed_item = $entity->get('feeds_item')->getItemByFeed($feeds_feed);
      $ago = $this->dateFormatter->formatInterval($this->time->getRequestTime() - $feed_item->imported);
      $row = [];

      // Entity ID.
@@ -118,14 +119,14 @@ class ItemListController extends ControllerBase {

      // Item GUID.
      $row[] = [
        'data' => $this->getPropertyFromFeedsItem($entity, 'guid'),
        'title' => $entity->get('feeds_item')->guid,
        'data' => $this->getPropertyFromFeedsItem($entity, 'guid', $feeds_feed),
        'title' => $feed_item->guid,
      ];

      // Item URL.
      $row[] = [
        'data' => $this->getPropertyFromFeedsItem($entity, 'url'),
        'title' => $entity->get('feeds_item')->url,
        'data' => $this->getPropertyFromFeedsItem($entity, 'url', $feeds_feed),
        'title' => $feed_item->url,
      ];

      $build['table']['#rows'][] = $row;
@@ -144,6 +145,8 @@ class ItemListController extends ControllerBase {
   *   The imported entity that is being listed.
   * @param string $property
   *   The property to get from the feeds item.
   * @param \Drupal\feeds\FeedInterface $feed
   *   The feed entity associate with the feed item.
   *
   * @return string|null|mixed
   *   If the value on the feed is a string, it will be returned truncated to 30
@@ -151,8 +154,8 @@ class ItemListController extends ControllerBase {
   *   value will be returned as is. Null is returned when it is not a scalar
   *   value.
   */
  protected function getPropertyFromFeedsItem(EntityInterface $entity, string $property) {
    $value = $entity->get('feeds_item')->{$property};
  protected function getPropertyFromFeedsItem(EntityInterface $entity, string $property, FeedInterface $feed) {
    $value = $entity->get('feeds_item')->getItemByFeed($feed)->{$property};
    if (!is_scalar($value)) {
      return NULL;
    }
+26 −9
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\TranslatableInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
@@ -214,7 +215,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces
    }

    $hash = $this->hash($item);
    $changed = $existing_entity_id && ($hash !== $entity->get('feeds_item')->hash);
    $changed = $existing_entity_id && ($hash !== $entity->get('feeds_item')->getItemHashByFeed($feed));

    // Do not proceed if the item exists, has not changed, and we're not
    // forcing the update.
@@ -230,8 +231,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces

    try {
      // Set feeds_item values.
      $feeds_item = $entity->get('feeds_item');
      $feeds_item->target_id = $feed->id();
      $feeds_item = $entity->get('feeds_item')->getItemByFeed($feed, TRUE);
      $feeds_item->hash = $hash;

      // Set field values.
@@ -239,7 +239,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces

      // Validate the entity.
      $feed->dispatchEntityEvent(FeedsEvents::PROCESS_ENTITY_PREVALIDATE, $entity, $item);
      $this->entityValidate($entity);
      $this->entityValidate($entity, $feed);

      // Dispatch presave event.
      $feed->dispatchEntityEvent(FeedsEvents::PROCESS_ENTITY_PRESAVE, $entity, $item);
@@ -247,7 +247,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces
      // This will throw an exception on failure.
      $this->entitySaveAccess($entity);
      // Set imported time.
      $entity->get('feeds_item')->imported = $this->dateTime->getRequestTime();
      $feeds_item->imported = $this->dateTime->getRequestTime();

      // And... Save! We made it.
      $this->storageController->save($entity);
@@ -348,7 +348,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces

    // If the entity was not deleted, update hash.
    if (isset($entity->feeds_item)) {
      $entity->get('feeds_item')->hash = $update_non_existent;
      $entity->get('feeds_item')->getItemByFeed($feed)->hash = $update_non_existent;
      $this->storageController->save($entity);
    }

@@ -590,7 +590,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces
  /**
   * {@inheritdoc}
   */
  protected function entityValidate(EntityInterface $entity) {
  protected function entityValidate(EntityInterface $entity, FeedInterface $feed) {
    // Check if an entity with the same ID already exists if the given entity is
    // new.
    if ($entity->isNew() && $this->entityExists($entity)) {
@@ -640,7 +640,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces
    // which item failed. Fallback to the GUID value (if available) or else
    // no indication.
    $label = (string) $entity->label();
    $guid = (string) $entity->get('feeds_item')->guid;
    $guid = (string) $entity->get('feeds_item')->getItemByFeed($feed)->guid;

    $messages = [];
    $args = [
@@ -797,6 +797,7 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces
        'entity_type' => $this->entityType(),
        'type' => 'feeds_item',
        'translatable' => FALSE,
        'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
      ])->save();
    }
    // Create field instance if it doesn't exist.
@@ -1204,13 +1205,29 @@ abstract class EntityProcessorBase extends ProcessorBase implements EntityProces
   *
   * @todo Avoid using the database service. Find an other way to clean up
   * references to feeds that are being removed.
   * @todo the cache clearing logic of target entity could probably be addressed
   * along with the todo above.
   */
  public function onFeedDeleteMultiple(array $feeds) {
    $fids = [];
    foreach ($feeds as $feed) {
      $fids[] = $feed->id();
    }
    $table = $this->entityType() . '__feeds_item';

    $entity_type_id = $this->entityType();
    $table = "{$entity_type_id}__feeds_item";

    // Clear the cache of associated target entities so that they won't
    // reference to the deleted feeds items.
    $target_entities = $this->database->select($table, 'fi')
      ->condition('feeds_item_target_id', $fids, 'IN')
      ->fields('fi', ['entity_id'])
      ->execute()
      ->fetchCol();

    $unique_ids = array_unique($target_entities);
    $this->entityTypeManager->getStorage($entity_type_id)->resetCache($unique_ids);

    $this->database->delete($table)
      ->condition('feeds_item_target_id', $fids, 'IN')
      ->execute();
+1 −1
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ class ConfigEntityReference extends FieldTargetBase implements ConfigurableTarge
        // import process more efficient by ignoring items it has already seen.
        // In this case we need to destroy the hash in order to be able to
        // import the reference on a next import.
        $entity->get('feeds_item')->hash = NULL;
        $entity->get('feeds_item')->getItemByFeed($feed)->hash = NULL;
        $feed->getState(StateInterface::PROCESS)->setMessage($e->getFormattedMessage(), 'warning', TRUE);
      }
      catch (EmptyFeedException $e) {
+5 −2
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ class EntityReference extends FieldTargetBase implements ConfigurableTargetInter
        // import process more efficient by ignoring items it has already seen.
        // In this case we need to destroy the hash in order to be able to
        // import the reference on a next import.
        $entity->get('feeds_item')->hash = NULL;
        $entity->get('feeds_item')->getItemByFeed($feed)->hash = NULL;
        $feed->getState(StateInterface::PROCESS)->setMessage($e->getFormattedMessage(), 'warning', TRUE);
      }
      catch (EmptyFeedException $e) {
@@ -156,7 +156,10 @@ class EntityReference extends FieldTargetBase implements ConfigurableTargetInter
   */
  protected function getPotentialFields() {
    $field_definitions = $this->entityFieldManager->getFieldStorageDefinitions($this->getEntityType());
    $field_definitions = array_filter($field_definitions, [$this, 'filterFieldTypes']);
    $field_definitions = array_filter($field_definitions, [
      $this,
      'filterFieldTypes',
    ]);
    $options = [];
    foreach ($field_definitions as $id => $definition) {
      $options[$id] = Html::escape($definition->getLabel());
Loading