/**
  * 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;
 }
 /**
  * Helper method to execute deferred HTTP requests.
  *
  * @param $request Request|Batch
  * @throws Exception
  * @return object of the type of the expected class or array.
  */
 public function execute($request)
 {
     if ($request instanceof Request) {
         $request->setUserAgent($this->getApplicationName() . " " . self::USER_AGENT_SUFFIX . $this->getLibraryVersion());
         if (!$this->getClassConfig("Request", "disable_gzip")) {
             $request->enableGzip();
         }
         $request->maybeMoveParametersToBody();
         return REST::execute($this, $request);
     } else {
         if ($request instanceof Batch) {
             return $request->execute();
         } else {
             throw new Exception("Do not know how to execute this type of object.");
         }
     }
 }