优化代码

main
gzydong 2021-08-14 17:31:21 +08:00
parent a221d49548
commit 267465d800
6 changed files with 280 additions and 242 deletions

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
namespace App\Constants;
@ -19,4 +20,18 @@ class TalkMessageType
const FRIEND_APPLY_MESSAGE = 7; //好友申请
const USER_LOGIN_MESSAGE = 8; //登录通知
const GROUP_INVITE_MESSAGE = 9; //入群退群消息
/**
* 获取可转发的消息类型列表
*
* @return array
*/
public static function getForwardTypes(): array
{
return [
self::TEXT_MESSAGE,
self::FILE_MESSAGE,
self::CODE_MESSAGE
];
}
}

View File

@ -9,6 +9,7 @@ use App\Constants\TalkModeConstant;
use App\Event\TalkEvent;
use App\Model\EmoticonItem;
use App\Model\FileSplitUpload;
use App\Service\TalkForwardService;
use App\Service\TalkMessageService;
use App\Support\UserRelation;
use App\Service\EmoticonService;
@ -300,7 +301,7 @@ class TalkMessageController extends CController
* 转发消息记录
* @RequestMapping(path="forward", methods="post")
*/
public function forward()
public function forward(TalkForwardService $forwardService)
{
$params = $this->request->inputs(['talk_type', 'receiver_id', 'records_ids', 'forward_mode', 'receive_user_ids', 'receive_group_ids']);
$this->validate($params, [
@ -310,26 +311,36 @@ class TalkMessageController extends CController
'forward_mode' => 'required|in:1,2',// 转发方方式[1:逐条转发;2:合并转发;]
]);
$user_id = $this->uid();
// 判断好友或者群关系
if (!UserRelation::isFriendOrGroupMember($user_id, (int)$params['receiver_id'], (int)$params['talk_type'])) {
return $this->response->fail('暂不属于好友关系或群聊成员,无法发送聊天消息!');
}
$receive_user_ids = $receive_group_ids = [];
$func = function (array $ids, int $talk_type) {
return array_map(function ($id) use ($talk_type) {
return ['talk_type' => $talk_type, 'id' => (int)$id];
}, $ids);
};
if (isset($params['receive_user_ids']) && !empty($params['receive_user_ids'])) {
$receive_user_ids = array_map(function ($friend_id) {
return ['talk_type' => TalkModeConstant::PRIVATE_CHAT, 'id' => (int)$friend_id];
}, $params['receive_user_ids']);
$receive_user_ids = $func($params['receive_user_ids'], TalkModeConstant::PRIVATE_CHAT);
}
if (isset($params['receive_group_ids']) && !empty($params['receive_group_ids'])) {
$receive_group_ids = array_map(function ($group_id) {
return ['talk_type' => TalkModeConstant::GROUP_CHAT, 'id' => (int)$group_id];
}, $params['receive_group_ids']);
$receive_group_ids = $func($params['receive_group_ids'], TalkModeConstant::GROUP_CHAT);
}
// 需要转发的好友或者群组
$items = array_merge($receive_user_ids, $receive_group_ids);
$user_id = $this->uid();
if ($params['forward_mode'] == 1) {// 单条转发
$ids = $this->talkService->forwardRecords($user_id, $params['receiver_id'], $params['records_ids']);
if ($params['forward_mode'] == 1) {// 逐条转发
$ids = $forwardService->multiSplitForward($user_id, (int)$params['receiver_id'], (int)$params['talk_type'], $params['records_ids'], $items);
} else {// 合并转发
$ids = $this->talkService->mergeForwardRecords($user_id, (int)$params['receiver_id'], (int)$params['talk_type'], $params['records_ids'], $items);
$ids = $forwardService->multiMergeForward($user_id, (int)$params['receiver_id'], (int)$params['talk_type'], $params['records_ids'], $items);
}
if (!$ids) return $this->response->fail('转发失败!');
@ -364,7 +375,7 @@ class TalkMessageController extends CController
'record_id' => 'required|integer'
]);
[$isTrue, $data] = $service->collect($this->uid(), $params['record_id']);
[$isTrue, $data] = $service->collect($this->uid(), (int)$params['record_id']);
if (!$isTrue) return $this->response->fail('添加表情失败!');
@ -384,7 +395,7 @@ class TalkMessageController extends CController
'record_id' => 'required|integer|min:1'
]);
[$isTrue, $message,] = $this->talkService->revokeRecord($this->uid(), $params['record_id']);
[$isTrue, $message,] = $this->talkService->revokeRecord($this->uid(), (int)$params['record_id']);
if (!$isTrue) return $this->response->fail($message);
return $this->response->success([], $message);
@ -405,8 +416,8 @@ class TalkMessageController extends CController
$isTrue = $this->talkService->removeRecords(
$this->uid(),
$params['talk_type'],
$params['receiver_id'],
(int)$params['talk_type'],
(int)$params['receiver_id'],
parse_ids($params['record_id'])
);

View File

@ -62,7 +62,7 @@ class FormatMessageService
* @param array $rows 聊天记录
* @return array
*/
public function handleChatRecords(array $rows)
public function handleChatRecords(array $rows): array
{
if (!$rows) return [];

View File

@ -0,0 +1,228 @@
<?php
declare(strict_types=1);
namespace App\Service;
use App\Model\Talk\TalkRecordsCode;
use App\Model\Talk\TalkRecordsFile;
use Exception;
use App\Constants\TalkMessageType;
use App\Constants\TalkModeConstant;
use App\Model\Talk\TalkRecords;
use App\Model\Talk\TalkRecordsForward;
use Hyperf\DbConnection\Db;
class TalkForwardService extends BaseService
{
/**
* 验证消息转发
*
* @param int $user_id 转发的用户ID
* @param int $receiver_id 当前转发消息的所属者(好友ID或者群聊ID)
* @param int $talk_type 消息来源 1:好友消息 2:群聊消息
* @param array $records_ids 转发消息的记录ID
* @return bool
*/
public function verifyForward(int $user_id, int $receiver_id, int $talk_type, array $records_ids): bool
{
// 支持转发的消息类型
$msg_type = TalkMessageType::getForwardTypes();
$sqlObj = TalkRecords::whereIn('id', $records_ids);
if ($talk_type == TalkModeConstant::PRIVATE_CHAT) {
$sqlObj->where(function ($query) use ($user_id, $receiver_id) {
$query->where([
['user_id', '=', $user_id],
['receiver_id', '=', $receiver_id]
])->orWhere([
['user_id', '=', $receiver_id],
['receiver_id', '=', $user_id]
]);
});
}
$result = $sqlObj->where('talk_type', $talk_type)->whereIn('msg_type', $msg_type)->where('is_revoke', 0)->get();
return count($result) == count($records_ids);
}
/**
* 转发消息(多条合并转发)
*
* @param int $user_id 转发的用户ID
* @param int $receiver_id 当前转发消息的所属者(好友ID或者群聊ID)
* @param int $talk_type 消息来源 1:好友消息 2:群聊消息
* @param array $records_ids 转发消息的记录ID
* @param array $receives 接受者数组 例如:[['talk_type' => 1,'id' => 3045]...] 二维数组
* @return array
*/
public function multiMergeForward(int $user_id, int $receiver_id, int $talk_type, array $records_ids, array $receives): array
{
$isTrue = $this->verifyForward($user_id, $receiver_id, $talk_type, $records_ids);
if (!$isTrue) return [];
// 默认取前3条聊天记录
$rows = TalkRecords::leftJoin('users', 'users.id', '=', 'talk_records.user_id')
->whereIn('talk_records.id', array_slice($records_ids, 0, 3))
->get(['talk_records.msg_type', 'talk_records.content', 'users.nickname']);
$jsonText = [];
foreach ($rows as $row) {
switch ($row->msg_type) {
case TalkMessageType::TEXT_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => mb_substr(str_replace(PHP_EOL, "", $row->content), 0, 30)
];
break;
case TalkMessageType::FILE_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => '【文件消息】'
];
break;
case TalkMessageType::CODE_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => '【代码消息】'
];
break;
}
}
$insRecordIds = [];
Db::beginTransaction();
try {
foreach ($receives as $item) {
$res = TalkRecords::create([
'talk_type' => $item['talk_type'],
'user_id' => $user_id,
'receiver_id' => $item['id'],
'msg_type' => TalkMessageType::FORWARD_MESSAGE,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
$insRecordIds[] = [
'record_id' => $res->id,
'receiver_id' => $res->receiver_id,
'talk_type' => $res->talk_type
];
TalkRecordsForward::create([
'record_id' => $res->id,
'user_id' => $user_id,
'records_id' => implode(',', $records_ids),
'text' => json_encode($jsonText),
'created_at' => date('Y-m-d H:i:s'),
]);
}
Db::commit();
} catch (Exception $e) {
Db::rollBack();
return [];
}
return $insRecordIds;
}
/**
* 转发消息(多条拆分转发)
* @param int $user_id 转发的用户ID
* @param int $receiver_id 当前转发消息的所属者(好友ID或者群聊ID)
* @param int $talk_type 消息来源 1:好友消息 2:群聊消息
* @param array $records_ids 转发消息的记录ID
* @param array $receives 接受者数组 例如:[['talk_type' => 1,'id' => 3045]...] 二维数组
* @return array
*/
public function multiSplitForward(int $user_id, int $receiver_id, int $talk_type, array $records_ids, array $receives): array
{
$isTrue = $this->verifyForward($user_id, $receiver_id, $talk_type, $records_ids);
if (!$isTrue) return [];
$rows = TalkRecords::whereIn('talk_records.id', $records_ids)
->get(['talk_records.id', 'talk_records.msg_type', 'talk_records.content']);
if (empty($rows)) return [];
$fileArray = $codeArray = [];
foreach ($rows as $val) {
if ($val['msg_type'] == TalkMessageType::FILE_MESSAGE) {
$fileArray[] = $val['id'];
} else if ($val['msg_type'] == TalkMessageType::CODE_MESSAGE) {
$codeArray[] = $val['id'];
}
}
if (!empty($fileArray)) {
$fileArray = TalkRecordsFile::where('record_id', $fileArray)->get()->keyBy('record_id')->toArray();
}
if (!empty($codeArray)) {
$codeArray = TalkRecordsCode::where('record_id', $codeArray)->get()->keyBy('record_id')->toArray();
}
$insRecordIds = [];
Db::beginTransaction();
try {
$file = $code = [];
foreach ($rows as $row) {
foreach ($receives as $receive) {
$res = TalkRecords::create([
'talk_type' => $receive['talk_type'],
'user_id' => $user_id,
'receiver_id' => $receive['id'],
'msg_type' => $row['msg_type'],
'content' => $row['content'],
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
$insRecordIds[] = [
'record_id' => $res->id,
'receiver_id' => $res->receiver_id,
'talk_type' => $res->talk_type
];
switch ($row['msg_type']) {
case TalkMessageType::FILE_MESSAGE:
$fileInfo = $fileArray[$row['id']];
$file[] = [
'record_id' => $res->id,
'user_id' => $fileInfo['user_id'],
'file_source' => $fileInfo['file_source'],
'file_type' => $fileInfo['file_type'],
'save_type' => $fileInfo['save_type'],
'original_name' => $fileInfo['original_name'],
'file_suffix' => $fileInfo['file_suffix'],
'file_size' => $fileInfo['file_size'],
'save_dir' => $fileInfo['save_dir'],
'created_at' => date('Y-m-d H:i:s')
];
break;
case TalkMessageType::CODE_MESSAGE:
$codeInfo = $codeArray[$row['id']];
$code[] = [
'record_id' => $res->id,
'user_id' => $user_id,
'code_lang' => $codeInfo['code_lang'],
'code' => $codeInfo['code'],
'created_at' => date('Y-m-d H:i:s')
];
break;
}
}
}
$code && TalkRecordsCode::insert($code);
$file && TalkRecordsFile::insert($file);
Db::commit();
} catch (\Exception $e) {
Db::rollBack();
return [];
}
return $insRecordIds;
}
}

View File

@ -8,10 +8,7 @@ use App\Constants\TalkModeConstant;
use App\Event\TalkEvent;
use App\Service\Group\GroupMemberService;
use App\Service\Message\FormatMessageService;
use Exception;
use App\Model\Talk\TalkRecords;
use App\Model\Talk\TalkRecordsCode;
use App\Model\Talk\TalkRecordsFile;
use App\Model\Talk\TalkRecordsForward;
use App\Traits\PagingTrait;
use Hyperf\DbConnection\Db;
@ -31,7 +28,7 @@ class TalkService extends BaseService
* @param array $msg_type 消息类型
* @return array
*/
public function getChatRecords(int $user_id, int $receiver_id, int $talk_type, int $record_id, $limit = 30, $msg_type = [])
public function getChatRecords(int $user_id, int $receiver_id, int $talk_type, int $record_id, $limit = 30, $msg_type = []): array
{
$fields = [
'talk_records.id',
@ -65,9 +62,10 @@ class TalkService extends BaseService
});
} else {
$rowsSqlObj->where('talk_records.receiver_id', $receiver_id);
$rowsSqlObj->where('talk_records.talk_type', $talk_type);
}
$rowsSqlObj->where('talk_records.talk_type', $talk_type);
if ($msg_type) {
$rowsSqlObj->whereIn('talk_records.msg_type', $msg_type);
}
@ -106,7 +104,7 @@ class TalkService extends BaseService
* @param int $record_id 聊天记录ID
* @return array
*/
public function getForwardRecords(int $user_id, int $record_id)
public function getForwardRecords(int $user_id, int $record_id): array
{
$result = TalkRecords::where('id', $record_id)->first([
'id', 'talk_type', 'msg_type', 'user_id', 'receiver_id', 'content', 'is_revoke', 'created_at'
@ -151,7 +149,7 @@ class TalkService extends BaseService
* @param array $record_ids 聊天记录ID
* @return bool
*/
public function removeRecords(int $user_id, int $talk_type, int $receiver_id, array $record_ids)
public function removeRecords(int $user_id, int $talk_type, int $receiver_id, array $record_ids): bool
{
if ($talk_type == TalkModeConstant::PRIVATE_CHAT) {// 私聊信息
$ids = TalkRecords::whereIn('id', $record_ids)->where(function ($query) use ($user_id, $receiver_id) {
@ -190,7 +188,7 @@ class TalkService extends BaseService
* @param int $record_id 聊天记录ID
* @return array
*/
public function revokeRecord(int $user_id, int $record_id)
public function revokeRecord(int $user_id, int $record_id): array
{
$result = TalkRecords::where('id', $record_id)->first(['id', 'talk_type', 'user_id', 'receiver_id', 'created_at']);
if (!$result) return [false, '消息记录不存在'];
@ -220,221 +218,6 @@ class TalkService extends BaseService
return [true, '消息已撤回', $result->toArray()];
}
/**
* 转发消息(单条转发)
*
* @param int $user_id 转发的用户ID
* @param int $record_id 转发消息的记录ID
* @param array $receiver_ids 接受者数组 例如:[['talk_type' => 1,'id' => 3045]...] 二维数组
* @return array
*/
public function forwardRecords(int $user_id, int $record_id, array $receiver_ids)
{
$msgTypeArray = [
TalkMessageType::TEXT_MESSAGE,
TalkMessageType::FILE_MESSAGE,
TalkMessageType::CODE_MESSAGE
];
$result = TalkRecords::where('id', $record_id)->whereIn('msg_type', $msgTypeArray)->first();
if (!$result) return [];
// 根据消息类型判断用户是否有转发权限
if ($result->talk_type == TalkModeConstant::PRIVATE_CHAT) {
if ($result->user_id != $user_id && $result->receiver_id != $user_id) {
return [];
}
} else if ($result->talk_type == TalkModeConstant::GROUP_CHAT) {
if (!di()->get(GroupMemberService::class)->isMember($result->receiver_id, $user_id)) {
return [];
}
}
$fileInfo = $codeBlock = null;
if ($result->msg_type == TalkMessageType::FILE_MESSAGE) {
$fileInfo = TalkRecordsFile::where('record_id', $record_id)->first();
} else if ($result->msg_type == TalkMessageType::CODE_MESSAGE) {
$codeBlock = TalkRecordsCode::where('record_id', $record_id)->first();
}
$insRecordIds = [];
Db::beginTransaction();
try {
foreach ($receiver_ids as $item) {
$res = TalkRecords::create([
'talk_type' => $item['talk_type'],
'msg_type' => $result->msg_type,
'user_id' => $user_id,
'receiver_id' => $item['id'],
'content' => $result->content,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
if (!$res) {
throw new Exception('插入消息记录失败');
}
$insRecordIds[] = [
'record_id' => $res->id,
'receiver_id' => $res->receiver_id,
'talk_type' => $res->talk_type
];
if ($result->msg_type == TalkMessageType::FILE_MESSAGE) {
if (!TalkRecordsFile::create([
'record_id' => $res->id,
'user_id' => $fileInfo->user_id,
'file_source' => $fileInfo->file_source,
'file_type' => $fileInfo->file_type,
'save_type' => $fileInfo->save_type,
'original_name' => $fileInfo->original_name,
'file_suffix' => $fileInfo->file_suffix,
'file_size' => $fileInfo->file_size,
'save_dir' => $fileInfo->save_dir,
'created_at' => date('Y-m-d H:i:s')
])) {
throw new Exception('插入文件消息记录失败');
}
} else if ($result->msg_type == TalkMessageType::CODE_MESSAGE) {
if (!TalkRecordsCode::create([
'record_id' => $res->id,
'user_id' => $user_id,
'code_lang' => $codeBlock->code_lang,
'code' => $codeBlock->code,
'created_at' => date('Y-m-d H:i:s')
])) {
throw new Exception('插入代码消息记录失败');
}
}
}
Db::commit();
} catch (Exception $e) {
Db::rollBack();
return [];
}
return $insRecordIds;
}
/**
* 转发消息(多条合并转发)
*
* @param int $user_id 转发的用户ID
* @param int $receiver_id 当前转发消息的所属者(好友ID或者群聊ID)
* @param int $talk_type 消息来源 1:好友消息 2:群聊消息
* @param array $records_ids 转发消息的记录ID
* @param array $receive_ids 接受者数组 例如:[['talk_type' => 1,'id' => 3045]...] 二维数组
* @return array
*/
public function mergeForwardRecords(int $user_id, int $receiver_id, int $talk_type, array $records_ids, array $receive_ids)
{
// 支持转发的消息类型
$msg_type = [
TalkMessageType::TEXT_MESSAGE,
TalkMessageType::FILE_MESSAGE,
TalkMessageType::CODE_MESSAGE
];
$sqlObj = TalkRecords::whereIn('id', $records_ids);
if ($talk_type == TalkModeConstant::PRIVATE_CHAT) {
if (!di()->get(UserFriendService::class)->isFriend($user_id, $receiver_id, true)) return [];
$sqlObj = $sqlObj->where(function ($query) use ($user_id, $receiver_id) {
$query->where([
['user_id', '=', $user_id],
['receiver_id', '=', $receiver_id]
])->orWhere([
['user_id', '=', $receiver_id],
['receiver_id', '=', $user_id]
]);
})->whereIn('msg_type', $msg_type)->where('talk_type', $talk_type)->where('is_revoke', 0);
} else {
if (!di()->get(GroupMemberService::class)->isMember($receiver_id, $user_id)) return [];
$sqlObj = $sqlObj->where('receiver_id', $receiver_id)->whereIn('msg_type', $msg_type)->where('talk_type', TalkModeConstant::GROUP_CHAT)->where('is_revoke', 0);
}
$result = $sqlObj->get();
// 判断消息记录是否存在
if (count($result) != count($records_ids)) {
return [];
}
$rows = TalkRecords::leftJoin('users', 'users.id', '=', 'talk_records.user_id')
->whereIn('talk_records.id', array_slice($records_ids, 0, 3))
->get(['talk_records.msg_type', 'talk_records.content', 'users.nickname']);
$jsonText = [];
foreach ($rows as $row) {
switch ($row->msg_type) {
case TalkMessageType::TEXT_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => mb_substr(str_replace(PHP_EOL, "", $row->content), 0, 30)
];
break;
case TalkMessageType::FILE_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => '【文件消息】'
];
break;
case TalkMessageType::CODE_MESSAGE:
$jsonText[] = [
'nickname' => $row->nickname,
'text' => '【代码消息】'
];
break;
}
}
$insRecordIds = [];
Db::beginTransaction();
try {
foreach ($receive_ids as $item) {
$res = TalkRecords::create([
'talk_type' => $item['talk_type'],
'user_id' => $user_id,
'receiver_id' => $item['id'],
'msg_type' => TalkMessageType::FORWARD_MESSAGE,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
if (!$res) {
throw new Exception('插入消息失败');
}
$insRecordIds[] = [
'record_id' => $res->id,
'receiver_id' => $res->receiver_id,
'talk_type' => $res->talk_type
];
if (!TalkRecordsForward::create([
'record_id' => $res->id,
'user_id' => $user_id,
'records_id' => implode(',', $records_ids),
'text' => json_encode($jsonText),
'created_at' => date('Y-m-d H:i:s'),
])) {
throw new Exception('插入转发消息失败');
}
}
Db::commit();
} catch (Exception $e) {
Db::rollBack();
return [];
}
return $insRecordIds;
}
/**
* 关键词搜索聊天记录
*
@ -446,7 +229,7 @@ class TalkService extends BaseService
* @param array $params 查询参数
* @return array
*/
public function searchRecords(int $user_id, int $receiver_id, int $talk_type, int $page, int $page_size, array $params)
public function searchRecords(int $user_id, int $receiver_id, int $talk_type, int $page, int $page_size, array $params): array
{
$fields = [
'talk_records.id',
@ -474,9 +257,10 @@ class TalkService extends BaseService
});
} else {
$rowsSqlObj->where('talk_records.receiver_id', $receiver_id);
$rowsSqlObj->where('talk_records.talk_type', $talk_type);
}
$rowsSqlObj->where('talk_records.talk_type', $talk_type);
if (isset($params['keywords'])) {
$rowsSqlObj->where('talk_records.content', 'like', "%{$params['keywords']}%");
}

View File

@ -22,7 +22,7 @@ class CreateTalkRecordsDeleteTable extends Migration
$table->collation = 'utf8_general_ci';
$table->engine = 'InnoDB';
$table->index(['record_id', 'user_id'], 'idx_record_user_id');
$table->unique(['record_id', 'user_id'], 'uk_record_id_user_id');
});
$prefix = config('databases.default.prefix');