diff --git a/.gitignore b/.gitignore
index 92bf9b0..224ad2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,5 @@
/windows.php
/bootstrap.php
/composer.lock
+.env_copy
+/public/excel
\ No newline at end of file
diff --git a/app/command/InquiryAssignInquiryCommand.php b/app/command/InquiryAssignInquiryCommand.php
new file mode 100644
index 0000000..adb8309
--- /dev/null
+++ b/app/command/InquiryAssignInquiryCommand.php
@@ -0,0 +1,161 @@
+ $v > 0
+ ));
+
+ if (empty($userIds)) {
+ throw new BusinessException('SALES_USER_IDS 业务员列表不能为空,请先在命令中配置.');
+ }
+
+ // 取出“待分配”的询盘(你可以根据自己系统调整条件)
+ // 当前策略:status = 0 且 recipient = 0 的视为未分配
+ $inquiries = Db::table('inquiry_log')
+ ->where('enter_user_id', 186)
+ ->where('channel', 10)
+ ->where('status', 0)
+ ->where('recipient', 0)
+ ->where('id', '>', 34426)
+ ->orderBy('id')
+ ->limit(static::BATCH_LIMIT)
+ ->get();
+
+ if ($inquiries->isEmpty()) {
+ $output->writeln('没有需要分配的询盘(status=0 且 recipient=0)');
+ return self::SUCCESS;
+ }
+
+ $now = time();
+ $count = 0;
+
+ foreach ($inquiries as $row) {
+ $inquiryId = (int)$row->id;
+ sleep(1);
+ // 轮询取出一个业务员 ID
+ $recipientUserId = $this->nextRecipientId($userIds, static::ROUND_ROBIN_GROUP_KEY);
+
+ // 对每一条记录单独事务,避免单条异常拖垮全部
+ Db::transaction(function () use ($inquiryId, $recipientUserId, $now, $output, &$count) {
+ // 1)更新 inquiry_log
+ $affected = Db::table('inquiry_log')
+ ->where('id', $inquiryId)
+ ->update([
+ 'recipient' => $recipientUserId,
+ 'status' => 2,
+ 'r_time' => $now,
+ 't_time' => $now,
+ 'updated_at' => $now,
+ ]);
+
+ if ($affected === 0) {
+ // 被其他进程抢先更新也有可能,这里只打印提示不中断整个批次
+ $output->writeln("询盘 {$inquiryId} 未更新(可能已被处理)");
+ return;
+ }
+
+ // 2)构造队列 payload(后续 CRM 消费时至少知道 ID)
+ $res = [
+ 'id' => $inquiryId,
+ 'recipient' => $recipientUserId,
+ 'dispatched_at' => $now,
+ 'source' => 'fb_leads_inquiry',
+ ];
+
+ // 3)推送到 CRM 队列
+ RedisQueueRedis::send('inquiry-to-crm-new', $res);
+
+ $count++;
+ $output->writeln("已分配询盘 {$inquiryId} 给业务员 {$recipientUserId},并推送到队列");
+ });
+ }
+
+ $output->writeln("本次共分配成功 {$count} 条询盘");
+
+ return self::SUCCESS;
+ }
+
+ /**
+ * 轮询获取“下一位业务员 ID”
+ *
+ * @param int[] $userIds
+ * @param string $groupKey
+ * @return int
+ * @throws BusinessException
+ */
+ protected function nextRecipientId(array $userIds, string $groupKey = 'default'): int
+ {
+ $userIds = array_values(array_filter(array_map('intval', $userIds), fn($v) => $v > 0));
+ if (empty($userIds)) {
+ throw new BusinessException('轮询分配失败:业务员列表为空');
+ }
+
+ $count = count($userIds);
+ $key = 'inquiry:assign:round_robin:' . $groupKey;
+
+ // Redis INCR 是原子操作,适合并发下使用
+ $val = Redis::incr($key); // 第一次会从 0 变成 1
+
+ // 换算为从 0 开始的下标
+ $index = ($val - 1) % $count;
+
+ return $userIds[$index];
+ }
+}
diff --git a/app/command/InquiryFbLeadCommand.php b/app/command/InquiryFbLeadCommand.php
new file mode 100644
index 0000000..aec2199
--- /dev/null
+++ b/app/command/InquiryFbLeadCommand.php
@@ -0,0 +1,164 @@
+where('sync_status', 0)
+ ->get();
+
+ if ($leads->isEmpty()) {
+ $output->writeln('没有需要同步的 fb_leads(sync_status = 0)');
+ return self::SUCCESS;
+ }
+
+ $now = time();
+
+ Db::transaction(function () use ($leads, $now, $output) {
+ $insert = [];
+ $ids = [];
+
+ foreach ($leads as $lead) {
+ $leadArr = (array)$lead;
+ $insert[] = $this->mapLeadToInquiry($leadArr, $now);
+ // 假设 fb_leads 的主键字段名为 id
+ $ids[] = $leadArr['id'];
+ }
+
+ if ($insert) {
+ // 1) 写入 inquiry_log
+ Db::table('inquiry_log')->insert($insert);
+
+ // 2) 回写 fb_leads 的同步状态
+ Db::table('fb_leads')
+ ->whereIn('id', $ids)
+ ->update([
+ 'sync_status' => 1,
+ 'updated_at' => $now,
+ ]);
+
+ $output->writeln('已导入 ' . count($insert) . ' 条数据到 inquiry_log,并更新 fb_leads.sync_status = 1');
+ }
+ });
+
+ return self::SUCCESS;
+ }
+
+ /**
+ * 将一条 fb_leads 记录映射为 inquiry_log 记录
+ */
+ protected function mapLeadToInquiry(array $lead, int $now): array
+ {
+ // 联系方式
+ $email = (string)($lead['email'] ?? '');
+ $tel = (string)($lead['phone'] ?? '');
+ $wa = $tel; // 先用电话号码当 WhatsApp
+
+ // 根据电话或 WhatsApp 区号识别国家
+ $countryId = PhoneCountryHelper::detectCountryId($tel ?: $wa);
+
+ // 所有默认值按你的要求设置
+ $data = [
+ 'order_no' => $this->orderNum(),
+ 'enter_user_id' => static::DEFAULT_ENTER_USER_ID,
+ 'recipient' => 0,
+ 'quality' => 2,
+ 'channel' => static::DEFAULT_CHANNEL,
+
+ 'email' => $email,
+ 'tel' => $tel,
+ 'whatsapp' => $wa,
+ 'country' => $countryId ?: 0,
+ 'contacts' => (string)($lead['full_name'] ?? ''),
+
+ 'content' => $this->buildContentHtml($lead),
+
+ 'status' => 0,
+ 'r_time' => 0,
+ 't_time' => 0,
+ 'sync_crm' => 0,
+
+ 'created_at' => $now,
+ 'updated_at' => $now,
+ ];
+
+ return $data;
+ }
+
+ /**
+ * 生成订单号
+ */
+ protected function orderNum(): string
+ {
+ return 'SN' . date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
+ }
+
+ /**
+ * 根据 fb_leads 的字段拼出富文本内容
+ */
+ protected function buildContentHtml(array $lead): string
+ {
+ $e = function ($v) {
+ return htmlspecialchars((string)$v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
+ };
+
+ $lines = [];
+
+ if (!empty($lead['car_model'])) {
+ $lines[] = '
意向车型:' . $e($lead['car_model']) . '
';
+ }
+ if (!empty($lead['car_quantity']) || !empty($lead['car_quantity_text'])) {
+ $qty = $lead['car_quantity'] ?? $lead['car_quantity_text'] ?? '';
+ $lines[] = '意向数量:' . $e($qty) . '
';
+ }
+ if (!empty($lead['favorite_color'])) {
+ $lines[] = '意向颜色:' . $e($lead['favorite_color']) . '
';
+ }
+ if (!empty($lead['usage_type'])) {
+ $lines[] = '用途:' . $e($lead['usage_type']) . '
';
+ }
+ if (!empty($lead['seat_preference'])) {
+ $lines[] = '座位数偏好:' . $e($lead['seat_preference']) . '
';
+ }
+
+ $lines[] = '
';
+ $lines[] = '广告与表单信息:
';
+ $lines[] = '平台:' . $e($lead['platform'] ?? '') . '
';
+ $lines[] = 'Campaign:' . $e($lead['campaign_name'] ?? '') . ' (#' . $e($lead['campaign_id'] ?? '') . ')
';
+ $lines[] = 'Adset:' . $e($lead['adset_name'] ?? '') . ' (#' . $e($lead['adset_id'] ?? '') . ')
';
+ $lines[] = 'Ad:' . $e($lead['ad_name'] ?? '') . ' (#' . $e($lead['ad_id'] ?? '') . ')
';
+ $lines[] = 'Form:' . $e($lead['form_name'] ?? '') . ' (#' . $e($lead['form_id'] ?? '') . ')
';
+
+ $lines[] = '
';
+ $lines[] = 'Meta 信息:
';
+ $lines[] = 'Lead ID:' . $e($lead['fb_lead_id'] ?? '') . '
';
+ $lines[] = 'FB 创建时间原始值:' . $e($lead['fb_created_time'] ?? '') . '
';
+
+ if (!empty($lead['inbox_url'])) {
+ $url = $e($lead['inbox_url']);
+ $lines[] = 'Inbox 链接:' . $url . '
';
+ }
+
+ return implode("\n", $lines);
+ }
+}
diff --git a/app/command/InquiryImportFbCommand.php b/app/command/InquiryImportFbCommand.php
new file mode 100644
index 0000000..3c9a3c0
--- /dev/null
+++ b/app/command/InquiryImportFbCommand.php
@@ -0,0 +1,256 @@
+addOption(
+ 'file',
+ null,
+ InputOption::VALUE_OPTIONAL,
+ '要导入的单个 Excel 文件名(相对 public/excel 的路径,或绝对路径)'
+ )
+ ->addOption(
+ 'dir',
+ null,
+ InputOption::VALUE_OPTIONAL,
+ 'Excel 目录(相对 public/ 的路径)',
+ 'excel' // 默认就是 public/excel
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $fileOption = $input->getOption('file');
+ $dirOption = $input->getOption('dir') ?? 'excel';
+
+ // 基准目录:public/{$dirOption}
+ $baseDir = rtrim(public_path($dirOption), DIRECTORY_SEPARATOR);
+
+ if ($fileOption) {
+ // 如果传的是绝对路径,直接用;否则认为是相对 baseDir 的文件名
+ if ($this->isAbsolutePath($fileOption)) {
+ $filePath = $fileOption;
+ } else {
+ $filePath = $baseDir . DIRECTORY_SEPARATOR . $fileOption;
+ }
+
+ $output->writeln("开始导入单个文件: {$filePath}");
+
+ $this->importOneFile($filePath, $output);
+ } else {
+ // 不指定 file 时,默认导入目录下所有 .xlsx
+ if (!is_dir($baseDir)) {
+ throw new BusinessException("目录不存在:{$baseDir}");
+ }
+
+ $pattern = $baseDir . DIRECTORY_SEPARATOR . '*.xlsx';
+ $files = glob($pattern);
+
+ if (empty($files)) {
+ $output->writeln("目录 {$baseDir} 下没有找到 .xlsx 文件");
+ return self::SUCCESS;
+ }
+
+ $output->writeln("开始批量导入目录: {$baseDir}");
+ foreach ($files as $filePath) {
+ $output->writeln(" -> 文件:{$filePath}");
+ try {
+ $this->importOneFile($filePath, $output);
+ $output->writeln(" 导入成功");
+ } catch (\Throwable $e) {
+ // 某个文件失败,不影响后面的文件
+ $output->writeln(" 导入失败:{$e->getMessage()}");
+ }
+ }
+ }
+
+ return self::SUCCESS;
+ }
+
+ /**
+ * 导入单个 Excel 文件
+ */
+ protected function importOneFile(string $filePath, OutputInterface $output): void
+ {
+ if (!is_file($filePath)) {
+ throw new BusinessException("文件不存在:{$filePath}");
+ }
+
+ $spreadsheet = IOFactory::load($filePath);
+ $sheet = $spreadsheet->getActiveSheet();
+ $rows = $sheet->toArray(null, true, true, true);
+
+ if (empty($rows)) {
+ throw new BusinessException('Excel 内容为空:' . $filePath);
+ }
+
+ // 取第一行表头
+ $headerRow = array_shift($rows);
+
+ // 表头映射器
+ $mapper = new FbLeadHeaderMapper();
+
+ // 如果有未知表头,这里会直接抛异常中断当前文件
+ $colToField = $mapper->buildColumnFieldMap($headerRow);
+
+ $insertData = [];
+ $now = time();
+
+ foreach ($rows as $row) {
+ $item = [];
+
+ foreach ($colToField as $colIndex => $field) {
+ $raw = $row[$colIndex] ?? null;
+
+ switch ($field) {
+ // 1) is_organic: Excel 里是 true/false,这里转成 0/1
+ case 'is_organic':
+ $item['is_organic'] = $this->normalizeIsOrganic($raw);
+ break;
+
+ // 2) fb_created_time: 统一转成 Y-m-d H:i:s
+ case 'fb_created_time':
+ $item['fb_created_time'] = $this->normalizeFbCreatedTime($raw);
+ break;
+
+ default:
+ if (is_string($raw)) {
+ $raw = trim($raw);
+ }
+ $item[$field] = $raw;
+ break;
+ }
+ }
+
+ // 补充公共字段
+ $item['source_file'] = basename($filePath);
+ $item['created_at'] = $now;
+ $item['updated_at'] = $now;
+
+ // 整行都空就跳过
+ $allNull = true;
+ foreach ($item as $v) {
+ if ($v !== null && $v !== '') {
+ $allNull = false;
+ break;
+ }
+ }
+ if ($allNull) {
+ continue;
+ }
+
+ $insertData[] = $item;
+ }
+
+ if ($insertData) {
+ Db::table('fb_leads')->insert($insertData);
+ } else {
+ $output->writeln(" 文件 {$filePath} 没有有效数据行");
+ }
+ }
+
+ /**
+ * 将 Excel 里的 is_organic 值转换为 0/1
+ */
+ protected function normalizeIsOrganic($value): int
+ {
+ if ($value === null) {
+ return 0;
+ }
+
+ $v = strtolower(trim((string)$value));
+
+ // 认为这些是 “true”
+ $trueValues = ['1', 'true', 'yes', 'y'];
+
+ return in_array($v, $trueValues, true) ? 1 : 0;
+ }
+
+ /**
+ * 统一处理 fb_created_time
+ * Excel 目前是类似 '12/8/25',这里尽量转成 'Y-m-d H:i:s'
+ * 解析失败时返回 null
+ */
+ protected function normalizeFbCreatedTime($value): ?string
+ {
+ if ($value === null || $value === '') {
+ return null;
+ }
+
+ if ($value instanceof \DateTimeInterface) {
+ return $value->format('Y-m-d H:i:s');
+ }
+
+ $v = trim((string)$value);
+
+ $formats = [
+ 'Y-m-d H:i:s',
+ 'Y-m-d',
+ 'n/j/y', // 12/8/25
+ 'n/j/Y',
+ 'd/m/Y',
+ 'd.m.Y',
+ ];
+
+ foreach ($formats as $fmt) {
+ $dt = \DateTime::createFromFormat($fmt, $v);
+ if ($dt !== false) {
+ return $dt->format('Y-m-d H:i:s');
+ }
+ }
+
+ // 纯数字当时间戳试一下
+ if (is_numeric($v) && strlen($v) >= 9 && strlen($v) <= 11) {
+ $ts = (int)$v;
+ if ($ts > 0) {
+ return date('Y-m-d H:i:s', $ts);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * 判断是否为绝对路径(简单兼容 Windows / Linux)
+ */
+ protected function isAbsolutePath(string $path): bool
+ {
+ // Windows: X:\ 或 \\server\share
+ if (preg_match('/^[a-zA-Z]:\\\\/', $path) || str_starts_with($path, '\\\\')) {
+ return true;
+ }
+
+ // *nix: / 开头
+ return str_starts_with($path, '/');
+ }
+}
+
+/*
+
+php webman tb-db
+# 等价于 php webman tb-db --dir=excel
+# 会遍历 public/excel/*.xlsx 逐个导入
+
+# 相对路径(相对 public/excel)
+php webman tb-db --file="BYD tang_Leads_2025-12-04_2025-12-09.xlsx"
+
+# 或给绝对路径
+php webman tb-db --file="/www/wwwroot/xxx/public/excel/BYD tang_Leads_2025-12-04_2025-12-09.xlsx"
+
+*/
\ No newline at end of file
diff --git a/app/inquiry/utils/FbLeadHeaderMapper.php b/app/inquiry/utils/FbLeadHeaderMapper.php
new file mode 100644
index 0000000..ed048ed
--- /dev/null
+++ b/app/inquiry/utils/FbLeadHeaderMapper.php
@@ -0,0 +1,154 @@
+ DB 字段名
+ * 注意:key 用的是“原始表头字符串”(包括下划线)
+ */
+ protected array $headerMap = [
+ // ===== 基础公共字段 =====
+ 'id' => 'fb_lead_id',
+ 'created_time' => 'fb_created_time',
+ 'ad_id' => 'ad_id',
+ 'ad_name' => 'ad_name',
+ 'adset_id' => 'adset_id',
+ 'adset_name' => 'adset_name',
+ 'campaign_id' => 'campaign_id',
+ 'campaign_name' => 'campaign_name',
+ 'form_id' => 'form_id',
+ 'form_name' => 'form_name',
+ 'is_organic' => 'is_organic',
+ 'platform' => 'platform',
+
+ 'full_name' => 'full_name',
+ 'phone' => 'phone',
+ 'phone_number' => 'phone', // 兼容写法
+ 'email' => 'email',
+ 'lead_status' => 'lead_status',
+ 'inbox_url' => 'inbox_url',
+
+ // ===== 车型相关:全部归到 car_model =====
+ 'which_model_of_this_car_would_you_like_to_purchase?_' => 'car_model',
+ 'which_model_of_this_car_would_you_like_to_purchase?' => 'car_model',
+ 'which_car_model_would_you_like_to_purchase?' => 'car_model',
+ 'which_model_do_you_want_to_purchase?' => 'car_model',
+ 'which_model_would_you_like_to_purchase?' => 'car_model',
+ 'which_version_do_you_want_to_buy?' => 'car_model', // 这里也归到车型/版本字段
+
+ // ===== 数量相关:全部归到 car_quantity =====
+ 'how_many_cars_would_you_like_to_buy?_' => 'car_quantity',
+ 'how_many_cars_would_you_like_to_buy?' => 'car_quantity',
+ '_how_many_cars_would_you_like_to_buy?' => 'car_quantity',
+ 'how_many_cars_do_you_buy?' => 'car_quantity',
+ 'how_many_cars_do_you_want_to_purchase?' => 'car_quantity',
+ 'how_many_cars_do_you_want_to_buy?' => 'car_quantity',
+ 'what_quantity_do_you_want_to_buy?' => 'car_quantity',
+
+ // ===== 颜色相关:归到 favorite_color =====
+ 'what_color_do_you_like?' => 'favorite_color',
+ 'which_color_would_you_like_to_purchase?' => 'favorite_color',
+
+ // ===== 用途相关:归到 usage_type =====
+ 'are_you_using_it_for_business_or_personal_use?' => 'usage_type',
+ 'business_use_or_personal_use?' => 'usage_type',
+ 'personal_use_or_business_use?' => 'usage_type',
+
+ // ===== 座位数相关 =====
+ 'do_you_want_to_buy_six_seats_or_seven_seats?' => 'seat_preference',
+ ];
+
+ /**
+ * 返回所有支持的 Excel 表头
+ */
+ public function getSupportedHeaders(): array
+ {
+ return array_keys($this->headerMap);
+ }
+
+ /**
+ * 单个表头映射:原始表头 -> DB 字段名
+ */
+ public function mapHeader(string $rawHeader): ?string
+ {
+ $key = $this->normalizeHeader($rawHeader);
+
+ return $this->headerMap[$key] ?? null;
+ }
+
+ /**
+ * 校验一整行表头:
+ * - 有任何不认识的表头,就抛 BusinessException
+ */
+ public function validateHeaders(array $rawHeaders): void
+ {
+ $unsupported = [];
+
+ foreach ($rawHeaders as $header) {
+ $header = (string)$header;
+ $key = $this->normalizeHeader($header);
+
+ // 允许空表头(多余空列)
+ if ($key === '') {
+ continue;
+ }
+
+ if (!isset($this->headerMap[$key])) {
+ $unsupported[] = $header;
+ }
+ }
+
+ if (!empty($unsupported)) {
+ $msg = 'Excel 表头包含未兼容字段:' . implode('、', $unsupported)
+ . '。请检查这些字段是否需要加入映射配置。';
+ throw new BusinessException($msg);
+ }
+ }
+
+ /**
+ * 根据第一行表头,构建 “列索引 => DB 字段” 映射
+ */
+ public function buildColumnFieldMap(array $rawHeaders): array
+ {
+ // 先做一遍校验(发现问题直接抛异常)
+ $this->validateHeaders($rawHeaders);
+
+ $colToField = [];
+
+ foreach ($rawHeaders as $index => $header) {
+ $key = $this->normalizeHeader((string)$header);
+ if ($key === '') {
+ continue;
+ }
+
+ $field = $this->headerMap[$key] ?? null;
+ if ($field === null) {
+ continue; // 理论上不会到这儿,双保险
+ }
+
+ $colToField[$index] = $field;
+ }
+
+ return $colToField;
+ }
+
+ /**
+ * 表头标准化:
+ * 目前只去 BOM + trim,保持和 headerMap 中 key 完全一致
+ * 如果后面再出现“有空格/大小写”的版本,我们可以在这里做 strtolower / 替换空格 为 _
+ */
+ protected function normalizeHeader(string $header): string
+ {
+ // 去掉 UTF-8 BOM
+ $header = preg_replace('/^\xEF\xBB\xBF/', '', $header);
+
+ // 去掉前后空白
+ $header = trim($header);
+
+ return $header;
+ }
+}
diff --git a/app/inquiry/utils/PhoneCountryHelper.php b/app/inquiry/utils/PhoneCountryHelper.php
new file mode 100644
index 0000000..e6b0a48
--- /dev/null
+++ b/app/inquiry/utils/PhoneCountryHelper.php
@@ -0,0 +1,58 @@
+ +
+ if (str_starts_with($phone, '00')) {
+ $phone = '+' . substr($phone, 2);
+ } elseif ($phone[0] !== '+') {
+ // 没有 +,默认补一个(大多数线索都是国际号)
+ $phone = '+' . $phone;
+ }
+
+ $digits = ltrim($phone, '+');
+ if ($digits === '') {
+ return null;
+ }
+
+ // 3. 国家区号最长 3 位,从长到短匹配
+ for ($len = 3; $len >= 1; $len--) {
+ $code = substr($digits, 0, $len);
+ if ($code === '') {
+ continue;
+ }
+
+ $country = Db::table('country')
+ ->where('phone_code', $code)
+ ->first();
+
+ if ($country) {
+ return (int)$country->id;
+ }
+ }
+
+ // 没找到
+ return null;
+ }
+}
diff --git a/app/inquiry/utils/RoundRobinAssigner.php b/app/inquiry/utils/RoundRobinAssigner.php
new file mode 100644
index 0000000..dc0ac77
--- /dev/null
+++ b/app/inquiry/utils/RoundRobinAssigner.php
@@ -0,0 +1,46 @@
+ $v > 0));
+ if (empty($userIds)) {
+ throw new BusinessException('轮询分配业务员失败:业务员列表不能为空');
+ }
+
+ $count = count($userIds);
+
+ // Redis key:同一个 groupKey 共用一条轮询链
+ $key = self::REDIS_KEY_PREFIX . $groupKey;
+
+ // 使用 INCR 做自增计数,天然是原子操作,适合并发环境
+ // 第一次调用 INCR 返回 1,我们用 (value - 1) 来做索引,从 0 开始
+ $val = Redis::incr($key); // 如果不存在,Redis 会先置为 0 再加 1
+
+ $index = ($val - 1) % $count;
+
+ return $userIds[$index];
+ }
+}
diff --git a/composer.json b/composer.json
index a696240..d502105 100644
--- a/composer.json
+++ b/composer.json
@@ -48,7 +48,8 @@
"webman/gateway-worker": "^1.0",
"mpdf/mpdf": "^8.2",
"jaeger/querylist": "^4.4",
- "zoujingli/ip2region": "^3.0"
+ "zoujingli/ip2region": "^3.0",
+ "webman/log": "^2.1"
},
"suggest": {
"ext-event": "For better performance. "
diff --git a/composer.lock b/composer.lock
index 2bf0ca9..ecd2fc5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "ac2fa5a625069729975d072614509e1f",
+ "content-hash": "bf987c3cd5510fc0637d6b64d460dde1",
"packages": [
{
"name": "aliyuncs/oss-sdk-php",
@@ -18,13 +18,7 @@
"type": "zip",
"url": "https://api.github.com/repos/aliyun/aliyun-oss-php-sdk/zipball/483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5",
"reference": "483dd0b8bff5d47f0e4ffc99f6077a295c5ccbb5",
- "shasum": "",
- "mirrors": [
- {
- "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
- "preferred": true
- }
- ]
+ "shasum": ""
},
"require": {
"php": ">=5.3"
@@ -59,16 +53,16 @@
},
{
"name": "brick/math",
- "version": "0.14.0",
+ "version": "0.14.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
- "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2"
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
- "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
+ "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0",
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0",
"shasum": ""
},
"require": {
@@ -107,7 +101,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.14.0"
+ "source": "https://github.com/brick/math/tree/0.14.1"
},
"funding": [
{
@@ -115,7 +109,7 @@
"type": "github"
}
],
- "time": "2025-08-29T12:40:03+00:00"
+ "time": "2025-11-24T14:40:29+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -420,31 +414,31 @@
},
{
"name": "fruitcake/php-cors",
- "version": "v1.3.0",
+ "version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/fruitcake/php-cors.git",
- "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b"
+ "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b",
- "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b",
+ "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379",
+ "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379",
"shasum": ""
},
"require": {
- "php": "^7.4|^8.0",
- "symfony/http-foundation": "^4.4|^5.4|^6|^7"
+ "php": "^8.1",
+ "symfony/http-foundation": "^5.4|^6.4|^7.3|^8"
},
"require-dev": {
- "phpstan/phpstan": "^1.4",
+ "phpstan/phpstan": "^2",
"phpunit/phpunit": "^9",
- "squizlabs/php_codesniffer": "^3.5"
+ "squizlabs/php_codesniffer": "^4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.2-dev"
+ "dev-master": "1.3-dev"
}
},
"autoload": {
@@ -475,7 +469,7 @@
],
"support": {
"issues": "https://github.com/fruitcake/php-cors/issues",
- "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0"
+ "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0"
},
"funding": [
{
@@ -487,7 +481,7 @@
"type": "github"
}
],
- "time": "2023-10-12T05:21:21+00:00"
+ "time": "2025-12-03T09:33:47+00:00"
},
{
"name": "graham-campbell/result-type",
@@ -964,16 +958,16 @@
},
{
"name": "illuminate/bus",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/bus.git",
- "reference": "797f768b7a52fb98443b8127cda71840cc2dbc5b"
+ "reference": "fdb568a20ad96461caa83b98ffc36d9e95894491"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/bus/zipball/797f768b7a52fb98443b8127cda71840cc2dbc5b",
- "reference": "797f768b7a52fb98443b8127cda71840cc2dbc5b",
+ "url": "https://api.github.com/repos/illuminate/bus/zipball/fdb568a20ad96461caa83b98ffc36d9e95894491",
+ "reference": "fdb568a20ad96461caa83b98ffc36d9e95894491",
"shasum": ""
},
"require": {
@@ -1013,20 +1007,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-30T12:22:29+00:00"
+ "time": "2025-11-30T17:14:13+00:00"
},
{
"name": "illuminate/collections",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/collections.git",
- "reference": "deb291b109b6f7fd776a3550a120771137b3c5d1"
+ "reference": "16657effa6a5a4e728f9aeb3e38fb4fa9ba70e7d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/collections/zipball/deb291b109b6f7fd776a3550a120771137b3c5d1",
- "reference": "deb291b109b6f7fd776a3550a120771137b3c5d1",
+ "url": "https://api.github.com/repos/illuminate/collections/zipball/16657effa6a5a4e728f9aeb3e38fb4fa9ba70e7d",
+ "reference": "16657effa6a5a4e728f9aeb3e38fb4fa9ba70e7d",
"shasum": ""
},
"require": {
@@ -1072,11 +1066,11 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-30T12:22:05+00:00"
+ "time": "2025-12-06T18:08:25+00:00"
},
{
"name": "illuminate/conditionable",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/conditionable.git",
@@ -1122,20 +1116,21 @@
},
{
"name": "illuminate/container",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
- "reference": "d6eaa8afd48dbe16b6b3c412a87479cad67eeb12"
+ "reference": "326667a4c813e3ad5a645969a7e3f5c10d159de2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/container/zipball/d6eaa8afd48dbe16b6b3c412a87479cad67eeb12",
- "reference": "d6eaa8afd48dbe16b6b3c412a87479cad67eeb12",
+ "url": "https://api.github.com/repos/illuminate/container/zipball/326667a4c813e3ad5a645969a7e3f5c10d159de2",
+ "reference": "326667a4c813e3ad5a645969a7e3f5c10d159de2",
"shasum": ""
},
"require": {
"illuminate/contracts": "^12.0",
+ "illuminate/reflection": "^12.0",
"php": "^8.2",
"psr/container": "^1.1.1|^2.0.1",
"symfony/polyfill-php84": "^1.33",
@@ -1179,20 +1174,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-09-12T14:35:11+00:00"
+ "time": "2025-12-08T22:34:25+00:00"
},
{
"name": "illuminate/contracts",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
- "reference": "5ab717c8f0dd4e84be703796bbb415ccff8de57a"
+ "reference": "19e8938edb73047017cfbd443b96844b86da4a59"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/contracts/zipball/5ab717c8f0dd4e84be703796bbb415ccff8de57a",
- "reference": "5ab717c8f0dd4e84be703796bbb415ccff8de57a",
+ "url": "https://api.github.com/repos/illuminate/contracts/zipball/19e8938edb73047017cfbd443b96844b86da4a59",
+ "reference": "19e8938edb73047017cfbd443b96844b86da4a59",
"shasum": ""
},
"require": {
@@ -1227,20 +1222,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-07T19:59:08+00:00"
+ "time": "2025-11-26T21:36:01+00:00"
},
{
"name": "illuminate/database",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/database.git",
- "reference": "e42bec6ad999bcc78ce9f3789f5ef937ee2e5982"
+ "reference": "b44f021fee7b48289312e22fd6e4d580374a86ac"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/database/zipball/e42bec6ad999bcc78ce9f3789f5ef937ee2e5982",
- "reference": "e42bec6ad999bcc78ce9f3789f5ef937ee2e5982",
+ "url": "https://api.github.com/repos/illuminate/database/zipball/b44f021fee7b48289312e22fd6e4d580374a86ac",
+ "reference": "b44f021fee7b48289312e22fd6e4d580374a86ac",
"shasum": ""
},
"require": {
@@ -1298,20 +1293,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-11-03T14:22:34+00:00"
+ "time": "2025-12-06T18:08:25+00:00"
},
{
"name": "illuminate/events",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/events.git",
- "reference": "e0de667c68040d59a6ffc09e914536a1186870f0"
+ "reference": "5fbf9a127cb649699071c2fe98ac1d39e4991da3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/events/zipball/e0de667c68040d59a6ffc09e914536a1186870f0",
- "reference": "e0de667c68040d59a6ffc09e914536a1186870f0",
+ "url": "https://api.github.com/repos/illuminate/events/zipball/5fbf9a127cb649699071c2fe98ac1d39e4991da3",
+ "reference": "5fbf9a127cb649699071c2fe98ac1d39e4991da3",
"shasum": ""
},
"require": {
@@ -1353,11 +1348,11 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-21T15:10:34+00:00"
+ "time": "2025-12-01T15:02:02+00:00"
},
{
"name": "illuminate/filesystem",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/filesystem.git",
@@ -1424,16 +1419,16 @@
},
{
"name": "illuminate/http",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/http.git",
- "reference": "5c864f562b2fded08622ee19cd53260aef3db9a0"
+ "reference": "b7997f2faffb3c31f2a0fa079428ff6bfcce8907"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/http/zipball/5c864f562b2fded08622ee19cd53260aef3db9a0",
- "reference": "5c864f562b2fded08622ee19cd53260aef3db9a0",
+ "url": "https://api.github.com/repos/illuminate/http/zipball/b7997f2faffb3c31f2a0fa079428ff6bfcce8907",
+ "reference": "b7997f2faffb3c31f2a0fa079428ff6bfcce8907",
"shasum": ""
},
"require": {
@@ -1482,11 +1477,11 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-28T14:38:15+00:00"
+ "time": "2025-12-09T15:25:50+00:00"
},
{
"name": "illuminate/macroable",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/macroable.git",
@@ -1532,16 +1527,16 @@
},
{
"name": "illuminate/pagination",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/pagination.git",
- "reference": "1d95e70671177108b202e6ceb61bc7bc9924bdbf"
+ "reference": "87e7e3e7b02d6809b1bcd41782e1ca2c6d2a413b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/pagination/zipball/1d95e70671177108b202e6ceb61bc7bc9924bdbf",
- "reference": "1d95e70671177108b202e6ceb61bc7bc9924bdbf",
+ "url": "https://api.github.com/repos/illuminate/pagination/zipball/87e7e3e7b02d6809b1bcd41782e1ca2c6d2a413b",
+ "reference": "87e7e3e7b02d6809b1bcd41782e1ca2c6d2a413b",
"shasum": ""
},
"require": {
@@ -1578,11 +1573,11 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-09-02T15:31:06+00:00"
+ "time": "2025-11-16T14:36:17+00:00"
},
{
"name": "illuminate/pipeline",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/pipeline.git",
@@ -1634,16 +1629,16 @@
},
{
"name": "illuminate/redis",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/redis.git",
- "reference": "8a397f00036974404d5d4d94eacfe8050af8e7f2"
+ "reference": "8dc6682638100db9feceaac3db206de752dd0f9a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/redis/zipball/8a397f00036974404d5d4d94eacfe8050af8e7f2",
- "reference": "8a397f00036974404d5d4d94eacfe8050af8e7f2",
+ "url": "https://api.github.com/repos/illuminate/redis/zipball/8dc6682638100db9feceaac3db206de752dd0f9a",
+ "reference": "8dc6682638100db9feceaac3db206de752dd0f9a",
"shasum": ""
},
"require": {
@@ -1684,11 +1679,62 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-26T17:11:19+00:00"
+ "time": "2025-11-20T20:50:40+00:00"
+ },
+ {
+ "name": "illuminate/reflection",
+ "version": "v12.42.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/illuminate/reflection.git",
+ "reference": "7b86bc570d5b75e4a3ad79f8cca1491ba24b7c75"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/illuminate/reflection/zipball/7b86bc570d5b75e4a3ad79f8cca1491ba24b7c75",
+ "reference": "7b86bc570d5b75e4a3ad79f8cca1491ba24b7c75",
+ "shasum": ""
+ },
+ "require": {
+ "illuminate/collections": "^12.0",
+ "illuminate/contracts": "^12.0",
+ "php": "^8.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "12.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "helpers.php"
+ ],
+ "psr-4": {
+ "Illuminate\\Support\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "The Illuminate Reflection package.",
+ "homepage": "https://laravel.com",
+ "support": {
+ "issues": "https://github.com/laravel/framework/issues",
+ "source": "https://github.com/laravel/framework"
+ },
+ "time": "2025-12-09T15:11:22+00:00"
},
{
"name": "illuminate/session",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/session.git",
@@ -1745,16 +1791,16 @@
},
{
"name": "illuminate/support",
- "version": "v12.37.0",
+ "version": "v12.42.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
- "reference": "480df979c8ffe700d6adb6e6e64abe04b32e02e3"
+ "reference": "d35411be5657e0b5560a5885f3c9140e4cbe0be5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/support/zipball/480df979c8ffe700d6adb6e6e64abe04b32e02e3",
- "reference": "480df979c8ffe700d6adb6e6e64abe04b32e02e3",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/d35411be5657e0b5560a5885f3c9140e4cbe0be5",
+ "reference": "d35411be5657e0b5560a5885f3c9140e4cbe0be5",
"shasum": ""
},
"require": {
@@ -1766,6 +1812,7 @@
"illuminate/conditionable": "^12.0",
"illuminate/contracts": "^12.0",
"illuminate/macroable": "^12.0",
+ "illuminate/reflection": "^12.0",
"nesbot/carbon": "^3.8.4",
"php": "^8.2",
"symfony/polyfill-php83": "^1.33",
@@ -1820,7 +1867,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-31T16:20:10+00:00"
+ "time": "2025-12-09T15:26:52+00:00"
},
{
"name": "jaeger/g-http",
@@ -1979,16 +2026,16 @@
},
{
"name": "laravel/serializable-closure",
- "version": "v2.0.6",
+ "version": "v2.0.7",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
- "reference": "038ce42edee619599a1debb7e81d7b3759492819"
+ "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/038ce42edee619599a1debb7e81d7b3759492819",
- "reference": "038ce42edee619599a1debb7e81d7b3759492819",
+ "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/cb291e4c998ac50637c7eeb58189c14f5de5b9dd",
+ "reference": "cb291e4c998ac50637c7eeb58189c14f5de5b9dd",
"shasum": ""
},
"require": {
@@ -1997,7 +2044,7 @@
"require-dev": {
"illuminate/support": "^10.0|^11.0|^12.0",
"nesbot/carbon": "^2.67|^3.0",
- "pestphp/pest": "^2.36|^3.0",
+ "pestphp/pest": "^2.36|^3.0|^4.0",
"phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0"
},
@@ -2036,7 +2083,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
- "time": "2025-10-09T13:42:30+00:00"
+ "time": "2025-11-21T20:52:36+00:00"
},
{
"name": "league/flysystem",
@@ -2515,16 +2562,16 @@
},
{
"name": "mpdf/mpdf",
- "version": "v8.2.6",
+ "version": "v8.2.7",
"source": {
"type": "git",
"url": "https://github.com/mpdf/mpdf.git",
- "reference": "dd30e3b01061cf8dfe65e7041ab4cc46d8ebdd44"
+ "reference": "b59670a09498689c33ce639bac8f5ba26721dab3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mpdf/mpdf/zipball/dd30e3b01061cf8dfe65e7041ab4cc46d8ebdd44",
- "reference": "dd30e3b01061cf8dfe65e7041ab4cc46d8ebdd44",
+ "url": "https://api.github.com/repos/mpdf/mpdf/zipball/b59670a09498689c33ce639bac8f5ba26721dab3",
+ "reference": "b59670a09498689c33ce639bac8f5ba26721dab3",
"shasum": ""
},
"require": {
@@ -2592,7 +2639,7 @@
"type": "custom"
}
],
- "time": "2025-08-18T08:51:51+00:00"
+ "time": "2025-12-01T10:18:02+00:00"
},
{
"name": "mpdf/psr-http-message-shim",
@@ -2748,16 +2795,16 @@
},
{
"name": "nesbot/carbon",
- "version": "3.10.3",
+ "version": "3.11.0",
"source": {
"type": "git",
"url": "https://github.com/CarbonPHP/carbon.git",
- "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f"
+ "reference": "bdb375400dcd162624531666db4799b36b64e4a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
- "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f",
+ "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/bdb375400dcd162624531666db4799b36b64e4a1",
+ "reference": "bdb375400dcd162624531666db4799b36b64e4a1",
"shasum": ""
},
"require": {
@@ -2765,9 +2812,9 @@
"ext-json": "*",
"php": "^8.1",
"psr/clock": "^1.0",
- "symfony/clock": "^6.3.12 || ^7.0",
+ "symfony/clock": "^6.3.12 || ^7.0 || ^8.0",
"symfony/polyfill-mbstring": "^1.0",
- "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0"
+ "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0"
},
"provide": {
"psr/clock-implementation": "1.0"
@@ -2849,7 +2896,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-06T13:39:36+00:00"
+ "time": "2025-12-02T21:04:28+00:00"
},
{
"name": "nikic/fast-route",
@@ -3898,16 +3945,16 @@
},
{
"name": "symfony/cache",
- "version": "v7.3.6",
+ "version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
- "reference": "1277a1ec61c8d93ea61b2a59738f1deb9bfb6701"
+ "reference": "21e0755783bbbab58f2bb6a7a57896d21d27a366"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/cache/zipball/1277a1ec61c8d93ea61b2a59738f1deb9bfb6701",
- "reference": "1277a1ec61c8d93ea61b2a59738f1deb9bfb6701",
+ "url": "https://api.github.com/repos/symfony/cache/zipball/21e0755783bbbab58f2bb6a7a57896d21d27a366",
+ "reference": "21e0755783bbbab58f2bb6a7a57896d21d27a366",
"shasum": ""
},
"require": {
@@ -3915,12 +3962,14 @@
"psr/cache": "^2.0|^3.0",
"psr/log": "^1.1|^2|^3",
"symfony/cache-contracts": "^3.6",
- "symfony/deprecation-contracts": "^2.5|^3.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/service-contracts": "^2.5|^3",
- "symfony/var-exporter": "^6.4|^7.0"
+ "symfony/var-exporter": "^6.4|^7.0|^8.0"
},
"conflict": {
"doctrine/dbal": "<3.6",
+ "ext-redis": "<6.1",
+ "ext-relay": "<0.12.1",
"symfony/dependency-injection": "<6.4",
"symfony/http-kernel": "<6.4",
"symfony/var-dumper": "<6.4"
@@ -3935,13 +3984,13 @@
"doctrine/dbal": "^3.6|^4",
"predis/predis": "^1.1|^2.0",
"psr/simple-cache": "^1.0|^2.0|^3.0",
- "symfony/clock": "^6.4|^7.0",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/filesystem": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/clock": "^6.4|^7.0|^8.0",
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/filesystem": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -3976,7 +4025,7 @@
"psr6"
],
"support": {
- "source": "https://github.com/symfony/cache/tree/v7.3.6"
+ "source": "https://github.com/symfony/cache/tree/v7.4.1"
},
"funding": [
{
@@ -3996,7 +4045,7 @@
"type": "tidelift"
}
],
- "time": "2025-10-30T13:22:58+00:00"
+ "time": "2025-12-04T18:11:45+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -4076,16 +4125,16 @@
},
{
"name": "symfony/clock",
- "version": "v7.3.0",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/clock.git",
- "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24"
+ "reference": "9169f24776edde469914c1e7a1442a50f7a4e110"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
- "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24",
+ "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110",
+ "reference": "9169f24776edde469914c1e7a1442a50f7a4e110",
"shasum": ""
},
"require": {
@@ -4130,7 +4179,7 @@
"time"
],
"support": {
- "source": "https://github.com/symfony/clock/tree/v7.3.0"
+ "source": "https://github.com/symfony/clock/tree/v7.4.0"
},
"funding": [
{
@@ -4141,25 +4190,29 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2024-09-25T14:21:43+00:00"
+ "time": "2025-11-12T15:39:26+00:00"
},
{
"name": "symfony/console",
- "version": "v7.3.6",
+ "version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a"
+ "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
- "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
+ "url": "https://api.github.com/repos/symfony/console/zipball/6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e",
+ "reference": "6d9f0fbf2ec2e9785880096e3abd0ca0c88b506e",
"shasum": ""
},
"require": {
@@ -4167,7 +4220,7 @@
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^7.2"
+ "symfony/string": "^7.2|^8.0"
},
"conflict": {
"symfony/dependency-injection": "<6.4",
@@ -4181,16 +4234,16 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/lock": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/stopwatch": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
+ "symfony/http-foundation": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/lock": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/stopwatch": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4224,7 +4277,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.6"
+ "source": "https://github.com/symfony/console/tree/v7.4.1"
},
"funding": [
{
@@ -4244,7 +4297,7 @@
"type": "tidelift"
}
],
- "time": "2025-11-04T01:21:42+00:00"
+ "time": "2025-12-05T15:23:39+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -4315,32 +4368,33 @@
},
{
"name": "symfony/error-handler",
- "version": "v7.3.6",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
- "reference": "bbe40bfab84323d99dab491b716ff142410a92a8"
+ "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/error-handler/zipball/bbe40bfab84323d99dab491b716ff142410a92a8",
- "reference": "bbe40bfab84323d99dab491b716ff142410a92a8",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/48be2b0653594eea32dcef130cca1c811dcf25c2",
+ "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/log": "^1|^2|^3",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/polyfill-php85": "^1.32",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
},
"conflict": {
"symfony/deprecation-contracts": "<2.5",
"symfony/http-kernel": "<6.4"
},
"require-dev": {
- "symfony/console": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
"symfony/deprecation-contracts": "^2.5|^3",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/serializer": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^6.4|^7.0|^8.0",
"symfony/webpack-encore-bundle": "^1.0|^2.0"
},
"bin": [
@@ -4372,7 +4426,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/error-handler/tree/v7.3.6"
+ "source": "https://github.com/symfony/error-handler/tree/v7.4.0"
},
"funding": [
{
@@ -4392,20 +4446,20 @@
"type": "tidelift"
}
],
- "time": "2025-10-31T19:12:50+00:00"
+ "time": "2025-11-05T14:29:59+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v7.3.3",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191"
+ "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191",
- "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9dddcddff1ef974ad87b3708e4b442dc38b2261d",
+ "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d",
"shasum": ""
},
"require": {
@@ -4422,13 +4476,14 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/error-handler": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/error-handler": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/framework-bundle": "^6.4|^7.0|^8.0",
+ "symfony/http-foundation": "^6.4|^7.0|^8.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/stopwatch": "^6.4|^7.0"
+ "symfony/stopwatch": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4456,7 +4511,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3"
+ "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.0"
},
"funding": [
{
@@ -4476,7 +4531,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-13T11:49:31+00:00"
+ "time": "2025-10-28T09:38:46+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@@ -4556,16 +4611,16 @@
},
{
"name": "symfony/filesystem",
- "version": "v7.3.6",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a"
+ "reference": "d551b38811096d0be9c4691d406991b47c0c630a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a",
- "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a",
+ "reference": "d551b38811096d0be9c4691d406991b47c0c630a",
"shasum": ""
},
"require": {
@@ -4574,7 +4629,7 @@
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
- "symfony/process": "^6.4|^7.0"
+ "symfony/process": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4602,7 +4657,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.3.6"
+ "source": "https://github.com/symfony/filesystem/tree/v7.4.0"
},
"funding": [
{
@@ -4622,27 +4677,27 @@
"type": "tidelift"
}
],
- "time": "2025-11-05T09:52:27+00:00"
+ "time": "2025-11-27T13:27:24+00:00"
},
{
"name": "symfony/finder",
- "version": "v7.3.5",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "9f696d2f1e340484b4683f7853b273abff94421f"
+ "reference": "340b9ed7320570f319028a2cbec46d40535e94bd"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
- "reference": "9f696d2f1e340484b4683f7853b273abff94421f",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/340b9ed7320570f319028a2cbec46d40535e94bd",
+ "reference": "340b9ed7320570f319028a2cbec46d40535e94bd",
"shasum": ""
},
"require": {
"php": ">=8.2"
},
"require-dev": {
- "symfony/filesystem": "^6.4|^7.0"
+ "symfony/filesystem": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4670,7 +4725,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.3.5"
+ "source": "https://github.com/symfony/finder/tree/v7.4.0"
},
"funding": [
{
@@ -4690,27 +4745,26 @@
"type": "tidelift"
}
],
- "time": "2025-10-15T18:45:57+00:00"
+ "time": "2025-11-05T05:42:40+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v7.3.6",
+ "version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "6379e490d6ecfc5c4224ff3a754b90495ecd135c"
+ "reference": "bd1af1e425811d6f077db240c3a588bdb405cd27"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6379e490d6ecfc5c4224ff3a754b90495ecd135c",
- "reference": "6379e490d6ecfc5c4224ff3a754b90495ecd135c",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/bd1af1e425811d6f077db240c3a588bdb405cd27",
+ "reference": "bd1af1e425811d6f077db240c3a588bdb405cd27",
"shasum": ""
},
"require": {
"php": ">=8.2",
- "symfony/deprecation-contracts": "^2.5|^3.0",
- "symfony/polyfill-mbstring": "~1.1",
- "symfony/polyfill-php83": "^1.27"
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/polyfill-mbstring": "^1.1"
},
"conflict": {
"doctrine/dbal": "<3.6",
@@ -4719,13 +4773,13 @@
"require-dev": {
"doctrine/dbal": "^3.6|^4",
"predis/predis": "^1.1|^2.0",
- "symfony/cache": "^6.4.12|^7.1.5",
- "symfony/clock": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/mime": "^6.4|^7.0",
- "symfony/rate-limiter": "^6.4|^7.0"
+ "symfony/cache": "^6.4.12|^7.1.5|^8.0",
+ "symfony/clock": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/mime": "^6.4|^7.0|^8.0",
+ "symfony/rate-limiter": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -4753,7 +4807,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v7.3.6"
+ "source": "https://github.com/symfony/http-foundation/tree/v7.4.1"
},
"funding": [
{
@@ -4773,29 +4827,29 @@
"type": "tidelift"
}
],
- "time": "2025-11-06T11:05:57+00:00"
+ "time": "2025-12-07T11:13:10+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v7.3.6",
+ "version": "v7.4.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "f9a34dc0196677250e3609c2fac9de9e1551a262"
+ "reference": "f6e6f0a5fa8763f75a504b930163785fb6dd055f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f9a34dc0196677250e3609c2fac9de9e1551a262",
- "reference": "f9a34dc0196677250e3609c2fac9de9e1551a262",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f6e6f0a5fa8763f75a504b930163785fb6dd055f",
+ "reference": "f6e6f0a5fa8763f75a504b930163785fb6dd055f",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
- "symfony/error-handler": "^6.4|^7.0",
- "symfony/event-dispatcher": "^7.3",
- "symfony/http-foundation": "^7.3",
+ "symfony/error-handler": "^6.4|^7.0|^8.0",
+ "symfony/event-dispatcher": "^7.3|^8.0",
+ "symfony/http-foundation": "^7.4|^8.0",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
@@ -4805,6 +4859,7 @@
"symfony/console": "<6.4",
"symfony/dependency-injection": "<6.4",
"symfony/doctrine-bridge": "<6.4",
+ "symfony/flex": "<2.10",
"symfony/form": "<6.4",
"symfony/http-client": "<6.4",
"symfony/http-client-contracts": "<2.5",
@@ -4822,27 +4877,27 @@
},
"require-dev": {
"psr/cache": "^1.0|^2.0|^3.0",
- "symfony/browser-kit": "^6.4|^7.0",
- "symfony/clock": "^6.4|^7.0",
- "symfony/config": "^6.4|^7.0",
- "symfony/console": "^6.4|^7.0",
- "symfony/css-selector": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/dom-crawler": "^6.4|^7.0",
- "symfony/expression-language": "^6.4|^7.0",
- "symfony/finder": "^6.4|^7.0",
+ "symfony/browser-kit": "^6.4|^7.0|^8.0",
+ "symfony/clock": "^6.4|^7.0|^8.0",
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
+ "symfony/css-selector": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/dom-crawler": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/finder": "^6.4|^7.0|^8.0",
"symfony/http-client-contracts": "^2.5|^3",
- "symfony/process": "^6.4|^7.0",
- "symfony/property-access": "^7.1",
- "symfony/routing": "^6.4|^7.0",
- "symfony/serializer": "^7.1",
- "symfony/stopwatch": "^6.4|^7.0",
- "symfony/translation": "^6.4|^7.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/property-access": "^7.1|^8.0",
+ "symfony/routing": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^7.1|^8.0",
+ "symfony/stopwatch": "^6.4|^7.0|^8.0",
+ "symfony/translation": "^6.4|^7.0|^8.0",
"symfony/translation-contracts": "^2.5|^3",
- "symfony/uid": "^6.4|^7.0",
- "symfony/validator": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0",
- "symfony/var-exporter": "^6.4|^7.0",
+ "symfony/uid": "^6.4|^7.0|^8.0",
+ "symfony/validator": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0",
+ "symfony/var-exporter": "^6.4|^7.0|^8.0",
"twig/twig": "^3.12"
},
"type": "library",
@@ -4871,7 +4926,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-kernel/tree/v7.3.6"
+ "source": "https://github.com/symfony/http-kernel/tree/v7.4.2"
},
"funding": [
{
@@ -4891,24 +4946,25 @@
"type": "tidelift"
}
],
- "time": "2025-11-06T20:58:12+00:00"
+ "time": "2025-12-08T07:43:37+00:00"
},
{
"name": "symfony/mime",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35"
+ "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/b1b828f69cbaf887fa835a091869e55df91d0e35",
- "reference": "b1b828f69cbaf887fa835a091869e55df91d0e35",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/bdb02729471be5d047a3ac4a69068748f1a6be7a",
+ "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a",
"shasum": ""
},
"require": {
"php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-intl-idn": "^1.10",
"symfony/polyfill-mbstring": "^1.0"
},
@@ -4923,11 +4979,11 @@
"egulias/email-validator": "^2.1.10|^3.1|^4",
"league/html-to-markdown": "^5.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/property-access": "^6.4|^7.0",
- "symfony/property-info": "^6.4|^7.0",
- "symfony/serializer": "^6.4.3|^7.0.3"
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/property-access": "^6.4|^7.0|^8.0",
+ "symfony/property-info": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^6.4.3|^7.0.3|^8.0"
},
"type": "library",
"autoload": {
@@ -4959,7 +5015,7 @@
"mime-type"
],
"support": {
- "source": "https://github.com/symfony/mime/tree/v7.3.4"
+ "source": "https://github.com/symfony/mime/tree/v7.4.0"
},
"funding": [
{
@@ -4979,7 +5035,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-16T08:38:17+00:00"
+ "time": "2025-11-16T10:14:42+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -5816,22 +5872,23 @@
},
{
"name": "symfony/string",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "f96476035142921000338bad71e5247fbc138872"
+ "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872",
- "reference": "f96476035142921000338bad71e5247fbc138872",
+ "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003",
+ "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003",
"shasum": ""
},
"require": {
"php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3.0",
"symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-grapheme": "~1.33",
"symfony/polyfill-intl-normalizer": "~1.0",
"symfony/polyfill-mbstring": "~1.0"
},
@@ -5839,11 +5896,11 @@
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/emoji": "^7.1",
- "symfony/http-client": "^6.4|^7.0",
- "symfony/intl": "^6.4|^7.0",
+ "symfony/emoji": "^7.1|^8.0",
+ "symfony/http-client": "^6.4|^7.0|^8.0",
+ "symfony/intl": "^6.4|^7.0|^8.0",
"symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^6.4|^7.0"
+ "symfony/var-exporter": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -5882,7 +5939,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.3.4"
+ "source": "https://github.com/symfony/string/tree/v7.4.0"
},
"funding": [
{
@@ -5902,27 +5959,27 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T14:36:48+00:00"
+ "time": "2025-11-27T13:27:24+00:00"
},
{
"name": "symfony/translation",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "ec25870502d0c7072d086e8ffba1420c85965174"
+ "reference": "2d01ca0da3f092f91eeedb46f24aa30d2fca8f68"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/ec25870502d0c7072d086e8ffba1420c85965174",
- "reference": "ec25870502d0c7072d086e8ffba1420c85965174",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/2d01ca0da3f092f91eeedb46f24aa30d2fca8f68",
+ "reference": "2d01ca0da3f092f91eeedb46f24aa30d2fca8f68",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/translation-contracts": "^2.5|^3.0"
+ "symfony/translation-contracts": "^2.5.3|^3.3"
},
"conflict": {
"nikic/php-parser": "<5.0",
@@ -5941,17 +5998,17 @@
"require-dev": {
"nikic/php-parser": "^5.0",
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/console": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/finder": "^6.4|^7.0",
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/finder": "^6.4|^7.0|^8.0",
"symfony/http-client-contracts": "^2.5|^3.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/intl": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/intl": "^6.4|^7.0|^8.0",
"symfony/polyfill-intl-icu": "^1.21",
- "symfony/routing": "^6.4|^7.0",
+ "symfony/routing": "^6.4|^7.0|^8.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/yaml": "^6.4|^7.0"
+ "symfony/yaml": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -5982,7 +6039,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/translation/tree/v7.3.4"
+ "source": "https://github.com/symfony/translation/tree/v7.4.0"
},
"funding": [
{
@@ -6002,7 +6059,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-07T11:39:36+00:00"
+ "time": "2025-11-27T13:27:24+00:00"
},
{
"name": "symfony/translation-contracts",
@@ -6088,16 +6145,16 @@
},
{
"name": "symfony/var-dumper",
- "version": "v7.3.5",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
+ "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
- "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/41fd6c4ae28c38b294b42af6db61446594a0dece",
+ "reference": "41fd6c4ae28c38b294b42af6db61446594a0dece",
"shasum": ""
},
"require": {
@@ -6109,10 +6166,10 @@
"symfony/console": "<6.4"
},
"require-dev": {
- "symfony/console": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/uid": "^6.4|^7.0",
+ "symfony/console": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/uid": "^6.4|^7.0|^8.0",
"twig/twig": "^3.12"
},
"bin": [
@@ -6151,7 +6208,7 @@
"dump"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
+ "source": "https://github.com/symfony/var-dumper/tree/v7.4.0"
},
"funding": [
{
@@ -6171,20 +6228,20 @@
"type": "tidelift"
}
],
- "time": "2025-09-27T09:00:46+00:00"
+ "time": "2025-10-27T20:36:44+00:00"
},
{
"name": "symfony/var-exporter",
- "version": "v7.3.4",
+ "version": "v7.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
- "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4"
+ "reference": "03a60f169c79a28513a78c967316fbc8bf17816f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f020b544a30a7fe8ba972e53ee48a74c0bc87f4",
- "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4",
+ "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f",
+ "reference": "03a60f169c79a28513a78c967316fbc8bf17816f",
"shasum": ""
},
"require": {
@@ -6192,9 +6249,9 @@
"symfony/deprecation-contracts": "^2.5|^3"
},
"require-dev": {
- "symfony/property-access": "^6.4|^7.0",
- "symfony/serializer": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/property-access": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -6232,7 +6289,7 @@
"serialize"
],
"support": {
- "source": "https://github.com/symfony/var-exporter/tree/v7.3.4"
+ "source": "https://github.com/symfony/var-exporter/tree/v7.4.0"
},
"funding": [
{
@@ -6252,7 +6309,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-11T10:12:26+00:00"
+ "time": "2025-09-11T10:15:23+00:00"
},
{
"name": "topthink/think-container",
@@ -6587,22 +6644,22 @@
},
{
"name": "webman/console",
- "version": "v2.1.9",
+ "version": "v2.1.10",
"source": {
"type": "git",
"url": "https://github.com/webman-php/console.git",
- "reference": "09c995bf3d9a136c7c471b6db837a1fd56b7d206"
+ "reference": "6b24bb77d04588c7c3b235087073e69ddfdaa773"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webman-php/console/zipball/09c995bf3d9a136c7c471b6db837a1fd56b7d206",
- "reference": "09c995bf3d9a136c7c471b6db837a1fd56b7d206",
+ "url": "https://api.github.com/repos/webman-php/console/zipball/6b24bb77d04588c7c3b235087073e69ddfdaa773",
+ "reference": "6b24bb77d04588c7c3b235087073e69ddfdaa773",
"shasum": ""
},
"require": {
"doctrine/inflector": "^2.0",
"php": ">=8.1",
- "symfony/console": ">=6.0"
+ "symfony/console": "^6.0 || ^7.0"
},
"require-dev": {
"workerman/webman": "^2.1"
@@ -6637,20 +6694,20 @@
"source": "https://github.com/webman-php/console",
"wiki": "http://www.workerman.net/doc/webman"
},
- "time": "2025-10-14T09:11:21+00:00"
+ "time": "2025-12-08T08:23:12+00:00"
},
{
"name": "webman/database",
- "version": "v2.1.6",
+ "version": "v2.1.7",
"source": {
"type": "git",
"url": "https://github.com/webman-php/database.git",
- "reference": "943c5a0f92d8959d9160c2ee3925112b15c308c8"
+ "reference": "81a8a834cc8db5a5dbb46fe0073a9d5ac73848f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webman-php/database/zipball/943c5a0f92d8959d9160c2ee3925112b15c308c8",
- "reference": "943c5a0f92d8959d9160c2ee3925112b15c308c8",
+ "url": "https://api.github.com/repos/webman-php/database/zipball/81a8a834cc8db5a5dbb46fe0073a9d5ac73848f6",
+ "reference": "81a8a834cc8db5a5dbb46fe0073a9d5ac73848f6",
"shasum": ""
},
"require": {
@@ -6673,9 +6730,9 @@
"description": "Webman database",
"support": {
"issues": "https://github.com/webman-php/database/issues",
- "source": "https://github.com/webman-php/database/tree/v2.1.6"
+ "source": "https://github.com/webman-php/database/tree/v2.1.7"
},
- "time": "2025-04-04T13:23:25+00:00"
+ "time": "2025-11-27T08:09:25+00:00"
},
{
"name": "webman/gateway-worker",
@@ -6710,6 +6767,40 @@
},
"time": "2024-04-30T01:05:42+00:00"
},
+ {
+ "name": "webman/log",
+ "version": "v2.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webman-php/log.git",
+ "reference": "14e3f3e64e87783952417a68cf5205c1293aba69"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webman-php/log/zipball/14e3f3e64e87783952417a68cf5205c1293aba69",
+ "reference": "14e3f3e64e87783952417a68cf5205c1293aba69",
+ "shasum": ""
+ },
+ "require": {
+ "workerman/webman-framework": "^2.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Webman\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Webman plugin webman/log",
+ "support": {
+ "issues": "https://github.com/webman-php/log/issues",
+ "source": "https://github.com/webman-php/log/tree/v2.1.3"
+ },
+ "time": "2025-02-26T11:43:36+00:00"
+ },
{
"name": "webman/redis",
"version": "v2.1.3",
@@ -6748,16 +6839,16 @@
},
{
"name": "webman/redis-queue",
- "version": "v2.1.0",
+ "version": "v2.1.1",
"source": {
"type": "git",
"url": "https://github.com/webman-php/redis-queue.git",
- "reference": "12e1c9915ec64c91c0c9c255606bd0c7de27334c"
+ "reference": "ff4791e21f3c324a47e21da7b6f2dae5a7311dcb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/webman-php/redis-queue/zipball/12e1c9915ec64c91c0c9c255606bd0c7de27334c",
- "reference": "12e1c9915ec64c91c0c9c255606bd0c7de27334c",
+ "url": "https://api.github.com/repos/webman-php/redis-queue/zipball/ff4791e21f3c324a47e21da7b6f2dae5a7311dcb",
+ "reference": "ff4791e21f3c324a47e21da7b6f2dae5a7311dcb",
"shasum": ""
},
"require": {
@@ -6776,9 +6867,9 @@
"description": "Redis message queue plugin for webman.",
"support": {
"issues": "https://github.com/webman-php/redis-queue/issues",
- "source": "https://github.com/webman-php/redis-queue/tree/v2.1.0"
+ "source": "https://github.com/webman-php/redis-queue/tree/v2.1.1"
},
- "time": "2025-01-24T12:56:01+00:00"
+ "time": "2025-11-14T07:12:52+00:00"
},
{
"name": "workerman/coroutine",
@@ -7135,28 +7226,31 @@
"type": "patreon"
}
],
- "time": "2025-06-12T13:34:04+00:00"
+ "time": "2025-11-12T01:36:20+00:00"
},
{
"name": "zoujingli/ip2region",
- "version": "v3.0.0",
+ "version": "v3.0.8",
"source": {
"type": "git",
"url": "https://github.com/zoujingli/ip2region.git",
- "reference": "fd31d7a023f28f4e2f3e63f46f1fd51f8b2672f6"
+ "reference": "4ab4283f4b4ea4222da6cb97fbf7f7167f1ebb53"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/zoujingli/ip2region/zipball/fd31d7a023f28f4e2f3e63f46f1fd51f8b2672f6",
- "reference": "fd31d7a023f28f4e2f3e63f46f1fd51f8b2672f6",
+ "url": "https://api.github.com/repos/zoujingli/ip2region/zipball/4ab4283f4b4ea4222da6cb97fbf7f7167f1ebb53",
+ "reference": "4ab4283f4b4ea4222da6cb97fbf7f7167f1ebb53",
"shasum": ""
},
"require": {
- "php": ">=5.4"
+ "php": ">=7.1.0"
},
"suggest": {
"ext-opcache": "启用 OPcache 以获得更好的性能"
},
+ "bin": [
+ "bin/ip2down"
+ ],
"type": "library",
"extra": {
"branch-alias": {
@@ -7165,10 +7259,13 @@
},
"autoload": {
"files": [
- "ip2region.php"
+ "src/common.php"
],
+ "psr-4": {
+ "ip2region\\": "src/ip2region/"
+ },
"classmap": [
- "src/"
+ "src/Ip2Region.php"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -7182,30 +7279,28 @@
"homepage": "https://thinkadmin.top"
}
],
- "description": "Ip2Region v3.0 for PHP - 企业级 IP 地理位置查询库,支持 IPv4/IPv6,分片文件管理,智能缓存,零依赖",
+ "description": "ip2region v3.0 for PHP - 企业级 IP 地理位置查询库,支持 IPv4 和 IPv6,多种缓存策略,零依赖,开箱即用",
"homepage": "https://github.com/zoujingli/Ip2Region",
"keywords": [
"IP",
- "IP定位",
"Ip2Region",
- "geoip",
+ "composer",
"geolocation",
"ipv4",
"ipv6",
"location",
+ "php",
"企业级",
- "分片数据库",
- "压缩",
- "地理位置",
- "地理位置查询",
- "缓存",
+ "智能加载",
+ "缓存策略",
+ "零依赖",
"高性能"
],
"support": {
"issues": "https://github.com/zoujingli/ip2region/issues",
- "source": "https://github.com/zoujingli/ip2region/tree/v3.0.0"
+ "source": "https://github.com/zoujingli/ip2region/tree/v3.0.8"
},
- "time": "2025-09-15T12:27:22+00:00"
+ "time": "2025-11-20T11:02:33+00:00"
}
],
"packages-dev": [],
diff --git a/config/plugin/webman/log/app.php b/config/plugin/webman/log/app.php
new file mode 100644
index 0000000..6217553
--- /dev/null
+++ b/config/plugin/webman/log/app.php
@@ -0,0 +1,19 @@
+ true,
+ 'exception' => [
+ // 是否记录异常到日志
+ 'enable' => true,
+ // 不会记录到日志的异常类
+ 'dontReport' => [
+ support\exception\BusinessException::class
+ ]
+ ],
+ 'dontReport' => [
+ 'app' => [],
+ 'controller' => [],
+ 'action' => [],
+ 'path' => []
+ ],
+ 'channel' => 'default' // 日志通道(在config/log.php里配置,默认是default)
+];
diff --git a/config/plugin/webman/log/middleware.php b/config/plugin/webman/log/middleware.php
new file mode 100644
index 0000000..7c7b0a9
--- /dev/null
+++ b/config/plugin/webman/log/middleware.php
@@ -0,0 +1,21 @@
+
+ * @copyright walkor
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+use Webman\Log\Middleware;
+
+return [
+ '@' => [
+ Middleware::class
+ ]
+];