/** * @param ConnectionInterface $connection * @param string $table_name * @param string[] $fields * @param int $rows_per_batch * @param string $mode */ public function __construct(ConnectionInterface $connection, $table_name, array $fields, $rows_per_batch = 50, $mode = ConnectionInterface::INSERT) { if (empty($fields)) { throw new InvalidArgumentException('Array of fields expected'); } if ($mode != ConnectionInterface::INSERT && $mode != ConnectionInterface::REPLACE) { throw new InvalidArgumentException("Mode '{$mode}' is not a valid batch insert mode"); } $this->connection = $connection; $this->table_name = $table_name; $this->fields = $fields; $this->fields_num = count($fields); $escaped_field_names = $question_marks = []; foreach ($fields as $k => $v) { $escaped_field_names[] = $this->connection->escapeFieldName($v); $question_marks[] = '?'; } if ($mode == ConnectionInterface::REPLACE) { $this->sql_foundation = 'REPLACE INTO ' . $this->connection->escapeTableName($table_name) . ' (' . implode(', ', $escaped_field_names) . ') VALUES '; } else { $this->sql_foundation = 'INSERT INTO ' . $this->connection->escapeTableName($table_name) . ' (' . implode(', ', $escaped_field_names) . ') VALUES '; } $this->row_prepare_pattern = '(' . implode(', ', $question_marks) . ')'; $this->rows_per_batch = (int) $rows_per_batch; if ($this->rows_per_batch < 1) { $this->rows_per_batch = 50; } $this->mode = $mode; }
/** * @param string $table_name * @param string $field_name * @return $this */ public function &joinTable($table_name, $field_name = null) { $join_table = $this->connection->escapeTableName($table_name); $join_field = $this->connection->escapeFieldName($field_name ? $field_name : $this->getJoinFieldNameFromType()); $this->join = "LEFT JOIN {$join_table} ON {$this->getEscapedTableName()}.`id` = {$join_table}.{$join_field}"; return $this; }
/** * {@inheritdoc} */ public function getTypeTable($type, $escaped = false) { $registered_type = $this->requireRegisteredType($type); if ($escaped) { if (empty($this->types[$registered_type]['escaped_table_name'])) { $this->types[$registered_type]['escaped_table_name'] = $this->connection->escapeTableName($this->types[$registered_type]['table_name']); } return $this->types[$registered_type]['escaped_table_name']; } else { return $this->types[$registered_type]['table_name']; } }
/** * {@inheritdoc} */ public function uniqueWhere($field_name, $where, ...$context) { if (empty($field_name)) { throw new InvalidArgumentException("Value '{$field_name}' is not a valid field name"); } if (empty($context) && (!array_key_exists($field_name, $this->field_values) || $this->field_values[$field_name] === null)) { return true; // NULL is always good for single column keys because MySQL does not check NULL for uniqueness } $field_names = [$field_name]; if (count($context)) { $field_names = array_merge($field_names, $context); } // Check if we have existsing columns foreach ($field_names as $v) { if (!array_key_exists($v, $this->field_values)) { throw new InvalidArgumentException("Field '{$v}' is not known"); } } $table_name = $this->connection->escapeTableName($this->table_name); $conditions = []; if ($where) { $conditions[] = $this->connection->prepareConditions($where); } foreach ($field_names as $v) { $escaped_field_name = $this->connection->escapeFieldName($v); if ($this->field_values[$v] === null) { $conditions[] = "{$escaped_field_name} IS NULL"; } else { $conditions[] = $this->connection->prepare("{$escaped_field_name} = ?", $this->field_values[$v]); } } $conditions = implode(' AND ', $conditions); if (empty($this->object_id)) { $sql = sprintf("SELECT COUNT(`id`) AS 'row_count' FROM {$table_name} WHERE {$conditions}"); } else { $sql = $this->connection->prepare("SELECT COUNT(`id`) AS 'row_count' FROM {$table_name} WHERE ({$conditions}) AND (`id` != ?)", $this->old_object_id ? $this->old_object_id : $this->object_id); } if ($this->connection->executeFirstCell($sql) > 0) { if (empty($context)) { $this->addFieldError($field_name, "Value of '{$field_name}' needs to be unique"); } else { $this->addFieldError($field_name, "Value of '{$field_name}' needs to be unique in context of " . implode(', ', array_map(function ($field_name) { return "'{$field_name}'"; }, $context))); } return false; } return true; }
/** * {@inheritdoc} */ public function getTypeTable($type, $escaped = false) { if ($registered_type = $this->getRegisteredType($type)) { if ($escaped) { if (empty($this->types[$registered_type]['escaped_table_name'])) { $this->types[$registered_type]['escaped_table_name'] = $this->connection->escapeTableName($this->types[$registered_type]['table_name']); } return $this->types[$registered_type]['escaped_table_name']; } else { return $this->types[$registered_type]['table_name']; } } else { throw new InvalidArgumentException("Type '{$type}' is not registered"); } }
/** * Return name of the table where we store info about executed migrations. * * @return string */ public function getTableName() { if ($this->table_exists === null && !in_array($this->table_name, $this->connection->getTableNames())) { $this->connection->execute('CREATE TABLE ' . $this->connection->escapeTableName($this->table_name) . ' ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `migration` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL, `executed_at` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `migration` (`migration`), KEY `executed_on` (`executed_at`) ) ENGINE=InnoDB CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'); $this->table_exists = true; } return $this->table_name; }