<?php
/*
 * framework-spider
 * spider/tags/SetAttribute.class.php
 * 
 * CopyRight(C)Framework-Spider Developer Team. 2010. All Right Reserved. 
 * URL         : http://sourceforge.jp/projects/frameworkspider/
 * Mail        : frameworkspider-dev@lists.sourceforge.jp
 * Auther      : Masanori Nakashima
 * Modifier    : Masanori Nakashima
 * Last Updated: 2010.06.23
 * 
 */
require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'TagBase.class.php');
/**
 * HTML用変換タグ：setAttributeを実行するクラス
 * 
 * {set:[新たに登録する属性名] [属性名]->[メンバ名]}
 * {set:[新たに登録する属性名] [属性名][配列添え字]}
 * 
 * と指定することでオブジェクトや配列の中の値を属性として新たに設定することができます。
 * 
 * @package spider spiderのコアパッケージ
 * @version 1.2.00
 * @copyright Copyright &copy; 2008, <m_nakashima@users.sourceforge.jp> http://sourceforge.jp/projects/shopformer/
 * @author  m.nakashima <m_nakashima@users.sourceforge.jp>
 * @since PHP 4.3
 */
class spider_tags_SetAttribute extends spider_tags_TagBase {

	/**
	 * コンストラクタ
	 */
	function spider_tags_SetAttribute() {
		$this->priority	= 15;
	}
	/**
	 * コンバートメソッド
	 */
	function convert( &$result_strings, &$build_information ){
		// set の変換
		$tagStringsHash			= array();
		preg_match_all( '/\\{set\\:[^\\}]*?}/'
			, $result_strings
			, $tagStringsHash
			, PREG_PATTERN_ORDER );
		$valiable_counter	= 0;
		foreach ( $tagStringsHash as $tagStringsArray ) {
			foreach ( $tagStringsArray as $tagStrings ) {
				$optionStrings	= preg_replace( '/\\{set\\:/','', $tagStrings );
				$optionStrings	= preg_replace( '/\\}$/','', $optionStrings );
				$optionStrings	= trim( $optionStrings );
				if( strlen($optionStrings) > 0 ) {
					// オプションがあるなら分解
					$optionArray	= $this->splitOptionBySpace( $optionStrings );
					if( count($optionArray) < 2 ) {
						// オプション数が足りない場合
						$result_strings = str_replace( $tagStrings, '[set tag requre 2 parameters! '.$tagStrings.']', $result_strings );
					} else if( count($optionArray) == 2 ) {
						// オプション数が2つの場合
						// 新規登録属性名
						$attributeName	= trim(array_shift($optionArray));
						// 属性値
						$attibuteValue	= trim(array_shift($optionArray));
						if( preg_match('/^\'/',$attibuteValue) > 0 && preg_match('/\'$/',$attibuteValue) > 0 ) {
							// シングルクォートで全体が囲まれているなら
							$repCode	= '<?php $GLOBALS[\''.$attributeName.'\'] = '.$attibuteValue.'; ?>';
							$result_strings	= str_replace( $tagStrings, $repCode, $result_strings );
						} else if( preg_match('/\\:\\:/',$attibuteValue) > 0 ) {
							// コロン連続を含むなら下位互換
							$repCode	= $this->cnvOldCode( $attributeName, $attibuteValue );
							$result_strings	= str_replace( $tagStrings, $repCode, $result_strings );
						} else if( preg_match('/\\-\\>[a-zA-Z_][0-9a-zA-Z_]*$/',$attibuteValue) > 0 ) {
							// ''で囲まれないメンバ変数が記述されていたら下位互換
							$repCode	= $this->cnvOldCode( $attributeName, $attibuteValue );
							$result_strings	= str_replace( $tagStrings, $repCode, $result_strings );
						} else {
							// 含まないならPHPコード化
							$attributeNameArray	= array();
							$attributeValue	= $this->tagCode2NativeCode( $attibuteValue, $attributeNameArray );
							// 下位互換の為setAttributeも行う
							$repCode	= '<?php '
								.' $GLOBALS[\''.$attributeName.'\'] = '.$attributeValue.'; '
								.'$request->setAttribute(\''.$attributeName.'\',$GLOBALS[\''.$attributeName.'\']); ?>';
							$result_strings	= str_replace( $tagStrings, $repCode, $result_strings );
						}
					} else {
						// オプション数が3つ以上複数ある場合
						// 新規登録属性名
						$attributeName	= array_shift($optionArray);
						// 属性値はPHPコード化する
						$attributeValue	= '';
						foreach( $optionArray as $option ) {
							$attributeNameArray	= array();
							$attributeValue	.= ' '.$this->tagCode2NativeCode( $option, $attributeNameArray );
						}
						// 下位互換の為setAttributeも行う
						$repCode	= '<?php '
							.' $GLOBALS[\''.$attributeName.'\'] = '.$attributeValue.'; '
							.'$request->setAttribute(\''.$attributeName.'\',$GLOBALS[\''.$attributeName.'\']); ?>';
						$result_strings	= str_replace( $tagStrings, $repCode, $result_strings );
					}
				} else {
					// オプションパラメーターがないならエラー表示に切り替え
					$result_strings = str_replace( $tagStrings, '[set tag requre 2 parameters! '.$tagStrings.']', $result_strings );
				}
				$valiable_counter++;
			}
		}
		// presetタグの機能追加
		if( preg_match_all( '/\\{preset\\:[^\\}]*?\\}/'
			, $result_strings
			, $output_array
			, PREG_PATTERN_ORDER ) > 0 ) {
			foreach ( $output_array as $output ) {
				foreach ( $output as $target ) {
					$option_strings	= preg_replace( '/\\{preset\\:/','', $target );
					$option_strings	= preg_replace( '/\\}/','', $option_strings );
					$option_strings	= trim($option_strings);
					if( strpos($option_strings,' ') !== false ) {
						// 空白が存在するなら分割して復元
						$option_array	= $this->splitOptionBySpace( $option_strings );
						if( count($option_array) >= 2 ) {
							// パラメータが2つ以上ならモジュール実行前コードを追加
							$this->createPresetCode( $build_information, $option_array );
							// タグ行の削除
							$result_strings = str_replace( "\n".$target."\n", "", $result_strings );
							$result_strings = str_replace( $target, "", $result_strings );
						} else {
							// 空白が存在しないなら使い方が違うのでエラーメッセージを表示する
							$result_strings = str_replace( $target, "[preset tag requre 2 parameters! ".$target."]", $result_strings );
						}
					} else {
						// 空白が存在しないなら使い方が違うのでエラーメッセージを表示する
						$result_strings = str_replace( $target, "[preset tag requre 2 parameters! ".$target."]", $result_strings );
					}
				}
			}
		}
	}
	/**
	 * 旧setタグの変換ロジックで変換した個別変換文字列を取得します。
	 */
	function cnvOldCode( $var_name, $var_value ) {
		$var_name	= trim( $var_name );
		if( ( preg_match('/^"/',$var_name) > 0 && preg_match('/"$/',$var_name) > 0 )
			|| ( preg_match('/^\'/',$var_name) > 0 && preg_match('/\'$/',$var_name) > 0 )
		) {
			$var_name	= substr($var_name,1,strlen($var_name)-2);
		}
		$rep_string = "<?php ";
		if( preg_match('/^\\".+?\\"$/',$var_value) || preg_match('/^\\\'.+?\\\'$/',$var_value) ) {
			// 値がクォーテーションで囲まれている場合は中の値をそのまま登録する
			$rep_string .= '$tmp='.$var_value.'; ';
			$rep_string .= '$request_object->setAttribute( "' . $var_name . '",$tmp ); ';
			$rep_string .= '$GLOBALS["' . $var_name . '"] =$tmp; ';
		} else {
			// 値がクォーテーションで囲まれていない場合は、スコープから変数を探して登録
			if( preg_match('/\\:\\:/',$var_value) > 0 ) {
				// コロン二つがつく場合はオブジェクトかハッシュの属性自動判別
				list( $obj_name, $at_name )		= explode('::',$var_value);
				$rep_string .= '$tmp=$request_object->getAttribute( "' . $obj_name . '" ); ';
				$rep_string	.= '$type=gettype($tmp); ';
				if ( strlen(trim($at_name)) > 0 ) {
					$rep_string	.= 'if(\'array\'==$type) { ';
					$rep_string	.= '$tmp=$tmp[\''.$at_name.'\'];';
					$rep_string	.= ' } ';
					$rep_string	.= 'if(\'object\'==$type) { $tmp=$tmp->'.$at_name.'; } ';
				}
			} else if( preg_match('/\\->/',$var_value) > 0 ) {
				// オブジェクト指定子の場合はオブジェクトのメソッドまたはメンバ値である
				list( $obj_name, $member_strings )	= explode('->',$var_value);
				$rep_string .= '$tmp=$request_object->getAttribute( "' . $obj_name . '" ); ';
				$rep_string	.= '$type=gettype($tmp); ';
				$member_strings	= trim($member_strings);
				if( strlen($member_strings) > 0 ) {
					if( preg_match('/\\(/',$member_strings) > 0 && preg_match('/\\)$/',$member_strings) > 0 ) {
						// 開始括弧があり、閉じ括弧で終了しているならメソッドの引数部分を確認
						list( $method_name, $method_param_strings )	= explode('(',$member_strings );
						list( $method_param_strings )				= explode(')',$method_param_strings );
						$method_param_strings						= trim( $method_param_strings );
						$method_param_tmp_array						= explode(',',$method_param_strings);
						$method_param_array							= array();
						foreach( $method_param_tmp_array as $param ) {
							$param	= trim( $param );
							if( strlen( $param ) > 0 ) {
								if( ( preg_match('/^"/',$param) > 0 && preg_match('/"$/',$param) > 0 )
									|| ( preg_match('/^\'/',$param) > 0 && preg_match('/\'$/',$param) > 0 )
								) {
									// シングルクォートかダブルクォートで囲まれているなら固定文字列
									array_push( $method_param_array, $param );
								} else if( is_numeric($param) ){
									// 数値ならそのまま登録
									array_push( $method_param_array, $param );
								} else {
									// 文字列でないなら属性から取得
									$strmp	= '$request_object->getAttribute( "' . $param . '" ); ';
									array_push( $method_param_array, $strmp );
								}
							}
						}
						$rep_string	.= 'if(\'object\'==$type) { $tmp=$tmp->'.$method_name.'('.implode(',',$method_param_array).'); } ';
					} else {
						// 開始括弧も閉じ括弧もないならメンバ変数として処理
						$rep_string	.= 'if(\'object\'==$type) { $tmp=$tmp->'.$member_strings.'; } ';
					}
				}
			} else if( preg_match('/\\[/',$var_value) > 0 && preg_match('/\\[/',$var_value) > 0 ) {
				// 開始大括弧と閉じ大括弧があるなら配列・ハッシュと判断する
				list( $hash_name, $hash_key_strings )	= explode('[',$var_value );
				$rep_string .= '$tmp=$request_object->getAttribute( "' . $hash_name . '" ); ';
				$rep_string	.= '$type=gettype($tmp); ';
				list( $hash_key_strings )				= explode(']',$hash_key_strings );
				$hash_key_strings						= trim( $hash_key_strings );
				if( ( preg_match('/^"/',$hash_key_strings) > 0 && preg_match('/"$/',$hash_key_strings) > 0 )
					|| ( preg_match('/^\'/',$hash_key_strings) > 0 && preg_match('/\'$/',$hash_key_strings) > 0 )
				) {
					// キー文字列がクォートされているなら文字列としてそのまま利用
					$rep_string	.= 'if(\'array\'==$type) { $tmp=$tmp['.$hash_key_strings.']; } ';
				} else if( is_numeric($hash_key_strings) ) {
					// キー文字列が数値ならそのまま利用
					$rep_string	.= 'if(\'array\'==$type) { $tmp=$tmp['.$hash_key_strings.']; } ';
				} else {
					// キー文字列が数字でなくクォートされていないなら属性から取得
					if( preg_match('/\\:\\:/',$hash_key_strings) > 0 ) {
						// コロン二つがつく場合はオブジェクトかハッシュの属性自動判別
						list( $key_object_name, $key_at_name )		= explode('::',$hash_key_strings);
						$rep_string .= '$tmp_key=$request_object->getAttribute( "' . $key_object_name . '" ); ';
						$rep_string	.= '$type_key=gettype($tmp_key); ';
						if ( strlen(trim($key_at_name)) > 0 ) {
							$rep_string	.= 'if(\'array\'==$type_key) { $tmp_key=$tmp_key[\''.$key_at_name.'\']; } ';
							$rep_string	.= 'if(\'object\'==$type_key) { $tmp_key=$tmp_key->'.$key_at_name.'; } ';
							$rep_string	.= 'if(\'array\'==$type) { $tmp=$tmp[$tmp_key]; } ';
						}
					} else {
						// とりあえず配列キーではメソッド呼び出しはできない仕様。その他の場合はそのままgetAttribute
						$hash_key_strings	= '$request_object->getAttribute("'.$hash_key_strings.'")';
						$rep_string	.= 'if(\'array\'==$type) { $tmp=$tmp['.$hash_key_strings.']; } ';
					}
				}
			} else {
				// 単体文字列なら属性から取得
				$rep_string .= '$tmp = $request_object->getAttribute( "' . $var_value . '" ); ';
			}
			$rep_string .= '$request_object->setAttribute( "' . $var_name . '", $tmp ); ';
			$rep_string .= '$GLOBALS["' . $var_name . '"] =$tmp; ';
		}
		$rep_string .= " ?>";
		return $rep_string;
	}
	/**
	 * presetタグのパラメータを受け取って実行前コードを作成します
	 */
	function createPresetCode( &$build_information, $paramArray ) {
		$process_code	= '';
		if( count( $paramArray ) >= 2 ) {
			$name	= array_shift( $paramArray );
			if( preg_match('/^\\\'[^\\\']+\\\'$/',$name) > 0 ) {
				$name	= preg_replace('/^\\\'/','',$name);
				$name	= preg_replace('/\\\'$/','',$name);
			}
			if( preg_match('/^\\"[^\\\']+\\"$/',$name) > 0 ) {
				$name	= preg_replace('/^\\"/','',$name);
				$name	= preg_replace('/\\"$/','',$name);
			}
			$value	= implode(' ',$paramArray);
			$attributeNameArray	= array();
			$value	= $this->tagCode2NativeCode( $value, $attributeNameArray );
			$processCode	= '$GLOBALS[\''.$name.'\'] = '.$value.'; ';
			$processCode	.= '$request_object->setAttribute("'.$name.'", $GLOBALS[\''.$name.'\'] );'."\n";
			// ビルド情報に実行コードを追加
			if( !isset($build_information->processPreViewHash)
				|| !is_array($build_information->processPreViewHash) ){
				$build_information->processPreViewHash	= array();
			}
			if( !isset($build_information->processPreViewHash[$this->priority])
				|| !is_array($build_information->processPreViewHash[$this->priority]) ){
				$build_information->processPreViewHash[$this->priority]	= array();
			}
			array_push( $build_information->processPreViewHash[$this->priority], $processCode );
			return true;
		} else {
			return false;
		}
	}
}
?>