hasTable('agents') && DB::getSchemaBuilder()->hasColumn('agents', 'is_test'); } /** 当前所有测试代理的 ID(用于在 PHP 里过滤已加载的数据)。 */ public static function testAgentIdList(): array { return self::enabled() ? array_map('intval', self::testAgentIds()->pluck('id')->all()) : []; } /** 测试代理 ID 子查询。 */ public static function testAgentIds() { return DB::table('agents')->select('id')->where('is_test', 1); } /** 测试会员的某一列(member_id / id)子查询。 */ public static function testMembers(string $column = 'member_id') { return DB::table('users')->select($column)->whereNotNull($column)->whereIn('agent_id', self::testAgentIds()); } /** 不进正式统计的会员的某一列子查询:模拟会员、游客(from = 2)、测试会员。 */ private static function excludedMembers(string $column) { $testAgents = self::enabled(); return DB::table('users')->select($column)->whereNotNull($column)->where(function ($q) use ($testAgents) { $q->where('user_type', '<>', 0)->orWhere('from', 2); if ($testAgents) $q->orWhereIn('agent_id', self::testAgentIds()); }); } /** users 查询:排除测试会员和模拟会员(游客保留,由调用方按 from 区分)。$alias 为 users 表在查询里的别名或表名。 */ public static function excludeTestUsers($query, string $alias = 'users') { MemberAudience::visibleUsers($query, $alias); if (MemberAudience::isSimulated() || !self::enabled()) return $query; return $query->where(fn ($q) => $q->whereNull($alias . '.agent_id')->orWhereNotIn($alias . '.agent_id', self::testAgentIds())); } /** users 查询:只留真实会员(排除游客、模拟会员和测试会员)。模拟口径下只留模拟会员。 */ public static function realUsers($query, string $alias = 'users') { if (MemberAudience::isSimulated()) return MemberAudience::visibleUsers($query, $alias); $query->where(fn ($q) => $q->whereNull($alias . '.from')->orWhere($alias . '.from', '<>', 2)); return self::excludeTestUsers($query, $alias); } /** users 查询:只留游客(from = 2 且不是模拟会员)。 */ public static function guestUsers($query, string $alias = 'users') { if (MemberAudience::isSimulated()) return $query->whereRaw('1 = 0'); return MemberAudience::visibleUsers($query->where($alias . '.from', 2), $alias); } /** 原生 SQL 用:users 别名为 $alias 时追加的条件(以 AND 开头),只留真实会员;模拟口径下只留模拟会员。 */ public static function rawExcludeTestUsers(string $alias = 'u'): string { if (MemberAudience::isSimulated()) return MemberAudience::rawVisibleUsers($alias); $sql = MemberAudience::enabled() ? " AND {$alias}.user_type = 0 AND ({$alias}.`from` IS NULL OR {$alias}.`from` <> '2')" : ''; if (!self::enabled()) return $sql; $agents = DB::getTablePrefix() . 'agents'; return $sql . " AND ({$alias}.agent_id IS NULL OR {$alias}.agent_id NOT IN (SELECT id FROM {$agents} WHERE is_test = 1))"; } /** 按会员统计的表(member_id 或 user_id 列):只留真实会员的数据;模拟口径下只留模拟会员的数据。 */ public static function excludeTestMembers($query, string $column = 'member_id', string $userColumn = 'member_id') { if (MemberAudience::isSimulated()) return MemberAudience::visibleMembers($query, $column, $userColumn); if (MemberAudience::enabled()) return $query->whereNotIn($column, self::excludedMembers($userColumn)); if (!self::enabled()) return $query; return $query->whereNotIn($column, self::testMembers($userColumn)); } /** 代理资金表(agent_id 列):排除测试代理。agent_id 为空的行保留。 */ public static function excludeTestAgents($query, string $column = 'agent_id') { if (MemberAudience::isSimulated()) return $query->whereRaw('1 = 0'); if (!self::enabled()) return $query; return $query->where(fn ($q) => $q->whereNull($column)->orWhereNotIn($column, self::testAgentIds())); } }