* @author AllCreator * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project */ App::uses('AppModel', 'Model'); App::uses('CalendarRruleUtil', 'Calendars.Utility'); App::uses('Space', 'Rooms.Model'); /** * CalendarsApp Model * * @author AllCreator * @package NetCommons\Calendars\Model */ class CalendarsAppModel extends AppModel { /** * getReadableRoomIds関数が何度も繰り返し呼び出された時のための保持変数 * * @var array */ protected $_readableRoomIds = null; /** * getReadableRoomIds * * 読み取り可能なルームのID配列を返す * * @return array */ public function getReadableRoomIds() { // 読み取り可能なルームを取得 // 読み取り可能なルームはフレームが異なろうとも、1アクセス中で変わることはないので // 保存して使いまわす if (! is_null($this->_readableRoomIds)) { return $this->_readableRoomIds; } $this->Room = ClassRegistry::init('Rooms.Room', true); $condition = $this->Room->getReadableRoomsConditions(); $roomBase = $this->Room->find('all', $condition); $roomIds = []; $hasPrivateSpace = false; foreach ($roomBase as $room) { $roomIds[$room['Room']['id']] = $room['Room']['id']; if ($room['Room']['space_id'] === Space::PRIVATE_SPACE_ID) { $hasPrivateSpace = true; } } // カレンダーは特別にプライベートスペースIDを入れる // カレンダーは特別に全会員向けルームIDを入れる if (Current::read('User.id')) { if ($hasPrivateSpace) { $privateRoomId = Space::getRoomIdRoot(Space::PRIVATE_SPACE_ID); $roomIds[$privateRoomId] = $privateRoomId; } $communityRoomId = Space::getRoomIdRoot(Space::COMMUNITY_SPACE_ID); $roomIds[$communityRoomId] = $communityRoomId; } $this->_readableRoomIds = $roomIds; return $roomIds; } /** * _setAndMergeDateTime * * 日付時刻系のパラメータを整形し、予定パラメータにマージして返す * * @param array $planParam merge前の予定パラメータ * @param array $data POSTされたデータ * @return array 成功時 整形,merged後の予定パラメータ. 失敗時 例外をthrowする. * @throws InternalErrorException */ protected function _setAndMergeDateTime($planParam, $data) { //詳細画面からのデータ //時間指定なしの場合 // [detail_start_datetime] => 2016-03-06  ユーザ系日付(から) // [detail_end_datetime] => 2016-03-08 ユーザ系日付(まで) //時間指定有の場合 // [detail_start_datetime] => 2016-03-06 09:00 ユーザ系日付時刻(秒はなし)(から) // [detail_end_datetime] => 2016-03-08 12:00 ユーザ系日付時刻(秒はなし)(まで) if ($data[$this->alias]['enable_time']) { $planParam['is_allday'] = 0; //時間指定あり $nctm = new NetCommonsTime(); $serverStartDatetime = $nctm->toServerDatetime( $data[$this->alias]['detail_start_datetime'] . ':00', $data[$this->alias]['timezone_offset']); $planParam['start_date'] = CalendarTime::stripDashColonAndSp(substr($serverStartDatetime, 0, 10)); $planParam['start_time'] = CalendarTime::stripDashColonAndSp(substr($serverStartDatetime, 11, 8)); $planParam['dtstart'] = $planParam['start_date'] . $planParam['start_time']; $serverEndDatetime = $nctm->toServerDatetime($data[$this->alias]['detail_end_datetime'] . ':00', $data[$this->alias]['timezone_offset']); $planParam['end_date'] = CalendarTime::stripDashColonAndSp(substr($serverEndDatetime, 0, 10)); $planParam['end_time'] = CalendarTime::stripDashColonAndSp(substr($serverEndDatetime, 11, 8)); $planParam['dtend'] = $planParam['end_date'] . $planParam['end_time']; } else { $planParam['is_allday'] = 1; //ユーザー系の開始日と終了日とタイムゾーンを、サーバ系の開始日の00:00:00から終了翌日の00:00:00に変換する // FUJI start, end が翌日に設定されているときはNextDateにするなとわたす list($serverStartDate, $serverEndNextDate) = (new CalendarTime())->convUserFromTo2SvrFromTo( $data[$this->alias]['detail_start_datetime'], $data[$this->alias]['detail_end_datetime'], $data[$this->alias]['timezone_offset'], $planParam['is_allday']); $planParam['start_date'] = CalendarTime::stripDashColonAndSp(substr($serverStartDate, 0, 10)); $planParam['start_time'] = CalendarTime::stripDashColonAndSp(substr($serverStartDate, 11, 8)); $planParam['dtstart'] = $planParam['start_date'] . $planParam['start_time']; $planParam['end_date'] = CalendarTime::stripDashColonAndSp(substr($serverEndNextDate, 0, 10)); $planParam['end_time'] = CalendarTime::stripDashColonAndSp(substr($serverEndNextDate, 11, 8)); $planParam['dtend'] = $planParam['end_date'] . $planParam['end_time']; } return $planParam; } /** * _setAndMergeRrule * * Rruleのパラメータを整形し、予定パラメータにマージして返す * * @param array $planParam merge前の予定パラメータ * @param array $data POSTされたデータ * @param string $completedRrule すでに完成しているrrule文字列(''以外の時に有効) * @return array 成功時 整形,merged後の予定パラメータ. 失敗時 例外をthrowする. * @throws InternalErrorException */ protected function _setAndMergeRrule($planParam, $data, $completedRrule = '') { //CakeLog::debug("DBGY: data[" . $this->alias . "]=[" . print_r($data[$this->alias], true), "]"); $rrule = array(); if ($data[$this->alias]['is_repeat']) { if ($completedRrule !== '') { //下記の$data[$this->alias]['repeat_freq']などをつかわず、 //指定された完成形のrrule文字列をそのままセットして返す。 //主に、プラグイン連携用 $planParam['rrule'] = $completedRrule; return $planParam; } //$wdayArray = explode('|', CalendarsComponent::CALENDAR_REPEAT_WDAY); $repeatFreq = $data[$this->alias]['repeat_freq']; $rruleInterval = $data[$this->alias]['rrule_interval']; $rruleByday = $data[$this->alias]['rrule_byday']; $rruleBymonthday = $data[$this->alias]['rrule_bymonthday']; $rruleBymonth = $data[$this->alias]['rrule_bymonth']; $rruleTerm = $data[$this->alias]['rrule_term']; //validateはすでに終わっているので、以下では、データ加工のみに集中する。 // //rruleTermの設定 // if ($rruleTerm === 'COUNT') { $rruleCount = $data[$this->alias]['rrule_count']; //validateはすでにおわっているので省略 $rrule['COUNT'] = $rruleCount; } if ($rruleTerm === 'UNTIL') { $this->__doRruleTermUntil($planParam, $data, $rrule, $repeatFreq, $rruleInterval, $rruleByday, $rruleBymonthday, $rruleBymonth, $rruleTerm); } // // repeatFreqの設定 // switch ($repeatFreq) { case CalendarsComponent::CALENDAR_REPEAT_FREQ_DAILY: //日単位 $rrule['FREQ'] = $repeatFreq; $rrule['INTERVAL'] = intval($rruleInterval[$repeatFreq]); break; case CalendarsComponent::CALENDAR_REPEAT_FREQ_WEEKLY: //週単位 $rrule['FREQ'] = $repeatFreq; $rrule['INTERVAL'] = intval($rruleInterval[$repeatFreq]); $rrule['BYDAY'] = $rruleByday[$repeatFreq]; break; case CalendarsComponent::CALENDAR_REPEAT_FREQ_MONTHLY: //月単位 $this->__doRruleRepeatFreqMonthly( $planParam, $data, $rrule, $repeatFreq, $rruleInterval, $rruleByday, $rruleBymonthday, $rruleBymonth, $rruleTerm); break; case CalendarsComponent::CALENDAR_REPEAT_FREQ_YEARLY: //年単位 $this->__doRruleRepeatFreqYearly( $planParam, $data, $rrule, $repeatFreq, $rruleInterval, $rruleByday, $rruleBymonthday, $rruleBymonth, $rruleTerm); break; default: $rrule['FREQ'] = 'NONE'; } } else { //繰返しなし $rrule['FREQ'] = 'NONE'; } //rrule配列を、concatRrule()を使って文字列化 $planParam['rrule'] = (new CalendarRruleUtil())->concatRrule($rrule); return $planParam; } /** * __doRruleTermUntil * * RruleTermUntilのrrule設定処理 * * @param array &$planParam planParam * @param array &$data data * @param array &$rrule rrule 最終的な結果はこのrruleにセットする。 * @param array &$repeatFreq repeatFreq * @param array &$rruleInterval rruleInterval * @param mixed &$rruleByday rruleByday * @param mixed &$rruleBymonthday rruleBymonthday * @param array &$rruleBymonth rruleBymonth * @param array &$rruleTerm rruleTerm * @return void 参照引数$rruleに値をセットして返すので戻り値なし */ private function __doRruleTermUntil(&$planParam, &$data, &$rrule, &$repeatFreq, &$rruleInterval, &$rruleByday, &$rruleBymonthday, &$rruleBymonth, &$rruleTerm) { //$rruleUntil = $data[$this->alias]['rrule_until']; //validateはすでにおわっているので省略 //注釈) NC2の時は、UNTILを同日24:00:00から作り出していたが、NC3では、翌日00:00:00をUNTILとしている。 // $untilDateS = $data[$this->alias]['rrule_until'] . ' 00:00:00'; //Y-m-d H:i:s形式 $untilDateA = CalendarTime::transFromYmdHisToArray($untilDateS); if (is_array($untilDateA)) { list($yearOfNextDay, $monthOfNextDay, $nextDay) = CalendarTime::getNextDay($untilDateA['year'], $untilDateA['month'], $untilDateA['day']); $nextDayOfUntilDateS = sprintf("%04d-%02d-%02d 00:00:00", (int)$yearOfNextDay, (int)$monthOfNextDay, (int)$nextDay); //untilDateSの翌日00:00:00を作り出し、サーバー系に直す $nctm = new NetCommonsTime(); $svrNxtDayOfUntilDtS = $nctm->toServerDatetime($nextDayOfUntilDateS, $data[$this->alias]['timezone_offset']); $ymdHis = CalendarTime::dt2CalDt($svrNxtDayOfUntilDtS); $rrule['UNTIL'] = substr($ymdHis, 0, 8) . 'T' . substr($ymdHis, 8); } } /** * __doRruleRepeatFreqMonthly * * RruleRepeatFreqの月のrrule設定処理 * * @param array &$planParam planParam * @param array &$data data * @param array &$rrule rrule 最終的な結果はこのrruleにセットする。 * @param array &$repeatFreq repeatFreq * @param array &$rruleInterval rruleInterval * @param mixed &$rruleByday rruleByday * @param mixed &$rruleBymonthday rruleBymonthday * @param array &$rruleBymonth rruleBymonth * @param array &$rruleTerm rruleTerm * @return void 参照引数$rruleに値をセットして返すので戻り値なし */ private function __doRruleRepeatFreqMonthly( &$planParam, &$data, &$rrule, &$repeatFreq, &$rruleInterval, &$rruleByday, &$rruleBymonthday, &$rruleBymonth, &$rruleTerm) { $rrule['FREQ'] = $repeatFreq; $rrule['INTERVAL'] = intval($rruleInterval[$repeatFreq]); //CakeLog::debug("DBG: MONTHLY case. repeatFreq[" . $repeatFreq . "] rruleByday[" . $repeatFreq . "]=[" . print_r($rruleByday[$repeatFreq], true) . "]"); if (isset($rruleByday) && isset($rruleByday[$repeatFreq])) { $this->__toArrayRrruleByanyway($rruleByday, $repeatFreq); $rrule['BYDAY'] = $this->__makeArrayOfRruleByDay($rruleByday, $repeatFreq); } if (isset($rruleBymonthday) && isset($rruleBymonthday[$repeatFreq])) { $this->__toArrayRrruleByanyway($rruleBymonthday, $repeatFreq); $rrule['BYMONTHDAY'] = $this->__makeArrayOfRruleByMonthday($rruleBymonthday, $repeatFreq); } //実際には、$byday, $bymonthdayいずれか一方は空配列で、他方に1要素のみ存在する形になることがvalidatorで保証されている。 } /** * __toArrayRrruleByanyway * * Rrule用汎用配列統一関数 * * @param mixed &$rruleByanyway rruleByanyway * @param string &$repeatFreq repeatFreq * @return void 参照引数$rruleByanywayに値をセットして返すので戻り値なし */ private function __toArrayRrruleByanyway(&$rruleByanyway, &$repeatFreq) { //NC3のcakePHPのViewの場合、singleSelectの場合、配列ではなく文字列で渡ってくる. //が、本プログラムの繰り返し処理は、rrule_byday[MONTHLY] or rrule_bymonthday[MONTHLY] or rrule_byday[YEARLY] //が配列であるとを想定して実装してある。 //よって、文字列の場合、配列化する。 if (!is_array($rruleByanyway[$repeatFreq])) { if (empty($rruleByanyway[$repeatFreq])) { //空文字=未選択の場合 $rruleByanyway[$repeatFreq] = array(); } else { $rruleByanyway[$repeatFreq] = array($rruleByanyway[$repeatFreq]); } } } /** * __makeArrayOfRruleByDay * * Rrule用BYDAY配列生成関数 * * @param array &$rruleByday rruleByday * @param string &$repeatFreq repeatFreq * @return array 作成したbyday配列を返す */ private function __makeArrayOfRruleByDay(&$rruleByday, &$repeatFreq) { $wdays = explode('|', CalendarsComponent::CALENDAR_REPEAT_WDAY); //SU,MO, ... ,SA $byday = array(); foreach ($rruleByday[$repeatFreq] as $val) { $wday = substr($val, -2); //4SA,-1MOより、"SA","MO"の部分を抜き出す。 $num = intval(substr($val, 0, -2)); //4SA,-1MOより、"4","-1"の部分を抜き出し整数化 if ($num === 0) { //YEARYの「開始日と同日」($val==='')のケース $val = $wday; } if (!in_array($wday, $wdays)) { //YEARYの「開始日と同日」指定時は代入しない continue; } //$wdayがSU-SAにあるかどうか、$numが-1以上4以下であるかのチェックは、すでにvalidateでおわっているので省略 $byday[] = $val; } return $byday; } /** * __makeArrayOfRruleByMonthday * * Rrule用BYMONTHDAY配列生成関数 * * @param array &$rruleBymonthday rruleBymonthday * @param string &$repeatFreq repeatFreq * @return array 作成したbymonthday配列を返す */ private function __makeArrayOfRruleByMonthday(&$rruleBymonthday, &$repeatFreq) { $bymonthday = array(); foreach ($rruleBymonthday[$repeatFreq] as $val) { $val = intval($val); if ($val > 0 && $val <= 31) { $bymonthday[] = $val; } } return $bymonthday; } /** * __doRruleRepeatFreqYearly * * RruleRepeatFreqの年のrrule設定処理 * * @param array &$planParam planParam * @param array &$data data * @param array &$rrule rrule 最終的な結果はこのrruleにセットする。 * @param array &$repeatFreq repeatFreq * @param array &$rruleInterval rruleInterval * @param mixed &$rruleByday rruleByday * @param mixed &$rruleBymonthday rruleBymonthday * @param array &$rruleBymonth rruleBymonth * @param array &$rruleTerm rruleTerm * @return void 参照引数$rruleに値をセットして返すので戻り値なし */ private function __doRruleRepeatFreqYearly( &$planParam, &$data, &$rrule, &$repeatFreq, &$rruleInterval, &$rruleByday, &$rruleBymonthday, &$rruleBymonth, &$rruleTerm) { $rrule['FREQ'] = $repeatFreq; $rrule['INTERVAL'] = intval($rruleInterval[$repeatFreq]); $bymonth = array(); foreach ($rruleBymonth[$repeatFreq] as $val) { $val = intval($val); if ($val > 0 && $val <= 12) { $bymonth[] = $val; } } $rrule['BYMONTH'] = $bymonth; if (isset($rruleByday) && isset($rruleByday[$repeatFreq])) { $this->__toArrayRrruleByanyway($rruleByday, $repeatFreq); $rrule['BYDAY'] = $this->__makeArrayOfRruleByDay($rruleByday, $repeatFreq); } } /** * _getStatus * * $data['save_N']のN(=status)を抜き出す * * @param array $data request->data配列 * @return mixed 成功した時はstatus。失敗した時はfalseを返す。 */ protected function _getStatus($data) { $statuses = array( WorkflowComponent::STATUS_PUBLISHED, WorkflowComponent::STATUS_APPROVAL_WAITING, WorkflowComponent::STATUS_IN_DRAFT, WorkflowComponent::STATUS_DISAPPROVED, ); foreach ($statuses as $status) { $saveStatus = 'save_' . $status; //save_Nの値は空なので、emptyではなくissetで判断すること if (isset($data[$saveStatus])) { return $status; } } return false; } }