LoginSignup
4
1

More than 5 years have passed since last update.

cakephp3 updateを禁止したい(insert限定)

Last updated at Posted at 2017-03-10

課題

CakePHPは save() でインサートもアップデートも行います。
エンティティのidがあれば、インサート、なければアップデートが行われます。

ログやプロセス、ステータスなどを記録する機能で、インサートのみを期待するDB:テーブルに対して、例えばボタンの連打などによる、"連続save"でアップデートが発生していました。

[03/11 追記]
例えばアクセスログなどの場合、重複したデータのログをとることは出来ないので、適していないというご指摘をうけました。その通りです。ご注意くださいませ。

解決策

1. DB側で制約を設ける(ARCHIVEストレージエンジン/複合ユニークキー)

  • ARCHIVEストレージエンジン良いけどインデックス欲しいしなー。使ったこと無いし心配...。
  • cakeの仕様にあわせるためにDB構造いじるって...!?
  • かなりレコードがたまるテーブルでidとcreatedの複合ユニークって大丈夫?

2. save時に$entity->idがあるかどうか確かめる

  • saveしている全箇所修正か...。

3. cakeのテーブル or エンティティで共通で処理する

  • :point_up:これができればベスト

テーブル or エンティティで共通で処理する

アプリケーションルール

cakeのテーブルファイルで実装できる buildRules メソッドは、save前にバリデーションをかけることができます。

アップデート処理時のバリデートを常にfalseを返すようにしてみる

    /*
     * @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
     * @return \Cake\ORM\RulesChecker
     */
    public function buildRules(RulesChecker $rules)
    {
        $rules->addUpdate(function($entity, $options) {
            return false;
        }, 'ruleName');
        return $rules;
    }

うまくいきました!

※下記失敗例

    /*
     * @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
     * @return \Cake\ORM\RulesChecker
     */
    public function buildRules(RulesChecker $rules)
    {
        $rules->add($rules->isUnique(['id']));
        return $rules;
    }

:point_up:これはうまくいきませんでした。そもそもidはprimary_keyとしてユニークがかかっているわけだし...

謝辞

本件は、 slack の cakephp公式チームの japaneseチャンネルにて、
相談させて頂いたものをまとめたものです。
この場を借りて改めてお礼申し上げます。
@chinpei215 さん、@icchii さんありがとうございます!!

[CakePHP公式の日本語話者向けSlackチャンネル開設のご案内]
http://qiita.com/chinpei215/items/3c116171c5308365c314

4
1
2

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
4
1