<?php
/*
 * database2/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-06-18
 */
require_once(dirname(__FILE__)
.DIRECTORY_SEPARATOR.'PackageConfig.class.php');
require_once(dirname(__FILE__)
.DIRECTORY_SEPARATOR.'Connection.class.php');
require_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'util'.DIRECTORY_SEPARATOR.'CharUtility.class.php');
/**
 * データベースパッケージ拡張用PackageConfigBaseクラス
 * 
 * - 概要
 * データベースパッケージを必要とするパッケージのPackageConfigクラスを作成する場合
 * 本クラスを拡張して作成すれば基本的なテーブル作成SQLファイル実行などの機能を提供
 * することができます。
 * 
 * - 対応データベース
 *   MySQL
 *   PostgreSQL
 * - パッケージの詳細
 * 
 * @package database データベースパッケージ
 * @version 1.0.0
 * @author  <m_nakashima@users.sourceforge.jp>
 * @since PHP 4.3
 * 
 */
class database2_PackageConfigBase extends system_package_PackageConfigBase {
	function database2_PackageConfigBase() {
	}
	/**
	 * パッケージ初期化オプション変換文字列をパッケージ名に即した文字列に変換します。
	 */
	function convertPackageInitOptionName( $str ) {
		$class_name		= get_class($this);
		$package_name	= substr($class_name, 0, strpos($class_name,'_') );
		if( !is_array($this->definitionHash) || count($this->definitionHash) == 0 ) {
			$this->definitionHash					= array(
				strtoupper($package_name.'_init_option')		=> '2',
			);
		}
		$str		= str_replace( 'package_init_option', strtoupper($package_name.'_init_option'), $str );
		return $str;
	}
	/**
	 * インストールチェックを行います。
	 */
	function validateDifinitionHash( & $request ) {
		
		$database_config	= new database2_PackageConfig();
		if( $database_config->load( $request ) ) {
		} else {
			$database_config	= $request->getAttribute('database.configuration_object');
			if( is_null($database_config) || get_class($database_config) != get_class(new database2_PackageConfig()) ) {
				$request->addLocaledError('database2.error.extconfig.nodb2package',SPIDER_LOG_LEVEL_FATAL,array($this->getPackageViewName()));
			}
		}
		if( !$request->isError() ) {
			$class_name		= get_class($this);
			$package_name	= substr($class_name, 0, strpos($class_name,'_') );
			if( !is_array($this->definitionHash) || count($this->definitionHash) == 0 ) {
				$this->definitionHash					= array(
					strtoupper($package_name.'_init_option')			=> '2',
				);
			}
			parent::validateDifinitionHash( $request );
			
			// 2010-03-09 データベース接続２がインストール済みの場合のみ接続チェックする
			$installedIdHash	= $request->getAttribute('system.package.installedPackageObjectHash');
			$installObjectHash	= $request->getAttribute('system.package.install.install_object_hash');
			if( array_key_exists('database2',$installedIdHash) ) {
				$connection	= $database_config->getWritableConnection( $request );
				if( $connection ) {
					$init_option	= $this->definitionHash[strtoupper($package_name.'_init_option')];
					$table_hash		= $this->getRequireTableHash( $request );
					if( '1' == $init_option ) {
						// [既存テーブルを利用]の場合は存在チェック
						foreach( $table_hash as $tableName => $sql ) {
							if( $connection->existsTable( $tableName ) ) {
							} else {
								$request->addLocaledError('database2.error.extconfig.notable',SPIDER_LOG_LEVEL_FATAL,array($tableName));
							}
						}
					} else if( '2' == $init_option ) {
						// [テーブルがなければ作成]の場合も何もしない
					} else if( '3' == $init_option ) {
						// [テーブルを削除して作成]の場合は削除する
					} else {
						$request->addLocaledError('database2.error.extconfig.invalidoption',SPIDER_LOG_LEVEL_FATAL,array($this->getPackageViewName()));
					}
					$connection->disconnect();
				} else {
					$request->addLocaledError('database2.error.connect',SPIDER_LOG_LEVEL_FATAL,array());
				}
			} else if( array_key_exists('database2',$installObjectHash) ) {
				// インストールする
			} else {
				// インストールされていなくて新規にもしない
				$request->addLocaledError('database2.error.extconfig.nodb2package',SPIDER_LOG_LEVEL_FATAL,array($this->getPackageViewName()));
			}
		}

		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * インストールを実行します。
	 */
	function install( & $request ) {
		if( !parent::install( $request ) ) {
			return false;
		}
		$database_config	= new database2_PackageConfig();
		if( $database_config->load( $request ) ) {
		} else {
			$database_config	= $request->getAttribute('database.configuration_object');
			if( is_null($database_config) || get_class($database_config) != get_class(new database2_PackageConfig()) ) {
				$request->addLocaledError('database2.error.extconfig.nodb2package',SPIDER_LOG_LEVEL_FATAL,array($this->getPackageViewName()));
			}
		}
		if( !$request->isError() ) {
			$class_name		= get_class($this);
			$package_name	= substr($class_name, 0, strpos($class_name,'_') );
			if( !is_array($this->definitionHash) || count($this->definitionHash) == 0 ) {
				$this->definitionHash					= array(
					strtoupper($package_name.'_init_option')			=> '2',
				);
			}
			$message_array	= array();
			$connection	= $database_config->getWritableConnection( $request );
			if( $connection ) {
				$init_option		= $this->definitionHash[strtoupper($package_name.'_init_option')];
				$database_charset	= $database_config->definitionHash['DATABASE_DATABASE_CHARSET'];
				$sql_array			= $this->getCreateQueryArray( $request );
				$createdTableNameArray	= array();
				if( is_array( $sql_array ) ) {
					$connection->beginTransaction();
					
					if( '3' == $init_option ) {
						// [テーブルを削除して作成]の場合は削除する
						$sqlArrayCopy	= $sql_array;
						while( $sql = array_pop($sqlArrayCopy) ) {
							if( $tableName	= $this->getTargetSqlTableName( $sql ) ) {
								if( $connection->existsTable( $tableName ) ) {
									// テーブルが存在するなら
									$sql	= 'DROP TABLE '.$tableName;
									if( $connection->query( $sql ) ) {
									} else {
										$request->addLocaledError('database2.error.extconfig.failtodroptable',SPIDER_LOG_LEVEL_FATAL,array($tableName));
									}
								}
							}
						}
					}
					foreach( $sql_array as $sql ) {
						if( $tableName	= $this->getTargetSqlTableName( $sql ) ) {
							if( $connection->existsTable( $tableName ) ) {
								// テーブルが存在するなら何もしない
							} else {
								// テーブルが存在しないなら
								if( '1' == $init_option ) {
									// [既存テーブルを利用]の場合はエラー
									$request->addLocaledError('database2.error.extconfig.notable',SPIDER_LOG_LEVEL_FATAL,array($tableName));
								} else if( '2' == $init_option || '3' == $init_option ) {
									// テーブルを作成する
									if( 'UTF-8' != $database_charset && mb_detect_encoding($sql) != $database_charset ) {
										$sql	= mb_convert_encoding( $sql, $database_charset, 'UTF-8' );
									}
									$result = $connection->query( $sql );
									if( $result === false ) {
										$request->addLocaledError('database2.error.extconfig.failtocreatetable',SPIDER_LOG_LEVEL_FATAL,array($tableName));
									} else {
										array_push($message_array,$tableName.'テーブルを作成しました。' );
										array_push( $createdTableNameArray, $tableName );
									}
									// テーブルを作成した時のみ初期データSQL文を実行する
									$initialQueryArray	= $this->getInitialQueryArray( $request, $tableName );
									if( $initialQueryArray ) {
										// 初期データSQLファイルがあるなら実行
										foreach( $initialQueryArray as $initialQuery ) {
											if( strlen(trim($initialQuery)) > 0 ) {
												// そのまま実行
												$result = $connection->query( $initialQuery );
												if( $result === false ) {
													$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($connection->error_message.':'.$initialQuery));
												} else {
													array_push($message_array,'クエリ成功:' . $initialQuery );
												}
											}
										}
									}
								}
							}
						} else {
							if( preg_match('/^[cC][rR][eE][aA][tT][eE](\\s)[iI][nN][dD][eE][xX]/',$sql) > 0 ) {
								// クエリがインデックス作成文の場合
								$indexTableName	= trim(preg_replace('/^[cC][rR][eE][aA][tT][eE]\\s[iI][nN][dD][eE][xX](\\s)+(.)+[oO][nN]/','',$sql));
								$indexTableName	= trim(substr($indexTableName,0,strpos($indexTableName,'(')));
								if( in_array($indexTableName,$createdTableNameArray) ) {
									// 今回作成したテーブルに含まれているならインデックス作成を実行
									if( 'UTF-8' != $database_charset && mb_detect_encoding($sql) != $database_charset ) {
										$sql	= mb_convert_encoding( $sql, $database_charset, 'UTF-8' );
									}
									$result = $connection->query( $sql );
									if( $result === false ) {
										$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($connection->error_message.':'.$sql));
									} else {
										array_push($message_array,'クエリ成功:' . $sql );
									}
								}
							} else {
								// インデックス作成文ではない場合そのまま実行
								$result = $connection->query( $sql );
								if( $result === false ) {
									$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($connection->error_message.':'.$sql));
								} else {
									array_push($message_array,'クエリ成功:' . $sql );
								}
							}
						}
					}
					if( $request->isError() ) {
						$connection->rollback();
					} else {
						$connection->commit();
					}
				}
				$connection->disconnect();
			} else {
				$request->addLocaledError('database2.error.connect',SPIDER_LOG_LEVEL_FATAL,array($connection->error_message));
			}
		}
		// インストールが完了したら初期化オプションは既存テーブル利用に変更
		$this->definitionHash[strtoupper($package_name.'_init_option')]	= 1;
		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * アンインストールを実行します。
	 */
	function uninstall( & $request ) {
		$database_config	= new database2_PackageConfig();
		if( $database_config->load( $request ) ) {
			$class_name		= get_class($this);
			$package_name	= substr($class_name, 0, strpos($class_name,'_') );
			$connection	= $database_config->getWritableConnection( $request );
			if( $connection ) {
				$table_hash				= $this->getRequireTableHash( $request );
				$tableName_rev_array	= array();
				foreach( $table_hash as $tableName => $sql ) {
					array_unshift( $tableName_rev_array, $tableName );
				}
				$connection->beginTransaction();
				foreach( $tableName_rev_array as $tableName ) {
					if( $connection->existsTable( $tableName ) ) {
						// テーブルが存在するなら
						$sql	= 'DROP TABLE '.$tableName;
						if( $connection->query( $sql ) ) {
						} else {
							$request->addLocaledError('database2.error.extconfig.failtodroptable',SPIDER_LOG_LEVEL_FATAL,array($tableName));
						}
					} else {
						// テーブルが存在しないなら何もしない
					}
				}
				if( $request->isError() ) {
					$connection->rollback();
				} else {
					$connection->commit();
				}
				$connection->disconnect();
			}
		} else {
			$request->addLocaledError('database2.error.connect',SPIDER_LOG_LEVEL_FATAL,array($connection->error_message));
		}
		parent::uninstall($request);
		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * 本パッケージオブジェクトで作成するテーブル名=>CREATE文のハッシュを取得します
	 */
	function getRequireTableHash( & $request ) {
		// 全てのsql文を取得
		$sql_array	= $this->getCreateQueryArray( $request );
		// sql文が読み込めたら
		if( $sql_array ) {
			// sql文があるならCREATE TABLE文を抜き出し
			$return_array	= array();
			foreach( $sql_array as $sql ) {
				if( $tableName	= $this->getTargetSqlTableName( $sql ) ) {
					$return_array[$tableName]	= $sql;
				}
			}
			return $return_array;
		} else {
			return array();
		}
	}
	/**
	 * 本パッケージオブジェクトで利用するテーブル作成SQL文の配列を取得します
	 */
	function getCreateQueryArray( & $request ) {
		$database_config	= new database2_PackageConfig();
		if( $database_config->load( $request ) ) {
			// テーブル作成ファイル
			$sqlFilePath	= null;
			$install_dir	= $this->getPackageConfigurationInfoDir();
			if( $database_config->definitionHash['DATABASE_DATABASE_TYPE'] == 'pgsql' ) {
				$sqlFilePath	= $install_dir.DIRECTORY_SEPARATOR.'create_table_pgsql.sql';
			} else {
				$sqlFilePath	= $install_dir.DIRECTORY_SEPARATOR.'create_table_mysql.sql';
			}
			// 全てのsql文を取得
			$sql_array	= database2_Connection::getQueryArrayFromFile( $sqlFilePath );
			return $sql_array;
		} else {
			return false;
		}
	}
	/**
	 * 本パッケージオブジェクトで利用する初期インサートデータのSQL文をテーブルごとに取得します
	 */
	function getInitialQueryArray( & $request, $tableName ) {
		$database_config	= new database2_PackageConfig();
		if( $database_config->load( $request ) ) {
			// テーブル作成ファイル
			$sqlFilePath	= null;
			$install_dir	= $this->getPackageConfigurationInfoDir();
			$sqlFilePath	= $install_dir.DIRECTORY_SEPARATOR.'initial_data_'.$tableName.'.sql';
			if( file_exists($sqlFilePath) ) {
				// 全てのsql文を取得
				$sql_array	= database2_Connection::getQueryArrayFromFile( $sqlFilePath );
				return $sql_array;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	/**
	 * 渡されたSQL文がCREATE TABLE文ならテーブル名を返す
	 */
	function getTargetSqlTableName( $query ) {
		if( preg_match('/^[cC][rR][eE][aA][tT][eE]\\s+[tT][aA][bB][lL][eE]/', $query ) > 0 ) {
			// create table文ならCREATE TABLE部分と最初の(移行を削除してテーブル名を取得
			$tableName	= preg_replace('/^[cC][rR][eE][aA][tT][eE]\\s+[tT][aA][bB][lL][eE]\\s+/', '', $query );
			if( strpos( $tableName, '(' ) !== false ) {
				$tableName	= trim(substr( $tableName, 0, strpos( $tableName, '(' ) ));
			}
			return $tableName;
		}
		return false;
	}
}
?>