StatsScope.php 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. <?php
  2. namespace App\Support;
  3. use Illuminate\Support\Facades\DB;
  4. /**
  5. * 统计口径:排除试玩账号(users.from = 2)和测试会员 / 测试代理(agents.is_test = 1)。
  6. * 测试会员 = users.agent_id 指向测试代理的会员,按代理当前设置判断(切换后历史数据跟着变)。
  7. * 只用于统计;明细列表、待办角标、代理看自己名下会员的数据不用它。
  8. */
  9. final class StatsScope
  10. {
  11. private static ?\WeakMap $enabled = null;
  12. /** agents.is_test 存在时才过滤(迁移执行前、或没有代理表时不过滤)。按数据库连接缓存,避免每次查表结构。 */
  13. public static function enabled(): bool
  14. {
  15. self::$enabled ??= new \WeakMap();
  16. $connection = DB::connection();
  17. return self::$enabled[$connection] ??= DB::getSchemaBuilder()->hasTable('agents') && DB::getSchemaBuilder()->hasColumn('agents', 'is_test');
  18. }
  19. /** 当前所有测试代理的 ID(用于在 PHP 里过滤已加载的数据)。 */
  20. public static function testAgentIdList(): array
  21. {
  22. return self::enabled() ? array_map('intval', self::testAgentIds()->pluck('id')->all()) : [];
  23. }
  24. /** 测试代理 ID 子查询。 */
  25. public static function testAgentIds()
  26. {
  27. return DB::table('agents')->select('id')->where('is_test', 1);
  28. }
  29. /** 测试会员的某一列(member_id / id)子查询。 */
  30. public static function testMembers(string $column = 'member_id')
  31. {
  32. return DB::table('users')->select($column)->whereIn('agent_id', self::testAgentIds());
  33. }
  34. /** users 查询:排除测试会员。$alias 为 users 表在查询里的别名或表名。 */
  35. public static function excludeTestUsers($query, string $alias = 'users')
  36. {
  37. if (!self::enabled()) return $query;
  38. return $query->where(fn ($q) => $q->whereNull($alias . '.agent_id')->orWhereNotIn($alias . '.agent_id', self::testAgentIds()));
  39. }
  40. /** users 查询:只留真实会员(排除试玩账号和测试会员)。 */
  41. public static function realUsers($query, string $alias = 'users')
  42. {
  43. $query->where(fn ($q) => $q->whereNull($alias . '.from')->orWhere($alias . '.from', '<>', 2));
  44. return self::excludeTestUsers($query, $alias);
  45. }
  46. /** 原生 SQL 用:users 别名为 $alias 时追加的条件(以 AND 开头),未启用时为空串。 */
  47. public static function rawExcludeTestUsers(string $alias = 'u'): string
  48. {
  49. if (!self::enabled()) return '';
  50. $agents = DB::getTablePrefix() . 'agents';
  51. return " AND ({$alias}.agent_id IS NULL OR {$alias}.agent_id NOT IN (SELECT id FROM {$agents} WHERE is_test = 1))";
  52. }
  53. /** 按会员统计的表(member_id 或 user_id 列):排除测试会员。 */
  54. public static function excludeTestMembers($query, string $column = 'member_id', string $userColumn = 'member_id')
  55. {
  56. if (!self::enabled()) return $query;
  57. return $query->whereNotIn($column, self::testMembers($userColumn));
  58. }
  59. /** 代理资金表(agent_id 列):排除测试代理。agent_id 为空的行保留。 */
  60. public static function excludeTestAgents($query, string $column = 'agent_id')
  61. {
  62. if (!self::enabled()) return $query;
  63. return $query->where(fn ($q) => $q->whereNull($column)->orWhereNotIn($column, self::testAgentIds()));
  64. }
  65. }