Github初-公開-体験

自分用に作ったプラグインをGithubに公開してみた。

https://github.com/Zuborawka/Backupable

Githubに何かを公開したのはこれが初めてで戸惑うことばかり。少しわかったような気にもなりましたが、それ以上に分からないことの多さに改めて気づいた、そんな感じです。markdownの書き方も最初全くわからず、それ以上に英語の書き方もわからないのでREADMEの作成にやたらと時間がかかりましたし、あと、Backupable って何か変な言葉のような気がするけれど、それ以外思いつかないです。Restoreable とかのほうがいいのだろうかなんて思ってみたり。。。ちなみに up+able をあえて書くなら uppable ではなく、 upable でよさそうです(by グーグル先生)けど、最初 Backuppable ってしてしまってたので全部修正しました。

とはいえ、ひとまず目的は達成したので今回はこれでよしとしよう。

プラグイン自体は簡単にバックアップとリストアを実装したい時に使うために作ったものです。似たような機能を実装したプラグインがあるような気がするのですが探すことができずじまいで自作しました。さてこれをお使いになる方がいるのかどうかわかりませんが、自分のためにも解説。

これは何?

レコードのバックアップと復元をするための、CakePHP2.x 用のプラグインです。

たとえば何か記事を編集して更新した後、やっぱり前のに戻したいなとか、最初に書いたのってどんな内容だったか確認したい、なんていう望みを叶えるためのツールです。おれおれCMSで絶賛稼働中(笑)!なので、まぁ、ある程度は安心してお使いになれるかなと。

データベース全体やテーブル全体のバックアップ用プラグインは見たことあったのですが、レコード単位というのが欲しかったのに見当たらなかったので作りました。

何に似ている?

WordPressの記事のrevision機能みたいなものです。いえいえ、ほんの少し似ているだけですよ。これはめちゃくちゃ単純で機能も少ないです。更新中に自動的にAjaxでばんばん保存されるなんてのは当然用意してません。もちろんビューやコントローラをうまく作ればそういう機能も加えられますけど。

どうやって使う?

  1. プラグインディレクトリにファイルを設置
  2. バックアップ用のテーブル作成
  3. プラグインをロードするためのbootstrap.phpを設定をする
  4. モデルに”Backupable”のビヘイビアを設定をする
  5. API と使い方
  6. 幾つかのオプション

1.プラグインディレクトリにファイルを設置

app/Plugin/Backupable/Model/BackupableAppModel.php
app/Plugin/Backupable/Model/BasicBackup.php
app/Plugin/Backupable/Model/Interface/BackupEngine.php
app/Plugin/Backupable/Model/Behavior/BackupableBehavior.php

2.バックアップ用のテーブル作成

CREATE TABLE `backups` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `table_name` varchar(255) CHARACTER SET ascii NOT NULL,
  `src_id` int(10) unsigned NOT NULL,
  `data` longblob NOT NULL,
  `created` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `table_and_src_id` (`table_name`,`src_id`,`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

このテーブルは BasicBackup クラスと関連づいています。なので、Backupable/Model/BasicBackup.php において設定すればテーブルの名前を変更できます。

当初 `data` のデータ型を text にしていましたが、バイナリが保存される可能性を考慮して longblob に変更しました。

3.プラグインをロードするためにbootstrap.php を設定する

CakePlugin::load('Backupable');

4.モデルに “Backupable” ビヘイビアの設定をする

  class Post extends AppModel {
      $actsAs = array('Backupable.Backupable');
  }

5.API と使い方

API

BackupableBehavior::backup(Model $model, $options = array())

  • 現在のレコードをバックアップ保存します。
  • デフォルトでは、モデルのafterSaveの際に自動的に呼び出されます。この振る舞いは “autoSave” オプションで変更可能です。
  • デフォルトでは、直前のバックアップ内容と同じ場合には保存しません。この振る舞いは”skipSame” オプションで変更可能です。
  • デフォルトでは、レコードのすべてのフィールドを保存します。対象となるフィールドは”backupFields” オプションで指定可能です。
  • @param Model
  • @param mixed (array or integer. default is array())
  • @return mixed (array of a result or false)

BackupableBehavior::history(Model $model, $options = array())

  • バックアップの履歴を返します。
  • この結果は、バックアップレコードのIDと保存時刻を新しいものから順に20件含みます。
  • 結果の配列は array(‘Backup’ => array(‘id’ => 1, ‘created’ => ‘2012-12-12 12:12:12’)) という形式の配列が複数セットされたものです。
  • 結果の取得のためのパラメータは、通常のModel::findのものとほぼ同じ物が使用できます。
  • @param Model
  • @param mixed
  • @return array

BackupableBehavior::remember()

  • 指定したバックアップデータを返します。
  • 取得のためのパラメータはBackupレコードのIDだけでなく、元となったレコードのIDも必要です。
  • 取得するためには三つの値、すなわちBackupレコードのID、元となったレコードのID、モデルの使用しているテーブル名、以上が一つのバックアップレコード内において一致している必要があります。この冗長性は無関係なバックアップのデータを単にIDだけで操作してしまわないために設けられています。
  • @param Model
  • @param mixed “id”[元になったレコードのID]、”backupId”[バックアップレコードのID]
  • @return array

BackupableBehavior::restore()

  • バックアップされたレコードにより、データを復元します。
  • 必要なパラメータ、およびテーブル名などの一致の制約はremember()と同じです。
  • @param Model
  • @param mixed (remember() と同じ)
  • @return mixed (Model::saveの結果がそのまま返ります)

Usage

モデルの例

/**
 * app/Model/Post.php
 * Post class
 */
class Post extends AppModel {
    public $actsAs = array('Backupable.Backupable');
}

コントローラの例

/**
 * app/Controller/PostsController.php
 * PostsController
 */
class PostsController extends AppController {

/**
 * Usage of BackupableBehavior::history()
 */
    function history($id) {
        $history = $this->Post->history($id);
        $this->set(compact('history'));
    }

/**
 * Usage of BackupableBehavior::remember()
 */
    function remember($id, $backupId) {
        $remember = $this->Post->remember(compact('id', 'backupId'));
        $this->set(compact('remember'));
    }

/**
 * Usage of BackupableBehavior::restore()
 */
    function restore($id, $backupId) {
        $result = $this->Post->restore(compact('id', 'backupId'));
        $message = $result ? 'Restored' : 'Fault';
        $this->Session->setFlash($message);
        $this->redirect(array('action' => 'view', $id));
    }
}

ビューテンプレート

history.ctp

<?php
/**
 * app/View/Posts/history.ctp
 */
?>
<h2>History</h2>
<ul>
<?php foreach ($history as $data): ?>
    <li><?php echo $this->Html->link(
        $data['Backup']['created'],
        array(
            'action' => 'remember',
            $this->request->params['pass'][0],
            $data['Backup']['id']
        )); ?></li>
<?php endforeach; ?>
</ul>

remember.ctp

<?php
/**
 * app/View/Posts/remember.ctp
 */
?>
<h2>Do you restore the record?</h2>
<dl>
    <dt>Title</dt>
    <dd><?php echo $remember['Backup']['data']['title']; ?></dd>
    <dt>Content</dt>
    <dt><?php echo $remember['Backup']['data']['content']; ?></dt>
</dl>
<p>
<?php
echo $this->Html->link(
    'Yes, I restore it now!',
    array(
        'action' => 'restore',
        $this->request->params['pass'][0],
        $this->request->params['pass'][1]
    )
);
?>
</p>

6.幾つかのオプション

ビヘイビアの設定時に7種類のオプションを指定できます。

  • “backupFields” array default null. バックアップ対象のフィールドをカラムで指定します。デフォルトでは全フィールドをバックアップ対象にします。
  • “autoSave” boolean default true. モデルの保存時に自動的にバックアップを取るかどうか。デフォルトでは取得する設定になっています。
  • “skipSame” boolean default true. true の場合、前回の履歴と同じデータの場合はバックアップを取りません。false にすると同じデータであってもバックアップされます。
  • “dependent” boolean default false. true の場合、元データの削除と同時にバックアップデータも削除されます。false の場合、元データを削除してもバックアップデータは削除されません。デフォルトは false です。
  • “backupEngineClass” string default “Backupable.BasicBackup”. バックアップロジックを実装したモデルクラス。 Backup.BackupEngine インターフェイスを実装しなくてはなりません。デフォルトはプラグイン付属の BasicBackup クラスが指定されています。
  • “backupEngineAlias” string default “Backup”. バックアップエンジンモデルのエイリアスを指定。デフォルトは “Backup”
  • “backupConfig” string. バックアップエンジンオブジェクトに渡す設定。キーと値のペアで指定します。

eg.)

/**
 * app/Model/Post.php
 * Post.php
 */
public $actsAs = array(
    'Backupable.Backupable' => array(
        'backupFields' => array('title', 'content'),
        'autoSave' => false,
        'skipSame' => false,
    ),
);