| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- <?php
- namespace App\Support;
- use Illuminate\Support\Facades\DB;
- /**
- * 统计口径:排除游客(users.from = 2)、后台模拟会员(users.user_type = 2)和测试会员 / 测试代理(agents.is_test = 1)。
- * 模拟口径(MemberAudience::simulated())下反过来:只统计模拟会员,代理资金一律不计。
- * 测试会员 = users.agent_id 指向测试代理的会员,按代理当前设置判断(切换后历史数据跟着变)。
- * 只用于统计;明细列表、待办角标、代理看自己名下会员的数据不用它。
- */
- final class StatsScope
- {
- private static ?\WeakMap $enabled = null;
- /** agents.is_test 存在时才过滤(迁移执行前、或没有代理表时不过滤)。按数据库连接缓存,避免每次查表结构。 */
- public static function enabled(): bool
- {
- self::$enabled ??= new \WeakMap();
- $connection = DB::connection();
- return self::$enabled[$connection] ??= DB::getSchemaBuilder()->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()));
- }
- }
|