acquia_commercemanager-8.x-1.122/modules/acm_sku_position/src/Commands/AcmSkuPositionCommands.php
modules/acm_sku_position/src/Commands/AcmSkuPositionCommands.php
<?php namespace Drupal\acm_sku_position\Commands; use Drupal\acm\Connector\APIWrapper; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Database\Connection; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drush\Commands\DrushCommands; /** * Class AcmSkuPositionCommands. * * @package Drupal\acm_sku_position\Commands */ class AcmSkuPositionCommands extends DrushCommands { /** * Config Factory. * * @var \Drupal\Core\Config\ConfigFactoryInterface */ private $configFactory; /** * Module Handler service. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ private $moduleHandler; /** * Database connection object. * * @var \Drupal\Core\Database\Connection */ private $connection; /** * Commerce Api Wrapper. * * @var \Drupal\acm\Connector\APIWrapper */ private $apiWrapper; /** * Logger Factory. * * @var \Drupal\Core\Logger\LoggerChannelInterface */ protected $logger; /** * AcmSkuPositionCommands constructor. * * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * Config Factory. * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger * Looger Factory. * @param \Drupal\acm\Connector\APIWrapper $api_wrapper * Commerce Api Wrapper. * @param \Drupal\Core\Database\Connection $connection * Database Connection object. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * Module Handler service. */ public function __construct(ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger, APIWrapper $api_wrapper, Connection $connection, ModuleHandlerInterface $module_handler) { $this->configFactory = $config_factory; $this->logger = $logger->get('AcmSkuPositionCommands'); $this->apiWrapper = $api_wrapper; $this->connection = $connection; $this->moduleHandler = $module_handler; } /** * Drush command to sync sku product position based on category. * * @param string $position_type * Name of the position type. * * @command acm_sku_position:position-sync * * @aliases aapps,position-sync,sync-positions * * @usage drush aapps * Sync product position based on category, by default "position". * @usage drush aapps myargument * Sync product position based on category, by "myargument". */ public function syncPositions($position_type = 'position') { $config = $this->configFactory->get('acm.connector'); $product_node_type = $config->get('product_node_type'); $field_skus = $config->get('sku_field_name'); $this->logger->notice('Product position sync in progress...'); // SQL query to fetch categories from DB. // SQL query to fetch categories from DB. $query = $this->connection->select('taxonomy_term__field_commerce_id', 'tc'); $query->innerJoin('taxonomy_term_field_data', 'td', 'td.tid = tc.entity_id AND td.langcode = tc.langcode'); $query->addField('tc', 'entity_id', 'tid'); $query->addField('tc', 'field_commerce_id_value', 'commerce_id'); $query->addField('td', 'name'); $terms = $query->execute()->fetchAll(); // Allow other modules to skip terms from position sync. $this->moduleHandler->alter('acm_sku_position_sync', $terms); $chunk_size = 100; foreach (array_chunk($terms, $chunk_size) as $categories_chunk) { $is_data_available = FALSE; $insert_query = $this->connection->insert('acm_sku_position') ->fields(['nid', 'tid', 'position', 'position_type']); foreach ($categories_chunk as $term) { // Find the commerce id from the term. Skip if not found. $commerce_id = $term->commerce_id; if (!$commerce_id) { continue; } // Get product position for this category from commerce backend. try { $response = $this->apiWrapper->getProductPosition($commerce_id); if (!is_array($response)) { continue; } } catch (\Exception $e) { $this->logger->error(dt('Exception while fetching position for category @name (tid: @tid). The category probably does not exist in commerce backend', [ '@name' => $term->name, '@tid' => $term->tid, ])); continue; } // Skip sync if error is found in response for a particular category. if (is_array($response) && isset($response['message'])) { $this->logger->error(dt('Error in position sync for @name (tid: @tid). Response: @message', [ '@name' => $term->name, '@tid' => $term->tid, '@message' => $response['message'], ])); continue; } // Start product position sync for this category. $this->logger->notice(dt('Product position sync for !name (tid: !tid) in progress...', [ '!name' => $term->name, '!tid' => $term->tid, ])); // Get all skus from the response. $skus = array_column($response, 'sku'); if (empty($skus)) { continue; } // Get all product nids from skus. $query = $this->connection->select('node__' . $field_skus, 'n'); $query->fields('n', ['field_' . $field_skus, 'entity_id']); $query->condition('n.bundle', $product_node_type); $query->condition('n.' . $field_skus . '_value', $skus, 'IN'); $nids = $query->execute()->fetchAllKeyed(); // Skip if not product found for any sku. if (empty($nids)) { continue; } foreach ($response as $product_position) { if (isset($nids[$product_position['sku']])) { // Insert new position data for the product. $record = [ 'nid' => $nids[$product_position['sku']], 'tid' => $term->tid, 'position' => $product_position['position'], 'position_type' => $position_type, ]; $is_data_available = TRUE; $insert_query->values($record); } } } try { if (!empty($categories_chunk)) { // Delete existing records of position for this category. $this->connection->delete('acm_sku_position') ->condition('tid', array_column($categories_chunk, 'tid'), 'IN') ->condition('position_type', $position_type) ->execute(); } // Run query only if there is any record to insert. if ($is_data_available) { $insert_query->execute(); } } catch (\Exception $e) { $this->logger->error('Error while deleting and inserting data for product position for terms: @tids. Message: @message', [ '@tids' => implode(',', array_column($categories_chunk, 'tid')), '@message' => $e->getMessage(), ]); } } // Allow other modules to take action after position sync finished. $this->moduleHandler->invokeAll('acm_sku_position_sync_finished'); $this->logger->notice(dt('Product position sync completed!')); } }