19
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CakePHP3Advent Calendar 2016

Day 8

CakePHP3向け楽観的ロックプラグインを作った

Last updated at Posted at 2016-12-07

kaihiroといいます。
普段は主にCakePHP3を使ったWebアプリケーションの開発を行っています。

今日は温めていた自作プラグインについてご紹介したいと思います。

業務システムを開発していて、楽観的ロックが必要になりました。
編集画面で保存ボタンを押したときに、他の人が同じデータを先に更新していたらユーザーに通知するアレです。

CakePHP3向けの楽観的ロックプラグインがなさそうだったので作ってみることにしました。

kaihiro/optimistic-lock

楽観的ロック

前職でJavaを使っていたのでその時のフレームワークの処理を思い出しながら実装してみました。

仕組みとしては、排他制御を行いたいテーブルにversion(INT型)のカラムを定義し、画面を表示したタイミングと、保存するタイミングでその値が変わったかどうかを検証することで他ユーザーによる更新を検知します。
versionの値は、保存のたびに、1, 2, 3,...とインクリメントされていきます。

処理の流れは以下の通りです。

  1. 排他制御を行いたいテーブルに楽観的ロック制御用のversion番号を定義しておき、編集画面を表示する際にversionをformのhiddenに埋め込む。(Plugin側)
  2. 更新ボタンでPOSTされたversionと、最新のDBのversionを比較し、同じであればversionをインクリメントして、保存処理を完了する。もし、versionが違っていればOptimisticLockExceptionをthrowする。(Plugin側)
  3. throwされたExceptionをControllerでcatchしてエラーハンドリングを行う。(各自で実装)

準備

排他制御をかけたいテーブルに対して、INT型でversionカラムを定義します。
デフォルト値は特に必要ありません。

使い方

kaihiro/optimistic-lock
こちらのREADMEを参照してください。

工夫した点

  1. OptimisticLockFormTraitをFormHelperに読み込むことで、createメソッドを拡張して、編集対象のEntityにversionカラムがある場合のみ、formにhiddenを自動で埋め込むようにしています。

  2. 排他エラーが発生した場合のエラーハンドリングについては、色々な要件があると思うので、OptimisticLockExceptionをthrowするようにして、組み込み側が自由にハンドリングするようにしました。

やり残したこと

本当は任意のカラム名を指定できるようにしたかったけど、きれいなOptimisticLockFormTraitとの連携方法が思いつかず、実装していません。
任意の名前にしたいシーンもあまりないと思うので、versionという名前にするという規約として、組み込む側の実装がシンプルになるほうがいいかなと思っています。

まとめ

今回は昔、使ったJavaの記憶をたよりに実装してみました。
他の言語のフレームワークやプラグインを色々見てみると、CakePHP3にも活用できそうなものがたくさんありそうですね。

バグや改善あれば、プルリクお待ちしています!

19
5
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?