Yii2中如何生成含两个工作表的Excel文件并作为邮件附件?
嘿,这个问题我太懂了!因为CSV格式本身就不支持多工作表,所以咱们得换个思路——生成真正的Excel文件(比如XLSX格式),把两组数据分别放到不同的工作表里,再作为附件用SwiftMailer发送。下面给你一步步实现:
步骤1:安装PhpSpreadsheet库
Yii2本身没有内置多工作表Excel生成工具,咱们用PhpSpreadsheet(PHPExcel的官方替代,功能更完善)。在项目根目录执行composer命令安装:
composer require phpoffice/phpspreadsheet
步骤2:编写生成多工作表Excel的函数
替换原来的getAttachment函数,改成生成包含两个工作表的XLSX文件:
use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; use PhpOffice\PhpSpreadsheet\Style\Alignment; use yii\helpers\ArrayHelper; /** * 生成带双工作表的Excel附件 * @param array|object $data1 3-Phase类型数据(支持ActiveRecord集合或二维数组) * @param array|object $data2 L.T.TOU类型数据(支持ActiveRecord集合或二维数组) * @param array $headers 共用表头数组 * @return \Swift_Attachment */ public function getDualSheetExcelAttachment($data1, $data2, $headers) { // 把ActiveRecord对象转成二维数组(如果你的查询结果是对象集合的话) $data1 = ArrayHelper::toArray($data1); $data2 = ArrayHelper::toArray($data2); // 创建Excel实例 $spreadsheet = new Spreadsheet(); // 第一个工作表:3-Phase $sheet1 = $spreadsheet->getActiveSheet(); $sheet1->setTitle('3-Phase'); // 设置表头并美化样式 $col = 'A'; foreach ($headers as $header) { $sheet1->setCellValue($col . '1', $header); $sheet1->getStyle($col . '1')->getFont()->setBold(true); $sheet1->getStyle($col . '1')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); $col++; } // 填充3-Phase数据 $row = 2; foreach ($data1 as $item) { $col = 'A'; foreach ($item as $value) { $sheet1->setCellValue($col . $row, $value); $col++; } $row++; } // 添加第二个工作表:L.T.TOU $sheet2 = $spreadsheet->createSheet(); $sheet2->setTitle('L.T.TOU'); // 复用表头设置 $col = 'A'; foreach ($headers as $header) { $sheet2->setCellValue($col . '1', $header); $sheet2->getStyle($col . '1')->getFont()->setBold(true); $sheet2->getStyle($col . '1')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); $col++; } // 填充L.T.TOU数据 $row = 2; foreach ($data2 as $item) { $col = 'A'; foreach ($item as $value) { $sheet2->setCellValue($col . $row, $value); $col++; } $row++; } // 自动调整列宽(提升用户体验) foreach ([$sheet1, $sheet2] as $sheet) { foreach (range('A', $sheet->getHighestColumn()) as $column) { $sheet->getColumnDimension($column)->setAutoSize(true); } } // 生成临时文件(避免占用服务器永久存储) $tempFile = tempnam(sys_get_temp_dir(), 'report_'); $writer = new Xlsx($spreadsheet); $writer->save($tempFile); // 创建SwiftMailer附件对象 $attachment = \Swift_Attachment::fromPath($tempFile) ->setFilename('data_report.xlsx') // 收件人看到的附件名 ->setContentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // 释放Excel资源 $spreadsheet->disconnectWorksheets(); unset($spreadsheet); // 邮件发送后自动删除临时文件(防止垃圾文件堆积) \Yii::$app->mailer->on(\yii\swiftmailer\Mailer::EVENT_AFTER_SEND, function ($event) use ($tempFile) { if (file_exists($tempFile)) { unlink($tempFile); } }); return $attachment; }
步骤3:在邮件发送逻辑中调用函数
把生成的附件添加到邮件里发送:
// 替换成你实际的表头数组 $headers = ['ID', '名称', '数值1', '数值2', '时间']; // 你的SQL查询结果:3-Phase和L.T.TOU数据 $result = // 3-Phase类型数据集合/数组 $result_set = // L.T.TOU类型数据集合/数组 // 生成双工作表Excel附件 $attachment = $this->getDualSheetExcelAttachment($result, $result_set, $headers); // 发送邮件 \Yii::$app->mailer->compose() ->setTo('user@example.com') ->setSubject('双工作表数据报告') ->setTextBody('您好,附件包含3-Phase和L.T.TOU两组数据,分别在两个工作表中。') ->attach($attachment) ->send();
注意事项
- 如果你的SQL查询结果是ActiveRecord对象集合,
ArrayHelper::toArray()会自动把对象转成键值对数组,完美匹配表头列。 - 临时文件用系统临时目录存储,发送后自动删除,不会占用服务器空间。
- ContentType设置为XLSX的标准类型,确保邮箱客户端能正确识别文件格式。
内容的提问来源于stack exchange,提问作者Moeez
相关产品推荐
相关产品推荐

