<?php define("CORE_PATH", dirname(__FILE__) . '/'); define("MODEL_PATH", CORE_PATH . "../Model/"); define("ACTION_PATH", CORE_PATH . "../Action/"); define("VIEW_PATH", CORE_PATH . "../View/"); define("TMPL_PATH", CORE_PATH . "../Tpl/"); define("CORE_CONFIG_PATH", CORE_PATH . "Conf/"); function load_runtime_file() { $file = array(CORE_PATH . "MVCCore.class.php", CORE_PATH . "App.class.php", CORE_PATH . "URLDispatch.class.php", CORE_PATH . "functions.php", CORE_PATH . "Action.class.php", VIEW_PATH . "View.class.php"); foreach ($file as $val) { require_once $val; } config(require_once CORE_CONFIG_PATH . "coreconfig.php"); } load_runtime_file(); MVCCore::init(); App::start(); App::exec();
/** * 次のFlowを特定し、ロードし、そのクラス名を返却する * @param string クラス名 * @param string ターゲットファイルパスのヒント * @return mixed 成功時は対象のクラス名 失敗した場合はFALSEを返す */ public static function loadNextFlow($argClassName = NULL, $argTargetPath = '') { // 先ずbackflowなのかどうか if ('backflow' === strtolower($argClassName)) { // backflowが特定出来無かった時ように強制的にIndexを指定しておく $argClassName = 'index'; if (strlen($argTargetPath) > 0) { $argClassName = $argTargetPath . '/' . $argClassName; } // PostパラメータからBackflowを特定する if (isset($_POST['flowpostformsection-backflow-section'])) { $argClassName = $_POST['flowpostformsection-backflow-section']; // if(FALSE !== strpos($argClassName, '/')){ // // sectionとtargetを分割する // $targetTmp = explode('/', $argClassName); // // 最後だけをsectionIDとして使う // $argClassName = $targetTmp[count($targetTmp)-1]; // unset($targetTmp[count($targetTmp)-1]); // $argTargetPath = implode('/', $targetTmp) . '/'; // } // if(FALSE !== strpos($argClassName, '-')){ // $argClassName = str_replace('-', '_', $argClassName); // } } // backflowはリダイレクトポスト(307リダイレクト) $query = ''; if (isset($_POST['flowpostformsection-backflow-section-query']) && strlen($_POST['flowpostformsection-backflow-section-query']) > 0) { $query = $_POST['flowpostformsection-backflow-section-query']; } header('Location: ./' . self::reverseRewriteURL('?_c_=' . $argClassName . '&_o_=' . $_GET['_o_'], $query), TRUE, 307); exit; } $className = MVCCore::loadMVCModule($argClassName, FALSE, $argTargetPath); debug('backflowClass=' . var_export($className, true)); return $className; }
/** * PUTメソッド リソースの新規作成、更新(冪等性を持ちます) * XXX モデルの位置付けが、テーブルリソースで無い場合は、継承して、RESTの”冪等性”に従って実装して下さい * @return mixed 成功時は最新のリソース配列 失敗時はFALSE */ public function put($argRequestParams = NULL) { $this->_init(); $gmtDate = Utilities::date('Y-m-d H:i:s', NULL, NULL, 'GMT'); $requestParams = array(); $resources = FALSE; if (NULL === $argRequestParams) { $requestParams = $this->getRequestParams(); } else { $requestParams = $argRequestParams; } debug('PUT param='); debug($requestParams); if (isset($requestParams['datas']) && isset($requestParams['datas'][0])) { // 配列のPOSTはリカーシブルで処理をする for ($requestIdx = 0; $requestIdx < count($requestParams['datas']); $requestIdx++) { $tmpRes = $this->put($requestParams['datas'][$requestIdx]); if (is_array($tmpRes) && isset($tmpRes[0])) { $resources[$requestIdx] = $tmpRes[0]; } else { return FALSE; } } } else { // 更新を行うリソースを特定する $baseQuery = ' 1=1 '; $baseBinds = NULL; if (TRUE === $this->restResource['me']) { // 認証ユーザーのリソース指定 // bind使うので自力で組み立てる $baseQuery = ' `' . $this->authUserIDFieldName . '` = :' . $this->authUserIDFieldName . ' '; $baseBinds = array($this->authUserIDFieldName => $this->authUserID); } // リソースの更新 // XXX 因みに更新はDEEP指定されていてもDEEPしない! if (NULL !== $this->restResource['ids'] && count($this->restResource['ids']) >= 1) { // id指定でループする for ($IDIdx = 0; $IDIdx < count($this->restResource['ids']); $IDIdx++) { // 空のモデルを先ず作る try { if (TRUE === $this->restResource['me'] && NULL !== $this->AuthUser && is_object($this->AuthUser) && strtolower($this->restResourceModel) == strtolower($this->AuthUser->tableName) && $this->restResource['ids'][$IDIdx] == $this->AuthUser->pkeyName) { // 自分自身のAuthモデルに対しての処理とする $Model = $this->AuthUser; $fields = $Model->getFieldKeys(); if (TRUE === $this->restResource['me'] && FALSE === in_array($this->authUserIDFieldName, $fields)) { // フィールドが無いなら$baseQueryを再初期化 $baseQuery = ' 1=1 '; $baseBinds = NULL; } } else { $Model = $this->_getModel($this->restResourceModel); $fields = $Model->getFieldKeys(); if (TRUE === $this->restResource['me'] && FALSE === in_array($this->authUserIDFieldName, $fields)) { // フィールドが無いなら$baseQueryを再初期化 $baseQuery = ' 1=1 '; $baseBinds = NULL; } $query = $baseQuery . ' AND `' . $Model->pkeyName . '` = :' . $Model->pkeyName . ' '; $binds = $baseBinds; if (NULL === $binds) { $binds = array(); } $binds[$Model->pkeyName] = $this->restResource['ids'][$IDIdx]; // 読み込み debug($query); debug($binds); $Model->load($query, $binds); } } catch (Exception $Exception) { // リソースが存在しない $this->httpStatus = 404; throw new RESTException($Exception->getMessage(), $this->httpStatus); break; } // 最初の一回目はバリデーションを必ず実行 if (0 === $IDIdx) { $datas = array(); if (FALSE === in_array($this->authUserIDFieldName, $fields)) { // フィールドが無いなら$baseQueryを再初期化 $baseQuery = ' 1=1 '; $baseBinds = NULL; } // オートバリデート try { for ($fieldIdx = 0; $fieldIdx < count($fields); $fieldIdx++) { if (isset($requestParams[$fields[$fieldIdx]])) { // XXX intのincrementとdecrimentは許可する if (FALSE === ('int' === $Model->describes[$fields[$fieldIdx]]['type'] && TRUE === ('increment' === strtolower($requestParams[$fields[$fieldIdx]]) || 'decrement' === strtolower($requestParams[$fields[$fieldIdx]])))) { // exec系以外はオートバリデート $Model->validate($fields[$fieldIdx], $requestParams[$fields[$fieldIdx]]); } // バリデートに成功したので更新値として認める $datas[$fields[$fieldIdx]] = $requestParams[$fields[$fieldIdx]]; } elseif ($fields[$fieldIdx] == $this->restResourceCreateDateKeyName && TRUE !== 0 < strlen($Model->{$this->restResourceCreateDateKeyName})) { // データ作成日付の自動補完 $datas[$fields[$fieldIdx]] = $gmtDate; } elseif ($fields[$fieldIdx] == $this->restResourceModifyDateKeyName) { // データ更新日付の自動補完 $datas[$fields[$fieldIdx]] = $gmtDate; } elseif ($fields[$fieldIdx] == $Model->pkeyName) { // Pkeyも入れえておく(複合キーの為の処理) $datas[$fields[$fieldIdx]] = $this->restResource['ids'][$IDIdx]; } elseif ($fields[$fieldIdx] == $this->authUserIDFieldName) { // 自分自身のIDを入れる $datas[$fields[$fieldIdx]] = $this->authUserID; } // Filterがあったらフィルター処理をする $filerName = str_replace(' ', '', ucwords(str_replace('_', ' ', $this->restResourceModel . ' ' . $fields[$fieldIdx]))) . 'Filter'; debug('$filerName=' . $filerName); if (FALSE !== MVCCore::loadMVCFilter($filerName, TRUE)) { $filterClass = MVCCore::loadMVCFilter($filerName); $Filter = new $filterClass(); $Filter->REST = $this; $Filter->Model = $Model; if (!isset($datas[$fields[$fieldIdx]])) { // 初期化 $datas[$fields[$fieldIdx]] = NULL; if (0 < strlen($Model->{$fields[$fieldIdx]})) { $datas[$fields[$fieldIdx]] = $Model->{$fields[$fieldIdx]}; } } debug('original value=' . $datas[$fields[$fieldIdx]]); $filterMethod = 'filter' . ucfirst(strtolower($_SERVER['REQUEST_METHOD'])); $datas[$fields[$fieldIdx]] = $Filter->{$filterMethod}($datas[$fields[$fieldIdx]]); debug('$filered value=' . $datas[$fields[$fieldIdx]]); } } } catch (Exception $Exception) { // バリデーションエラー(必須パラメータチェックエラー) $this->httpStatus = 400; throw new RESTException($Exception->getMessage(), $this->httpStatus); break; } } // POSTに従ってModelを更新する $Model->save($datas); // 更新の完了した新しいモデルのデータをレスポンスにセット $resources[] = $this->_convertArrayFromModel($Model); } } else { try { if (TRUE === $this->restResource['me'] && NULL !== $this->AuthUser && is_object($this->AuthUser) && strtolower($this->restResourceModel) == strtolower($this->AuthUser->tableName)) { // 自分自身のAuthモデルに対しての処理とする $Model = $this->AuthUser; } else { $Model = $this->_getModel($this->restResourceModel); } $datas = array(); $isDeepModel = FALSE; $deepDatas = array(); $fields = $Model->getFieldKeys(); if (TRUE === $this->restResource['me'] && FALSE === in_array($this->authUserIDFieldName, $fields)) { // フィールドが無いなら$baseQueryを再初期化 $baseQuery = ' 1=1 '; $baseBinds = NULL; } } catch (Exception $Exception) { // リソースが存在しない $this->httpStatus = 404; throw new RESTException($Exception->getMessage(), $this->httpStatus); } // オートバリデート for ($fieldIdx = 0; $fieldIdx < count($fields); $fieldIdx++) { if (isset($requestParams[$fields[$fieldIdx]])) { try { // XXX intのincrementとdecrimentは許可する if (FALSE === ('int' === $Model->describes[$fields[$fieldIdx]]['type'] && TRUE === ('increment' === strtolower($requestParams[$fields[$fieldIdx]]) || 'decrement' === strtolower($requestParams[$fields[$fieldIdx]])))) { // exec系以外はオートバリデート $Model->validate($fields[$fieldIdx], $requestParams[$fields[$fieldIdx]]); } // バリデートに成功したので更新値として認める $datas[$fields[$fieldIdx]] = $requestParams[$fields[$fieldIdx]]; } catch (Exception $Exception) { // バリデーションエラー(必須パラメータチェックエラー) $this->httpStatus = 400; throw new RESTException($Exception->getMessage(), $this->httpStatus); break; } } elseif (TRUE === $this->deepRESTMode && strlen($fields[$fieldIdx]) - 3 === strpos($fields[$fieldIdx], '_id') && $this->authUserIDFieldName != $fields[$fieldIdx]) { $deepResource = substr($fields[$fieldIdx], 0, -3); $deepResourcePath = $deepResource; if (TRUE === $this->restResource['me']) { $deepResourcePath = 'me/' . $deepResource; } debug('deep??' . $deepResourcePath . ' & ' . $this->authUserIDFieldName . ' & ' . $fields[$fieldIdx] . ' & ' . (strlen($fields[$fieldIdx]) - 3) . ' & ' . strpos($fields[$fieldIdx], '_id')); $isDeepModel = TRUE; try { $deepModel = $this->_getModel($deepResource); } catch (Exception $Exception) { $isDeepModel = FALSE; } if (TRUE === $isDeepModel) { // deepRESTを実行し、IDの取得をする $DeepREST = new REST(); $DeepREST->AuthUser = $this->AuthUser; $DeepREST->authUserID = $this->authUserID; $DeepREST->authUserIDFieldName = $this->authUserIDFieldName; $DeepREST->authUserQuery = $this->authUserQuery; $DeepREST->rootREST = FALSE; $res = $DeepREST->execute($deepResourcePath, $requestParams); $datas[$fields[$fieldIdx]] = $res[0]['id']; $deepDatas[$deepResource] = $res; } } elseif (TRUE === $this->deepRESTMode && $this->authUserIDFieldName == $fields[$fieldIdx]) { // ログインIDの自動補完 $datas[$fields[$fieldIdx]] = $this->authUserID; } elseif ($fields[$fieldIdx] == $this->restResourceCreateDateKeyName && TRUE !== 0 < strlen($Model->{$this->restResourceCreateDateKeyName})) { // データ作成日付の自動補完 $datas[$fields[$fieldIdx]] = $gmtDate; } elseif ($fields[$fieldIdx] == $this->restResourceModifyDateKeyName) { // データ更新日付の自動補完 $datas[$fields[$fieldIdx]] = $gmtDate; } // Filterがあったらフィルター処理をする $filerName = str_replace(' ', '', ucwords(str_replace('_', ' ', $this->restResourceModel . ' ' . $fields[$fieldIdx]))) . 'Filter'; debug('$filerName=' . $filerName); if (FALSE !== MVCCore::loadMVCFilter($filerName, TRUE)) { $filterClass = MVCCore::loadMVCFilter($filerName); debug($filterClass); $Filter = new $filterClass(); $Filter->REST = $this; $Filter->Model = $Model; if (!isset($datas[$fields[$fieldIdx]])) { // 初期化 $datas[$fields[$fieldIdx]] = NULL; if (0 < strlen($Model->{$fields[$fieldIdx]})) { $datas[$fields[$fieldIdx]] = $Model->{$fields[$fieldIdx]}; } } debug('original value=' . $datas[$fields[$fieldIdx]]); $filterMethod = 'filter' . ucfirst(strtolower($_SERVER['REQUEST_METHOD'])); $datas[$fields[$fieldIdx]] = $Filter->{$filterMethod}($datas[$fields[$fieldIdx]]); debug('$filered value=' . $datas[$fields[$fieldIdx]]); } } // POSTに従ってModelを作成する $Model->save($datas); // 更新の完了した新しいモデルのデータをレスポンスにセット $resources[] = $this->_convertArrayFromModel($Model); if (TRUE === $isDeepModel && 0 < count($deepDatas)) { foreach ($deepDatas as $key => $val) { $resources[count($resources) - 1][$key] = $val; } } } } return $resources; }
/** * MVCクラスモジュールの読み込み処理 * @param string クラス名 * @param string クラスの読み込事にエラーが在る場合にbooleanを返すかどうか * @param string クラスの読み込事にエラーが在る場合にbooleanを返すかどうか * @return mixed 成功時は対象のクラス名 失敗した場合はFALSEを返す */ public static function loadMVCModule($argClassName = NULL, $argClassExistsCalled = FALSE, $argTargetPath = '') { static $currentTargetPath = ''; $targetPath = ''; if (NULL !== $argClassName) { $controlerClassName = $argClassName; } else { // コントロール対象を自動特定 $controlerClassName = 'Index'; if (isset($_GET['_c_']) && strlen($_GET['_c_']) > 0) { $controlerClassName = str_replace('-', '_', ucfirst($_GET['_c_'])); if (FALSE !== strpos($_GET['_c_'], '/') && strlen($_GET['_c_']) > 1) { $matches = NULL; if (preg_match('/(.*)\\/([^\\/]*)$/', $_GET['_c_'], $matches) && is_array($matches) && isset($matches[2])) { $controlerClassName = str_replace('-', '_', ucfirst($matches[2])); if (isset($matches[1]) && strlen($matches[1]) > 0) { $targetPath = $matches[1] . '/'; if ('' === $currentTargetPath) { $currentTargetPath = $targetPath; } } } } } } if ('' !== $argTargetPath) { $targetPath = $argTargetPath; } if ('' === $targetPath) { $targetPath = $currentTargetPath; } $version = ''; if (isset($_GET['_v_']) && strlen($_GET['_v_']) > 0) { $version = $_GET['_v_']; } debug('path=' . $targetPath); debug('class=' . $controlerClassName); if (!class_exists($controlerClassName, FALSE)) { // コントローラを読み込み if ('' !== $version) { // バージョン一致のファイルを先ず走査する loadModule('default.controlmain.' . $targetPath . $version . '/' . $controlerClassName, TRUE); } if (!class_exists($controlerClassName, FALSE)) { loadModule('default.controlmain.' . $targetPath . $controlerClassName, TRUE); } if (!class_exists($controlerClassName, FALSE)) { loadModule('default.controlmain.' . $controlerClassName, TRUE); } if (class_exists($controlerClassName, FALSE)) { // FlowGenerateする必要がなさそうなのでココで終了 return $controlerClassName; } else { if ('' === self::$flowXMLBasePath) { // エラー終了 return FALSE; } else { // ココからはFlow処理 if (TRUE === self::$flowXMLBasePath) { // self::$flowXMLBasePathがTRUEとなっていた場合はConfigureにFLOWXML_PATH定義が無いか調べる if (class_exists('Configure', FALSE) && NULL !== Configure::constant('FLOWXML_PATH')) { self::$flowXMLBasePath = Configure::FLOWXML_PATH; } } // Flow出来ない! if ('' === self::$flowXMLBasePath) { // エラー終了 return FALSE; } // XML定義の存在チェック // クラス名は分解しておく $classHint = explode('_', $controlerClassName); debug($targetPath); debug($classHint); $classXMLName = $classHint[0]; debug($classXMLName); $flowXMLPath = ''; if ('' !== $version) { // バージョン一致のファイルを先ず走査する if (file_exists_ip(self::$flowXMLBasePath . '/' . $targetPath . $version . '/' . $classXMLName . '.flow.xml')) { $flowXMLPath = self::$flowXMLBasePath . '/' . $targetPath . $version . '/' . $classXMLName . '.flow.xml'; } } if ('' === $flowXMLPath) { // バージョン関係ナシのファイルを走査する if (file_exists_ip(self::$flowXMLBasePath . '/' . $targetPath . $classXMLName . '.flow.xml')) { $flowXMLPath = self::$flowXMLBasePath . '/' . $targetPath . $classXMLName . '.flow.xml'; } } debug($flowXMLPath); if ('' === $flowXMLPath) { // エラー終了 return FALSE; } // flowファイルの履歴を残しておく self::$flowXMLPaths[] = array('class' => $controlerClassName, 'xml' => $flowXMLPath); // Flowに応じたクラス定義の自動生成を委任 loadModule('Flow'); if (FALSE === Flow::generate($flowXMLPath, $controlerClassName, $targetPath)) { // エラー終了 return FALSE; } if (!class_exists($controlerClassName, FALSE)) { // エラー終了 return FALSE; } } } } return $controlerClassName; }