You are here

protected function FeedImportProcessor::saveEntities in Feed Import 8

Saves created entities.

Parameters

array &$entities: An array of entities to be saved

1 call to FeedImportProcessor::saveEntities()
FeedImportProcessor::process in feed_import_base/src/FeedImportProcessor.php
Processes the import.

File

feed_import_base/src/FeedImportProcessor.php, line 871

Class

FeedImportProcessor
Class that processess the import.

Namespace

Drupal\feed_import_base

Code

protected function saveEntities(array &$entities) {
  static $loadArr = array(
    NULL,
  );

  // Number of entities.
  $total = count($entities);
  $this->report['total'] += $total;

  // Get ids from hashes.
  $ids = $this->hashes
    ->get();

  // Entity create callback.
  $createCallback =& $this->entityInfo->createCallback;

  // Entity save callback.
  $saveCallback =& $this->entityInfo->saveCallback;

  // Entity before combine callback
  $beforeCombine =& $this->beforeCombine;

  // Entity after combine callback
  $afterCombine =& $this->afterCombine;

  // Entity before create callback
  $beforeCreate =& $this->beforeCreate;

  // Entity before save callback
  $beforeSave =& $this->beforeSave;

  // Entity after save callback
  $afterSave =& $this->afterSave;

  // Entity load id.
  $loadId =& $loadArr[0];
  $i = -1;

  // Save each entity.
  while (++$i < $total) {
    $entity =& $entities[$i];
    unset($entities[$i]);
    if ($entity == NULL) {
      continue;
    }

    // Save hash.
    $hash =& $entity[static::TEMP_HASH];

    // Not needed anymore.
    unset($entity[static::TEMP_HASH]);

    // Check if item is already imported or is not monitored.
    if ($hash !== NULL && isset($ids[$hash])) {

      // Check if is used option to skip item if already imported
      // or entity is protected (import cannot make changes).
      if ($this->skipImportedItems || $ids[$hash]->expire == FeedImportHashManager::MARK_PROTECTED) {
        $this->report[$this->skipImportedItems ? 'skipped' : 'protected_skipped']++;
        unset($ids[$hash]);
        continue;
      }

      // Current entity id.
      $loadId = $ids[$hash]->entity_id;

      // Load current entity.
      $current = \Drupal::entityManager()
        ->getStorage($this->entityInfo->name);

      // If entity is missing then skip.
      if (!isset($current[$loadId])) {
        $this->report['missing']++;
        $this->orphanHashes[] = $ids[$hash]->id;
        unset($ids[$hash], $current);
        continue;
      }

      // Get current entity value.
      $current =& $current[$loadId];

      // Entity might be in static cache.
      $this->staticCacheEntities++;

      // Merge status of entity.
      $changed = FALSE;

      // Check for before combine callback.
      if ($beforeCombine) {
        switch ($beforeCombine($entity, $current, $changed)) {
          case static::ENTITY_RESCHEDULE:
            $this->report['rescheduled']++;
            goto ADD_HASH_UPDATE;
          case static::ENTITY_SKIP:
            $this->report['skipped']++;
            goto UNSET_VARS;
          case static::ENTITY_NO_COMBINE:
            goto COMBINE_FINISHED;
          case static::ENTITY_MARK_PROTECTED:
            $this->report['protected']++;
            $this->hashes
              ->protect($ids[$hash]->id);
            goto UNSET_VARS;
        }
      }

      // Check for diff.
      $changed = $this
        ->combineEntities($entity, $current);

      // Check for after combine callback.
      if ($afterCombine) {
        switch ($afterCombine($entity, $current, $changed)) {
          case static::ENTITY_RESCHEDULE:
            $this->report['rescheduled']++;
            goto ADD_HASH_UPDATE;
          case static::ENTITY_SKIP:
            $this->report['skipped']++;
            goto UNSET_VARS;
          case static::ENTITY_MARK_PROTECTED:
            $this->report['protected']++;
            $this->hashes
              ->protect($ids[$hash]->id);
            goto UNSET_VARS;
        }
      }
      COMBINE_FINISHED:

      // Not needed anymore.
      unset($entity);

      // Check if entity is changed and save changes.
      if ($changed) {

        // Save entity.
        if ($saveCallback) {
          $saveCallback($current);
        }
        elseif (method_exists($current, 'save')) {
          if (!$current
            ->save()) {
            unset($current);
            continue;
          }
        }
        elseif ($this->entityInfo->controller->canSave) {
          if (!$this->entityInfo->controller
            ->save($current)) {
            unset($current);
            continue;
          }
        }
        else {

          // Don't know how to save entity...
          unset($current);
          continue;
        }

        // Set report about updated items.
        $this->report['updated']++;

        // Check after save callback
        $afterSave && $afterSave($current, FALSE);
      }
      else {

        // Set report about rescheduled items.
        $this->report['rescheduled']++;
      }
      ADD_HASH_UPDATE:

      // Add to update ids.
      $this->hashes
        ->update($ids[$hash]->id);
      UNSET_VARS:

      // Free some memory.
      unset($ids[$hash], $current, $entity, $hash);
    }
    else {

      // Check if this imports accepts only updates.
      if ($this->updatesOnly) {
        $this->report['skipped']++;
        goto UNSET_E_VARS;
      }

      // Check before save callback
      if ($beforeCreate) {
        switch ($beforeCreate($entity)) {
          case static::ENTITY_SKIP:
            $this->report['skipped']++;
            goto UNSET_E_VARS;
          case static::ENTITY_SKIP_CREATE:
            goto ENTITY_SAVE;
          case static::ENTITY_SKIP_SAVE:
            goto ENTITY_SAVED;
        }
      }

      // Create a new entity.
      if ($createCallback) {
        $entity = $createCallback($entity, $this->entityInfo->name);
      }
      elseif ($this->entityInfo->controller->canCreate) {
        $entity = $this->entityInfo->controller
          ->create($entity);
      }
      else {
        $entity = (object) $entity;
      }
      ENTITY_SAVE:

      // Check before save callback
      if ($beforeSave) {
        switch ($beforeSave($entity)) {
          case static::ENTITY_SKIP:
            $this->report['skipped']++;
            goto UNSET_E_VARS;
          case static::ENTITY_SKIP_SAVE:
            goto ENTITY_SAVED;
        }
      }

      // No entity to save.
      if (!$entity) {
        unset($entity);
        continue;
      }
      elseif ($saveCallback) {
        $saveCallback($entity);
      }
      elseif (method_exists($entity, 'save')) {
        if (!$entity
          ->save()) {
          unset($entity);
          continue;
        }
      }
      elseif ($this->entityInfo->controller->canSave) {
        if (!$this->entityInfo->controller
          ->save($entity)) {
          unset($entity);
          continue;
        }
      }
      else {

        // Don't know how to save entity...
        unset($entity);
        continue;
      }
      ENTITY_SAVED:

      // Entity might be added in static cache.
      $this->staticCacheEntities++;

      // Check after save callback
      $afterSave && $afterSave($entity, TRUE);

      // Check if is monitored.
      if ($hash !== NULL) {

        // Insert into feed import hash table.
        $this->hashes
          ->insert($entity->{$this->entityInfo->idKey}, $hash);
      }

      // Set report about new items.
      $this->report['new']++;
      UNSET_E_VARS:

      // Not needed anymore.
      unset($entity, $hash);
    }

    // Remove entity cache.
    if ($this->staticCacheEntities == $this->resetStaticCache) {
      $this->entityInfo->controller->canResetCache && $this->entityInfo->controller
        ->resetCache();
      $this->staticCacheEntities = 0;
    }
  }
}