initializeApi($request); if ($response !== null) { return $response; } $action = $this->getActionFromPath($request->path()); $needLogin = !action_in_arr($this->noNeedLogin, $action); $needPermission = !action_in_arr($this->noNeedPermission, $action); try { $this->auth = Auth::instance(); $token = get_auth_token(['ba', 'token'], $request); if ($token) { $this->auth->init($token); } } catch (TokenExpirationException) { if ($needLogin) { return $this->error(__('Token expiration'), [], 409); } } if ($needLogin) { if (!$this->auth->isLogin()) { return $this->error(__('Please login first'), [ 'type' => Auth::NEED_LOGIN, ], 0, ['statusCode' => Auth::LOGIN_RESPONSE_CODE]); } if ($needPermission) { $controllerPath = $this->getControllerPath($request); $routePath = $controllerPath . '/' . $action; if (!$this->auth->check($routePath)) { return $this->error(__('You have no permission'), [], 401); } } } event_trigger('backendInit', $this->auth); if (method_exists($this, 'initController')) { $initResp = $this->initController($request); if ($initResp !== null) { return $initResp; } } return null; } /** * 子类可覆盖,用于初始化 model 等(替代原 initialize) * @return Response|null 需直接返回时返回 Response,否则 null */ protected function initController(WebmanRequest $request): ?Response { return null; } public function index(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; return $this->_index(); } public function add(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; return $this->_add(); } public function edit(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; return $this->_edit(); } public function del(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; return $this->_del(); } public function sortable(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; return $this->_sortable(); } public function select(WebmanRequest $request): Response { $response = $this->initializeBackend($request); if ($response !== null) return $response; $this->select(); return $this->success(); } /** * 查询参数构建器 */ public function queryBuilder(): array { if (empty($this->model) || !$this->request) { return [[], [], 10, []]; } $pk = $this->model->getPk(); $quickSearch = $this->request->get('quickSearch', ''); $limit = $this->request->get('limit', 10); $limit = is_numeric($limit) ? intval($limit) : 10; $search = $this->request->get('search', []); $search = is_array($search) ? $search : []; $initKey = $this->request->get('initKey', $pk); $initValue = $this->request->get('initValue', ''); $initOperator = $this->request->get('initOperator', 'in'); $where = []; $modelTable = strtolower($this->model->getTable()); $alias = []; $alias[$modelTable] = parse_name(basename(str_replace('\\', '/', get_class($this->model)))); $mainTableAlias = $alias[$modelTable] . '.'; if ($quickSearch) { $quickSearchArr = is_array($this->quickSearchField) ? $this->quickSearchField : explode(',', $this->quickSearchField); foreach ($quickSearchArr as $k => $v) { $quickSearchArr[$k] = str_contains($v, '.') ? $v : $mainTableAlias . $v; } $where[] = [implode('|', $quickSearchArr), 'LIKE', '%' . str_replace('%', '\%', $quickSearch) . '%']; } if ($initValue) { $where[] = [$initKey, $initOperator, $initValue]; $limit = 999999; } foreach ($search as $field) { if (!is_array($field) || !isset($field['operator']) || !isset($field['field']) || !isset($field['val'])) { continue; } $field['operator'] = $this->getOperatorByAlias($field['operator']); if (str_contains($field['field'], '.')) { $fieldNameParts = explode('.', $field['field']); $fieldNamePartsLastKey = array_key_last($fieldNameParts); foreach ($fieldNameParts as $fieldNamePartsKey => $fieldNamePart) { if ($fieldNamePartsKey !== $fieldNamePartsLastKey) { $fieldNameParts[$fieldNamePartsKey] = parse_name($fieldNamePart); } } $fieldName = implode('.', $fieldNameParts); } else { $fieldName = $mainTableAlias . $field['field']; } if (isset($field['render']) && $field['render'] == 'datetime') { if ($field['operator'] == 'RANGE') { $datetimeArr = explode(',', $field['val']); if (!isset($datetimeArr[1])) { continue; } $datetimeArr = array_filter(array_map('strtotime', $datetimeArr)); $where[] = [$fieldName, str_replace('RANGE', 'BETWEEN', $field['operator']), $datetimeArr]; continue; } $where[] = [$fieldName, '=', strtotime($field['val'])]; continue; } if ($field['operator'] == 'RANGE' || $field['operator'] == 'NOT RANGE') { $arr = explode(',', $field['val']); if (!isset($arr[0]) || $arr[0] === '') { $operator = $field['operator'] == 'RANGE' ? '<=' : '>'; $arr = $arr[1]; } elseif (!isset($arr[1]) || $arr[1] === '') { $operator = $field['operator'] == 'RANGE' ? '>=' : '<'; $arr = $arr[0]; } else { $operator = str_replace('RANGE', 'BETWEEN', $field['operator']); } $where[] = [$fieldName, $operator, $arr]; continue; } switch ($field['operator']) { case '=': case '<>': $where[] = [$fieldName, $field['operator'], strval($field['val'])]; break; case 'LIKE': case 'NOT LIKE': $where[] = [$fieldName, $field['operator'], '%' . str_replace('%', '\%', $field['val']) . '%']; break; case '>': case '>=': case '<': case '<=': $where[] = [$fieldName, $field['operator'], intval($field['val'])]; break; case 'FIND_IN_SET': if (is_array($field['val'])) { foreach ($field['val'] as $val) { $where[] = [$fieldName, 'find in set', $val]; } } else { $where[] = [$fieldName, 'find in set', $field['val']]; } break; case 'IN': case 'NOT IN': $where[] = [$fieldName, $field['operator'], is_array($field['val']) ? $field['val'] : explode(',', $field['val'])]; break; case 'NULL': case 'NOT NULL': $where[] = [$fieldName, strtolower($field['operator']), '']; break; } } $dataLimitAdminIds = $this->getDataLimitAdminIds(); if ($dataLimitAdminIds) { $where[] = [$mainTableAlias . $this->dataLimitField, 'in', $dataLimitAdminIds]; } return [$where, $alias, $limit, $this->queryOrderBuilder()]; } /** * 查询的排序参数构建器 */ public function queryOrderBuilder(): array { $pk = $this->model->getPk(); $order = $this->request ? $this->request->get('order') : null; $order = $order ?: $this->defaultSortField; if ($order && is_string($order)) { $order = explode(',', $order); $order = [$order[0] => $order[1] ?? 'asc']; } if (!$this->orderGuarantee) { $this->orderGuarantee = [$pk => 'desc']; } elseif (is_string($this->orderGuarantee)) { $orderParts = explode(',', $this->orderGuarantee); $this->orderGuarantee = [$orderParts[0] => $orderParts[1] ?? 'asc']; } $orderGuaranteeKey = array_key_first($this->orderGuarantee); if (!is_array($order) || !array_key_exists($orderGuaranteeKey, $order)) { $order[$orderGuaranteeKey] = $this->orderGuarantee[$orderGuaranteeKey]; } return $order; } /** * 数据权限控制 - 获取有权限访问的管理员 IDs */ protected function getDataLimitAdminIds(): array { if (!$this->dataLimit || !$this->auth || $this->auth->isSuperAdmin()) { return []; } $adminIds = []; if ($this->dataLimit == 'parent') { $parentGroups = $this->auth->getAdminChildGroups(); if ($parentGroups) { $adminIds = $this->auth->getGroupAdmins($parentGroups); } } elseif (is_numeric($this->dataLimit) && $this->dataLimit > 0) { $adminIds = $this->auth->getGroupAdmins([$this->dataLimit]); return in_array($this->auth->id, $adminIds) ? [] : [$this->auth->id]; } elseif ($this->dataLimit == 'allAuth' || $this->dataLimit == 'allAuthAndOthers') { $allAuthGroups = $this->auth->getAllAuthGroups($this->dataLimit); $adminIds = $this->auth->getGroupAdmins($allAuthGroups); } $adminIds[] = $this->auth->id; return array_unique($adminIds); } /** * 从别名获取原始的逻辑运算符 */ protected function getOperatorByAlias(string $operator): string { $alias = [ 'ne' => '<>', 'eq' => '=', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', ]; return $alias[$operator] ?? $operator; } /** * 从 path 解析 action */ protected function getActionFromPath(string $path): string { $parts = explode('/', trim($path, '/')); return $parts[array_key_last($parts)] ?? ''; } /** * 从 Request 或路由解析控制器路径(如 auth/admin) * 优先从 $request->controller(Webman 路由匹配时设置)解析,否则从 path 解析 */ protected function getControllerPath(WebmanRequest $request): string { return get_controller_path($request); } }