CakePHP3 ではデフォルトでは論理削除の機能は実装されていない。調べると1番上にいい感じに利用できるプラグインがあるので、これを利用するとよい。
とりあえず PGBI/cakephp3-soft-delete を使ってみる
composer でパッケージを追加して。
$ composer require pgbi/cakephp3-soft-delete "~1.0"
プラグインの読み込みを追加して。
// config/bootstrap.php
Plugin::load('SoftDelete');
テーブルで SoftDeleteTrait を読み込んで。
// src/Model/Table/UserTable.php
...
use SoftDelete\Model\Table\SoftDeleteTrait;
class UsersTable extends Table
{
use SoftDeleteTrait;
...
該当のテーブルに deleted というカラムを追加して。
// config/Migrations/20171114120000_CreateUsers.php
...
$table->addColumn('deleted', 'datetime', [
'default' => null,
'null' => true,
]);
...
Enjoy!
// コンソール機能を使って動作確認をしてみる
//==============================
$ bin/cake console
// Table の読み込み
//==============================
>>> use Cake\ORM\TableRegistry;
>>> $Users = TableRegistry::get('Users');
=> App\Model\Table\UsersTable {#214
+"registryAlias": "Users",
+"table": "users",
+"alias": "Users",
+"entityClass": "App\Model\Entity\User",
+"associations": [],
+"behaviors": [
"Timestamp",
],
+"defaultConnection": "default",
+"connectionName": "default",
}
// Entity の作成
//==============================
>>> $entity = $Users->newEntity();
=> App\Model\Entity\User {#216
+"[new]": true,
+"[accessible]": [],
+"[dirty]": [],
+"[original]": [],
+"[virtual]": [],
+"[errors]": [],
+"[invalid]": [],
+"[repository]": "Users",
}
// データの保存
//==============================
>>> $Users->save($entity);
=> App\Model\Entity\User {#216
+"created": Cake\I18n\Time {#232
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"modified": Cake\I18n\Time {#218
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"id": 2,
+"[new]": false,
+"[accessible]": [],
+"[dirty]": [],
+"[original]": [],
+"[virtual]": [],
+"[errors]": [],
+"[invalid]": [],
+"[repository]": "Users",
}
// データ保存の確認
//==============================
>>> $Users->get(2);
=> App\Model\Entity\User {#295
+"id": 2,
+"created": Cake\I18n\FrozenTime {#286
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"modified": Cake\I18n\FrozenTime {#285
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"deleted": null,
+"[new]": false,
+"[accessible]": [],
+"[dirty]": [],
+"[original]": [],
+"[virtual]": [],
+"[errors]": [],
+"[invalid]": [],
+"[repository]": "Users",
}
// SoftDeleteTrait を読み込むと delete の挙動が SoftDelete に変わる
//==============================
>>> $Users->delete($entity);
=> true
// SoftDelete されたデータが検索できないことを確認
//==============================
>>> $Users->get(2);
Cake\Datasource\Exception\RecordNotFoundException with message 'Record not found in table "users"'
// 'withDeleted' をつけることによって SoftDelete されたデータを検索できる
//==============================
>>> $Users->find('all', ['withDeleted'])->where(['id' => 2])->first();
=> App\Model\Entity\User {#521
+"id": 2,
+"created": Cake\I18n\FrozenTime {#512
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"modified": Cake\I18n\FrozenTime {#511
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"deleted": Cake\I18n\FrozenTime {#522
+"time": "2017-11-14T12:42:48+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"[new]": false,
+"[accessible]": [],
+"[dirty]": [],
+"[original]": [],
+"[virtual]": [],
+"[errors]": [],
+"[invalid]": [],
+"[repository]": "Users",
}
// restore によって SoftDelete されたデータを元に戻せる
//==============================
>>> $Users->restore($entity);
=> App\Model\Entity\User {#216
+"created": Cake\I18n\Time {#232
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"modified": Cake\I18n\Time {#229
+"time": "2017-11-14T12:44:30+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"id": 2,
+"deleted": null,
+"[new]": false,
+"[accessible]": [],
+"[dirty]": [],
+"[original]": [],
+"[virtual]": [],
+"[errors]": [],
+"[invalid]": [],
+"[repository]": "Users",
}
// restore の結果について確認
//==============================
>>> $Users->get(2);
=> App\Model\Entity\User {#548
+"id": 2,
+"created": Cake\I18n\FrozenTime {#539
+"time": "2017-11-14T12:41:19+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"modified": Cake\I18n\FrozenTime {#538
+"time": "2017-11-14T12:44:30+09:00",
+"timezone": "Asia/Tokyo",
+"fixedNowTime": false,
},
+"deleted": null,
+"[new]": false,
+"[accessible]": [],
+"[dirty]": [],
+"[original]": [],
+"[virtual]": [],
+"[errors]": [],
+"[invalid]": [],
+"[repository]": "Users",
}
// hardDelete をすることによって、復元できない削除をする
//==============================
>>> $Users->hardDelete($entity);
=> true
// hardDelete の結果について確認
//==============================
>>> $Users->get(2);
Cake\Datasource\Exception\RecordNotFoundException with message 'Record not found in table "users"'
>>> $Users->find('all', ['withDeleted'])->where(['id' => 2])->first();
=> null
かゆいところに手を伸ばす
デフォルトでは deleted というカラムだが、テーブルにプロパティを追加することで違うカラム名にもできる。
// UserTable.php
...
use SoftDelete\Model\Table\SoftDeleteTrait;
class UsersTable extends Table
{
use SoftDeleteTrait;
protected $softDeleteField = 'kokoga_deleted_no_field_desu';
..
とはいえ CakePHP3 におけるデフォルトのタイムスタンプのフィールドは created と modified という名前になっているので、そこは deleted という名前で合わせにいくのがわかりやすさも高くて良いと思う。