acquia_commercemanager-8.x-1.122/modules/acm_sku/src/ProductOptionsManager.php

modules/acm_sku/src/ProductOptionsManager.php
<?php

namespace Drupal\acm_sku;

use Drupal\acm\Connector\APIWrapperInterface;
use Drupal\acm\I18nHelper;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;

/**
 * Provides a service for product options data to taxonomy synchronization.
 *
 * @ingroup acm_sku
 */
class ProductOptionsManager implements ProductOptionsManagerInterface {

  /**
   * Connector Agent Category Data API Endpoint.
   *
   * @const CONDUCTOR_API_CATEGORY
   */
  const PRODUCT_OPTIONS_VOCABULARY = 'sku_product_option';

  /**
   * Taxonomy Term Entity Storage.
   *
   * @var \Drupal\taxonomy\TermStorageInterface
   */
  private $termStorage;

  /**
   * API Wrapper object.
   *
   * @var \Drupal\acm\Connector\APIWrapperInterface
   */
  private $apiWrapper;

  /**
   * Instance of I18nHelper service.
   *
   * @var \Drupal\acm\I18nHelper
   */
  private $i18nHelper;

  /**
   * Instance of LoggerChannelInterface.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  private $logger;

  /**
   * Database connection service.
   *
   * @var \Drupal\Core\Database\Connection
   */
  private $connection;

  /**
   * Constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   EntityTypeManager object.
   * @param \Drupal\acm\Connector\APIWrapperInterface $api_wrapper
   *   ApiWrapper object.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   LoggerFactory object.
   * @param \Drupal\acm\I18nHelper $i18nHelper
   *   Instance of I18nHelper service.
   * @param \Drupal\Core\Database\Connection $connection
   *   Database connection service.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager,
                              APIWrapperInterface $api_wrapper,
                              LoggerChannelFactoryInterface $logger_factory,
                              I18nHelper $i18nHelper,
                              Connection $connection) {
    $this->termStorage = $entity_type_manager->getStorage('taxonomy_term');
    $this->apiWrapper = $api_wrapper;
    $this->logger = $logger_factory->get('acm_sku');
    $this->i18nHelper = $i18nHelper;
    $this->connection = $connection;
  }

  /**
   * {@inheritdoc}
   */
  public function loadProductOptionByOptionId($attribute_code, $option_id, $langcode, $log_error = TRUE) {
    $query = $this->termStorage->getQuery();
    $query->condition('field_sku_option_id', $option_id);
    $query->condition('field_sku_attribute_code', $attribute_code);
    $query->condition('vid', self::PRODUCT_OPTIONS_VOCABULARY);
    $tids = $query->execute();

    // We won't log no term found error during sync.
    if (count($tids) === 0) {
      if ($log_error) {
        $this->logger->error('No term found for option_id: @option_id having attribute_code @attribute_code.', [
          '@option_id' => $option_id,
          '@attribute_code' => $attribute_code,
        ]);
      }
      return NULL;
    }
    elseif (count($tids) > 1) {
      $this->logger->critical('Multiple terms found for option_id: @option_id having attribute_code @attribute_code.', [
        '@option_id' => $option_id,
        '@attribute_code' => $attribute_code,
      ]);
    }

    // We use the first term and continue even if we have multiple terms.
    $tid = array_shift($tids);

    /** @var \Drupal\taxonomy\Entity\Term $term */
    $term = $this->termStorage->load($tid);

    if ($langcode && $term->hasTranslation($langcode)) {
      $term = $term->getTranslation($langcode);
    }

    return $term;
  }

  /**
   * {@inheritdoc}
   */
  public function createProductOptionWrapper($langcode, $option_id, $option_value, $attribute_id, $attribute_code, $weight) {
    return $this->createProductOption();
  }

  /**
   * Create product option if not available or update the name.
   *
   * @param string $langcode
   *   Lang code.
   * @param int $option_id
   *   Option id.
   * @param string $option_value
   *   Value (term name).
   * @param int $attribute_id
   *   Attribute id.
   * @param string $attribute_code
   *   Attribute code.
   * @param int $weight
   *   Taxonomy term weight == attribute option sort order.
   *
   * @return \Drupal\taxonomy\Entity\Term|null
   *   Term object or null.
   */
  protected function createProductOption($langcode, $option_id, $option_value, $attribute_id, $attribute_code, $weight) {
    if (strlen($option_value) == 0) {
      $this->logger->warning('Got empty value while syncing production options: @data', [
        '@data' => json_encode([
          'langcode' => $langcode,
          'option_id' => $option_id,
          'attribute_id' => $attribute_id,
          'attribute_code' => $attribute_code,
        ]),
      ]);

      return NULL;
    }

    // Update the term if already available.
    if ($term = $this->loadProductOptionByOptionId($attribute_code, $option_id, NULL, FALSE)) {
      $save_term = FALSE;

      // Save term even if weight changes.
      if ($term->getWeight() != $weight) {
        $save_term = TRUE;
      }

      if ($term->hasTranslation($langcode)) {
        $term = $term->getTranslation($langcode);

        // We won't allow editing name here, if required it must be done from
        // Magento.
        if ($term->getName() != $option_value) {
          $term->setName($option_value);
          $save_term = TRUE;
        }
      }
      else {
        $term = $term->addTranslation($langcode, []);
        $term->setName($option_value);
        $save_term = TRUE;
      }

      if ($save_term) {
        $term->setWeight($weight);
        $term->save();
      }
    }
    else {
      $term = $this->termStorage->create([
        'vid' => self::PRODUCT_OPTIONS_VOCABULARY,
        'langcode' => $langcode,
        'name' => $option_value,
        'weight' => $weight,
        'field_sku_option_id' => $option_id,
        'field_sku_attribute_id' => $attribute_id,
        'field_sku_attribute_code' => $attribute_code,
      ]);
      try {
        $term->save();
      }
      catch (EntityStorageException $exception) {
        $this->logger->critical('Product option "@option" wasn\'t saved. Try again later please.', ['@option' => $option_value]);
      }
    }

    return $term;
  }

  /**
   * {@inheritdoc}
   */
  public function synchronizeProductOptions() {
    $options_available = [];

    foreach ($this->i18nHelper->getStoreLanguageMapping() as $langcode => $store_id) {
      $this->apiWrapper->updateStoreContext($store_id);
      $option_sets = $this->apiWrapper->getProductOptions();

      $weight = 0;
      foreach ($option_sets as $options) {
        foreach ($options['options'] as $key => $value) {
          $this->createProductOption($langcode, $key, $value, $options['attribute_id'], $options['attribute_code'], $weight++);
          $options_available[$options['attribute_code']][$options['attribute_id']] = $options['attribute_id'];
        }
      }
    }

    if ($options_available) {
      $this->deleteUnavailableOptions($options_available);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function deleteUnavailableOptions(array $synced_options) {
    // Cleanup queries can be done only for one language.
    $query = $this->connection->select('taxonomy_term__field_sku_attribute_code', 'ttfsac');
    $query->addExpression('count(entity_id)', 'cnt');
    $query->condition('field_sku_attribute_code_value', array_keys($synced_options), 'IN');
    $result = $query->execute()->fetchAllKeyed(0, 0);
    $options_in_db = reset($result);

    $synced_option_ids = [];
    foreach ($synced_options as $attribute_code => $options) {
      $synced_option_ids = array_merge($synced_option_ids, $options);
    }

    // Do nothing if count of option ids synced and in DB match.
    if (count($synced_option_ids) === $options_in_db) {
      return;
    }

    $query = $this->termStorage->getQuery();
    $query->condition('field_sku_option_id', $synced_option_ids, 'NOT IN');
    $query->condition('field_sku_attribute_code', array_keys($synced_options), 'IN');
    $query->condition('vid', self::PRODUCT_OPTIONS_VOCABULARY);
    $tids = $query->execute();

    if ($tids) {
      foreach (array_chunk($tids, 50) as $ids) {
        $this->termStorage->resetCache();

        try {
          $entities = $this->termStorage->loadMultiple($ids);
          $this->termStorage->delete($entities);
        }
        catch (\Exception $e) {
          $this->logger->error(t('Error occurred while deleting options that are no longer available. Error: @message', [
            '@message' => $e->getMessage(),
          ]));
        }
      }
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc