/** * Convert a primary key column from one format to another. * * @param IdProperty $newProp The new ID property. * @param PropertyField $newField The new ID field. * @param IdProperty $oldProp The previous ID property. * @param PropertyField $oldField The previous ID field. * @throws InvalidArgumentException If the new property does not implement the proper mode. * @return self */ protected function convertIdField(IdProperty $newProp, PropertyField $newField, IdProperty $oldProp, PropertyField $oldField) { $cli = $this->climate(); $keepId = $cli->arguments->defined('keep_id'); $model = $this->targetModel(); $source = $model->source(); $table = $source->table(); $db = $source->db(); $newKey = $newProp->ident(); $oldKey = $oldProp->ident(); $this->insertNewField($newField, $newProp); $rows = $this->fetchTargetRows(); if ($this->describeCount($rows)) { if (!$this->quiet()) { $cli->br(); $progress = $cli->progress($rows->rowCount()); } if ($newProp->mode() === IdProperty::MODE_AUTO_INCREMENT) { $pool = 0; $ids = function () use(&$pool) { return ++$pool; }; } else { $pool = []; $ids = function () use(&$pool, $newProp) { $id = $newProp->autoGenerate(); while (in_array($id, $pool)) { $id = $newProp->autoGenerate(); } $pool[] = $id; return $id; }; } foreach ($rows as $row) { $id = $ids(); $sql = strtr('UPDATE `%table` SET `%newKey` = :new WHERE `%oldKey` = :old;', ['%table' => $table, '%newKey' => $newKey, '%oldKey' => $oldKey]); $source->dbQuery($sql, ['new' => $id, 'old' => $row[$oldKey]], ['new' => $newField->sqlPdoType(), 'old' => $oldField->sqlPdoType()]); if (!$this->quiet()) { $progress->advance(); } } } $this->dropPrimaryKey($oldField, $oldProp); $this->applyPrimaryKey($newField, $newProp); /** @todo Alter related tables */ $this->syncRelatedFields($newProp, $newField, $oldProp, $oldField); if (!$keepId) { $this->removeColumn($oldField); } $this->renameColumn($newField, $newKey, $oldKey); return $this; }