目次
CakePHP3 で 自動的にできる id カラムの AUTO_INCREMENT を止める方法について調べました。
検証環境
今回調べたのは MySQL の場合です。
- CakePHP 3.0.9 (Phinx 0.4.4, MySQL 5.6.19)
- PHP 5.5.9
php bin/cake.php bake migration CreateXXXXXXX ...
というコマンドを実行すると、 migration のコードができます。 その後 php bin/cake.php migraitons migrate
を実行すると、 特に migration コード に変更を加えていなければ 自動採番が有効になった id カラム がもれなく作られます。 今回のテーマは id カラム はほしいんだけど 自動採番はいらない、 という場合の対処法です。
最終的な migration コード
次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php use PhinxMigrationAbstractMigration; class CreateSomeThings extends AbstractMigration { public function change() { $table = $this->table('some_things', ['id' => false, 'primary_key' => 'id']); $table->addColumn('id', 'integer'); $table->addColumn('name', 'string', [ 'defalt' => null, 'limit' => 255, 'null' => false, ]); $table->create(); } } |
'id' => false
で id カラム が自動的に作られないようにしています。 そして 'primary_key' => 'id'
で主キーの設定をしています。 また、 id カラム はコードで別途追加しておく必要があります。
id カラム の自動生成までオフにするんじゃなくて、 AUTO_INCREMENT だけオフにする設定はないのか? と思って詳しく調べてみました。
ID カラム を作るコード
私が調べたところによると、 AUTO_INCREMENT だけをオフにすることはできません。 これは vendor/robmorgan/phinx/src/Phinx/Db/Adapter/MysqlAdapter.php
を見ると分かります。
次のコードは、 MysqlAdapter.php
の 210-230行です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// Add the default primary key $columns = $table->getPendingColumns(); if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) { $column = new Column(); $column->setName('id') ->setType('integer') ->setIdentity(true); array_unshift($columns, $column); $options['primary_key'] = 'id'; } elseif (isset($options['id']) && is_string($options['id'])) { // Handle id => "field_name" to support AUTO_INCREMENT $column = new Column(); $column->setName($options['id']) ->setType('integer') ->setIdentity(true); array_unshift($columns, $column); $options['primary_key'] = $options['id']; } |
自動で id カラム が追加される部分のコードです。 id が自動で追加されるときは integer になります。 更に setIdentity(true)
で (下でもう少し詳しく見てみますが)自動採番になっています。 パラメータで分岐するようにはなっていません。 $options['primary_key'] = 'id'
というのが、 上で自分で追加した 'primary_key' => 'id'
に相当する部分です。
また、 id カラム を作らないようにするには if
の条件が false
になるように 'id' => false
と設定する必要があることもわかりますね。 また、 elseif
の条件も false
になるように設定しないと 別の AUTO_INCREMENT のカラムができてしまいます。
次のコードは、 同じファイル vendor/robmorgan/phinx/src/Phinx/Db/Adapter/MysqlAdapter.php
の
992-1020行目 です。 setIdentity(true)
が実行されると自動採番になることがわかります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
protected function getColumnSqlDefinition(Column $column) { $sqlType = $this->getSqlType($column->getType(), $column->getLimit()); $def = ''; $def .= strtoupper($sqlType['name']); if ($column->getPrecision() && $column->getScale()) { $def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')'; } elseif (isset($sqlType['limit'])) { $def .= '(' . $sqlType['limit'] . ')'; } if (($values = $column->getValues()) && is_array($values)) { $def .= "('" . implode("', '", $values) . "')"; } $def .= (!$column->isSigned() && isset($this->signedColumnTypes[$column->getType()])) ? ' unsigned' : '' ; $def .= ($column->isNull() == false) ? ' NOT NULL' : ' NULL'; $def .= ($column->isIdentity()) ? ' AUTO_INCREMENT' : ''; $def .= $this->getDefaultValueDefinition($column->getDefault()); if ($column->getComment()) { $def .= ' COMMENT ' . $this->getConnection()->quote($column->getComment()); } if ($column->getUpdate()) { $def .= ' ON UPDATE ' . $column->getUpdate(); } return $def; } |
以上より、 id カラム が自動で作られるときは必ず自動採番になってしまうことがわかります。 つまり、自動採番をやめるには、 id カラム を作らないようにするしかありません。
オプションはどのように実行されるのか
自動採番を防ぐには 'id' => false
とする必要があることが分かりました。 ところで、 'primary_key' => 'id'
というオプションは、 どこでどのように活用されるのでしょうか。
次のコードは MysqlAdapter.php
の 258-280行目です。 ここで 設定に応じて主キーを作成する準備が行われます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// set the primary key(s) if (isset($options['primary_key'])) { $sql = rtrim($sql); $sql .= ' PRIMARY KEY ('; if (is_string($options['primary_key'])) { // handle primary_key => 'id' $sql .= $this->quoteColumnName($options['primary_key']); } elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id') // PHP 5.4 will allow access of $this, so we can call quoteColumnName() directly in the // anonymous function, but for now just hard-code the adapter quotes $sql .= implode( ',', array_map( function ($v) { return '`' . $v . '`'; }, $options['primary_key'] ) ); } $sql .= ')'; } else { $sql = substr(rtrim($sql), 0, -1); // no primary keys } |
必要な条件
ここまで読んでくださってありがとうございます。
上述の内容から ['id' => false, 'primary_key' => 'id']
というオプションの設定と、 意図的な id カラム の追加が必要だということがわかります。 'id' => false
がなければ 自動採番の id カラム が作られますし、 ‘primary_key’ => ‘id’ がなければ主キーにはなりません。 もちろん 'primary_key' => 'id'
を使わずに インデックスだけでよければ addIndex
でインデックスを追加する方法もあります。