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(); } }