* @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('UsersAppModel', 'Users.Model');
App::uses('NetCommonsTime', 'NetCommons.Utility');
/**
* UserSearchAppModel
*
* @author Shohei Nakajima
* @package NetCommons\Users\Model
*
* 速度改善の修正に伴って発生したため抑制
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
*/
class UserSearchAppModel extends UsersAppModel {
/**
* more_than_days定数
* ○日以上前(○日以上ログインしていない)
*
* @var const
*/
const MORE_THAN_DAYS = 'more_than_days';
/**
* within_days定数
* ○日以内(○日以内ログインしている)
*
* @var const
*/
const WITHIN_DAYS = 'within_days';
/**
* Custom database table name, or null/false if no table association is desired.
*
* @var string
* @link http://book.cakephp.org/2.0/ja/models/model-attributes.html#usetable
*/
public $useTable = false;
/**
* 閲覧可のフィールドセット
* self::__prepare()から実行される
*
* @param string $attrKey 会員項目キー
* @param array $userAttributes 会員項目データ
* @return void
*
* 速度改善の修正に伴って発生したため抑制
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
protected function _setReadableField($attrKey, $userAttributes) {
$dataTypeKey = '';
$userAttr = [];
foreach ($userAttributes as $arr) {
foreach ($arr as $item) {
foreach ($item as $userAttribute) {
if ($userAttribute['UserAttribute']['key'] === $attrKey) {
$dataTypeKey = $userAttribute['UserAttributeSetting']['data_type_key'];
$userAttr = $userAttribute['UserAttribute'];
break;
}
}
}
}
$label = $userAttr['name'];
//Fieldのチェック
if ($dataTypeKey === DataType::DATA_TYPE_IMG) {
$this->readableFields[$attrKey]['field'] =
$this->UploadFile->alias . Inflector::classify($attrKey) . '.field_name';
$this->readableFields[$attrKey]['label'] = $label;
$this->readableFields[$attrKey]['options'] = array(
'0' => __d('user_manager', 'No avatar.'),
'1' => __d('user_manager', 'Has avatar.')
);
$this->readableFields[$attrKey]['data_type'] = $dataTypeKey;
} elseif (in_array($attrKey, UserAttribute::$typeDatetime, true) ||
$dataTypeKey === DataType::DATA_TYPE_DATETIME) {
if (in_array($attrKey, ['last_login', 'previous_login'], true)) {
//最終ログイン日時の場合、ラベル変更(○日以上ログインしていない、○日以内ログインしている)
$moreThanDays =
__d('user_manager', 'Not logged more than %sdays ago');
$withinDays =
__d('user_manager', 'Have logged in within %sdays');
} else {
//○日以上前、○日以内
$moreThanDays =
__d('user_manager', 'more than %sdays ago');
$withinDays =
__d('user_manager', 'within %sdays');
}
//日時型の場合
$this->readableFields[$attrKey]['field'] = $this->alias . '.' . $attrKey;
$this->readableFields[$attrKey]['data_type'] = $dataTypeKey;
$fieldKey = $attrKey . '_' . self::MORE_THAN_DAYS;
$this->readableFields[$fieldKey]['field'] = $this->alias . '.' . $attrKey;
$this->readableFields[$fieldKey]['label'] = $label;
$this->readableFields[$fieldKey]['format'] = $moreThanDays;
$this->readableFields[$fieldKey]['data_type'] = $dataTypeKey;
$fieldKey = $attrKey . '_' . self::WITHIN_DAYS;
$this->readableFields[$fieldKey]['field'] = $this->alias . '.' . $attrKey;
$this->readableFields[$fieldKey]['label'] = $label;
$this->readableFields[$fieldKey]['format'] = $withinDays;
$this->readableFields[$fieldKey]['data_type'] = $dataTypeKey;
} elseif ($this->hasField($attrKey)) {
//Userモデル
$this->readableFields[$attrKey]['field'] = $this->alias . '.' . $attrKey;
$this->readableFields[$attrKey]['label'] = $label;
$this->readableFields[$attrKey]['data_type'] = $dataTypeKey;
} elseif ($this->UsersLanguage->hasField($attrKey)) {
//UsersLanguageモデル
$this->readableFields[$attrKey]['field'] = $this->UsersLanguage->alias . '.' . $attrKey;
$this->readableFields[$attrKey]['label'] = $label;
$this->readableFields[$attrKey]['data_type'] = $dataTypeKey;
}
$userAttrChoices = [];
foreach ($userAttributes as $arr) {
foreach ($arr as $item) {
foreach ($item as $userAttribute) {
if (isset($userAttribute['UserAttributeChoice'])) {
foreach ($userAttribute['UserAttributeChoice'] as $choice) {
if ($choice['user_attribute_id'] == $userAttr['id']) {
$userAttrChoices[$choice['key']] = $choice['name'];
}
}
}
}
}
}
if ($userAttrChoices) {
$this->readableFields[$attrKey]['options'] = $userAttrChoices;
if ($attrKey === 'role_key') {
$this->readableFields[$attrKey]['option_field'] = 'key';
} else {
$this->readableFields[$attrKey]['option_field'] = 'code';
}
}
////Field(is_xxxx_public)のチェック
//$fieldKey = sprintf(UserAttribute::PUBLIC_FIELD_FORMAT, $field);
//if ($this->hasField($fieldKey)) {
// $this->readableFields[$fieldKey] = $this->alias . '.' . $fieldKey;
//}
}
/**
* リクエストキーのパース処理
*
* @param string $requestKey リクエストキー
* @return array array(フィールド名、setting, 符号)
*/
protected function _parseRequestKey($requestKey) {
$setting = null;
$sign = null;
if (preg_match('/' . self::MORE_THAN_DAYS . '$/', $requestKey)) {
$field = substr($requestKey, 0, (strlen(self::MORE_THAN_DAYS) + 1) * -1);
$setting = self::MORE_THAN_DAYS;
} elseif (preg_match('/' . self::WITHIN_DAYS . '$/', $requestKey)) {
$field = substr($requestKey, 0, (strlen(self::WITHIN_DAYS) + 1) * -1);
$setting = self::WITHIN_DAYS;
} elseif (preg_match('/ NOT$/', $requestKey)) {
$field = substr($requestKey, 0, -4);
$sign = ' NOT';
} else {
$field = $requestKey;
}
if (isset($this->convRealToFieldKey[$field])) {
$field = $this->convRealToFieldKey[$field]['key'];
}
return array($field, $setting, $sign);
}
/**
* JOINテーブルを取得
*
* @param array $conditions 条件(Conditions)リスト
* @return array Findで使用するJOIN配列
*/
protected function _getSearchJoinTablesByConditions($conditions) {
$joinModels = array();
$fieldKeys = array_keys($conditions);
if (in_array('group_id', $fieldKeys, true)) {
$joinModels = Hash::merge(array('Group' => true), $joinModels);
}
if (in_array('created_user', $fieldKeys, true)) {
$joinModels = Hash::merge(array('TrackableCreator' => true), $joinModels);
}
if (in_array('modified_user', $fieldKeys, true)) {
$joinModels = Hash::merge(array('TrackableUpdater' => true), $joinModels);
}
foreach ($fieldKeys as $field) {
$modelName = $this->UploadFile->alias . Inflector::classify($field);
if ($this->getOriginalField($field) === $modelName . '.field_name') {
$joinModels = Hash::merge(array($modelName => array(
'table' => $this->UploadFile->table,
'alias' => $modelName,
'type' => 'LEFT',
'conditions' => array(
$modelName . '.content_key' . ' = ' . $this->alias . '.id',
$modelName . '.plugin_key' => 'users',
$modelName . '.field_name' => $field,
),
)), $joinModels);
}
}
return $joinModels;
}
/**
* 検索可能のフィールドをチェックして、検索不可なフィールドは削除する
*
* @param array $fields 表示するフィールドリスト
* @return array 実際に表示できるフィールドリスト
*/
public function cleanSearchFields($fields) {
$fieldKeys = array_keys($fields);
foreach ($fieldKeys as $key) {
list($field, ) = $this->_parseRequestKey($key);
if (! isset($this->readableFields[$field])) {
unset($fields[$key]);
}
}
if (! $fields) {
$fields = array();
}
return $fields;
}
/**
* 検索フィールドから実際のテーブルフィールドを取得する
*
* @param string $field 表示するフィールドリスト
* @return string 実際のフィールド
*/
public function getOriginalField($field) {
return Hash::get($this->readableFields, $field . '.' . 'field');
}
/**
* 検索フィールド名(ラベル)を取得する
*
* @param string $field 表示するフィールド
* @return string フィールド名(ラベル)
*/
public function getReadableFieldName($field) {
return Hash::get($this->readableFields, $field . '.' . 'label');
}
/**
* 検索フィールドのオプションを取得する
*
* @param string $field 表示するフィールド
* @return string オプション
*/
public function getReadableFieldOptions($field) {
return Hash::get($this->readableFields, $field . '.' . 'options');
}
/**
* 検索フィールドのソートキーを取得する
*
* @param string $field 表示するフィールド
* @return string ソートキー
*/
public function getReadableFieldOrderKey($field) {
$key = 'order';
if (! Hash::get($this->readableFields, $field . '.' . $key)) {
$key = 'field';
}
return Hash::get($this->readableFields, $field . '.' . $key);
}
/**
* 検索フィールドの値をフォーマットに当てはめて出力する。
*
* @param string $field 表示するフィールドリスト
* @param string $value 値
* @return string 値
*/
public function getSearchFieldValue($field, $value) {
if (Hash::get($this->readableFields, $field . '.' . 'format')) {
return sprintf(Hash::get($this->readableFields, $field . '.' . 'format'), h($value));
} elseif (Hash::get($this->readableFields, $field . '.' . 'options')) {
$options = Hash::get($this->readableFields, $field . '.' . 'options', array());
return Hash::get($options, $value);
} else {
return h($value);
}
}
/**
* 検索可能のフィールドをチェックして、検索不可なフィールドは削除する
*
* @param array $field フィールド
* @param array $setting セッティングモード(日時型のみ使用)
* @param array $value 値
* @param string $defaultSign デフォルトの符号
* @return array array(符号, SQL値)
*/
protected function _creanSearchCondition($field, $setting, $value, $defaultSign = null) {
$userAttributes = $this->UserAttribute->getUserAttributesForLayout();
$dataType = Hash::extract(
$userAttributes, '{n}.{n}.{n}.UserAttributeSetting[user_attribute_key=' . $field . ']'
);
$dataTypeKey = Hash::get($dataType, '0.data_type_key', '');
$forwardTypes = array(
DataType::DATA_TYPE_TEXT, DataType::DATA_TYPE_TEXTAREA, DataType::DATA_TYPE_EMAIL
);
$optionTypes = array(
DataType::DATA_TYPE_RADIO, DataType::DATA_TYPE_SELECT, DataType::DATA_TYPE_CHECKBOX,
DataType::DATA_TYPE_PREFECTURE, DataType::DATA_TYPE_TIMEZONE, DataType::DATA_TYPE_MULTIPLE_SELECT
);
if ($dataTypeKey === DataType::DATA_TYPE_IMG) {
if ($value) {
$sign = ' NOT';
} else {
$sign = $defaultSign;
}
$value = null;
} elseif (in_array($field, UserAttribute::$typeDatetime, true) ||
$dataTypeKey === DataType::DATA_TYPE_DATETIME) {
//日付型の場合
if ($setting === self::MORE_THAN_DAYS) {
//○日以上前(○日以上ログインしていない)
$sign = ' <=';
} else {
//○日以内(○日以内ログインしている)
$sign = ' >=';
}
$date = new DateTime(NetCommonsTime::getNowDatetime());
$date->sub(new DateInterval(sprintf('P%dD', (int)$value)));
$value = $date->format('Y-m-d H:i:s');
} elseif (in_array($dataTypeKey, $forwardTypes, true) ||
in_array($field, ['created_user', 'modified_user'], true)) {
// テキスト型、テキストエリア型、メールアドレス型、作成者、更新者の場合
// ->あいまい検索※今後、MatchAgainstもしくは、前方一致にする必要あり。
$sign = ' LIKE';
$value = '%' . $value . '%';
} elseif (in_array($dataTypeKey, $optionTypes, true)) {
$sign = $defaultSign;
$userAttribute = Hash::extract(
$userAttributes, '{n}.{n}.{n}.UserAttribute[key=' . $field . ']'
);
$userAttrId = Hash::get($userAttribute, '0.id');
$options = Hash::extract(
$userAttributes,
'{n}.{n}.{n}.UserAttributeChoice.{n}[user_attribute_id=' . $userAttrId . ']'
);
$value = Hash::get(
Hash::extract($options, '{n}[key=' . $value . ']', array()),
'0.' . Hash::get($this->readableFields, $field . '.' . 'option_field', '')
);
} else {
$sign = $defaultSign;
}
return array($sign, $value);
}
/**
* 検索フィールドを取得する
*
* @param array $fields フィールド配列
* @return array 実際に検索できるフィールドリスト
*/
protected function _getSearchFields($fields) {
$originalFields = array(
'User.id'
);
foreach ($fields as $field) {
$originalFields[] = $this->getOriginalField($field);
}
if (in_array('room_role_key', $fields, true)) {
$originalFields = array_merge(
$originalFields,
array(
$this->RolesRoomsUser->alias . '.id',
$this->RolesRoomsUser->alias . '.roles_room_id',
$this->RolesRoomsUser->alias . '.user_id',
$this->RolesRoomsUser->alias . '.room_id',
),
array(
$this->RolesRoom->alias . '.id',
$this->RolesRoom->alias . '.room_id',
$this->RolesRoom->alias . '.role_key',
)
);
}
$originalFields = array_unique($originalFields);
return $originalFields;
}
/**
* 検索フィールドを取得する
*
* @param array $fields フィールド配列
* @return array 実際に検索できるフィールドリスト
*/
protected function _getSearchFieldsByRoomRoleKey($fields) {
$fields = Hash::merge(array(
'user_id',
'role_id',
'roles_room_id',
'roles_room_room_id',
'roles_room_role_key',
'roles_rooms_user_id',
'roles_rooms_user_roles_room_id',
'roles_rooms_user_user_id',
'roles_rooms_user_room_id'
), $fields);
$originalFields = array();
foreach ($fields as $field) {
$originalField = $this->getOriginalField($field);
if ($originalField) {
$originalFields[$field] = $originalField . ' AS ' . $field;
}
}
$originalFields = array_unique($originalFields);
return $originalFields;
}
/**
* 検索取得するためのrolesリスト取得
*
* @param array $extra findのオプション
* @return array 検索取得するためのrolesリスト
*/
protected function _getRolesByRoomRoleKey($extra) {
$roles = array(
Role::ROOM_ROLE_KEY_ROOM_ADMINISTRATOR,
Role::ROOM_ROLE_KEY_CHIEF_EDITOR,
Role::ROOM_ROLE_KEY_EDITOR,
Role::ROOM_ROLE_KEY_GENERAL_USER,
Role::ROOM_ROLE_KEY_VISITOR,
);
if (Hash::get($extra, 'extra.search', false)) {
$roles[] = null;
}
return $roles;
}
}