CakePHP3・4で論理削除(ソフトデリート)を自作する方法

CakePHP3・4で論理削除(ソフトデリート)を自作する方法

395 回閲覧されました

みなさんこんにちは、jonioです。

今回はCakePHPで論理削除のやり方のアウトプットの記事になります。

CakePHPのバージョン

3.1.0と4.5.3でうまく行きました。

削除のやり方のコードが変わってなければ5系にも対応すると思います。

論理削除とは

あるテーブルと他のテーブルがアソシエーションしている時にあるテーブルのレコードを削除すると他のテーブルに紐づいている情報がなくてエラーになる場合があり都合が悪いです。

エラーを防ぐ為に削除のフラグのカラムをテーブルに作ってデフォルトをboolean型のfalseにして削除ボタンを押した時にtrueに変えることで削除したように見せます。

これを論理削除といい本当に削除してしまうことを物理削除といいます。

今回はusersテーブルに論理削除を実装します。

usersテーブル

マイグレーションファイルを下記にします。

public function change(): void
{
  $table = $this->table('reviews');
  $table
  ->addColumn('name', 'string', [
    'limit' => 255,
    'null' => false
  ])
  ->addColumn('email', 'string', [
    'limit' => 255,
    'null' => false
  ])
  ->addColumn('hidden', 'boolean', [
     'default' => 0,
  ])
  ->addColumn('password', 'string', [
     'limit' => 255,
     'null' => false
  ])
  ->addColumn('created', 'datetime', [
     'null' => true
  ])
  ->addColumn('modified', 'datetime', [
     'null' => true
  ])
  ->create();
}

今回必要なのは13行目のhiddenカラムです。

私はAllコマンドを使ってコントローラー・モデル・ビューを作成してユーザーの登録をしています。

あなたはユーザーを数人登録してください。

私が作成した例だと下記になります。

indexアクションとビュー

Usersコントローラーのindexアクションのコードは下記になります。

public function index()
{
  $users = $this->paginate($this->Users);

  $this->set(compact('users'));
}

ビュー(index.php)のコードは下記になります。

<?php
/**
 * @var \App\View\AppView $this
 * @var iterable<\App\Model\Entity\User> $users
 */
?>
<div class="users index content">
    <?= $this->Html->link(__('New User'), ['action' => 'add'], ['class' => 'button float-right']) ?>
    <h3><?= __('Users') ?></h3>
    <div class="table-responsive">
        <table>
            <thead>
                <tr>
                    <th><?= $this->Paginator->sort('id') ?></th>
                    <th><?= $this->Paginator->sort('name') ?></th>
                    <th><?= $this->Paginator->sort('email') ?></th>
                    <th><?= $this->Paginator->sort('hidden') ?></th>
                    <th><?= $this->Paginator->sort('created') ?></th>
                    <th><?= $this->Paginator->sort('modified') ?></th>
                    <th class="actions"><?= __('Actions') ?></th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($users as $user): ?>
                <tr>
                    <td><?= $this->Number->format($user->id) ?></td>
                    <td><?= h($user->name) ?></td>
                    <td><?= h($user->email) ?></td>
                    <td><?= h($user->hidden == 0) ? '削除してない' : '削除した' ?></td>
                    <td><?= h($user->created) ?></td>
                    <td><?= h($user->modified) ?></td>
                    <td class="actions">
                        <?= $this->Html->link(__('View'), ['action' => 'view', $user->id]) ?>
                        <?= $this->Html->link(__('Edit'), ['action' => 'edit', $user->id]) ?>
                        <?= ($user->hidden == 0) ? $this->Form->postLink(__('Delete'), ['action' => 'delete', $user->id], ['confirm' => __('Are you sure you want to delete # {0}?', $user->id)]) : '' ?>
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>
    <div class="paginator">
        <ul class="pagination">
            <?= $this->Paginator->first('<< ' . __('first')) ?>
            <?= $this->Paginator->prev('< ' . __('previous')) ?>
            <?= $this->Paginator->numbers() ?>
            <?= $this->Paginator->next(__('next') . ' >') ?>
            <?= $this->Paginator->last(__('last') . ' >>') ?>
        </ul>
        <p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
    </div>
</div>

これで「http://localhost/users/」にアクセスすると下記の表示になります。

Hiddenの項目に「削除してない」と表示されていますがActionsの項目の「Delete」を押した時に「削除した」に表示を切り替えます。

削除してない・削除したの表示を切り替えているのはindex.phpの29行目の部分です。

それでは論理削除の機能を実装しましょう、ユーザーの削除をしたら「削除してない」が「削除した」に変わります。

deleteアクション

Usersコントローラーのdeleteアクションのコードを下記にします。

public function delete($id = null)
{
  $this->request->allowMethod(['post', 'delete']);

  $user = $this->Users->get($id);

  $user->hidden = 1;

  $this->Users->save($user);

  return $this->redirect(['action' => 'index']);
}

デフォルトのコードを少しいじっています。

7行目でActionsのDeleteを押した時にhiddenカラムの値を0から1に変えて削除したことにします。

Deleteボタンを押した時の見た目は下記の赤枠の変化をします。

これで完成です。