[CakePHP] Transactionを使う方法とEntityクラスを利用してInsert、Update、Deleteする方法


Study / PHP    作成日付 : 2020/02/19 03:00:00   修正日付 : 2020/02/19 03:00:00

こんにちは。明月です。


この投稿はPHPのCakeフレームワークでTransactionを使う方法とEntityクラスを利用してInsert、Update、Deleteする方法に関する説明です。

以前、CakePHPのフレームワークを利用せずに、データベースにInsertやUpdate、Deleteに関して説明したことがあります。

link - [CakePHP] データベース(MariaDB(Mysql))を接続する方法


でも、我々はデータ無欠性のため、トランザクションを使うし、Fetch機能でオブジェクト単位でデータを追加する方法で実装しなければならないです。

テーブルの例は以前の投稿を続けて利用します。

link - [CakePHP] ORMのテーブルFetch設定


Userテーブルでデータを入力する後、派生テーブルのInfoテーブルのデータを入力します。そしてInfo2テーブルのデータを入力することで考えましょう。

UserテーブルのキーとInfoテーブルの外部キーが自動生成するタイプじゃなく、nvarcharタイプのユーザかUserテーブルのキーとInfoテーブルの外部キーが自動生成するタイプじゃなく、nvarcharタイプのユーザから取得するデータなのでUserテーブルをInsertした後InfoテーブルをInsertすることの順番で問題ありません。

でも、Info2のテーブルの場合はInfoテーブルのキーで外部キーが結んでいますが、この場合は自動生成タイプなのでInfoテーブルがinsertした後、キーを検索してInfo2テーブルに入力しなければならないです。

この順番のテーブル入力する作業が多いと思えば、ソースがすごく複雑になるでしょう。

また、データベース処理する中でエラーが発生する時、全てをロールバックしなければならないですが、それ時にトランザクション(transaction)を利用すればできるでしょう。

<?php
namespace App\Controller; 	
use Cake\Datasource\ConnectionManager;
use Cake\ORM\TableRegistry;
use Cake\Core\Exception\Exception;

class HomeController extends AppController {	
  public function index() {
    // connectionマネージャーからconnectionを取得する。
    $connection = ConnectionManager::get('default');
    // トランザクション処理
    $connection->transactional(function ($conn) {
      // トランザクション中でエラーがなければcommitになるし、エラーが発生する時にrollbackになる。
    });
  }
}

CakePHPフレームワークではトランザクションがオブザーバーパターンにもう実装されています。JavaやC#はパターンを実装しましたが。。


トランザクションを利用してデータを入力しましょう。

<?php
namespace App\Controller;
use Cake\Datasource\ConnectionManager;
use Cake\ORM\TableRegistry;

class HomeController extends AppController {	
  public function index() {
    // connectionマネージャーからconnectionを取得する。
    $connection = ConnectionManager::get('default');
    //トランザクション
    $connection->transactional(function ($conn) {
      // Userテーブルのレジストリを取得
      $userTable = TableRegistry::get('User');
      // Entityを生成する。
      $user = $userTable->newEntity();
      // idカラムに「new」を入力してnameカラムに「new Name」を入力する。
      $user->id = "new";
      $user->name = "new Name";
      // 格納(transactionの中でエラーが発生しなければ、格納される。)
      $userTable->save($user);
      // Infoテーブルのレジストリを取得
      $infoTable = TableRegistry::get('Info');
      // Entityを生成する。
      $info = $infoTable->newEntity();
      // Userクラスからidを取得してInfoクラスに外部キーを設定する。
      $info->id = $user->id;
      $info->age = 10;
      // 格納(transactionの中でエラーが発生しなければ、格納される。)
      $infoTable->save($info);
      // Info2テーブルのレジストリを取得
      $info2Table = TableRegistry::get('Info2');
      // Entityを生成する。
      $info2 = $info2Table->newEntity();
      // Infoクラスのidxを取得してInfo2クラスの外部キーに設定する。
      $info2->info_idx = $info->idx;
      $info2->birth = 10;
      // 格納(transactionの中でエラーが発生しなければ、格納される。)
      $info2Table->save($info2);
    });
  }
}


上の例でInfoテーブルの場合は外部キー(id)に入力するデータにはEntityデータの「id」で設定するので別にデータベースから受取るのはありませんが、Info2テーブルの場合はInfoテーブルの外部キーが自動生成のキーなのでInfoデータがinsertした後のデータをデータベースから受け取らければならないです。

実際にtransation中で「$info->idx」キーがありませんが、「$info2->info = $info->idx」を設定することで、連携することが出来ます。


今回はUpdateとDeleteです。

UpdateとDeleteはデータベースからデータを修正や削除することで一応検索してデータを取得します。

<?php
namespace App\Controller;
use Cake\Datasource\ConnectionManager;
use Cake\ORM\TableRegistry;

class HomeController extends AppController {	
  public function index() {
    // connectionマネージャーからconnectionを取得する。
    $connection = ConnectionManager::get('default');
    // トランザクション
    $connection->transactional(function ($conn) {
      // Userテーブルのレジストリを取得
      $table = TableRegistry::get('User');
      // Query式を取得
      $query = $table->find();
      // idが「new」のデータを検索する。
      $query = $query->where(['id' => 'new']);
      // データを取得する。
      $user = $query->first();
      // nameを修正する。
      $user->name = "modified!!";
      // 格納(transactionの中でエラーが発生しなければ、格納される。)
      $table->save($user);
    });
  }
}


上のデータを取得してEntityインスタンスのnameのデータを修正してsave関数を呼出したらデータベースに格納されています。

<?php
namespace App\Controller;
use Cake\Datasource\ConnectionManager;
use Cake\ORM\TableRegistry;
use Cake\Core\Exception\Exception;

class HomeController extends AppController {
  public function index() {
    // connectionマネージャーからconnectionを取得する。
    $connection = ConnectionManager::get('default');
    // トランザクション
    $connection->transactional(function ($conn) {
      // Userテーブルのレジストリを取得
      $table = TableRegistry::get('User');
      // Query式を取得
      $query = $table->find();
      // idが「new」のデータを検索する。
      $query = $query->where(['id' => 'new']);
      // データを取得
      $user = $query->first();
      // 派生データを全て削除する。
      // Infoテーブルを繰り返す。
      foreach($user->infos as $info) {
        // Info2テーブルを繰り返す。
        foreach($info->info2s as $info2) {
          // Info2テーブルのデータを削除(transactionの中でエラーが発生しなければ、格納される。)
          TableRegistry::get('Info2')->delete($info2);  
        }
        // Infoテーブルのデータを削除(transactionの中でエラーが発生しなければ、格納される。)
        TableRegistry::get('Info')->delete($info);
      }
      // Userテーブルデータを削除(transactionの中でエラーが発生しなければ、格納される。)
      $table->delete($user);
    });
  }
}


削除されたことを確認できました。


ここまでPHPのCakeフレームワークでTransactionを使う方法とEntityクラスを利用してInsert、Update、Deleteする方法に関する説明でした。


ご不明なところや間違いところがあればコメントしてください。

最新投稿