123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- <?php
- declare(strict_types=1);
- namespace App\Services\Interface\Database;
- use GuzzleHttp\Client;
- use Illuminate\Http\JsonResponse;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Carbon;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Request;
- use Illuminate\Support\Str;
- use Txj\Elastic\Facades\ES;
- class CommonDb
- {
- protected array $requestData;
- protected string $table;
- /**
- * 接口信息.
- */
- protected array $interfaceInfo;
- protected array $interfaceSettingInfo = [];
- protected array $conditionSettingsInfo = [];
- protected array $interfaceResultInfo = [];
- /**
- * 集合信息.
- */
- protected array $assembleInfo = [];
- /**
- * 集合字段信息
- * 、@var array.
- */
- protected array $assembleColumns = [];
- /**
- * 字段id到字段编码的映射.
- */
- protected array $columnIdToCodes = [];
- public function __construct(array $interfaceInfo, array $assembleInfo, array $assembleColumns, array $requestData, array $columnIdToCodes)
- {
- $this->interfaceInfo = $interfaceInfo;
- $this->assembleInfo = $assembleInfo;
- $this->assembleColumns = $assembleColumns;
- $this->requestData = $requestData;
- $this->columnIdToCodes = $columnIdToCodes;
- $this->table = $this->assembleInfo['schema'];
- // 请求参数配置
- $this->interfaceSettingInfo = $this->interfaceInfo['request_settings'] ? json_decode($this->interfaceInfo['request_settings'], true) : [];
- // 条件配置
- $this->conditionSettingsInfo = $this->interfaceInfo['condition_settings'] ? json_decode($this->interfaceInfo['condition_settings'], true) : [];
- // 请求结果配置
- $this->interfaceResultInfo = $this->interfaceInfo['result_settings'] ? json_decode($this->interfaceInfo['result_settings'], true) : [];
- }
- /**
- * 获取部分字段.
- *
- * @param $find
- */
- public function getSelectFields(): array
- {
- $column_only_one = $this->interfaceResultInfo['column_only_one'] ?? false; // 是否直接返回单个字段
- $needFiledIds = $this->interfaceResultInfo['columns'] ?? []; // 需要返回的字段id
- $showColumnsArr = [];
- if ($column_only_one) {
- $showColumnsArr[] = $this->columnIdToCodes[$needFiledIds];
- } else {
- if ($needFiledIds) { // 将id,转为字段
- foreach ($needFiledIds as $column_id) {
- if (isset($this->columnIdToCodes[$column_id])) {
- $showColumnsArr[] = $this->columnIdToCodes[$column_id];
- }
- }
- }
- }
- return $showColumnsArr;
- }
- /**
- * 排序规则.
- *
- * @param $find
- */
- public function sortFields($find): void
- {
- $sortSettings = $this->interfaceInfo['sort_settings'] ?? '';
- if ($sortSettings) {
- foreach ($sortSettings as $row) {
- $column = $this->columnIdToCodes[$row['column_id']];
- // 转化为json字符串的方式 替换数组里面的模板变量
- $params = $this->replaceParams($this->requestData, $row);
- if (isset($row['is_allow']) && $row['is_allow']) {
- if (isset($this->requestData['sort_' . $column]) && \in_array($this->requestData['sort_' . $column], ['asc', 'desc'], true)) {
- $find->orderBy($column, $this->requestData['sort_' . $column], $params);
- } else {
- if (isset($row['direction']) && $row['direction']) {
- $find->orderBy($column, $row['direction'], $params);
- }
- }
- } else {
- if (isset($row['direction']) && $row['direction']) {
- $find->orderBy($column, $row['direction'], $params);
- }
- }
- }
- }
- }
- /**
- * 转化为json字符串的方式
- * 替换数组里面的模板变量.
- *
- * $requestData = [
- * 'sort_location' => 12,
- * 'sort_order' => 13,
- * ];
- *
- * $params = [
- * 'location' => [
- * 'lon' => '${location}',
- * 'lat' => '${order}',
- * ]
- * ];
- *
- * @param $requestData
- */
- private function replaceParams($requestData, ?array $row): mixed
- {
- $params = (isset($row['is_params']) && $row['is_params']) ? $row['params'] : [];
- if ($params) {
- $paramsJson = json_encode($params);
- preg_match_all('/\$\{(.*?)}/', $paramsJson, $arr);
- if ($arr && isset($arr[1])) {
- $flagArr = $arr[1];
- foreach ($flagArr as $row) {
- $value = $requestData['sort_' . $row] ?? '';
- $paramsJson = preg_replace('/\$\{' . $row . '}/', $value, $paramsJson, 1);
- }
- }
- return json_decode($paramsJson, true);
- }
- return $params;
- }
- // //////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * 执行搜索的内容.
- */
- public function execSearchCon($find, $row): void
- {
- $es_type = $row['es_type'];
- $operate = $row['es_operate'];
- $childrenArr = $row['children'] ?? [];
- // 字段可能是数组,比如query_string
- if (\is_array($row['column_id'])) {
- foreach ($row['column_id'] as $id) {
- $column[] = $this->columnIdToCodes[$id];
- }
- } else {
- $column = $this->columnIdToCodes[$row['column_id']];
- }
- // 请求的参数,也有可能是数组,比如terms,range
- $value = [];
- if (\is_array($row['value'])) {
- foreach ($row['value'] as $name) {
- if (isset($this->requestData[$name])) {
- $value[] = $this->requestData[$name];
- } else {
- abort(508, '条件参数配置错误,' . $name . ' 值为空!');
- }
- }
- } else {
- if (isset($this->requestData[$row['value']])) {
- $value = $this->requestData[$row['value']];
- } else {
- // 如果没有值,忽略查询,如果不想忽略,则需要在请求参数设置为必填项
- // abort(508, '条件参数配置错误,' . $row['value'] . ' 值为空!');
- }
- }
- if ($value || 0 === $value) { // 如果值存在,则执行
- if (empty($childrenArr)) {
- $find->{$es_type}($column, $operate, $value);
- } else {
- $find->{$es_type}(function ($query) use ($childrenArr): void {
- if ($childrenArr) {
- foreach ($childrenArr as $child) {
- $this->execSearchCon($query, $child);
- }
- }
- });
- }
- }
- }
- // //////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * 判断条件执行参数,根据if-elseif-else逻辑获取结果.
- *
- * @param string $searchOrResultType 判断是搜索内容处理,还是结果集内容管理
- */
- public function checkExpression(string $searchOrResultType, array $data, array $condition, $find = null): array|null
- {
- $expressionResult = null;
- // if else 转换为代码执行
- foreach ($condition as $judge) {
- // 参数
- $paramsArr = $judge['params'];
- $resultBool = $parentCurrent = true;
- foreach ($paramsArr as $key => $row) {
- if (0 == $key) {
- $resultBool = $parentCurrent = $this->execExpression($data, $row);
- } else {
- if ('and' == $row['type']) {
- if (true === $parentCurrent) {
- $resultBool = $parentCurrent = $this->execExpression($data, $row);
- } else {
- $resultBool = false;
- break;
- }
- } elseif ('or' == $row['type']) {
- if (true === $parentCurrent) {
- $resultBool = true;
- break;
- } else {
- $resultBool = $parentCurrent = $this->execExpression($data, $row);
- }
- }
- }
- }
- if ($resultBool) { // 为真,执行内容
- if ('search_type' == $searchOrResultType) {
- // 搜索内容管理
- $searchCon = $judge['searchCon'];
- foreach ($searchCon as $con) {
- $this->execSearchCon($find, $con);
- }
- break; // 搜索参数判断成功后,直接停止向下执行
- } elseif ('result_type' == $searchOrResultType) {
- $manageCon = $judge['manageCon'];
- foreach ($manageCon as $con) {
- $expressionResult = $this->execManageCon($data, $con);
- // 根据返回类型判断,有的需要直接返回,不再继续向下执行
- // 1 继续执行 2 错误退出 3 返回退出 4 使用结果 5 直接退出
- if ($responseJson = $this->checkBackType($expressionResult, $data)) {
- return $responseJson;
- }
- }
- }
- break;
- }
- }
- // 返回最后一次执行的结果
- return $expressionResult;
- }
- /**
- * 执行函数或表达式.
- */
- private function execExpression(array $data, array $row): bool
- {
- $operate = $row['operate'];
- if ($row['isUseFn']) { // 使用函数
- $fnName = $row['fnName'];
- $fnParams = $row['fnParams'];
- // 如果存在! 则先截取出来
- preg_match('/^(!*)(.*)/', $fnName, $fnArr);
- $flag = $fnArr[1];
- $fnName = $fnArr[2];
- foreach ($fnParams as $requestColumn) {
- $val = Arr::get($data, $requestColumn);
- if ($val) {
- $fParams[] = $val;
- } else {
- $fParams[] = $requestColumn;
- }
- }
- $result = $this->execFunc($fnName, $fParams);
- if ($result) {
- $current = true;
- } else {
- $current = false;
- }
- // ! 非操作符
- if ($flag) {
- if (1 == \strlen($flag) % 2) {
- $current = !$current;
- }
- }
- } else { // 表达式
- $requestVal = Arr::get($data, $row['params']);
- if ($requestVal || 0 === $requestVal || true === $requestVal || false === $requestVal) {
- $current = $this->getOperateResult($requestVal, $operate, $row['value']);
- } else {
- $current = false;
- }
- }
- return $current;
- }
- /**
- * 普通查询处理.
- *
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- private function execManageCon(array $data, array $con): array|null
- {
- $success_code = (isset($con['success_code']) && $con['success_code']) ? $con['success_code'] : 1001;
- $success_msg = (isset($con['success_msg']) && $con['success_msg']) ? $con['success_msg'] : '恭喜你,操作成功!';
- $failed_code = (isset($con['failed_code']) && $con['failed_code']) ? $con['failed_code'] : 2001;
- $failed_msg = (isset($con['failed_msg']) && $con['failed_msg']) ? $con['failed_msg'] : '操作失败,请稍后再试!';
- // 返回类型为5,直接返回,终止执行
- if (5 == $con['back_type']) {
- $backResult = backJson($failed_code, $failed_msg);
- return ['error' => false, 'back_type' => $con['back_type'], 'result' => $backResult];
- }
- $requestParams = [];
- if (isset($con['column']) && $con['column']) {
- foreach ($con['column'] as $requestColumn) {
- $val = Arr::get($data, $requestColumn);
- if ($val) {
- $requestParams[$requestColumn] = $val;
- } else {
- $requestParams[] = $requestColumn; // 如果值不存在,则当前字段,会作为值来处理
- }
- }
- }
- // 防止非法参数向下传递
- Request::replace($requestParams);
- $param_type = $con['param_type']; // 1 接口 2 函数 3 自定义接口
- if (1 == $param_type) { // 接口
- $result = $this->execInterface($con['interface_id']);
- } elseif (2 == $param_type) { // 函数
- $result = $this->execFunc($con['fnName'], array_values($requestParams));
- } elseif (3 == $param_type) { // 自定义接口
- $result = $this->execCustomInterface($con['url'], $requestParams);
- }
- if ($result instanceof JsonResponse) {
- $backResult = json_decode($result->getContent(), true);
- return ['error' => $backResult['error'], 'back_type' => $con['back_type'], 'result' => $backResult];
- } elseif (empty($result) || (isset($result['error']) && $result['error'])) {
- $backResult = backJson($result['code'] ?? $failed_code, $result['msg'] ?? $failed_msg);
- return ['error' => true, 'back_type' => $con['back_type'], 'result' => $backResult];
- } else {
- $backResult = backJson($success_code, $success_msg, isset($result['error']) ? $result['result'] : $result);
- return ['error' => false, 'back_type' => $con['back_type'], 'flag_uuid' => $con['flag_uuid'] ?? '', 'result' => $backResult];
- }
- }
- /**
- * 执行函数.
- */
- private function execFunc(string $function, array $params = []): mixed
- {
- if (empty($function)) {
- abort(508, '结果集设置错误!- 函数为空');
- }
- if (($flag1 = Str::contains($function, '@')) || Str::contains($function, '::')) {
- $arr = explode($flag1 ? '@' : '::', $function);
- $class = $arr[0] ?? '';
- $method = $arr[1] ?? 'handler';
- if ($class && class_exists($class)) {
- if ($flag1) {
- return \call_user_func_array([new $class($this->requestData, $this->interfaceInfo, $this->websiteInfo, $this->assembleInfo, $this->assembleColumns), $method], $params);
- } else {
- return \call_user_func_array([$class, $method], $params);
- }
- } else {
- abort(508, '接口参数设置错误!- 类【' . $class . '】不存在');
- }
- } elseif (\function_exists($function)) { // 如果是函数,则使用函数处理,参数:当前字段信息,接口信息,站点信息
- return \call_user_func_array($function, $params);
- }
- return '';
- }
- /**
- * 请求系统接口.
- *
- * @throws \Exception
- */
- private function execInterface(int $interfaceId): mixed
- {
- if (empty($interfaceId)) {
- abort(508, '结果集设置错误!- 设置的接口为空!');
- }
- // 获取接口信息
- $otherInterfaceInfo = ES::table('interface')->find($interfaceId);
- if ($otherInterfaceInfo) {
- $interfaceService = new static($otherInterfaceInfo['en_alias'], $this->websiteInfo);
- $errorMsg = $interfaceService->validator();
- if ($errorMsg) {
- abort(508, '结果集设置错误!- ' . $errorMsg);
- } else {
- $response = $interfaceService->exec();
- return json_decode($response->getContent(), true);
- }
- } else {
- abort(508, '结果集设置错误!- 设置的接口不存在');
- }
- }
- /**
- * 请求自定义接口.
- *
- * @throws \Exception
- */
- private function execCustomInterface(string $url, array $params = []): mixed
- {
- if (empty($url)) {
- abort(508, '结果集设置错误!- 设置的接口为空!');
- }
- $method = 'POST';
- $options = [
- 'json' => $params,
- 'timeout' => 60,
- 'verify' => false,
- ];
- if (!Str::startsWith($url, 'http')) {
- if (Str::contains($url, '/')) { // 为了过滤通过route(name)生成的url
- $url = secure_url($url);
- } else {
- // 路由名生成一个 URL
- $url = route($url);
- }
- }
- $client = new Client();
- return $client->request($method, $url, $options);
- }
- /**
- * 根据返回类型判断,有的需要直接返回,不再继续向下执行
- * 1 继续执行 2 错误退出 3 返回退出 4 使用结果 5 直接退出.
- *
- * @throws \Exception
- */
- private function checkBackType($expressionResult, &$data)
- {
- // 如果未设置任何参数,则不做任何处理,允许代码继续向下执行
- if (empty($expressionResult)) {
- return null;
- }
- // 1 继续执行 2 错误退出 3 返回退出 4 使用结果 5 直接退出
- $back_type = $expressionResult['back_type'];
- $flag_uuid = $expressionResult['flag_uuid'] ?? '';
- $backResult = $expressionResult['result'];
- if (2 == $back_type) {
- if (true === $backResult['error']) { // 如果出现错误,则返回错误信息
- $backResult['error'] = $backResult['error'] ?: '系统错误,请重试!';
- return $expressionResult;
- }
- } elseif (3 == $back_type) {
- return $expressionResult;
- } elseif (4 == $back_type) {
- $data[] = ['&' . $flag_uuid => $backResult];
- } elseif (5 == $back_type) {
- $backResult['error'] = $backResult['error'] ?: '系统错误,请重试!';
- return $expressionResult;
- }
- }
- /**
- * 操作符的操作结果.
- */
- private function getOperateResult(mixed $requestVal, string $operate, mixed $value): bool
- {
- return match ($operate) {
- 'true' => true == $requestVal,
- 'false' => false == $requestVal,
- '==' => $requestVal == $value,
- '>' => $requestVal > $value,
- '<' => $requestVal < $value,
- '>=' => $requestVal >= $value,
- '<=' => $requestVal <= $value,
- '!=' => $requestVal != $value,
- '===' => $requestVal === $value,
- '!==' => $requestVal !== $value,
- 'in' => \in_array($value, $requestVal),
- default => false,
- };
- }
- // //////////////////////////////////////////////////////////////////////////////////////////////
- // //////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * 兼容 eav 模式,获取表对象
- */
- private function getDbObject(): \Illuminate\Database\Query\Builder
- {
- return DB::table($this->table);
- }
- /**
- * 添加数据时 获取表对应的数据信息.
- */
- public function getTableToData(string $sysType, array $data): array
- {
- // 获取所有的属性
- $tableToData = []; // 过滤数据
- $tableEntityData = []; // 存在子表数据的信息
- foreach ($this->assembleColumns as $attributeInfo) {
- $attrId = $attributeInfo['id'];
- $type = $attributeInfo['type'];
- $code = $attributeInfo['code'];
- // 判断字段是否存在 非法字段进行过滤
- if (!\array_key_exists($code, $data)) {
- continue;
- }
- $value = $data[$code];
- if ('' === $value) {
- $value = $attributeInfo['default'] ?? '';
- }
- // 强制类型转换
- if (\in_array($type, ['integer', 'tinyInteger', 'smallInteger', 'mediumInteger', 'bigInteger'], true)) {
- $value = (int)$value;
- } elseif ('decimal' === $type) {
- $value = (float)$value;
- }
- if ('object' === $type || 'json' === $type) { // array 数据转换
- if (!\is_array($value)) {
- abort(509, '【' . $attributeInfo['code'] . '】数据必须为数组!- 01');
- }
- $tableEntityData[$code] = json_encode($value);
- } else {
- $tableEntityData[$code] = $value;
- }
- }
- // 系统固有字段进行修复
- $sysEntity = $this->getSysEntityData($data, $sysType);
- $tableEntityData = array_merge($sysEntity, $tableEntityData);
- return [$tableToData, $tableEntityData];
- }
- /**
- * 获取实体数据.
- */
- public function getSysEntityData(array $requestData, string $type = 'add'): array
- {
- $entityData = [];
- $timestampMs = Carbon::now()->getTimestamp(); // 获取当前时间的毫秒数
- if ('add' == $type) {
- if (isset($requestData['id']) && $requestData['id']) {
- $entityData['id'] = $requestData['id'];
- }
- }
- if (!isset($requestData['mid'])) {
- if ('add' == $type) {
- $entityData['mid'] = Str::random(12);
- }
- } else {
- $entityData['mid'] = $requestData['mid'];
- }
- if (!isset($requestData['created_at'])) {
- if ('add' == $type) {
- $entityData['created_at'] = $timestampMs;
- }
- } else {
- $entityData['created_at'] = $requestData['created_at'];
- }
- if (!isset($requestData['is_delete'])) {
- if ('add' == $type) {
- $entityData['is_delete'] = 0;
- }
- } else {
- $entityData['is_delete'] = $requestData['is_delete'];
- }
- if (!isset($requestData['weight'])) {
- if ('add' == $type) {
- $entityData['weight'] = 0;
- }
- } else {
- $entityData['weight'] = $requestData['weight'];
- }
- $entityData['updated_at'] = $timestampMs; // 获取当前时间的毫秒数
- return $entityData;
- }
- /**
- * 设置该集合对应的数据库连接.
- */
- public function getDbConnection(): ?string
- {
- return DB::getDefaultConnection();
- }
- }
|