<?php
/*
 * system/package/PackageConfigBase.class.php
 * 
 * CopyRight(C) 2010 Shopformer Development Team. All Right Reserved
 * URL: http://sourceforge.jp/projects/shopformer/
 * 
 * 
 * Mail: m_nakashima@users.sourceforge.jp
 * Auther: Masanori Nakashima
 * Last Update: 2010-07-23
 */
require_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'AbstractData.class.php');
/**
 * システム パッケージ設定クラスの基底クラスです
 * 
 * formerウェブアプリケーションのパッケージを実装する際に、パッケージフォルダ直下にこのクラスを拡張したクラス定義を記述したPackageConfig.class.phpファイルを作成してください。
 * クラス名は(パッケージ)_PackageConfigと言う名前で実装する必要があります。
 * 
 * 本クラスを拡張実装してパッケージを制作することでユーザーログインオブジェクトの追加や、パッケージ設定機能の利用、管理パネルでの基本インターフェース実装を簡単におこなうことができます。
 * 
 * @package system
 * @subpackage package
 * @category DAO
 * @version 1.2.00
 * @copyright Copyright(c)2011, Shopformer Development Team. <shopformer-dev@lists.sourceforge.jp>
 * @author Masanori Nakashima
 * @access public
 * @abstract
 */
class system_package_PackageConfigBase extends system_AbstractData {
	/**
	 * 出力する定義ファイルの設定項目を保持する連想配列
	 * define名=>define値
	 * @var
	 * @access protected
	 */
	var $definitionHash	= array();
	/**
	 * コンストラクタ
	 */
	function system_package_PackageConfigBase() {
		$this->definitionHash	= array();
	}
	// オーバーライド必須メソッド
	/**
	 * パッケージの表示順序を取得
	 * 
	 * このメソッドはあなたが制作するパッケージに応じて必ず数値を戻すよう実装する必要があります。
	 * @return int パッケージ順序を戻してください。管理パネルで表示される順序の指標となります。
	 * @access public
	 */
	function getPackageOrder() {
		return 1;
	}
	/**
	 * パッケージの表示名を取得
	 * 
	 * このメソッドはあなたが制作するパッケージに応じて必ず文字列を戻すよう実装する必要があります。
	 * @return string パッケージ名称を戻してください。管理パネルで表示されるパッケージ名となります。
	 * @access public
	 */
	function getPackageViewName() {
		return '';
	}
	/**
	 * パッケージ概要説明を文字列で戻してください。
	 * 
	 * このメソッドはあなたが制作するパッケージに応じて必ず文字列を戻すよう実装する必要があります。
	 * @return string パッケージ概要説明文（HTML可)
	 * @access public
	 */
	function getPackageDescription() {
		return '';
	}
	// 必要ならオーバーライドした方がよいメソッド
	/**
	 * パッケージ依存関係のハッシュを戻します。
	 * 
	 * あなたが制作するパッケージが他のパッケージを必要とする場合に、
	 * そのパッケージと共存可能なバージョンをarray('packageId'=>array('version','version',...))の形式で戻すよう実装してください。
	 * @return hash array('packageId'=>array('version','version',...))
	 * @access public
	 */
	function getPackageDependenciesHash() {
		return array();
	}
	/**
	 * 共存可能な他パッケージ情報のハッシュを取得
	 * 
	 * あなたが作成するパッケージに付加パッケージとしてインストール可能なパッケージとバージョンをarray('packageId'=>array('version','version',...))の形式で戻すよう実装してください。
	 * 本実装はsystemパッケージ1.2時点では利用されませんが今後のバージョンで必ず実装が必要となります。
	 * @return hash array('packageId'=>array('version','version',...))
	 * @access public
	 */
	function getPackageAvailablesHash() {
		return array();
	}
	/**
	 * パッケージの設定に問題がある場合のアラートメッセージを取得
	 * 
	 * パッケージの設定に問題がある場合に管理パネルで警告を表示したい場合、妥当性検査をしてその問題を文字列で戻すように実装してください。
	 * 標準ではなにも戻しません。
	 * @return string アラートメッセージ
	 * @access public
	 */
	function getAlertMessages( & $request ) {
		return null;
	}
	// 必要に応じてオーバーライド
	/**
	 * ログインユーザーとして利用できるクラス名称を取得するインターフェースメソッド
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return array 作成パッケージ内でsystem_login_AbstractUserを拡張実装しログインユーザー定義として利用できるオブジェクトクラス名。
	 * @access public
	 */
	function getLoginClassNameArray( & $request ) {
		return array();
	}
	/**
	 * 本クラス実装メンバのdefinitionHashに設定された値の妥当性検査を行いエラーがある場合はfalseを戻してください。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean エラーがあるならfalse
	 * @access public
	 */
	function validateDifinitionHash( & $request ) {
		return true;
	}
	/**
	 * インストールを実行します。
	 * 
	 * 本メソッドは実装されています。
	 * 
	 * あなたの作成するパッケージに応じてインストール時の処理を記述してオーバーライドすることができます。
	 * デフォルトの動作はlib内自パッケージフォルダ直下installフォルダ内のdata,pages,templates,widgets,publicフォルダ内のファイルシステムを設置環境にコピーする処理をおこないます。
	 * インストール時にファイルをコピーしてページやデータ、テンプレート、HTML部品を配置したいだけであれば、オーバーライドしないでinstallフォルダ内にそのファイル構成を作成してください。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean インストールに成功したらtrue
	 * @access public
	 */
	function install( & $request ) {
		if( strlen($this->getPackageId()) > 0 ) {
			$installDir	= DIR_PATH_LIB.DIRECTORY_SEPARATOR.$this->getPackageId().DIRECTORY_SEPARATOR.'install';
			if( file_exists($installDir) && is_dir($installDir) ) {
				$dataDir	= $installDir.DIRECTORY_SEPARATOR.DIR_NAME_DATA;
				spider_Controller::loadClassDefinition('system_DataFileWriter');
				if( file_exists($dataDir) && is_dir($dataDir) ) {
					system_DataFileWriter::importDir( $request, '/', $dataDir, DIR_NAME_DATA );
				}
				$templatesDir	= $installDir.DIRECTORY_SEPARATOR.DIR_NAME_TEMPLATES;
				if( file_exists($templatesDir) && is_dir($templatesDir) ) {
					system_DataFileWriter::importDir( $request, '/', $templatesDir, DIR_NAME_TEMPLATES );
				}
				$widgetsDir	= $installDir.DIRECTORY_SEPARATOR.DIR_NAME_WIDGETS;
				if( file_exists($widgetsDir) && is_dir($widgetsDir) ) {
					system_DataFileWriter::importDir( $request, '/', $widgetsDir, DIR_NAME_WIDGETS );
				}
				if( defined('DIR_NAME_PAGES') ) {
					$pagesDir	= $installDir.DIRECTORY_SEPARATOR.DIR_NAME_PAGES;
					if( file_exists($pagesDir) && is_dir($pagesDir) ) {
						system_DataFileWriter::importDir( $request, '/', $pagesDir, DIR_NAME_PAGES );
					}
				}
				$publicDir	= $installDir.DIRECTORY_SEPARATOR.'public';
				if( file_exists($publicDir) && is_dir($publicDir) ) {
					system_DataFileWriter::importDir( $request, '/', $publicDir, 'public' );
				}
			}
		}
		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * アンインストールを実行します。
	 * 
	 * 本オブジェクトは実装されています。
	 * 
	 * デフォルトの動作はdataフォルダ内の自パッケージ関連のデータファイルとフォルダを全て削除します。
	 * 固有の処理、例えばデータベーステーブルの削除やレコード削除処理が必要な場合はオーバーライドしてください。
er	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean アンインストールに成功したらtrue
	 */
	function uninstall( & $request ) {
		require_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'DataFileWriter.class.php');
		system_DataFileWriter::deleteDir( $request, '/'.$this->getPackageId(), DIR_NAME_DATA );
		system_DataFileWriter::delete( $request, '/'.$this->getPackageId().'.define.inc.php', DIR_NAME_DATA );
		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	// オーバーライドの必要はないメソッド
	/**
	 * パッケージがインストール済みか確認します
	 * 
	 * このメソッドは実装されています。
	 * spider/dataフォルダ内に(パッケージ名).define.inc.phpファイルが存在すればtrueを返すように実装されています。
	 * @return boolean インストールされていればtrue
	 * @access public
	 */
	function isInstall() {
		$defFilePath	= DIR_PATH_DATA.DIRECTORY_SEPARATOR.$this->getPackageId().'.define.inc.php';
		if( file_exists($defFilePath) ) {
			return true;
		}
		return false;
	}
	/**
	 * パッケージIDを取得します
	 * 
	 * このメソッドは実装されています。
	 * 
	 * 実装クラスのパッケージ実装クラスのパッケージ部分文字列を戻すように実装されています。ルールに従ってパッケージを作成すればオーバーライドする必要はありません。
	 * @return string パッケージID
	 * @access public
	 */
	function getPackageId() {
		$packageId	= get_class($this);
		if( strpos( $packageId, '_' ) !== false ) {
			$packageId	= substr( $packageId, 0, strpos($packageId,'_') );
		}
		return $packageId;
	}
	/**
	 * パッケージのバージョンを取得
	 * 
	 * このメソッドは実装されています。
	 * 実装クラス定義を読み込む前に(パッケージID大文字_VERSION)でバージョン文字列がdefineされていればその値を戻すように実装されています。
	 * パッケージを作成する際はバージョンを定数として定義するように作成すれば特にオーバーライドする必要はありません。
	 * @return string パッケージバージョン
	 * @public
	 */
	function getVersion() {
		$defName	= strtoupper($this->getPackageId()).'_VERSION';
		if( defined($defName) ) {
			return constant($defName);
		}
		return '0.1.00';
	}
	/**
	 * 要求パッケージIDの配列を取得
	 * 
	 * 本メソッドは実装されています。
	 * {@link getPackageDependenciesHash getPackageDependenciesHash}メソッドが戻す連想配列のキー配列を戻します。
	 * @return array {@link getPackageDependenciesHash getPackageDependenciesHash}メソッドが戻す連想配列のキー配列
	 * @access public
	 */
	function getPackageDependenciesIdArray() {
		return array_keys($this->getPackageDependenciesHash());
	}
	/**
	 * 管理パネルパッケージURIを取得します
	 * 
	 * 本メソッドは/管理パネルフォルダ/(パッケージID)を戻すよう実装されています。特にオーバーライドする必要はありません。
	 * @return string URI文字列。/管理パネルフォルダ/(パッケージID)。
	 * @access public
	 */
	function getPanelBaseUri() {
		return '/'.SYSTEM_DIR_NAME_ADMIN_PANEL.'/'.$this->getPackageId();
	}
	/**
	 * パッケージメニューを保持しているか確認します
	 * 
	 * このメソッドは管理パネル配下のパッケージフォルダにsubmenu.phpが存在すればtrueを返すように実装されています。
	 * @return boolen 保持しているならtrue
	 * @access public
	 */
	function hasPackageMenu() {
		$menuFilePath	= APPLICATION_BASE_PATH
		.DIRECTORY_SEPARATOR.SYSTEM_DIR_NAME_ADMIN_PANEL
		.DIRECTORY_SEPARATOR.$this->getPackageId()
		.DIRECTORY_SEPARATOR.'submenu.php';
		if( file_exists($menuFilePath) ) {
			return true;
		}
		return false;
	}
	/**
	 * パッケージCSSを保持しているか確認します
	 * 
	 * このメソッドは管理パネル配下のパッケージフォルダにpackage.cssが存在すればtrueを返すように実装されています。
	 * @return boolen 保持しているならtrue
	 * @access public
	 */
	function hasPackageCss() {
		$menuFilePath	= APPLICATION_BASE_PATH
		.DIRECTORY_SEPARATOR.SYSTEM_DIR_NAME_ADMIN_PANEL
		.DIRECTORY_SEPARATOR.$this->getPackageId()
		.DIRECTORY_SEPARATOR.'package.css';
		if( file_exists($menuFilePath) ) {
			return true;
		}
		return false;
	}
	/**
	 * パッケージJavaScriptを保持しているか確認します
	 * 
	 * このメソッドは管理パネル配下のパッケージフォルダに(パッケージID).js.phpが存在すればtrueを返すように実装されています。
	 * @return boolen 保持しているならtrue
	 * @access public
	 */
	function hasPackageJs() {
		$menuFilePath	= APPLICATION_BASE_PATH
		.DIRECTORY_SEPARATOR.SYSTEM_DIR_NAME_ADMIN_PANEL
		.DIRECTORY_SEPARATOR.$this->getPackageId()
		.DIRECTORY_SEPARATOR.$this->getPackageId().'.js.php';
		if( file_exists($menuFilePath) ) {
			return true;
		}
		return false;
	}
	/**
	 * システム設定に必要な値をPOSTされた値から取得して本オブジェクトのハッシュに設定します
	 * 
	 * 本メソッドはメンバ{@link definitionHash definitionHash}は保持する連想配列キーと同名でPOSTされた値を配列かスカラーかに応じて
	 * {@link definitionHash definitionHash}に設定するように実装されています。オーバーライドの必要はありません。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return void
	 * @access public
	 */
	function setPostValues( & $request ) {
		foreach( $this->definitionHash as $key => $value ) {
			if( is_array($value) ){
				$this->definitionHash[$key]	= array();
				if( is_array($_POST[$key]) ) {
					foreach( $_POST[$key] as $k => $v ) {
						$this->definitionHash[$key][$k]	= stripslashes($v);
					}
				} else {
					array_push( $this->definitionHash[$key], stripslashes( $_POST[$key]) );
				}
			} else if( is_object($value) ) {
			} else {
				$this->definitionHash[$key]	= stripslashes($_POST[$key]);
			}
		}
	}
	/**
	 * 定義ファイルをプロパティにインポートします
	 * 
	 * このメソッドは実装されています。spider/data/(パッケージID).define.inc.php
	 * を読み込んでメンバ{@link definitionHash definitionHash}に値を設定します。
	 * @return boolean インポートに成功したらtrue
	 * @access public
	 */
	function importDefinition() {
		$export_path		= $this->getSaveDir().'.define.inc.php';
		if( file_exists( $export_path ) ) {
			require_once($export_path);
			foreach( $this->definitionHash as $key => $value ) {
				if( defined($key) ) {
					$this->definitionHash[$key]	= constant($key);
				} else if( isset($GLOBALS[$key]) && is_array($GLOBALS[$key]) ) {
					$this->definitionHash[$key]	= $GLOBALS[$key];
				}
			}
			return true;
		}
		return false;
	}
	/**
	 * 定義ファイルをエクスポートします。
	 * 
	 * このメソッドは実装されています。メンバ{@link definitionHash definitionHash}のキー名で、値がスカラーならdefine、
	 * 値が配列なら$_GLOBALSとして実行するspider/data/(パッケージID).define.inc.phpを作成・上書きします。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean エクスポートに成功したらtrue
	 * @access public
	 */
	function exportDefinition( & $request ) {
		$export_path		= $this->getSaveDir().'.define.inc.php';
		$define_str_array	= array();
		foreach( $this->definitionHash as $key => $value ) {
			$define_str	= null;
			if( is_object( $value ) ) {
			} else if ( is_array( $value ) ) {
				$define_str	= '$GLOBALS[\''.$key.'\'] = array(';
				foreach( $value as $k => $v ) {
					if( is_object( $v ) ) {
					} else if ( is_array( $v ) ) {
						// 二次元配列は本バージョンではサポートしない
					} else if( strlen($v) > 0 ){
						// スカラー値の場合
						if( is_numeric( $v ) ){
							$define_str	.= ' \''.$k.'\' => '. $v.',';
						} else {
							$define_str	.= ' \''.$k.'\' => \''.str_replace('\'','\\\'',$v).'\',';
						}
					}
				}
				$define_str	.= ');';
			} else if ( strlen($value) > 0 ){
				if( is_numeric( $value ) ){
					$define_str	= 'define(\''.str_replace('\'','\\\'',$key).'\','.$value.');';
				} else {
					if( strpos($value,"\n") === false ) {
						$define_str	= 'define(\''.str_replace('\'','\\\'',$key).'\',\''.str_replace('\'','\\\'',$value).'\');';
					} else {
						// 改行置き換え
						$value	= str_replace("\r\n","\n",$value);
						$value	= str_replace("\r","\n",$value);
						$value	= str_replace("\n",'\\n',$value);
						$define_str	= 'define(\''.str_replace('\'','\\\'',$key).'\',"'.str_replace('\'','\\\'',$value).'");';
					}
				}
			}
			if( !is_null( $define_str) ) {
				array_push( $define_str_array, $define_str );
			}
		}
		// エクスポートURIに書き出す
		$defineFileStrings	= implode("\n",$define_str_array);
		$fileUri	= '/'.str_replace(DIRECTORY_SEPARATOR,'/',$this->getPackageId()).'.define.inc.php';
		require_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'DataFileWriter.class.php');
		$fileWriter		= new system_DataFileWriter();
		if( $fileWriter->open( $request, $fileUri ) ) {
			// オープンできたらシリアル化して書き込み
			$fileWriter->write( "<?php\n" );
			$fileWriter->write( $defineFileStrings );
			$fileWriter->write( "\n?>" );
			if( $fileWriter->close($request) ) {
				return true;
			}
		}
		return false;
	}
	/**
	 * データ保存ディレクトリを取得します
	 * 
	 * 本メソッドはspider/lib/(パッケージID)/installの絶対パスを戻すよう実装されています。
	 * @return string spider/data/(パッケージID)の絶対パス
	 * @access protected
	 */
	function getSaveDir() {
		$package_name	= $this->getPackageId();
		return DIR_PATH_DATA.DIRECTORY_SEPARATOR.$package_name;
	}
	/**
	 * パッケージ設定の為の情報が保存されているディレクトリパスを取得します
	 * 
	 * 本メソッドはspider/lib/(パッケージID)/installの絶対パスを戻すよう実装されています。
	 * @return string spider/lib/(パッケージID)/installの絶対パス
	 * @access protected
	 */
	function getPackageConfigurationInfoDir() {
		return DIR_PATH_LIB.DIRECTORY_SEPARATOR.$this->getPackageId().DIRECTORY_SEPARATOR.'install';
	}
	//
	// system_AbstractDataからオーバーロード
	//
	/**
	 * system_AbstractDataから第二、第三引数を固定でオーバーロードした保存メソッドです。
	 * 
	 * このメソッドは実装されています。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean 保存に成功したらtrue
	 * @see system_AbstractData::save
	 */
	function save( & $request ) {
		if( $this->exportDefinition($request) ) {
			if( $result = parent::save( $request, 0, false ) ) {
				return $this->load($request);
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	/**
	 * system_AbstractDataから第二、第三引数を固定でオーバーロードした読み込みメソッドです。
	 * 
	 * このメソッドは実装されています。
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスオブジェクトの参照
	 * @return boolean 読み込みに成功したらtrue
	 * @see system_AbstractData::load
	 */
	function load( & $request ) {
		// ID固定で読み込み
		$thisClass						= get_class($this);
		$object							= new $thisClass;
		$result	= parent::load( $request, 'configuration', 0 );
		if( $result ) {
			foreach( $object->definitionHash as $key => $val ) {
				if( !array_key_exists($key,$this->definitionHash) ) {
					$this->definitionHash[$key]		= $val;
				}
			}
		}
		return $result;
	}
	//
	// system_AbstractDataの実装
	//
	/**
	 * データ保存区分名を取得する抽象メソッド
	 * @ignore
	 */
	function getDataClassName(){
		return '';
	}
	/**
	 * データ固有のIDを設定する抽象メソッド
	 * @ignore
	 */
	function getUniqueId() {
		return 'configuration';
	}
	/**
	 * データ固有のIDを設定する抽象メソッド
	 * 変更できません
	 * @ignore
	 */
	function setUniqueId( $uniqueId ) {
		return true;
	}
}
if( defined('DIR_PATH_LIB') ) {
	$mainPackageLibPath	= DIR_PATH_LIB.DIRECTORY_SEPARATOR.RELEASE_MAIN_PACKAGE;
	if( is_dir($mainPackageLibPath) ) {
		$configPath		= $mainPackageLibPath.DIRECTORY_SEPARATOR.'PackageConfig.class.php';
		$configClass	= RELEASE_MAIN_PACKAGE.'_PackageConfig';
		if( file_exists($configPath) ) {
			require_once($configPath);
			$obj		= new $configClass;
			$version	= $obj->getVersion();
			define('RELEASE_VERSION', $version);
			$obj		= null;
		}
	}
}
?>