STAFF BLOG スタッフブログ

【FuelPHP】CMSの機能をプラグイン化しインストール・アンインストール

サイト制作におけるCMSの機能で、ページ登録やニュースやトピックスの記事登録、
CMSログインアカウントの管理等は、よく使用しますが、
会員管理やブログ管理・祝祭日管理等の機能については、不要な場合もあります。

CMS機能をmaxで準備して不要な機能は
DBテーブルをDROP TABLEやソースファイルを手作業で削除していくと
無駄な作業時間にもなりますので
WordPressのようなプラグインみたいに
インストール・アンインストールの機能を作ってみました。
\fuel\app\modules\のモジュールに機能を追加していきます。

(・囚・)b

モジュール機能管理のDBテーブル

# DBテーブル構造

CREATE TABLE IF NOT EXISTS `module` (
  `id` int(10) unsigned NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '10' COMMENT 'ステータス(10:有効, 20:無効)',
  `code` varchar(100) NOT NULL COMMENT 'モジュールコード',
  `title` varchar(100) DEFAULT NULL COMMENT 'モジュール名',
  `version` varchar(100) NOT NULL DEFAULT '' COMMENT 'バージョン',
  `created_at` datetime NOT NULL,
  `modified_at` datetime NOT NULL,
  `del_flg` tinyint(1) NOT NULL DEFAULT '0' COMMENT '削除フラグ 1:削除済み'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='モジュール';

ALTER TABLE `module`
  ADD PRIMARY KEY (`id`),
  ADD KEY `del_flg` (`del_flg`);

ALTER TABLE `module`
  MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=1;

# Model

<?php

class Model_Module extends \Model_Crud
{
	// テーブル名
	protected static $_table_name = 'module';

	// 初期値
	protected static $_defaults = array(
		'status'             => 10,
		'code'               => '',
		'title'              => '',
		'version'            => '',
		'created_at'         => '',
		'modified_at'        => '',
		'del_flg'            => 0,
	);

	// 取得時のdel_flgチェック
	protected static function pre_find(&$query)
	{
		// 削除フラグ
		$query->where(self::$_table_name.'.del_flg', 0);
	}

}

?>

モジュールのソース

\fuel\app\modules\以下に置く、各ディレクトリ&ソースファイルをzipファイル化して置く。
\fuel\app\modules\以下に置くソースファイルは、namespaceの宣言はしておこう。


<?php

# zipファイル内の「\モジュールディレクトリ名\config\config.php」に、各モジュールのタイトル等の設定情報を書いておく。

return array(

	'module' => array(
		'code'             => 'モジュールのコード名',
		'title'            => 'モジュール名称',
		'version'          => 'モジュールのバージョン情報',
	)

);

?>

モジュール管理の画面

こんな感じで圧縮したzipファイルをアップロードし、登録するとインストールが実行され
削除ボタンをクリックし実行すると、アンインストールを実行する画面を準備します。

モジュールをインストール時のメソッド内容


<?php

class Model_Module extends \Model_Crud
{

	// ファイルを設置
	public static function mkdir($param)
	{
		// tmpディレクトリ
		$uniqid = uniqid();
		$tmp_dir = APPPATH.'tmp'.DS.'upload'.DS.$uniqid;

		// ZIPファイルを作成:Data URIスキームでPOSTされたzipファイル
		$zip_file = file_get_contents('{{zipファイル}}');
		// tmpディレクトリに一時的に置いて生成するzipファイル名を指定
		$new_file = $tmp_dir.'.zip';
		if ( is_file($new_file) )
		{
			// 既存のZIPを削除@tmp
			unlink($new_file);
		}
		if ( is_dir($tmp_dir) )
		{
			// 既存のディレクトリを削除@tmp
			\File::delete_dir($tmp_dir);
		}
		\File::create_dir(APPPATH.'tmp'.DS.'upload', $uniqid);

		$e_msg = '';

		$config = array();
		// POSTされたファイルをtmpディレクトリに保存
		file_put_contents($new_file, $zip_file);
		// 保存したzipファイルを解凍
		$za = new \ZipArchive();
		if( $za->open($new_file) )
		{
			$za->extractTo($tmp_dir);
			$za->close();

			// モジュールのコード・タイトル取得:\fuel\app\tmp\tmpディレクトリ\モジュールディレクトリ名\config\config.phpの内容を取得し、モジュールの名称等を取得。
			$list = \File::read_dir($tmp_dir, 1);
			foreach( $list as $dir => $file )
			{
				$config = include($tmp_dir.DS.$dir.'config'.DS.'config.php');
				$param['code']             = $config['module']['code'];
				$param['title']            = $config['module']['title'];
				$param['version']          = $config['module']['version'];
				break;
			}
		}

		// 既にインストールされていないかチェック
		$find_param = array(
			'where' => array(
				'code' => $param['code'],
			),
		);
		$exists = \Model_Module::find($find_param);
		if ( $exists )
		{
			$e_msg = 'このモジュールは既にインストールされています';
		}
		else
		{
			// copy先&元ディレクトリを指定
			$mod_dir  = APPPATH.'modules'.DS.$param['code'];
			$copy_dir = APPPATH.'tmp'.DS.'upload'.DS.$uniqid.DS.$param['code'];

			// 解凍したディレクトリをコピー
			\File::copy_dir($copy_dir, $mod_dir);
		}

		// tmpを掃除
		unlink($new_file);
		\File::delete_dir($tmp_dir);

		// エラーが出ていれば返す
		if ( strlen($e_msg) > 0 )
		{
			throw new \Exception($e_msg);
		}

		return $param;
	}


	// インストール
	public static function install($param = array())
	{
		// モジュールのコード・名称の取得
		$param = \Model_Module::mkdir($param);

		// レコード追加
		$rec = \Model_Module::dummy_rec();
		$rec->code         = $param['code'];
		$rec->title        = $param['title'];
		$rec->version      = $param['version'];
		$rec->created_at   = date('Y/m/d H:i:s');
		$rec->modified_at  = date('Y/m/d H:i:s');
		$rec->save();

		// インストール実行:\fuel\app\modules\モジュールディレクトリ名\classes\model\module.phpに、installメソッドを用意し、各モジュールのみ実行したいDBテーブルのCREATEやレコード追加等を記述
		// (※指定のファイル名は、解凍後におかれるファイル名:zipファイル内に用意しておくこと。)
		if ( \Module::exists($param['code']) )
		{
			\Module::load($param['code']);
			$model = '\\'.ucfirst($param['code']).'\Model_Module';
			call_user_func(array($model, 'install'));
		}
	}

}

?>

↓↓↓Data URI スキームとは
https://ja.wikipedia.org/wiki/Data_URI_scheme
↓↓↓ファイルアップロード画面でのData URIの取得方法
http://www.nickdesteffen.com/blog/file-uploading-over-ajax-using-html5
https://lab.syncer.jp/Web/JavaScript/Snippet/27/

モジュールをアンストール時のメソッド内容


<?php

	// アンインストール
	public static function uninstall($param = array())
	{
		// \Model_Moduleのレコードをdel_flg=1にするや、deleteレコードする等の処理を書いておく

		// アンインストール実行:\fuel\app\modules\モジュールディレクトリ名\classes\model\module.phpに、uninstallメソッドを用意し、各モジュールのみ実行したいDBテーブルのDROP CREATEやレコード削除等を記述
		// (※指定のファイル名は、解凍後におかれるファイル名:zipファイル内に用意しておくこと。)
		if ( \Module::exists('{{モジュールディレクトリ名}}') )
		{
			$model = '\\'.ucfirst('{{モジュールディレクトリ名}}').'\Model_Module';
			call_user_func(array($model, 'uninstall'));
		}

		// \fuel\app\modules\モジュールディレクトリ名\のディレクトリを削除
		\File::delete_dir(APPPATH.'modules'.DS.'{{モジュールディレクトリ名}}');
	}

?>

その他、モジュール使用での便利設定


<?php

# \fuel\app\classes\controller内のコントローラーや\fuel\app\views\内のビューから
# モジュール内のModelを使用したい場合、loadしないとModel使用できません

\Module::load('{{モジュール名}}');

# \fuel\app\config\event.phpのファイルを置き、以下の内容を書いておけば、\Module::loadをしなくてよくなる
# 以下のソースは、\fuel\app\modules\にある全ディレクトリをロードしている

// イベント予約
return array(
	'fuelphp' => array(
		'app_created' => function()
		{
			// モジュールの全ロード
			$dirs = \File::read_dir(APPPATH.'modules'.DS, 1);
			foreach ( $dirs as $dir => $type )
			{
				$dir = rtrim($dir, DS);
				if ( is_dir(APPPATH.'modules'.DS.$dir) )
				{
					try
					{
						\Module::load($dir);
					}
					catch (\Exception $e)
					{
						// エラーcatchした際の処理書く
					}
				}
			}
		},
	),
);

# \fuel\app\config\event.phpの設定をしておけば
# \fuel\app\classes\controller内のコントローラーや\fuel\app\views\内のビューからloadせずに
# モジュールのModelを使用できます

\モジュールのNamespace\モデル名::メソッド名();

?>

ご参考までに。。。


(・囚・)ノ

INDEXブログ一覧へ
CONTACTお問い合わせはこちら