* @author Shohei Nakajima
* @link http://www.netcommons.org NetCommons Project
* @license http://www.netcommons.org/license.txt NetCommons License
* @copyright Copyright 2014, NetCommons Project
*/
App::uses('AppHelper', 'View/Helper');
App::uses('Topic', 'Topics.Model');
App::uses('Block', 'Blocks.Model');
App::uses('WorkflowComponent', 'Workflow.Controller/Component');
/**
* Workflow Helper
*
* @author Shohei Nakajima
* @package NetCommons\Workflow\View\Helper
*/
class TopicsHelper extends AppHelper {
/**
* Other helpers used by FormHelper
*
* @var array
*/
public $helpers = array(
'NetCommons.NetCommonsForm',
'NetCommons.NetCommonsHtml',
'Rooms.RoomsForm',
'PluginManager.PluginsForm',
'Users.DisplayUser',
'Workflow.Workflow',
);
/**
* ステータス配列
*
* __constractorでセットする
*
* @var array
*/
public $statuses = array();
/**
* Default Constructor
*
* @param View $View The View this helper is being attached to.
* @param array $settings Configuration settings for the helper.
*/
public function __construct(View $View, $settings = array()) {
parent::__construct($View, $settings);
$this->statuses = array(
//一時保存
WorkflowComponent::STATUS_IN_DRAFT => array(
'key' => WorkflowComponent::STATUS_IN_DRAFT,
'class' => 'label-info',
'message' => __d('net_commons', 'Temporary'),
),
//承認待ち
WorkflowComponent::STATUS_APPROVAL_WAITING => array(
'key' => WorkflowComponent::STATUS_APPROVAL_WAITING,
'class' => 'label-warning',
'message' => __d('net_commons', 'Approving'),
),
//差し戻し
WorkflowComponent::STATUS_DISAPPROVED => array(
'key' => WorkflowComponent::STATUS_DISAPPROVED,
'class' => 'label-warning',
'message' => __d('net_commons', 'Disapproving'),
),
//公開前
Topic::STATUS_BEFORE_PUBLISH => array(
'key' => Topic::STATUS_BEFORE_PUBLISH,
'class' => 'label-default',
'message' => __d('topics', 'Before publishing'),
),
//受付終了
Topic::STATUS_ANSWER_END => array(
'key' => Topic::STATUS_ANSWER_END,
'class' => 'label-default',
'message' => __d('topics', 'Answer end'),
),
//回答済み
Topic::STATUS_ANSWERED => array(
'key' => Topic::STATUS_ANSWERED,
'class' => 'label-default',
'message' => __d('topics', 'Answered'),
),
//未回答
Topic::STATUS_UNANSWERED => array(
'key' => Topic::STATUS_UNANSWERED,
'class' => 'label-success',
'message' => __d('topics', 'Unanswered'),
),
//未確認
Topic::STATUS_UNCONFIRMED => array(
'key' => Topic::STATUS_UNCONFIRMED,
'class' => 'label-primary',
'message' => __d('topics', 'Unconfirmed'),
),
//ブロック非公開
Topic::STATUS_BLOCK_PRIVATE => array(
'key' => Topic::STATUS_BLOCK_PRIVATE,
'class' => 'label-default',
'message' => __d('blocks', 'Private'),
),
//ブロック期限付き公開(公開前)
Topic::STATUS_BLOCK_BEFORE_PUBLISH => array(
'key' => Topic::STATUS_BLOCK_BEFORE_PUBLISH,
'class' => 'label-default',
'message' => __d('blocks', 'Public before'),
),
//ブロック期限付き公開(公開中)
Topic::STATUS_BLOCK_PUBLISH => array(
'key' => Topic::STATUS_BLOCK_PUBLISH,
'class' => 'label-default',
'message' => __d('blocks', 'Limited'),
),
//ブロック期限付き公開(公開終了)
Topic::STATUS_BLOCK_END_PUBLISH => array(
'key' => Topic::STATUS_BLOCK_END_PUBLISH,
'class' => 'label-default',
'message' => __d('blocks', 'Public end'),
),
);
}
/**
* Before render callback. beforeRender is called before the view file is rendered.
*
* Overridden in subclasses.
*
* @param string $viewFile The view file that is going to be rendered
* @return void
*/
public function beforeRender($viewFile) {
$this->NetCommonsHtml->css('/topics/css/style.css');
$this->NetCommonsHtml->script('/topics/js/topics.js');
parent::beforeRender($viewFile);
}
/**
* Camelize処理
*
* @param array $orig 変換元データ
* @return array 変換後データ
*/
public function camelizeKeyRecursive($orig) {
$newResult = [];
foreach ($orig as $key => $value) {
if (isset($value['TrackableCreator'])) {
$avatar = $this->DisplayUser->avatar($value, [], 'TrackableCreator.id');
$value['TrackableCreator']['avatar'] = $avatar;
}
if (isset($value['TrackableUpdater'])) {
$avatar = $this->DisplayUser->avatar($value, [], 'TrackableUpdater.id');
$value['TrackableUpdater']['avatar'] = $avatar;
}
$newResult[$key] = $this->__camelizeKeyRecursive($value);
$displayStatus = $this->__getStatusLabel($newResult[$key]);
$newResult[$key]['Topic']['display_status'] = $displayStatus;
}
return $newResult;
}
/**
* Camelize処理
*
* @param array $orig 変換元データ
* @return array 変換後データ
*/
private function __camelizeKeyRecursive($orig) {
$newResult = [];
foreach ($orig as $key => $value) {
if (is_array($value)) {
$newResult[$key] = $this->__camelizeKeyRecursive($value);
} else {
$newResult = $this->__parseValueForCamelize($newResult, $key, $value);
}
}
return $newResult;
}
/**
* Hash::getを独自でやる(パフォーマンス向上のため)
*
* @param array $data データ
* @param string $key キー文字列(model.fieldの形)
* @param mixed $defualt デフォルト値
* @return mixed
*/
private function __hashGet($data, $key, $defualt = null) {
list($model, $field) = explode('.', $key);
if (isset($data[$model][$field])) {
return $data[$model][$field];
} else {
return $defualt;
}
}
/**
* keyによる変換処理
*
* self::camelizeKeyRecursiveから実行される
*
* @param array $newResult keyをcamel形式に変換して戻す配列
* @param string $key key値
* @param string $value 値
* @return string 変換後の値
*/
private function __parseValueForCamelize($newResult, $key, $value) {
if ($key === 'title') {
$newResult[$key] = $value;
$key = 'display_' . $key;
$newResult[$key] = mb_strimwidth($value, 0, Topic::DISPLAY_TITLE_LENGTH, '...');
} elseif ($key === 'name') {
$newResult[$key] = $value;
$key = 'display_' . $key;
$newResult[$key] = mb_strimwidth($value, 0, Topic::DISPLAY_ROOM_NAME_LENGTH, '...');
} elseif ($key === 'summary') {
$newResult[$key] = $value;
$key = 'display_' . $key;
$newResult[$key] = mb_strimwidth($value, 0, Topic::DISPLAY_SUMMARY_LENGTH, '...');
} elseif (in_array($key, ['publish_start', 'created', 'modified'], true)) {
$newResult[$key] = $value;
$key = 'display_' . $key;
$newResult[$key] = $this->NetCommonsHtml->dateFormat($value);
} elseif ($key === 'title_icon') {
$newResult[$key] = $this->NetCommonsHtml->titleIcon($value);
} else {
$newResult[$key] = $value;
}
return $newResult;
}
/**
* keyによる変換処理
* ※self::camelizeKeyRecursiveから実行される
*
* PHPMDでエラーになるが、別関数にすると見づらくなるため、PHPMD.CyclomaticComplexityで除外する
*
* @param array $newResult keyをcamel形式に変換して戻す配列
* @return string 変換後の値
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
private function __getStatusLabel($newResult) {
$topicStatus = $this->__hashGet($newResult, 'Topic.status');
$blockPublicType = $this->__hashGet($newResult, 'Block.public_type');
$topicPublishStart = $this->__hashGet($newResult, 'Topic.publish_start');
$topicPublishEnd = $this->__hashGet($newResult, 'Topic.publish_end');
$answerPeriodEnd = $this->__hashGet($newResult, 'Topic.answer_period_end');
$labels = $this->statuses;
$now = gmdate('Y-m-d H:i:s');
if (in_array((int)$topicStatus, array_keys($labels), true)) {
//承認待ち、差し戻し、一時保存
} elseif ($now < $topicPublishStart) {
//公開前
$topicStatus = Topic::STATUS_BEFORE_PUBLISH;
} elseif ($this->__hashGet($newResult, 'Topic.is_answer')) {
if ($topicPublishEnd && $topicPublishEnd < $now) {
//公開終了
$topicStatus = Topic::STATUS_BLOCK_END_PUBLISH;
} elseif ($this->__hashGet($newResult, 'TopicUserStatus.answered')) {
//回答済み
$topicStatus = Topic::STATUS_ANSWERED;
} elseif ($answerPeriodEnd && $answerPeriodEnd < $now) {
//受付終了
$topicStatus = Topic::STATUS_ANSWER_END;
} elseif ($this->__hashGet($newResult, 'TopicUserStatus.read')) {
//未回答
$topicStatus = Topic::STATUS_UNANSWERED;
} elseif (Current::read('User.id')) {
//未確認
$topicStatus = Topic::STATUS_UNCONFIRMED;
}
} elseif ($blockPublicType === Block::TYPE_PRIVATE) {
//ブロック非公開
$topicStatus = Topic::STATUS_BLOCK_PRIVATE;
} elseif ($blockPublicType === Block::TYPE_LIMITED) {
if ($now <= $this->__hashGet($newResult, 'Block.publish_start', '0000-00-00 00:00:00')) {
//ブロック期限付き公開(公開前)
$topicStatus = Topic::STATUS_BLOCK_BEFORE_PUBLISH;
} elseif ($now > $this->__hashGet($newResult, 'Block.publish_end', '9999-99-99 99:99:99')) {
//ブロック期限付き公開(公開終了)
$topicStatus = Topic::STATUS_BLOCK_END_PUBLISH;
} else {
//ブロック期限付き公開(公開中)
$topicStatus = Topic::STATUS_BLOCK_PUBLISH;
}
} else {
//公開中
}
return $this->Workflow->label($topicStatus, $labels);
}
/**
* ヘルプの表示
*
* @param string $content メッセージ内容(オリジナルタグの内容)
* @param string $placement ポジション
* @return string ヘルプHTML出力
*/
public function rssSettingHelp($content = '', $placement = 'bottom') {
$html = '';
$content = __d('topics', 'Each of the embedded keywords, will be sent is converted ' .
'to the corresponding content.
') . $content;
$html .= __d('topics', 'Can use an embedded keyword in the channel title line and summary') . ' ';
$html .= '';
$html .= '';
$html .= '';
$html .= '';
return $html;
}
/**
* ステータスの絞り込み
*
* @return string HTML出力
*/
public function dropdownStatus() {
$named = $this->_View->Paginator->params['named'];
$named['page'] = '1';
$named['limit'] = null;
$options = [0 => __d('net_commons', 'All Statuses')];
foreach ($this->statuses as $status) {
$options[$status['key']] = $status['message'];
}
return $this->_View->element('Topics.Topics/select_status', array(
'options' => $options,
'current' => isset($named['status'])
? $named['status']
: 0,
'url' => $named,
));
}
/**
* 特定のブロックを表示する選択ボックス群の初期処理
*
* @return string HTML出力
*/
public function initSelectBlock() {
$selectBlocks = NetCommonsAppController::camelizeKeyRecursive(
$this->_View->viewVars['selectBlocks']
);
$topicFramesBlock['topicFramesBlock'] = NetCommonsAppController::camelizeKeyRecursive(
$this->_View->request->data['TopicFramesBlock']
);
$html = 'initBlocks(' .
h(json_encode($selectBlocks, true)) . ', ' .
h(json_encode($topicFramesBlock, true)) .
')';
return $html;
}
/**
* 特定のブロックを表示する選択ボックス群の初期処理
*
* @return string HTML出力
*/
public function selectBlock() {
$html = '';
if ($this->_View->viewVars['selectBlocks']) {
$html .= '';
//ルーム選択
$html .= $this->RoomsForm->selectRooms('TopicFramesBlock.room_id',
array(
'ng-model' => 'topicFramesBlock.roomId',
//'ng-init' => 'selectBlockPluginKey = \'' . Hash::get($first, '0') . '\'',
'ng-click' => 'blockOptions = optionBlocks()',
)
);
//プラグイン選択
$options = [];
foreach ($this->_View->viewVars['pluginsRoom'] as $pluginsRoom) {
if (! in_array($pluginsRoom['Plugin']['key'], TopicFrameSetting::$outPlugins)) {
$options[$pluginsRoom['Plugin']['key']] = $pluginsRoom['Plugin']['name'];
}
}
$html .= $this->PluginsForm->selectPluginsRoom('TopicFramesBlock.plugin_key',
array(
'div' => false,
'label' => false,
'options' => $options,
'ng-model' => 'topicFramesBlock.pluginKey',
//'ng-init' => 'selectBlockPluginKey = \'' . Hash::get($first, '0') . '\'',
'ng-click' => 'blockOptions = optionBlocks()',
)
);
$html .= '
';
}
//ブロック選択
$html .= '';
return $html;
}
}