/** * 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'] . '.' . $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()); }
/** * Extends a query object for URL redirect filters. * * @param $query * Query object that should be filtered. * @param $keys * The filter string to use. */ protected function filterQuery(SelectInterface $query, array $fields, $keys = '') { if ($keys && $fields) { // Replace wildcards with PDO wildcards. $conditions = db_or(); $wildcard = '%' . trim(preg_replace('!\\*+!', '%', db_like($keys)), '%') . '%'; foreach ($fields as $field) { $conditions->condition($field, $wildcard, 'LIKE'); } $query->condition($conditions); } }
public function condition($field, $value = NULL, $operator = '=') { $this->query->condition($field, $value, $operator); return $this; }
/** * {@inheritdoc} */ public function addField($field, $type, $langcode) { $entity_type_id = $this->sqlQuery->getMetaData('entity_type'); $all_revisions = $this->sqlQuery->getMetaData('all_revisions'); // This variable ensures grouping works correctly. For example: // ->condition('tags', 2, '>') // ->condition('tags', 20, '<') // ->condition('node_reference.nid.entity.tags', 2) // The first two should use the same table but the last one needs to be a // new table. So for the first two, the table array index will be 'tags' // while the third will be 'node_reference.nid.tags'. $index_prefix = ''; $specifiers = explode('.', $field); $base_table = 'base_table'; $count = count($specifiers) - 1; // This will contain the definitions of the last specifier seen by the // system. $propertyDefinitions = array(); $entity_type = $this->entityManager->getDefinition($entity_type_id); $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); for ($key = 0; $key <= $count; $key++) { // This can either be the name of an entity base field or a configurable // field. $specifier = $specifiers[$key]; if (isset($field_storage_definitions[$specifier])) { $field_storage = $field_storage_definitions[$specifier]; } else { $field_storage = FALSE; } // If there is revision support, only the current revisions are being // queried, and the field is revisionable then use the revision id. // Otherwise, the entity id will do. if (($revision_key = $entity_type->getKey('revision')) && $all_revisions && $field_storage && $field_storage->isRevisionable()) { // This contains the relevant SQL field to be used when joining entity // tables. $entity_id_field = $revision_key; // This contains the relevant SQL field to be used when joining field // tables. $field_id_field = 'revision_id'; } else { $entity_id_field = $entity_type->getKey('id'); $field_id_field = 'entity_id'; } /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */ $table_mapping = $this->entityManager->getStorage($entity_type_id)->getTableMapping(); // Check whether this field is stored in a dedicated table. if ($field_storage && $table_mapping->requiresDedicatedTableStorage($field_storage)) { $delta = NULL; // Find the field column. $column = $field_storage->getMainPropertyName(); if ($key < $count) { $next = $specifiers[$key + 1]; // If this is a numeric specifier we're adding a condition on the // specific delta. if (is_numeric($next)) { $delta = $next; $index_prefix .= ".{$delta}"; // Do not process it again. $key++; $next = $specifiers[$key + 1]; } elseif ($next == TableMappingInterface::DELTA) { $index_prefix .= TableMappingInterface::DELTA; // Do not process it again. $key++; // If there are more specifiers to work with then continue // processing. If this is the last specifier then use the reserved // keyword as a column name. if ($key < $count) { $next = $specifiers[$key + 1]; } else { $column = TableMappingInterface::DELTA; } } // Is this a field column? $columns = $field_storage->getColumns(); if (isset($columns[$next]) || in_array($next, $table_mapping->getReservedColumns())) { // Use it. $column = $next; // Do not process it again. $key++; } // If there are more specifiers, the next one must be a // relationship. Either the field name followed by a relationship // specifier, for example $node->field_image->entity. Or a field // column followed by a relationship specifier, for example // $node->field_image->fid->entity. In both cases, prepare the // property definitions for the relationship. In the first case, // also use the property definitions for column. if ($key < $count) { $relationship_specifier = $specifiers[$key + 1]; $propertyDefinitions = $field_storage->getPropertyDefinitions(); // Prepare the next index prefix. $next_index_prefix = "{$relationship_specifier}.{$column}"; } } $table = $this->ensureFieldTable($index_prefix, $field_storage, $type, $langcode, $base_table, $entity_id_field, $field_id_field, $delta); $sql_column = $table_mapping->getFieldColumnName($field_storage, $column); $property_definitions = $field_storage->getPropertyDefinitions(); if (isset($property_definitions[$column])) { $this->caseSensitiveFields[$field] = $property_definitions[$column]->getSetting('case_sensitive'); } } else { // ensureEntityTable() decides whether an entity property will be // queried from the data table or the base table based on where it // finds the property first. The data table is preferred, which is why // it gets added before the base table. $entity_tables = array(); if ($all_revisions && $field_storage && $field_storage->isRevisionable()) { $data_table = $entity_type->getRevisionDataTable(); $entity_base_table = $entity_type->getRevisionTable(); } else { $data_table = $entity_type->getDataTable(); $entity_base_table = $entity_type->getBaseTable(); } if ($data_table) { $this->sqlQuery->addMetaData('simple_query', FALSE); $entity_tables[$data_table] = $this->getTableMapping($data_table, $entity_type_id); } $entity_tables[$entity_base_table] = $this->getTableMapping($entity_base_table, $entity_type_id); $sql_column = $specifier; // If there are more specifiers, get the right sql column name if the // next one is a column of this field. if ($key < $count) { $next = $specifiers[$key + 1]; // If this specifier is the reserved keyword "%delta" we're adding a // condition on a delta range. if ($next == TableMappingInterface::DELTA) { $key++; if ($key < $count) { $next = $specifiers[$key + 1]; } else { return 0; } } // If this is a numeric specifier we're adding a condition on the // specific delta. Since we know that this is a single value base // field no other value than 0 makes sense. if (is_numeric($next)) { if ($next > 0) { $this->sqlQuery->condition('1 <> 1'); } $key++; $next = $specifiers[$key + 1]; } // Is this a field column? $columns = $field_storage->getColumns(); if (isset($columns[$next]) || in_array($next, $table_mapping->getReservedColumns())) { // Use it. $sql_column = $table_mapping->getFieldColumnName($field_storage, $next); // Do not process it again. $key++; } } $table = $this->ensureEntityTable($index_prefix, $sql_column, $type, $langcode, $base_table, $entity_id_field, $entity_tables); // If there is a field storage (some specifiers are not), check for case // sensitivity. if ($field_storage) { $column = $field_storage->getMainPropertyName(); $base_field_property_definitions = $field_storage->getPropertyDefinitions(); if (isset($base_field_property_definitions[$column])) { $this->caseSensitiveFields[$field] = $base_field_property_definitions[$column]->getSetting('case_sensitive'); } } } // If there are more specifiers to come, it's a relationship. if ($field_storage && $key < $count) { // Computed fields have prepared their property definition already, do // it for properties as well. if (!$propertyDefinitions) { $propertyDefinitions = $field_storage->getPropertyDefinitions(); $relationship_specifier = $specifiers[$key + 1]; $next_index_prefix = $relationship_specifier; } // Check for a valid relationship. if (isset($propertyDefinitions[$relationship_specifier]) && $field_storage->getPropertyDefinition('entity')->getDataType() == 'entity_reference') { // If it is, use the entity type. $entity_type_id = $propertyDefinitions[$relationship_specifier]->getTargetDefinition()->getEntityTypeId(); $entity_type = $this->entityManager->getDefinition($entity_type_id); $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); // Add the new entity base table using the table and sql column. $join_condition = '%alias.' . $entity_type->getKey('id') . " = {$table}.{$sql_column}"; $base_table = $this->sqlQuery->leftJoin($entity_type->getBaseTable(), NULL, $join_condition); $propertyDefinitions = array(); $key++; $index_prefix .= "{$next_index_prefix}."; } else { throw new QueryException("Invalid specifier '{$relationship_specifier}'"); } } } return "{$table}.{$sql_column}"; }