denormalizer-8.x-1.x-dev/src/Denormalizer.php

src/Denormalizer.php
<?php

namespace Drupal\denormalizer;

use Drupal\Component\Utility\Unicode;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Database\Query\SelectInterface;

/**
 * Class Denormalizer.
 *
 * @package Drupal\denormalizer
 */
class Denormalizer {

  /**
   * The DN tables to be exported/created.
   *
   * @var array
   */
  private $dwTables = [];

  protected $entityTypeManager;

  /**
   * Generate all SQL for views.
   */
  public function build() {
    $databases = Database::getAllConnectionInfo();
    $other_database = $databases['default']['default'];
    $other_database['prefix'] = '';
    Database::addConnectionInfo('external', 'default', $other_database);

    $d = denormalizer_get_info();

    foreach ($d as $denormalizer_view => $dn_info) {
      $this->add($denormalizer_view, $dn_info);
    }
  }

  /**
   * Add a table to the denormalizer...list.
   *
   * @param string $denormalizer_view
   *   Name of the view.
   * @param array $dn_info
   *   Info bit from hook_denormalizer_info().
   */
  public function add($denormalizer_view, array $dn_info) {
    $query = $this->generateQuery($denormalizer_view, $dn_info);
    $this->dwTables[$denormalizer_view] = $query;
  }

  /**
   * Create a view.
   *
   * @param string $denormalizer_view
   *   Name of view to create.
   * @param array $dn_info
   *   Param info.
   *
   * @return string
   *   SQL to use to pull denormalized data or create a view.
   *
   * @throws \Exception
   */
  public function generateQuery($denormalizer_view, array $dn_info) {
    $d = denormalizer_get_info();
    $schema = drupal_get_module_schema($d[$denormalizer_view]['schema_module'], $d[$denormalizer_view]['base table']);
    $property_info = [];
    if (isset($dn_info['entity_type'])) {
      $injected_database = Database::getConnection();
      if ($dn_info['entity_type'] !== 'webform_submission') {
        $property_info = \Drupal::service('entity_field.manager')
          ->getBaseFieldDefinitions($dn_info['entity_type']);
        $base_fields = [];
        $results = $injected_database->query("SHOW COLUMNS FROM " . $dn_info['entity_type'] . ";");
        $base_columns = [];
        foreach ($results as $index => $info) {
          array_push($base_columns, $info->Field);
          array_push($base_fields, $info->Field);
        }
        $results = $injected_database->query("SHOW COLUMNS FROM " . $dn_info['entity_type'] . "_field_data;");
        $base_node_field = [];
        foreach ($results as $index => $info) {
          array_push($base_node_field, $info->Field);
          if (!in_array($info->Field, $base_fields, TRUE)) {
            array_push($base_fields, $info->Field);
          }
        }
      }
      else {
        $results = $injected_database->query("SHOW COLUMNS FROM " . $dn_info['entity_type'] . "_data;");
        $base_columns = [];
        foreach ($results as $index => $info) {
          array_push($base_columns, $info->Field);
        }
      }
    }
    else {
      if (empty($dn_info['external'])) {
        $property_info = $this->denormMetadataConvertSchema($dn_info['base table']);
      }
    }

    $base_table = $this->entityTypeManager()
      ->getDefinition($dn_info['entity_type'])
      ->getBaseTable();

    $injected_database = Database::getConnection();

    if (($dn_info['entity_type'] !== 'webform_submission')) {
      $q = $injected_database->select($base_table, $denormalizer_view);
      $q->leftJoin($base_table . '_field_data', 'field_data', "field_data.nid = $denormalizer_view.nid");
    }
    elseif ($dn_info['entity_type'] == 'webform_submission') {
      $q = $injected_database->select($base_table . '_data', $denormalizer_view);
    }

    if (!empty($dn_info['external'])) {
      $q->fields($denormalizer_view);
    }

    $properties_columns = [];
    foreach ($property_info as $property => $info) {
      if ($info['schema field']) {
        if (in_array($info['schema field'], [
          'revision_timestamp',
          'revision_uid',
          'revision_log',
          'revision_default',
          'path',
          'menu_link',
          'moderation_state',
        ])) {
          // ??? this column does not exist
          continue;
        }

        if (!empty($schema[$dn_info['base table']]['fields'][$info['schema field']]['serialize'])) {
          // No serialized fields.
          continue;
        }

        $properties_columns[$info['schema field']] = $info['schema field'];
        if (isset($info['type']) && $info['type'] == 'date') {
          $q->addExpression("from_unixtime($denormalizer_view.{$info['schema field']})", "{$info['schema field']}");
        }
        else {
          // @todo: How do we get column values for base fields and also field.
          // API fields?.
          // $baseColumnName = $info->getFieldStorageDefinition().
          // ->getMainPropertyName();.
          $q->fields($denormalizer_view, [$property]);
        }
      }
      else {
        // Todo handle serializable and date fields.
        if (in_array($property, $base_node_field) && in_array($property, $base_columns)) {
          $q->fields($denormalizer_view, [$property]);
        }
        elseif (in_array($property, $base_node_field)) {
          $q->fields('field_data', [$property]);
        }
        elseif (in_array($property, $base_columns)) {
          $q->fields($denormalizer_view, [$property]);
        }
        else {
          // ??? this column does not exist.
          continue;
        }
      }
    }

    if ($dn_info['entity_type'] == 'webform_submission' && isset($base_columns)) {
      foreach ($base_columns as $index => $property) {
        $q->fields($denormalizer_view, [$property]);
      }
    }

    // Track fields we already processed :.
    if (isset($dn_info['entity_type']) && $dn_info['fields'] !== FALSE && $dn_info['entity_type'] !== 'webform_submission') {
      $entity_info = $this->entityTypeManager()
        ->getDefinition($dn_info['entity_type']);

      if (count($dn_info['bundles']) != 0) {
        foreach ($dn_info['bundles'] as $bundles) {
          $fields = \Drupal::service('entity_field.manager')
            ->getFieldDefinitions($dn_info['entity_type'], $bundles);
          $flag = 0;
          $base_fields = $this->processFields($fields, $entity_info, $base_fields, $denormalizer_view, $q, $flag);
        }
        $q->condition($denormalizer_view . ".type", $dn_info['bundles'], 'IN');
      }
      else {
        $fields = \Drupal::service('entity_field.manager')
          ->getFieldStorageDefinitions($dn_info['entity_type']);
        $flag = 1;
        $base_fields = $this->processFields($fields, $entity_info, $base_fields, $denormalizer_view, $q, $flag);
      }
    }
    elseif ($dn_info['entity_type'] == 'webform_submission') {
      $q->condition($denormalizer_view . ".webform_id", $dn_info['bundles'], '=');
    }

    return $q;
  }

  /**
   * Converts the schema information available for the given table to property.
   *
   * Info.
   *
   * @param string $table
   *   The name of the table as used in hook_schema().
   *
   * @return array
   *   An array of property info as suiting for hook_entity_property_info().
   */
  public function denormMetadataConvertSchema($table) {

    // $schema = StorableConfigBase::getSchemaWrapper();.
    $properties = [];
    // Todo Find the best way to get the schema ??.
    $injected_database = Database::getConnection();
    $result = $injected_database->query("SHOW COLUMNS FROM " . $table . ";");

    foreach ($result as $index => $info) {
      $type = '';
      if (strpos($info->Type, 'int') !== FALSE || strpos($info->Type, 'serial') !== FALSE || strpos($info->Type, 'date') !== FALSE) {
        $type = 'integer';
      }
      elseif (strpos($info->Type, 'float') !== FALSE || strpos($info->Type, 'numeric') !== FALSE) {
        $type = 'decimal';
      }
      elseif (strpos($info->Type, 'char') !== FALSE || strpos($info->Type, 'varchar') !== FALSE || strpos($info->Type, 'text') !== FALSE) {
        $type = 'text';
      }

      if ($type) {
        $properties[$info->Field] = [
          'type' => $type,
          'label' => Unicode::ucfirst($info->Field),
          'schema field' => $info->Field,
          // As we cannot know about any setter access, leave out the setter
          // callback. For getting usually no further access callback is needed.
        ];
        if ($info->Type == 'serial') {
          $properties[$info->Field]['validation callback'] = 'entity_metadata_validate_integer_positive';
        }
      }
    }
    return $properties;
  }

  /**
   * Process fields.
   *
   * @param array $fields
   *   The fields definition to process.
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_info
   *   The entity info.
   * @param array $base_fields
   *   The base fields.
   * @param string $denormalizer_view
   *   The view to create.
   * @param \Drupal\Core\Database\Query\SelectInterface $q
   *   The query.
   * @param bool $flag
   *   A flag, whether the bundle is blank or no, this using two different way.
   *   To get fields info.
   *
   * @return array
   *   Return the base fields for checking to avoid replication of the same.
   *   Field name from different bundles.
   */
  public function processFields(array $fields, EntityTypeInterface $entity_info, array $base_fields, $denormalizer_view, SelectInterface $q, $flag) {
    foreach ($fields as $field_name => $info) {
      if (in_array($field_name, $base_fields, TRUE)) {
        // This column was already processed.
        continue;
      }

      if (empty($info->getTargetBundle())) {
        // This column does not exist.
        continue;
      }

      if ($flag) {
        $isMultiple = $info->isMultiple();
        $columns = $info->getColumns();
        $type = $info->getType();
        $cardinality = $info->getCardinality();
      }
      else {
        $isMultiple = $fields[$field_name]->getFieldStorageDefinition()
          ->isMultiple();
        $columns = $fields[$field_name]->getFieldStorageDefinition()
          ->getColumns();
        $type = $fields[$field_name]->getType();
        $cardinality = $fields[$field_name]->getFieldStorageDefinition()
          ->getCardinality();
      }

      if (!isset($used[$field_name])) {
        $used[$field_name] = $field_name;
        if (!$isMultiple) {
          $cols = [];
          if ($type != 'entity_reference') {
            $cols = [];
            if ($type == 'date') {

              // "Date" time, we need to special handle :( Cast into a real
              // datetime so ETL tools can pick it up.
              $q->addJoin('LEFT', 'node__' . $field_name, $field_name, "$field_name.entity_id = $denormalizer_view.{$entity_info->getKey('id')}", []);
              $col1 = $field_name . '_value';
              $q->addExpression("cast($col1 as datetime)", $col1);
              if (!empty($fields[$field_name]['settings']['todate'])) {
                $col2 = $field_name . '_value2';
                $q->addExpression("cast($col2 as datetime)", $col2);
              }
              // Skip this field.
              continue;
            }

            foreach ($columns as $column => $info) {
              // No full text fields.
              if ($type == 'text_long' || $type == 'text_with_summary') {
                continue;
              }
              $cols[] = $field_name . '_' . $column;
            }

            // Todo add entity_type condition like D7 ??.
            if (!empty($cols)) {
              // Join field table. Add columns to query.
              $q->addJoin('LEFT', 'node__' . $field_name, $field_name, "$field_name.entity_id = $denormalizer_view.{$entity_info->getKey('id')}", []);
              $q->fields($field_name, $cols);
            }
          }
          else {
            // Handle taxonomy terms. We get the term value.
            $q->addJoin('LEFT', 'node__' . $field_name, $field_name, "$field_name.entity_id = $denormalizer_view.{$entity_info->getKey('id')}", []);
            $q->addJoin('LEFT', 'taxonomy_term_field_data', "{$field_name}_tax", "{$field_name}_target_id = {$field_name}_tax.tid");
            $cols[] = 'name';
            $q->fields("{$field_name}_tax", $cols);
          }
        }
        elseif ($type == 'entity_reference') {
          // Handle taxonomy terms. We get the values and concatenate them into.
          // One column.
          $q->addJoin('LEFT', 'node__' . $field_name, $field_name, "$field_name.entity_id = $denormalizer_view.{$entity_info->getKey('id')}", []);
          $q->addJoin('LEFT', 'taxonomy_term_field_data', "{$field_name}_tax", "{$field_name}_target_id = {$field_name}_tax.tid");
          $q->addExpression("group_concat(distinct {$field_name}_tax.name SEPARATOR '|')", "{$field_name}_values");
          // Group by primary key, so group_concat will work.
          $q->groupBy("$denormalizer_view.{$entity_info->getKey('id')}");
        }
        elseif ($cardinality != 1) {
          if ($fields[$field_name]->getType() == 'list_string') {
            $q->addJoin('LEFT', 'node__' . $field_name, $field_name, "$field_name.entity_id = $denormalizer_view.{$entity_info->getKey('id')}", []);
            $q->addExpression("group_concat(distinct {$field_name}_value SEPARATOR '|')", "{$field_name}_values");
            // Group by primary key, so group_concat will work.
            $q->groupBy("$denormalizer_view.{$entity_info->getKey('id')}");
          }
        }
      }
      array_push($base_fields, $field_name);
    }
    return $base_fields;
  }

  /**
   * Create all database views.
   *
   * @param bool $reset
   *   Whether or not to drop and recreate tables.
   *
   * @throws \Exception
   */
  public function execute($reset = FALSE) {
    $config = \Drupal::service('config.factory')
      ->getEditable('denormalizer.settings');

    $prefix = $config->get('view_prefix', 'snowflake_');
    $db_prefix = '';
    $db_target = denormalizer_target_db();

    if ($db = denormalizer_target_db()) {
      $db_prefix = "{$db}.";
      $injected_database = Database::getConnection();
      $target_exists = $injected_database->query('SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = :name', [':name' => $db_target])
        ->fetchField();
      // $target_exists = db_query('SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA.
      // WHERE SCHEMA_NAME = :name', array(':name' => $db_target)).
      // ->fetchField();.
      if ($reset) {
        if ($target_exists) {
          $injected_database = Database::getConnection();
          $injected_database->query("DROP DATABASE $db_target");
          // Db_query("DROP DATABASE $db_target");.
          \Drupal::messenger()->addStatus(t('Dropped %target database.', ['%target' => $db_target]));
          $target_exists = FALSE;
        }
      }

      if (!$target_exists) {
        $injected_database = Database::getConnection();
        $injected_database->query("CREATE DATABASE $db_target");
        // db_query("CREATE DATABASE $db_target");.
        \Drupal::messenger()->addStatus(t('Created %target database.', ['%target' => $db_target]));
      }
    }

    if ($config->get('sql_mode', 'views') == 'views') {
      $type = 'VIEW';
    }
    else {
      $type = 'TABLE';
    }

    $out = [];
    $dn_info = denormalizer_get_info();
    $all_start = microtime(TRUE);

    // Hack to get around https://stackoverflow.com/questions/36882149/.
    // Error-1067-42000-invalid-default-value-for-created-at.
    // Some tables have a CURRENT_TIMESTAMP so the derived table gets a zero.
    // Date.
    $injected_database = Database::getConnection();
    $injected_database->query("SET sql_mode = 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'");
    // db_query("SET sql_mode = 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,.
    // IGNORE_SPACE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'");
    // A little more flexibility for handling multiple values.
    $config->set('group_concat_max_len', 255)->save();
    $group_concat_max_len = intval($config->get('group_concat_max_len'));
    $injected_database = Database::getConnection();
    $injected_database->query("SET group_concat_max_len = $group_concat_max_len");

    foreach ($this->dwTables as $denormalizer_view => $final_q) {
      $target = "{$db_prefix}" . "`$prefix$denormalizer_view`";
      $start = microtime(TRUE);
      $id_key = denormalizer_get_primary_key($denormalizer_view);
      $injected_database = Database::getConnection();
      $reset = ($type == 'VIEW') || (!$injected_database->query('SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :name', [
            ':schema' => $db_target,
            ':name' => $denormalizer_view,
          ])->fetchField() || $injected_database->query('SELECT 1 FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = :schema AND TABLE_NAME = :name', [
            ':schema' => $db_target,
            ':name' => $denormalizer_view,
          ])->fetchField());

      if (empty($reset)) {
        if (!$config->get('max_changed_' . $denormalizer_view)) {
          // No reset, but we can't reload.
          $injected_database = Database::getConnection();
          $count = $injected_database->query("SELECT COUNT(*) FROM $target")
            ->fetchField();
          // $count = db_query("SELECT COUNT(*) FROM $target")->fetchField();.
          if ($count > 0) {
            $injected_database = Database::getConnection();
            $injected_database->query("TRUNCATE $target");
            // db_query("TRUNCATE $target");.
            $out[] = t('Emptied :target.', [':target' => $target]);
          }
        }
        else {
          if (isset($dn_info[$denormalizer_view]['changed_key']) && $config->get('max_changed_' . $denormalizer_view)) {
            // If there is a last changed key, only replicate records.
            // That have changed.
            $final_q->havingCondition($dn_info[$denormalizer_view]['changed_key'], $config->get('max_changed_' . $denormalizer_view), '>');
          }
        }

        // Allow altering query before update.
        \Drupal::moduleHandler()
          ->alter('denormalizer', $final_q, $denormalizer_view, $dn_info[$denormalizer_view]);

        if (!empty($dn_info[$denormalizer_view]['external'])) {
          Database::setActiveConnection('external');
        }

        $final_sql = denormalizer_dpq($final_q);
        Database::setActiveConnection();
        try {
          $injected_database = Database::getConnection();
          $affected = $injected_database->query("REPLACE INTO {$db_prefix}$prefix{$denormalizer_view} $final_sql");
          // $affected = db_query("REPLACE INTO {$db_prefix}$prefix.
          // {$denormalizer_view} $final_sql");.
          $affected->allowRowCount = TRUE;
          $count = $affected->rowCount();
        }
        catch (Exception $e) {
          \Drupal::messenger()->addError(t('Could not denormalize @table: @message', [
            '@table' => $denormalizer_view,
            '@message' => $e->getMessage(),
          ]));
        }
        $end = microtime(TRUE);
        $time = round($end - $start, 2);
        $out[] = t('Loaded @records to %view in @time seconds.', [
          '%view' => "{$db_prefix}$prefix{$denormalizer_view}",
          '@records' => $affected,
          '@time' => $time,
        ]);
      }
      else {
        $injected_database = Database::getConnection();
        $injected_database->query("DROP TABLE IF EXISTS {$db_prefix}$prefix$denormalizer_view");
        $injected_database->query("DROP VIEW IF EXISTS {$db_prefix}$prefix$denormalizer_view");
        // Db_query("DROP TABLE IF EXISTS.
        // {$db_prefix}$prefix$denormalizer_view");.
        // Db_query("DROP VIEW IF EXISTS.
        // {$db_prefix}$prefix$denormalizer_view");.
        // $out[] = t('Dropped %name.', array('%name' => "{$db_prefix}.
        // $prefix$denormalizer_view"));.
        if (!empty($dn_info[$denormalizer_view]['external'])) {
          Database::setActiveConnection('external');
        }
        // Allow altering query before insert.
        \Drupal::moduleHandler()
          ->alter('denormalizer', $final_q, $denormalizer_view, $dn_info[$denormalizer_view]);
        $final_sql = denormalizer_dpq($final_q);
        Database::setActiveConnection();

        if ($dn_info[$denormalizer_view]['entity_type'] == 'webform_submission') {
          $injected_database = Database::getConnection();
          $affected = $injected_database->query("$final_sql");
          // @todo maybe find a way to load multiple webform bundle?
          $bundle = array_key_first($dn_info[$denormalizer_view]['bundles']);
          $elements = denormalizer_webform_get_columns($bundle);
          $sqlColumns = denormalizer_webform_sql_columns($elements);
          $implodedColumns = implode(",", $sqlColumns);
          $webformData = $affected->fetchAll();
          $sanitizedData = [];
          if ($webformData) {
            $sanitizedData = denormalizer_webform_data_sanitize($webformData, $elements);
          }
        }

        if ($type == 'TABLE') {
          // Create an empty table.
          // https://www.percona.com/blog/2018/01/10/.
          // Why-avoid-create-table-as-select-statement/.
          $injected_database = Database::getConnection();
          if ($dn_info[$denormalizer_view]['entity_type'] == 'webform_submission') {
            if (isset($implodedColumns)) {
              $affected = $injected_database->query("CREATE $type $target ($implodedColumns) CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = MYISAM");
              $injected_database->query("ALTER TABLE $target ADD PRIMARY KEY (webform_id,sid)");
            }
          }
          else {
            $affected = $injected_database->query("CREATE $type $target CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = MYISAM AS $final_sql LIMIT 0");
          }
          // $affected = db_query("CREATE $type $target CHARACTER SET utf8.
          // COLLATE utf8_general_ci ENGINE = MYISAM AS $final_sql LIMIT 0");.
          $affected->allowRowCount = TRUE;
          $count = $affected->rowCount();
          if ($id_key) {
            $injected_database = Database::getConnection();
            $injected_database->query("ALTER TABLE $target ADD PRIMARY KEY $id_key ($id_key)");
          }
          // Insert records into it.
          try {
            $injected_database = Database::getConnection();
            if ($dn_info[$denormalizer_view]['entity_type'] == 'webform_submission') {
              $columns = implode(", ", array_keys($sanitizedData[0] ?? []));

              foreach ($sanitizedData as $val) {
                $prep = [];
                foreach ($val as $k => $v) {
                  $prep[':' . $k] = $v;
                }
                $sth = $injected_database->prepare("INSERT INTO $target ( " . $columns . ") VALUES (" . implode(', ', array_keys($prep)) . ")");
                $result = $sth->execute($prep);
              }
            }
            else {
              $affected = $injected_database->query("INSERT INTO $target $final_sql");
              // $affected = db_query("INSERT INTO $target $final_sql");.
              $affected->allowRowCount = TRUE;
              $count = $affected->rowCount();
            }
          }
          catch (Exception $e) {
            \Drupal::messenger()->addError(t('Could not denormalize @table: @message', [
              '@table' => $denormalizer_view,
              '@message' => $e->getMessage(),
            ]));
          }
        }
        elseif ($type == 'VIEW') {
          try {
            $injected_database = Database::getConnection();

            // todo It's complex to get view from current webform table structure without creating a new table first.
            if ($dn_info[$denormalizer_view]['entity_type'] == 'webform_submission') {
              if (isset($implodedColumns)) {
                $temp = str_replace($prefix.$denormalizer_view.'`', $prefix.$denormalizer_view.'_for_view`',$target);
                $affected = $injected_database->query("CREATE TABLE $temp ($implodedColumns) CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = MYISAM");
                $injected_database->query("ALTER TABLE $temp ADD PRIMARY KEY (webform_id,sid)");
                $columns = implode(", ", array_keys($sanitizedData[0] ?? []));

                foreach ($sanitizedData as $val) {
                  $prep = [];
                  foreach ($val as $k => $v) {
                    $prep[':' . $k] = $v;
                  }
                  $sth = $injected_database->prepare("INSERT INTO $temp ( " . $columns . ") VALUES (" . implode(', ', array_keys($prep)) . ")");
                  $result = $sth->execute($prep);
                }
                $temp_q = $injected_database->select($temp,'temp');
                $temp_q->fields('temp');
                $temp_q_final = denormalizer_dpq($temp_q);
                $affected = $injected_database->query("CREATE $type $target AS $temp_q_final");
              }
            }
            else {
              // print_r("Final : ".$final_sql);.
              $affected = $injected_database->query("CREATE $type $target AS $final_sql");
            }
            // $affected = db_query("CREATE $type $target AS $final_sql");.
            $affected->allowRowCount = TRUE;
            $count = $affected->rowCount();
          }
          catch (Exception $e) {
            \Drupal::messenger()->addError(t('Could not denormalize @table: @message', [
              '@table' => $denormalizer_view,
              '@message' => $e->getMessage(),
            ]));
          }
        }

        $end = microtime(TRUE);
        $time = round($end - $start, 2);
        $out[] = t('Created @type %view with @records records in @time seconds.', [
          '@type' => $type,
          '%view' => "{$db_prefix}$prefix{$denormalizer_view}",
          '@records' => $affected,
          '@time' => $time,
        ]);
      }

      if ($type == 'TABLE') {
        if (!empty($dn_info[$denormalizer_view]['changed_key'])) {
          if (!empty($dn_info[$denormalizer_view]['external'])) {
            Database::setActiveConnection('external');
          }
          $injected_database = Database::getConnection();
          $changed = $injected_database->query("SELECT max({$dn_info[$denormalizer_view]['changed_key']}) from $target")
            ->fetchField();
          // $changed = db_query("SELECT max({$dn_info[$denormalizer_view].
          // ['changed_key']}) from $target")->fetchField();.
          Database::setActiveConnection();
          \Drupal::service('config.factory')
            ->getEditable('denormalizer_max_changed_' . $denormalizer_view, $changed);
        }
      }

      $args = [$denormalizer_view, $dn_info[$denormalizer_view]];
      \Drupal::moduleHandler()->invokeAll('denormalizer_post_execute', $args);
    }
    $all_end = microtime(TRUE);
    $all_time = round($all_end - $all_start, 2);
    $out[] = t('Created all in @time seconds.', ['@time' => $all_time]);
    \Drupal::messenger()->addStatus(implode("<br/>", $out));
  }

  /**
   * Show full SQL used to create all database items.
   */
  public function getSql() {
    $config = \Drupal::service('config.factory')
      ->getEditable('denormalizer.settings');
    $db_source = denormalizer_source_db();
    $sql = '';

    if ($config->get('db') == 'external') {
      $db_target = denormalizer_target_db();
      $db_prefix = "{$db_target}.";
      $sql .= "CREATE DATABASE IF NOT EXISTS $db_target;\n\n";
    }

    if ($config->get('sql_mode', 'views') == 'views') {
      $type = 'VIEW';
    }
    else {
      $type = 'TABLE';
    }

    $prefix = $config->get('view_prefix', 'snowflake_');

    $dn_info = denormalizer_get_info();
    foreach ($this->dwTables as $denormalizer_view => $final_q) {
      if (!empty($dn_info[$denormalizer_view]['external'])) {
        Database::setActiveConnection('external');
      }

      // Allow altering query before insert.
      \Drupal::moduleHandler()
        ->alter('denormalizer', $final_q, $denormalizer_view, $dn_info[$denormalizer_view]);

      $final_sql = denormalizer_dpq($final_q);
      $target = "{$db_prefix}{$prefix}{$denormalizer_view}";
      // Drop views and tables.
      $sql .= "DROP TABLE IF EXISTS $target;\n";
      $sql .= "DROP VIEW IF EXISTS $target;\n";
      $sql .= "CREATE $type $target AS $final_sql;\n";
      if ($key = denormalizer_get_primary_key($denormalizer_view)) {
        $sql .= "ALTER TABLE $target ADD PRIMARY KEY $key ($key);\n\n";
      }
      // Reset to default DB.
      Database::setActiveConnection();
    }

    $page = [];

    $page['header']['#markup'] = t('You can use the SQL below to generate database views of denormalized data on a copy of this database. This uses the entity property and field metadata from the current site, so queries may fail if the data is different.');

    $page['sql']['#type'] = 'textarea';
    $page['sql']['#rows'] = '100';
    $page['sql']['#value'] = $sql;

    return \Drupal::service('renderer')->render($page);
  }

  private function entityTypeManager() {
    if (empty($this->entityTypeManager)) {
      $this->entityTypeManager = \Drupal::entityTypeManager();
    }
    return $this->entityTypeManager;
  }

}

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

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