You are here

abstract class SqlBase in Zircon Profile 8.0

Same name in this branch
  1. 8.0 core/modules/views/src/Plugin/views/pager/SqlBase.php \Drupal\views\Plugin\views\pager\SqlBase
  2. 8.0 core/modules/migrate/src/Plugin/migrate/source/SqlBase.php \Drupal\migrate\Plugin\migrate\source\SqlBase
Same name and namespace in other branches
  1. 8 core/modules/migrate/src/Plugin/migrate/source/SqlBase.php \Drupal\migrate\Plugin\migrate\source\SqlBase

Sources whose data may be fetched via DBTNG.

By default, an existing database connection with key 'migrate' and target 'default' is used. These may be overridden with explicit 'key' and/or 'target' configuration keys. In addition, if the configuration key 'database' is present, it is used as a database connection information array to define the connection.

Hierarchy

Expanded class hierarchy of SqlBase

2 files declare their use of SqlBase
DrupalSqlBase.php in core/modules/migrate_drupal/src/Plugin/migrate/source/DrupalSqlBase.php
Contains \Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase.
SqlBaseTest.php in core/modules/migrate/tests/src/Unit/SqlBaseTest.php
Contains \Drupal\Tests\migrate\Unit\SqlBaseTest.

File

core/modules/migrate/src/Plugin/migrate/source/SqlBase.php, line 27
Contains \Drupal\migrate\Plugin\migrate\source\SqlBase.

Namespace

Drupal\migrate\Plugin\migrate\source
View source
abstract class SqlBase extends SourcePluginBase implements ContainerFactoryPluginInterface {

  /**
   * @var \Drupal\Core\Database\Query\SelectInterface
   */
  protected $query;

  /**
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * State service for retrieving database info.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * {@inheritdoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, StateInterface $state) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
    $this->state = $state;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
    return new static($configuration, $plugin_id, $plugin_definition, $migration, $container
      ->get('state'));
  }

  /**
   * Print the query string when the object is used a string.
   *
   * @return string
   *   The query string.
   */
  public function __toString() {
    return (string) $this->query;
  }

  /**
   * Get the database connection object.
   *
   * @return \Drupal\Core\Database\Connection
   *   The database connection.
   */
  public function getDatabase() {
    if (!isset($this->database)) {

      // See if the database info is in state - if not, fallback to
      // configuration.
      if (isset($this->configuration['database_state_key'])) {
        $this->database = $this
          ->setUpDatabase($this->state
          ->get($this->configuration['database_state_key']));
      }
      else {
        $this->database = $this
          ->setUpDatabase($this->configuration);
      }
    }
    return $this->database;
  }

  /**
   * Get a connection to the referenced database, adding the connection if
   * necessary.
   *
   * @param array $database_info
   *   Configuration for the source database connection. The keys are:
   *    'key' - The database connection key.
   *    'target' - The database connection target.
   *    'database' - Database configuration array as accepted by
   *      Database::addConnectionInfo.
   *
   * @return \Drupal\Core\Database\Connection
   *   The connection to use for this plugin's queries.
   */
  protected function setUpDatabase(array $database_info) {
    if (isset($database_info['key'])) {
      $key = $database_info['key'];
    }
    else {
      $key = 'migrate';
    }
    if (isset($database_info['target'])) {
      $target = $database_info['target'];
    }
    else {
      $target = 'default';
    }
    if (isset($database_info['database'])) {
      Database::addConnectionInfo($key, $target, $database_info['database']);
    }
    return Database::getConnection($target, $key);
  }

  /**
   * Wrapper for database select.
   */
  protected function select($table, $alias = NULL, array $options = array()) {
    $options['fetch'] = \PDO::FETCH_ASSOC;
    return $this
      ->getDatabase()
      ->select($table, $alias, $options);
  }

  /**
   * A helper for adding tags and metadata to the query.
   *
   * @return \Drupal\Core\Database\Query\SelectInterface
   *   The query with additional tags and metadata.
   */
  protected function prepareQuery() {
    $this->query = clone $this
      ->query();
    $this->query
      ->addTag('migrate');
    $this->query
      ->addTag('migrate_' . $this->migration
      ->id());
    $this->query
      ->addMetaData('migration', $this->migration);
    return $this->query;
  }

  /**
   * Implementation of MigrateSource::performRewind().
   *
   * We could simply execute the query and be functionally correct, but
   * we will take advantage of the PDO-based API to optimize the query up-front.
   */
  protected function initializeIterator() {
    $this
      ->prepareQuery();
    $high_water_property = $this->migration
      ->get('highWaterProperty');

    // Get the key values, for potential use in joining to the map table.
    $keys = array();

    // The rules for determining what conditions to add to the query are as
    // follows (applying first applicable rule)
    // 1. If the map is joinable, join it. We will want to accept all rows
    //    which are either not in the map, or marked in the map as NEEDS_UPDATE.
    //    Note that if high water fields are in play, we want to accept all rows
    //    above the high water mark in addition to those selected by the map
    //    conditions, so we need to OR them together (but AND with any existing
    //    conditions in the query). So, ultimately the SQL condition will look
    //    like (original conditions) AND (map IS NULL OR map needs update
    //      OR above high water).
    $conditions = $this->query
      ->orConditionGroup();
    $condition_added = FALSE;
    if (empty($this->configuration['ignore_map']) && $this
      ->mapJoinable()) {

      // Build the join to the map table. Because the source key could have
      // multiple fields, we need to build things up.
      $count = 1;
      $map_join = '';
      $delimiter = '';
      foreach ($this
        ->getIds() as $field_name => $field_schema) {
        if (isset($field_schema['alias'])) {
          $field_name = $field_schema['alias'] . '.' . $this->query
            ->escapeField($field_name);
        }
        $map_join .= "{$delimiter}{$field_name} = map.sourceid" . $count++;
        $delimiter = ' AND ';
      }
      $alias = $this->query
        ->leftJoin($this->migration
        ->getIdMap()
        ->getQualifiedMapTableName(), 'map', $map_join);
      $conditions
        ->isNull($alias . '.sourceid1');
      $conditions
        ->condition($alias . '.source_row_status', MigrateIdMapInterface::STATUS_NEEDS_UPDATE);
      $condition_added = TRUE;

      // And as long as we have the map table, add its data to the row.
      $n = count($this
        ->getIds());
      for ($count = 1; $count <= $n; $count++) {
        $map_key = 'sourceid' . $count;
        $this->query
          ->addField($alias, $map_key, "migrate_map_{$map_key}");
      }
      if ($n = count($this->migration
        ->get('destinationIds'))) {
        for ($count = 1; $count <= $n; $count++) {
          $map_key = 'destid' . $count++;
          $this->query
            ->addField($alias, $map_key, "migrate_map_{$map_key}");
        }
      }
      $this->query
        ->addField($alias, 'source_row_status', 'migrate_map_source_row_status');
    }

    // 2. If we are using high water marks, also include rows above the mark.
    //    But, include all rows if the high water mark is not set.
    if (isset($high_water_property['name']) && ($high_water = $this->migration
      ->getHighWater()) !== '') {
      if (isset($high_water_property['alias'])) {
        $high_water = $high_water_property['alias'] . '.' . $high_water_property['name'];
      }
      else {
        $high_water = $high_water_property['name'];
      }
      $conditions
        ->condition($high_water, $high_water, '>');
      $condition_added = TRUE;
    }
    if ($condition_added) {
      $this->query
        ->condition($conditions);
    }
    return new \IteratorIterator($this->query
      ->execute());
  }

  /**
   * @return \Drupal\Core\Database\Query\SelectInterface
   */
  public abstract function query();

  /**
   * {@inheritdoc}
   */
  public function count() {
    return $this
      ->query()
      ->countQuery()
      ->execute()
      ->fetchField();
  }

  /**
   * Check if we can join against the map table.
   *
   * This function specifically catches issues when we're migrating with
   * unique sets of credentials for the source and destination database.
   *
   * @return bool
   *   TRUE if we can join against the map table otherwise FALSE.
   */
  protected function mapJoinable() {
    if (!$this
      ->getIds()) {
      return FALSE;
    }
    $id_map = $this->migration
      ->getIdMap();
    if (!$id_map instanceof Sql) {
      return FALSE;
    }
    $id_map_database_options = $id_map
      ->getDatabase()
      ->getConnectionOptions();
    $source_database_options = $this
      ->getDatabase()
      ->getConnectionOptions();
    foreach (array(
      'username',
      'password',
      'host',
      'port',
      'namespace',
      'driver',
    ) as $key) {
      if (isset($source_database_options[$key])) {
        if ($id_map_database_options[$key] != $source_database_options[$key]) {
          return FALSE;
        }
      }
    }
    return TRUE;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
MigrateSourceInterface::fields public function Returns available fields on the source. 64
MigrateSourceInterface::getIds public function Defines the source fields uniquely identifying a source row. None of these fields should contain a NULL value - if necessary, use prepareRow() or hook_migrate_prepare_row() to rewrite NULL values to appropriate empty values (such as '' or 0). 64
PluginBase::$configuration protected property Configuration information passed into the plugin. 2
PluginBase::$pluginDefinition protected property The plugin implementation definition.
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
SourcePluginBase::$cache protected property
SourcePluginBase::$cacheCounts protected property Whether this instance should cache the source count.
SourcePluginBase::$cacheKey protected property Key to use for caching counts.
SourcePluginBase::$currentRow protected property The current row from the query
SourcePluginBase::$currentSourceIds protected property The primary key of the current row
SourcePluginBase::$highWaterProperty protected property The name and type of the highwater property in the source.
SourcePluginBase::$idMap protected property
SourcePluginBase::$iterator protected property
SourcePluginBase::$mapRowAdded protected property By default, next() will directly read the map row and add it to the data row. A source plugin implementation may do this itself (in particular, the SQL source can incorporate the map table into the query) - if so, it should set this TRUE so we…
SourcePluginBase::$migration protected property
SourcePluginBase::$moduleHandler protected property
SourcePluginBase::$originalHighWater protected property The high water mark at the beginning of the import operation.
SourcePluginBase::$skipCount protected property Whether this instance should not attempt to count the source.
SourcePluginBase::$trackChanges protected property If TRUE, we will maintain hashed source rows to determine whether incoming data has changed.
SourcePluginBase::aboveHighwater protected function Check if the incoming data is newer than what we've previously imported.
SourcePluginBase::current public function
SourcePluginBase::getCache protected function Get the cache object.
SourcePluginBase::getCurrentIds public function Getter for currentSourceIds data member.
SourcePluginBase::getIterator protected function Returns the iterator that will yield the row arrays to be processed.
SourcePluginBase::getModuleHandler protected function Get the module handler.
SourcePluginBase::key public function Get the iterator key.
SourcePluginBase::next public function The migration iterates over rows returned by the source plugin. This method determines the next row which will be processed and imported into the system.
SourcePluginBase::prepareRow public function Add additional data to the row. Overrides MigrateSourceInterface::prepareRow 33
SourcePluginBase::rewind public function Rewind the iterator.
SourcePluginBase::rowChanged protected function Check if the incoming row has changed since our last import.
SourcePluginBase::valid public function Whether the iterator is currently valid.
SqlBase::$database protected property 1
SqlBase::$query protected property 59
SqlBase::$state protected property State service for retrieving database info.
SqlBase::count public function Get the source count. Overrides SourcePluginBase::count 4
SqlBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 1
SqlBase::getDatabase public function Get the database connection object. 1
SqlBase::initializeIterator protected function Implementation of MigrateSource::performRewind(). Overrides SourcePluginBase::initializeIterator 18
SqlBase::mapJoinable protected function Check if we can join against the map table. 1
SqlBase::prepareQuery protected function A helper for adding tags and metadata to the query.
SqlBase::query abstract public function 59
SqlBase::select protected function Wrapper for database select.
SqlBase::setUpDatabase protected function Get a connection to the referenced database, adding the connection if necessary.
SqlBase::__construct public function Constructs a Drupal\Component\Plugin\PluginBase object. Overrides SourcePluginBase::__construct 2
SqlBase::__toString public function Print the query string when the object is used a string. Overrides MigrateSourceInterface::__toString
StringTranslationTrait::$stringTranslation protected property The string translation service.
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.