CakePHPのマイグレーションについて
PHPのフレームワークはマイグレーションの機能がついています。データーベスの構築をコードで管理することができ、
コーディングした時に
テーブルやカラムの追加、変更に必要になった時にコマンド一発で構築できる優れものです。
Laravelなどの他のフレームワークなどにもあります。
目次
1.開発環境
2.マイグレーションでテーブルを構築する
01.マイグレーションファイルの作成
02.マイグレーションの実行
3.マイグレーションでカラムを追加する
01.マイグレーションファイルの作成
02.マイグレーションの実行
4.マイグレーションでカラムを変更する
01.マイグレーションファイルの作成
02.マイグレーションの実行
5.マイグレーションでカラムを削除する
01.マイグレーションファイルの作成
02.マイグレーションの実行
6.ロールバックの実行
7.マイグレーションのステータス確認
開発環境
・Docker
・DockerCompose
・PHP7.2
・MySQL5.7
・CakePHP3.8
マイグレーションでテーブルを構築する
マイグレーションファイルの作成
# bakeコマンドでsamplesテーブル構築のマイグレーションファイルを生成する bin/cake bake migration CreateSamples name:string
cakephp/config/Migrations/XXXX_CreateSamples.php
<?php use Migrations\AbstractMigration; class CreateSamples extends AbstractMigration { public function change() { $table = $this->table('samples'); $table->addColumn('name', 'string', [ 'default' => null, 'limit' => 255, 'null' => false, ]); $table->create(); } } }
マイグレーションを実行する
bin/cake migrations migrate
MySQLにログインしてテーブルが作成されているか確認する
mysql> tables; +-------------------+ | Tables_in_cakephp | +-------------------+ | phinxlog | | samples | +------------------+
これでテーブルが構築されました。
マイグレーションでカラムを追加する
マイグレーションのカラム操作をします。
マイグレーションファイルの作成
最初にマイグレーションファイルを生成するが、一定の書式がある
bin/cake bake migration AddAgeToSamples age:integer?[3]
クラス名を「Add[カラム名]To[テーブル名]」とし、
その後に追加カラム情報を記述する事で、カラム追加のマイグレーションファイルが生成されます。
AddAgeToSamples
意味:ageカラムをsampleカラムに追加
age:integer?[3]
意味:ageカラムはint型 NULLを許容して、最大文字長3文字とする。 任意のディレクトリに移動して以下のコマンドを追加する
# bakeコマンドでageカラムをsamplesテーブルに追加するマイグレーションファイルを生成する bin/cake bake migration AddAgeToSamples age:integer?[3]
cakephp/config/Migrations/XXXX_AddAgeToSamples.php
<?php use Migrations\AbstractMigration; class AddAgeToSamples extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * @return void */ public function change() { $table = $this->table('samples'); $table->addColumn('age', 'integer', [ 'default' => null, 'limit' => 3, 'null' => true, ]); $table->update(); } }
sampleテーブルにageカラムをaddColumn()するクラスが生成されました。
しかし、ここで問題があり、自動生成されたメソッドはchange()メソッドで実装されていて、このままではロールバックの時にエラーになりロールバックができなくなるので、up()down()メソッドに実装し直します。
<?php use Migrations\AbstractMigration; class AddAgeToSamples extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * @return void */ public function up() { $table = $this->table('samples'); $table->addColumn('age', 'integer', [ 'default' => null, 'limit' => 3, 'null' => true, ]); $table->update(); } public function down() { $table = $this->table('samples'); $table->removeColumn('age'); $table->update(); } }
up()メソッドはマイグレーション時に実行されるメソッド、down()メソッドはロールバック時に実行されるメソッドです。
この場合では、マイグレーション時にはageカラムの追加を行いますが、down()メソッドではageカラムを削除します。
マイグレーションの実行
マイグレーションを実行し、samplesテーブルにaddカラムを追加します。
マイグレーションを実行する
bin/cake migrations migrate
MySQLへログインし、samplesテーブルに ageカラムが追加されているか確認します。
mysql> show columns from samples; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | NO | | NULL | | | age | int(3) | YES | | NULL | | +-------+--------------+------+-----+---------+----------------+
マイグレーションカラムの変更
マイグレーションファイルの作成
bin/cake bake migration ChangeAgeToSamples
追加した時と同じような命名規則にしておくとわかりやすいです。 コマンドを叩きます。
bin/cake bake migration ChangeAgeToSamples
cakephp/config/Migrations/XXXX_ChangeAgeToSamples.php
<?php use Migrations\AbstractMigration; class ChangeAgeToSamples extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * @return void */ public function change() { } }
カラムの変更を記述する
<?php use Migrations\AbstractMigration; class ChangeAgeToSamples extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * @return void */ public function change() { $table = $this->table('samples'); $table->changeColumn('age', 'integer', [ 'limit' => 2, ]); $table->update(); } }
changeColumn()メソッドを用いているところがポイント、そして、change()メソッドをup()down()メソッドに変更する
?php use Migrations\AbstractMigration; class ChangeAgeToSamples extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * @return void */ public function up() { $table = $this->table('samples'); $table->changeColumn('age', 'integer', [ 'limit' => 2, ]); $table->update(); } public function down() { $table = $this->table('samples'); $table->changeColumn('age', 'integer', [ 'limit' => 3, ]); $table->update(); } }
マイグレーションの実行
bin/cake migrations migrate
MySQLへログインし、ageカラムが変更されているか確認します。
mysql> show columns from samples; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | NO | | NULL | | | age | int(2) | NO | | NULL | | +-------+--------------+------+-----+---------+----------------+
マイグレーションでカラムを削除する
マイグレーションファイルの作成
bin/cake bake migration RemoveAgeFromSamples age
クラス名を「Remove[カラム名]To[テーブル名]」とし、その後に削除対象のカラム名を記述する事で、
カラム削除のマイグレーションファイルが生成されます。
RemoveAgeFromSamples
意味:samplesテーブルのageカラムを削除する
age
意味:削除対象のカラム名
コマンドを叩きます
bin/cake bake migration RemoveAgeFromSamples age
cakephp/config/Migrations/XXXX_RemoveAgeFromSamples.php
?php use Migrations\AbstractMigration; class RemoveAgeFromSamples extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * @return void */ public function change() { $table = $this->table('samples'); $table->removeColumn('age'); $table->update(); } }
これもup()down()メソッドに変える
<?php use Migrations\AbstractMigration; class RemoveAgeFromSamples extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * @return void */ public function up() { $table = $this->table('samples'); $table->removeColumn('age'); $table->update(); } public function down() { $table = $this->table('samples'); $table->addColumn('age', 'integer', [ 'default' => null, 'limit' => 2, 'null' => true, ]); $table->update(); } }
マイグレーションの実行
# マイグレーションを実行する bin/cake migrations migrate
MySQLへログインし、ageカラムが削除されているか確認します。
mysql> show columns from samples; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | NO | | NULL | | +-------+--------------+------+-----+---------+----------------+
削除されていることが確認できます。
まとめ
以上でマイグレーション作成は終わります。 このようにマイグレーションでデータベースを管理すると、テーブルやカラムの変更が容易にできます。 MySQLにログインしなくてもCakePHPのソースでテーブル内容が確認できるのは便利ですね。ぜひ利用してみてください。
リーダブルコードを読んだのでまとめ
第1章 理解しやすいコード
コードを書く原則 コードは理解しやすくしなければならない コードは他の人が短時間で理解できるように書かなければいけない
第2章 名前に情報を詰め込む
.明快な単語を選ぶ 例えばGetではなく、状況に応じて、DownloadやFetchなど .汎用的な名前を避ける(あるいは使う状況を選ぶ) tempやretvalなどより、目的や値を表すものであるべき。ただし、スコープにもよる。 .抽象的な名前よりも具体的な名前を使う ServerCanStart()では抽象的具体的にはCanListenOnPort()の方がいい .接尾辞や接頭辞を使って情報を追加する ミリ秒を表す変数に、_msを追加する、など。 .名前の長さを決める
.名前のフォーマットで情報を伝える クラスのメンバ変数にアンダースコアをつけるなど
明快な単語を選ぶ 例 Def GetPage(url);
Def DownloadPage();
変数や関数の構成要素の名前は抽象的でなはく具体的に
第3章 誤解されない名前
名前が他の意味と間違われないだろうか常に問う 限界値、包含的または排他的範囲などを意識した名前にする。 妙なプライドは捨て、ユーザーの期待に合わせる事を心がける 複数の名前を検討する。 > template/ reuse / copy / inherit、どれが良いだろうか
第4章 美しさ
3つの原則 一貫性のあるレイアウト 似ているコードは似ているようにみせる 空行を使い大きなブロックを段落に分ける
第5章 コメントするべきでないこと
コードからすぐにわかることはコメントに書かない 自分の考えを記録する ライターズブロックを乗り越える プログラマの多くはコメントを書きたがらない。コメントをうまく書くのは大変だと思っているからだ。 コメントを書くjことによって品質が次第によくなっていくことを理解する。 コメントのためのコメントをしない コードの欠陥にコメントをつける 読み手の立場になって考える
第6章コメントは正確に簡潔に
コメントは領域に対する情報の比率が高くなければいけない コメントを簡潔にしておく 曖昧な代名詞を避ける コードの意図を書く 情報密度の高い言葉を使う
第7章 制御フローを読みやすくする
条件式の引数の並び順 if(length>=10) or if(10<=length) if/elseブロックの並び順 .条件式は否定形よりも肯定形を使う。 .単純な条件式を先に書く。ifとelseが同じ画面に表示されるので見やすい。 .関心を引く条件や目立つ条件を先に書く。 do/whileループを避ける .do/whileはif文、while文、for文などの条件と違い「下から上」に読まなければならないので不自然 関数から早く返す return を早く返してあげることで読みやすくなることがある 行を短くするより他人が李愛するのにかかる時間を短くする ネストを浅くする
第8章 巨大な式を分割する
巨大な式は飲み込みやすい大きさに分割する 説明変数 .式を簡単に分割するには説明変数を用いてもいい .ド・モルガンの法則を使う 「notを分配してand/orを反転する」「notをくくりだす」 短絡評価の悪用 .プール演算子は短絡評価を行うものが多いので注意 .頭がいい」コードに気をつける。あとで他人がコードを読むときに分かりにくくなる
より優雅な手法を見つける 複雑なコードは「もっと簡単なコードがあるはずだ」と考える
巨大な文を分割する .巨大な文は理解するのが難しくなってしまうため分割することを検討する
第9章 変数と読みやすさ
①変数が多いと変数を追跡するのが難しくなる ②変数のスコープが大きいとスコープを把握するのに時間がかかる ③変数が頻繁に変更されると現在の値を把握するのが難しくなる
変数を削除する コードが読みやすくならない変数を削除する 役立たない一時変数
中間結果を削除する 制御フローを変数を削除する
グローバル変数は避ける グローバル変数はどこでどのように使われているのか追跡するのが難しい また「名前空間を汚染する」(ローカル変数と衝突する恐れがあること)から避けたほうが良い。 変数のことが見えるコード行数をできるだけ減らす
変数は一度だけ扱う 変数を操作する場所が多くなると、現在地の判断が難しくなるから
まとめ ・邪魔な変数を削除する ・変数のスコープを小さくする ・一度だけ書き込む変数をつかう
第10章 コードの再構成
①プログラムと主目的と関係のない「無関係の下位問題」を抽出する ②コードを再構成して、一度に一つのことをやるようにする ③最初にコードを言葉で説明する。その説明を元にキレイな解決策を作る ④コードを完全に削除できる状況について説明する。また、コードを書かずに済ませる状況についても説明する(コードを理解しやすくするにはコードを書かないのが一番)
エンジニアリングとは、大きな問題を小さな問題に分割して、それぞれの解決策を組み立てることに他ならない。この原則をコードに当てはめれば、堅ろうで読みやいコードになる
無関係に下位問題を積極的に見つけて抽出すること
①関数やコードブロックをみて「このコードの高レベルの目標は何か?」と自問する ②コードの各行に対して「高レベルの目標に直接的に効果があるのか?あるいは、無関係の下位問題を解決しているのか?」と自問する ③無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする
汎用コードをたくさん作る 凡庸コードはプロジェクトから切り離して考えられるので扱いやすい
このプログラミングはトップダウン?ボトムアップ? トップダウンプログラミングとは、先に高レベルのモジュール関数を設計してから、それらをサポートする低レベルの関数を実装していく方式だ。 ボトムアップとはプログラミングとは、先にすべての下位問題を解決してから、それらを利用する高レベルのコンポーネントを実装していく方式だ。
プロジェクトに特化した機能 抽出する下位問題というのは、プロジェクトから完全に独立したものであるほうがいい。ただし、完全に独立していなくても、それは問題ない。下位問題をのぞくだけでも効果がある。
既存のインターフェースを簡潔にする 「理想とは程遠いインターフェースに妥協することはない」 自分でラッパー関数を用意して汚いインターフェースを覆い隠すのも綺麗なコードをつくるための手法
やりすぎ 小さな関数を作りすぎても逆に見にくくなってしまう。 「無関係の下位問題を積極的に見つけ抽出する」ことは目的だが、やりすぎて見にくくなってしまうのには注意が必要
まとめ プロジェクト固有のコードから汎用コードを分離するということ。 ほとんどのコードは汎用化できる。
第11章
一度に一つのことを
一度に一つのことをするコードは理解しにくい。例えば、オブジェクトを生成して、データを綺麗にして、入力をパースして、ビジネスロジックを適用しているようなコードだ。 これらのコードがすべて絡みあっていると、「タスク」が完全に個別に完結しているコードよりも理解するのが難しい。 コードは一つずつタスクを行うようにしなければならない
一度に一つのタスクをする ①コードが行っている「タスク」をすべて列挙する。この「タスク」 という言葉はユルく使っている。「オブジェクトが妥当かどうかを確認する」のように小さなこともあれば、「ツリーのすべてのノードをイテレートする」のようにあいまいなこともある。 ②タスクをできるだけ異なる関数に分割する。少なくとも異なる領域に分割する。
オブジェクトから値を抽出する 「一度に一つのタスク」を適用する まとめ 「一度にひとつのタスク」を行う 読みにくいコードがあれば、そこで行われているタスクをすべて列挙する。そこには別の関数(やクラス)に分割できるタスクがあるだろう。 それ以外は関数の論理的な「段落」になる。 タスクをどのように分割するかよりも、分割するということが大切。
第12章 コードに想いを込める
おばあちゃんがわかるように説明できなければ、本当に理解したとは言えない アルバート・アインシュタイン
誰かに複雑な考えを伝えるときには、細かいことまで話すぎると相手を混乱させてしまう。自分よりも知識が少ない人が理解できるような「簡単な言葉」で説明する能力が必要だ。自分の考えを凝縮して、最も大切な概念にすることが必要になる。これは誰かに理解してもらうだけでなく、自分の考えをより明確にすることにもなる。 コードもこれと同様で読み手が理解できるように「簡単な言葉で」書くべきなのだ
①コードの動作を簡単な言葉で同僚にも分かるように説明する。 ②その説明の中で使っているキーワードやフレーズに注目する ③その説明に合わせてコードをかく
ロジックを簡単に説明する
短いコードを書く プログラマが学ぶべき大切な技法というのは、コードを書かないときを知ることなのかもしれない。自分で書いたコードであれば、すべての行をテストして保守しなければならない。 ライブラリの再利用や機能を削除することで、時間を節約したり、コードを簡潔に維持したりできる。 最も読みやすいコードは何も書かれていないコードだ!
その機能の実装について悩まないで、きっと必要ないから プロジェクトを開始するときには、これから実装するかっこいい機能のことを考えて興奮するものだ。そして、プロジェクトに欠かせない機能を過剰に見積もってしまう。その結果、多くの機能が、完結しないか、全く使われていないか、アプリケーションを複雑にするものになってしまう。 プログラマというのは、実装にかかる労力を過小評価するものでもある。プロトタイプの実装にかかる時間を楽観的に見積もったり、将来的には必要となる保守や文章化などの「負担」時間を忘れがちになる。
質問と要求の分割 すべてのプログラムが、高速で、100%正しくて、あらゆる入力をうまく処理する必要はない。要求を詳しく調べれば、問題をもっと簡単にできることもある。そうすれば、必要なコードも短くて済む。
キャッシュを追加する
コードを小さく保つ ソフトウェアプロジェクトを始めるときには、ソースファイルは一つや二つしかない。しかし、プロジェクトが進んでいくと、ファイルが増えていく。ディレクトリを分けてファイルを整理しなければならなくなっていく。どの関数がどの関数を呼び出しているのか分からなくなってくる。バグを見つけるのもだんだん面倒になってくる。 最終的には、いろんなディレクトリにファイルが散らばることになる。プロジェクトは巨大になって、すべてを把握できる人もいなくなる、新しい機能を追加するのが苦痛になってくる。コードを扱うのが厄介になり楽しくなくなる。 あらゆる協調システムは成長する。それらを結びつける複雑さはもっと速い速度で成長する。 つまり、プロジェクトが成長しても、コードをできるだけ小さく軽量に維持するしかない。 そのためにやること ①凡庸的な「ユーティリティ」コードを作って、重複コードを削除する。 ②未使用のコードや無用の機能を削除する ③プロジェクトをサブプロジェクトに分割する ④コードの重量を意識する。軽量で機敏にしておく。
身近なライブラリに親しむ 「ライブラリを熟知して、実際に活用することが大切」 たまには標準ライブラリの全ての関数・モジュール・型の名前を15分かけて読んでみよう! 標準ライブラリとはAPIや組み込みモジュールのことだ。
ライブラリの再利用はなぜいいことなのか 統計ではあるが、平均的なソフトウェアエンジニアが一日に書く出荷用のコードは10行なのだそうだ。 嘘だと思えるが、大切なのは"出荷用"という言葉だ。成熟したライブラリコードの裏側には、膨大な設計・デバッグ・修正・文書・最適化・テスト・が存在する。このダーウィンの進化を生き延びてきたコードには価値があるからだ。
まとめ ・不必要な機能をプロダクトから削除する。過剰な機能はもたせない。 ・最も簡単に問題を解決できるような要求を与える。 ・定期的にすべてのAPIを読んで、標準ライブラリに慣れ親しんでおく
Python基本文法まとめ チートシート
Pythonチートシートを作成しました。
興味本位でPythonを学んでいたのですが、忘れてしまうためまとめて整理します。
Hello world
print "Hello world!"
コメント
print "Hello" # Helloと表示します
インデント
Perl や PHP では文を { ... } で囲むことでブロック(複文)を構成しますが、Python ではインデント(行頭の空白文字の数)が重要な意味を持ち、同じ数の空白でインデントされた文がブロックとみなされます。
a = 3 if a == 5: print "AAA" # if文の対象 print "BBB" # if文の対象 print "CCC" # if文の対象ではない
エンコードルール(coding:)
日本語など、ASCII以外の文字を含むスクリプトを作成する場合は、スクリプトの1行目、または2行目に、下記の形式でスクリプトの エンコードルール(coding:) を指定してください。大文字・小文字は無視されます。
# coding: utf-8 print "Hello world" # 文字列やコメントに日本語を使えるようになります
エスケープシーケンス
\改行 #: バックスラッシュと改行が無視される \\ #: バックスラッシュ(\) \' #: シングルクォート(') \" #: ダブルクォート(") \a #: ベル(BEL) \b #: バックスペース(BS) \f #: フォームフィード(FF) \n #: 改行(LF) \r #: 復帰(CR) \t #: タブ(TAB) \v #: 垂直タブ(VT) \nnn #: 8進表記文字(nは0~7) \xnn #: 16進表記文字(nは0~f) \uxxxx #: ユニコード文字xxxx (例: u"\u3042") \U....xxxx #: ユニコード文字xxxxxxxx (例: U"\U00003042") \N{name} #: Unicodeデータベース文字 (例: u"\N{HIRAGANA LETTER A}") ※windowsはバックスラッシュを円マークに
ビット演算子
~a # ビット反転 a & b # AND:論理積(aもbも1のビットが1) a | b # OR:論理和(aまたはbが1のビットが1) a ^ b # XOR:排他的論理和(aまたはbが1のビットが1) a << b # b ビット左シフト a >> b # b ビット右シフト
代入演算子
value += 5 ... value = value + 5 と同じ value -= 5 ... value = value - 5 と同じ value *= 5 ... value = value * 5 と同じ value /= 5 ... value = value / 5 と同じ value **= 2 ... value = value ** 2 と同じ value //= 2 ... value = value // 2 と同じ value %= 2 ... value = value % 2 と同じ
文字列
ただの文字列でも配列みたいな扱いができる
# その1 str = "Apples" str[0] # 'A' # その2 "test"[2] # 's' # その3 ex = "Apples" ex[:3] # 'App' ex[1:4] # 'ppl' ex[3:] # 'les'
比較演算子
x == y # x が y と等しい x != y # x が y と異なる x < y # x が y よりも小さい(未満) x > y # x が y よりも大きい x <= y # x が y 以下 x >= y # x が y 以上 x <> y # x が y と異なる x is y # x が y と等しい x is not y # x が y と異なる x in y # x が y に含まれる x not in y # x が y に含まれない
ライブラリをインポート(from , import)
#ライブラリを指定してインポートする import ライブラリ名 #ライブラリを指定して別名を付けてインポートする import ライブラリ名 as 別名 #パッケージ配下のライブラリを指定してインポートする from パッケージ名 import ライブラリ名 as 別名 # モジュール配下のすべてをインポートする import * from パッケージ名 import *
相対パスでライブラリをインポート(from , import)
#同じパッケージ内のライブラリをインポート from . import ライブラリ名 #サブディレクトリのライブラリをインポート from サブディレクトリ名 import ライブラリ名
関数の処理
関数の作成(def) def 関数名(引数): 処理 return 戻り値 ※戻り値や引数は無くても作成可能,引数を複数指定する際は , でつなぐ #関数の作成 def func_a(a): return a + 11 #関数の実行 print(func_a(7)) ------------------------------ 18
ジェネレータ
ジェネレーターの作成 def 関数名(引数): 処理 yield 戻り値 処理 ※ジェネレーターは呼び出されるたび、行われた処理を記憶(ステート)。 リスト全体をメモリ内に保持するのが難しい時に役立つ #ジェネレーターの作成 def counts(): x = 0 while True: yield x x += 1 y = counts() for i in y: print(i) if i == 2: break ------------------------------ 0 1 2 for i in y: print(i) if i == 5: break ------------------------------ 3 4 5
今回はこの辺で