/** * RESTする * @return array 配列構造のリソースデータ */ public function execute($argResourceHint = NULL, $argRequestParams = NULL) { static $prepend = FALSE; static $append = FALSE; $this->_init(); debug($this->restResource); // RESTアクセスされるリソースの特定 $this->restResource = $argResourceHint; if (NULL === $argResourceHint) { $this->restResource = $_GET['_r_']; } if (isset($_GET['_deep_']) && TRUE == ('0' === $_GET['_deep_'] || 'false' === strtolower($_GET['_deep_']))) { // RESTのDEEPモードを無効にする // XXX DEEPモードがTRUEの場合、[model名]_idのフィールドがリソースに合った場合、そのリソースまで自動で参照・更新・作成を試みます $this->deepRESTMode = FALSE; } if (isset($_SERVER['REQUEST_METHOD'])) { $this->requestMethod = strtoupper($_SERVER['REQUEST_METHOD']); if (isset($_POST['_method_']) && strlen($_POST['_method_']) > 0) { $this->requestMethod = strtoupper($_POST['_method_']); } } debug($this->restResource); debug('rest method=' . strtolower($this->requestMethod)); $resource = self::resolveRESTResource($this->restResource); debug($resource); if (NULL === $resource) { // リソースの指定が無かったのでエラー終了 $this->httpStatus = 400; throw new RESTException(__CLASS__ . PATH_SEPARATOR . __METHOD__ . PATH_SEPARATOR . __LINE__, 400); } if ('GET' !== $this->requestMethod && 'HEAD' !== $this->requestMethod && 'POST' !== $this->requestMethod && NULL === $resource['ids']) { // GET,POST以外のメソッドの場合はリソースID指定は必須 $this->httpStatus = 400; throw new RESTException(__CLASS__ . PATH_SEPARATOR . __METHOD__ . PATH_SEPARATOR . __LINE__, 400); } $res = FALSE; $DBO = NULL; try { $DBO = self::_getDBO(); // RESTの実行 $this->restResourceModel = $resource['model']; if (NULL === $this->restResourceListed) { $this->restResourceListed = $resource['listed']; } $this->restResource = $resource; // Prepend処理 if (TRUE === $this->rootREST && FALSE === $prepend) { $prepend = TRUE; // Filterがあったらフィルター処理をする $filerName = 'RestPrependFilter'; debug('$filerName=' . $filerName); if (FALSE !== MVCCore::loadMVCFilter($filerName, TRUE)) { $filterClass = MVCCore::loadMVCFilter($filerName); $Filter = new $filterClass(); $Filter->REST = $this; $Filter->execute($argRequestParams); } } $classHint = str_replace(' ', '', ucwords(str_replace(' ', '', $this->restResourceModel))); debug('$classHint=' . $classHint); if (FALSE !== MVCCore::loadMVCModule($classHint, TRUE)) { debug('RestClassLoaded'); // オーバーライドされたModelへのリソース操作クラスが在る場合は、それをnewして実行する $className = MVCCore::loadMVCModule($classHint); $RestController = new $className(); // 自分自身の持っているパブリックパラメータをブリッジ先のRestControllerに引き渡す $RestController->controlerClassName = $this->restResourceModel; $RestController->httpStatus = $this->httpStatus; $RestController->outputType = $this->outputType; $RestController->requestMethod = $this->requestMethod; $RestController->restResource = $this->restResource; $RestController->jsonUnescapedUnicode = $this->jsonUnescapedUnicode; $RestController->deviceType = $this->deviceType; $RestController->appVersion = $this->appVersion; $RestController->appleReviewd = $this->appleReviewd; $RestController->mustAppVersioned = $this->mustAppVersioned; $RestController->deepRESTMode = $this->deepRESTMode; $RestController->restResource = $this->restResource; $RestController->restResourceModel = $this->restResourceModel; $RestController->restResourceListed = $this->restResourceListed; $RestController->restResourceCreateDateKeyName = $this->restResourceCreateDateKeyName; $RestController->restResourceModifyDateKeyName = $this->restResourceModifyDateKeyName; $RestController->AuthUser = $this->AuthUser; $RestController->authUserID = $this->authUserID; $RestController->authUserIDFieldName = $this->authUserIDFieldName; $RestController->authUserQuery = $this->authUserQuery; // リクエストメソッドで分岐する if ('POST' === $this->requestMethod || 'PUT' === $this->requestMethod) { $res = $RestController->{strtolower($this->requestMethod)}($argRequestParams); } else { $res = $RestController->{strtolower($this->requestMethod)}(); } // 結果のパラメータを受け取り直す $this->httpStatus = $RestController->httpStatus; $this->outputType = $RestController->outputType; $this->requestMethod = $RestController->requestMethod; $this->restResource = $RestController->restResource; $this->jsonUnescapedUnicode = $RestController->jsonUnescapedUnicode; $this->deviceType = $RestController->deviceType; $this->appVersion = $RestController->appVersion; $this->appleReviewd = $RestController->appleReviewd; $this->mustAppVersioned = $RestController->mustAppVersioned; $this->deepRESTMode = $RestController->deepRESTMode; $this->restResource = $RestController->restResource; $this->restResourceModel = $RestController->restResourceModel; $this->restResourceListed = $RestController->restResourceListed; $this->restResourceCreateDateKeyName = $RestController->restResourceCreateDateKeyName; $this->restResourceModifyDateKeyName = $RestController->restResourceModifyDateKeyName; $this->AuthUser = $RestController->AuthUser; $this->authUserID = $RestController->authUserID; $this->authUserIDFieldName = $RestController->authUserIDFieldName; $this->authUserQuery = $RestController->authUserQuery; } else { // リクエストメソッドで分岐する $res = $this->{strtolower($this->requestMethod)}(); } // Append処理 if (TRUE === $this->rootREST && FALSE === $append) { $append = TRUE; // Filterがあったらフィルター処理をする $filerName = 'RestAppendFilter'; debug('$filerName=' . $filerName); if (FALSE !== MVCCore::loadMVCFilter($filerName, TRUE)) { $filterClass = MVCCore::loadMVCFilter($filerName); $Filter = new $filterClass(); $Filter->REST = $this; $Filter->execute($argRequestParams); } } // トランザクションを正常終了する $DBO->commit(); } catch (Exception $Exception) { if (NULL !== $DBO && is_object($DBO)) { // トランザクションを異常終了する $DBO->rollback(); } // 実装の問題によるエラー $this->httpStatus = 500; if (400 === $Exception->getCode() || 401 === $Exception->getCode() || 404 === $Exception->getCode() || 405 === $Exception->getCode() || 503 === $Exception->getCode()) { $this->httpStatus = $Exception->getCode(); } throw new RESTException($Exception->getMessage(), $this->httpStatus); } debug('res='); debug($res); if (TRUE === $res) { $res = array('success' => TRUE); } if (FALSE === $res || TRUE !== is_array($res)) { // XXX ココを通るのは相当なイレギュラー! // 恐らく実装の問題 $this->httpStatus = 500; throw new RESTException(__CLASS__ . PATH_SEPARATOR . __METHOD__ . PATH_SEPARATOR . __LINE__, 400); } if (TRUE === is_array($res) && 'HEAD' !== $this->requestMethod) { if ('html' === $this->outputType) { debug('convert html'); $basehtml = ''; $URIs = explode('?', $_SERVER['REQUEST_URI']); if ("index" === strtolower($this->restResourceModel)) { $basehtml .= '<h2>Table List</h2>' . PHP_EOL; $basehtml .= '<ul>' . PHP_EOL; for ($idx = 0; $idx < count($res); $idx++) { $basehtml .= '<li><a class="tablelink" id="table_' . $res[$idx] . '" href="' . str_replace('/index.html', '/', $URIs[0]) . $res[$idx] . '.html">' . $res[$idx] . '</a></li>' . PHP_EOL; } $basehtml .= '</ul>' . PHP_EOL; } else { $requestParams = $this->getRequestParams(); $basehtml .= '<h2>' . $this->restResourceModel . '</h2>' . PHP_EOL; if (TRUE === $this->restResourceListed) { $basehtml .= '<h3><form id="crud-form-search" class="crud-form" method="GET"><input type="text" value="' . (isset($requestParams['LIKE']) ? $requestParams['LIKE'] : '') . '" name="LIKE"/><div class="submit-button search-button"><input type="submit" value="search"/></div></form></h3>' . PHP_EOL; if (isset($res[0])) { $basehtml .= '<table class="list">' . PHP_EOL; // リストヘッダ $basehtml .= '<tr>' . PHP_EOL; foreach ($res[0] as $key => $val) { $order = $requestParams['ORDER']; if (strlen($order) > 0 && 0 === strpos($order, $key) && FALSE !== strpos($order, 'DESC')) { $order = rawurlencode($key . ' ASC'); } else { $order = rawurlencode($key . ' DESC'); } $basehtml .= '<th class="crudkey"><a class="crudlink" id="crud_order_' . $this->restResourceModel . '_' . $key . '" href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=0&total=' . $requestParams['total'] . '&ORDER=' . $order . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">' . $key . '</a></th>'; } $basehtml .= '</tr>' . PHP_EOL; for ($idx = 0; $idx < count($res); $idx++) { $basehtml .= '<tr>' . PHP_EOL; $id = ''; foreach ($res[$idx] as $key => $val) { if ('' === $id) { $id = $val; } $basehtml .= '<td><a class="crudlink" id="crud_' . $this->restResourceModel . '_' . $id . '" target="_blank" href="' . str_replace('/' . $this->restResourceModel . '.html', '/' . $this->restResourceModel . '/' . $id . '.html', $URIs[0]) . '">' . $val . '</a></td>'; } $basehtml .= '</tr>' . PHP_EOL; } $basehtml .= '</table>' . PHP_EOL; if (isset($requestParams['LIMIT']) && is_numeric($requestParams['LIMIT']) && (int) $requestParams['LIMIT'] > 0 && isset($requestParams['OFFSET']) && is_numeric($requestParams['OFFSET']) && isset($requestParams['total']) && is_numeric($requestParams['total']) && (int) $requestParams['total'] > 0) { // ページング $nowPage = floor((int) $requestParams['OFFSET'] / (int) $requestParams['LIMIT']) + 1; if (1 < floor((int) $requestParams['total'] / (int) $requestParams['LIMIT']) + 1) { $basehtml .= '<table class="paging"><tr>' . PHP_EOL; if ($nowPage > 1) { // 先頭リンク $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=0&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '"><<</a></td>' . PHP_EOL; // 前へリンク $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . ((int) $requestParams['OFFSET'] - (int) $requestParams['LIMIT']) . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '"><</a></td>' . PHP_EOL; } // 2つ前のページ if ($nowPage - 2 > 0) { $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . ((int) $requestParams['OFFSET'] - (int) $requestParams['LIMIT'] * 2) . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">' . ($nowPage - 2) . '</a></td>' . PHP_EOL; } // 1つ前のページ if ($nowPage - 1 > 0) { $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . ((int) $requestParams['OFFSET'] - (int) $requestParams['LIMIT']) . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">' . ($nowPage - 1) . '</a></td>' . PHP_EOL; } // 現在ページ $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . $requestParams['OFFSET'] . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">' . $nowPage . '</a></td>' . PHP_EOL; // 1つ次のページ if ($nowPage + 1 <= floor((int) $requestParams['total'] / (int) $requestParams['LIMIT'])) { $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . ((int) $requestParams['OFFSET'] + (int) $requestParams['LIMIT']) . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">' . ($nowPage + 1) . '</a></td>' . PHP_EOL; } // 2つ次のページ if ($nowPage + 2 <= floor((int) $requestParams['total'] / (int) $requestParams['LIMIT'])) { $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . ((int) $requestParams['OFFSET'] + (int) $requestParams['LIMIT'] * 2) . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">' . ($nowPage + 2) . '</a></td>' . PHP_EOL; } if ($nowPage < floor((int) $requestParams['total'] / (int) $requestParams['LIMIT'])) { // 次へリンク $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . ((int) $requestParams['OFFSET'] + (int) $requestParams['LIMIT']) . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">></a></td>' . PHP_EOL; // 終端リンク $basehtml .= '<td class="list-paginglink"><a href="' . $URIs[0] . '?LIMIT=' . $requestParams['LIMIT'] . '&OFFSET=' . (floor((int) $requestParams['total'] / (int) $requestParams['LIMIT']) - 1) * (int) $requestParams['LIMIT'] . '&total=' . $requestParams['total'] . '&ORDER=' . rawurlencode($requestParams['ORDER']) . '&LIKE=' . rawurlencode($requestParams['LIKE']) . '">>></a></td>' . PHP_EOL; } $basehtml .= '</tr></table>' . PHP_EOL; } } $basehtml .= '<div class="csv-download-link"><a href="' . str_replace('.html', '.csv', $_SERVER['REQUEST_URI']) . '">download csv</a></div>' . PHP_EOL; $basehtml .= '<div class="csv-all-download-link"><a href="' . str_replace('.html', '.csv', $URIs[0]) . '?ORDER=' . rawurlencode($requestParams['ORDER']) . '">download csv all records</a></div>' . PHP_EOL; $basehtml .= '<div class="tablelist-link"><a href="' . str_replace('/' . $this->restResourceModel . '.html', '/index.html', $URIs[0]) . '">table list</a></div>' . PHP_EOL; } } else { if (isset($res[0])) { $basehtml .= '<form id="crud-form-put" class="crud-form" method="POST">' . PHP_EOL; $basehtml .= '<table class="detail">' . PHP_EOL; $id = ''; foreach ($res[0] as $key => $val) { if ('' === $id) { $id = $val; } $basehtml .= '<tr><th class="crudkey">' . $key . '</th></tr>' . PHP_EOL; $basehtml .= '<tr><td><input type="text" name="' . $key . '" value="' . htmlspecialchars($val) . '"/></td></tr>' . PHP_EOL; } $basehtml .= '<tr><td><div class="submit-button put-button"><input type="submit"/ value="PUT"></div></td></tr>' . PHP_EOL; $basehtml .= '<input type="hidden" name="_method_" value="PUT"/>' . PHP_EOL; $basehtml .= '</table>' . PHP_EOL; $basehtml .= '</form>' . PHP_EOL; $basehtml .= '<form id="crud-form-delete" class="crud-form" method="POST">' . PHP_EOL; $basehtml .= '<div class="submit-button delete-button"><input type="submit"/ value="DELETE"></div>' . PHP_EOL; $basehtml .= '<input type="hidden" name="_method_" value="DELETE"/>' . PHP_EOL; $basehtml .= '</form>' . PHP_EOL; $basehtml .= '<div class="list-link"><a href="' . str_replace('/' . $this->restResourceModel . '/' . $id . '.html', '/' . $this->restResourceModel . '.html', $URIs[0]) . '">' . $this->restResourceModel . ' list</a></div>' . PHP_EOL; } else { $basehtml .= '<div class="list-link"><a href="javascript:history.back()">back</a></div>' . PHP_EOL; } } } $res = $basehtml; } } if ('HEAD' === $this->requestMethod && isset($res['describes'])) { header('Head: ' . json_encode($res['describes'])); header('Rules: ' . json_encode($res['rules'])); header('Records: ' . $res['count']); $res = TRUE; } // 正常終了(のハズ!) return $res; }
/** * 次の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; }