Laravel9+maatwebsite/excel:从MySQL生成指定格式Excel矩阵
问题描述
需要从数据库生成如下格式的Excel文件:
| User Name | User Lastname | Group A | Group B | Group X |
|---|---|---|---|---|
| John | Doe | X | X | |
| Jane | Doe | X |
现有三张表:User表、Group表及关联用户与组的Group Matching表(一个用户可属于多个组)。已通过查询组列表动态构建表头,并将"User Name"和"User Lastname"添加至表头数组:
public function headings(): array { $header = array(); $search ="Group"; $groupList = new \App\Models\Group; $groupList = $groupList::where('name','LIKE',"%{$search}%")->get();; foreach($groupList as $key=>$value) { $header[]=$value["name"]; } array_unshift($header,"User Name", "User Lastname"); return $header; }
注:输出的组数量不可控。接下来,已获取包含用户名、姓氏及组归属的记录集合:
public function array(): array { $datas = array(); $MyUsers = MyUser::with(['groupMatching'])->get(); foreach($MyUsers as $MyUser) { $datas[$MyUser->id]["name"] = $MyUser->lastname; $datas[$MyUser->id]["firstname"] = $MyUser->firstname; foreach($MyUser->groupMatching as $MyMember) { $datas[$MyUser->id]["groups"][] = $MyMember->Group_name; } } return $datas; }
$datas结构如下:
array:23 [▼ // app/Exports/MyUsersExport.php:31 4 => array:3 [▼ "name" => "Doe" "firstname" => "John" "groups" => array:3 [▼ 0 => "Group A" 1 => "Group X" ] 5 => array:3 [▼ "name" => "Jane" "firstname" => "Doe" "groups" => array:2 [▼ 0 => "Group X" ] ] ]
使用Laravel 9和maatwebsite/excel 3.1,如何实现目标输出,在匹配的列名/数据对应位置填充X?
解决方案
核心思路是让返回的每行数据与表头顺序完全对应,逐个判断用户是否属于对应组,填充X或空值。具体步骤如下:
1. 抽离表头逻辑(避免重复查询)
把生成表头的代码抽成私有方法,同时供headings()和array()调用,减少数据库查询次数:
private function getHeaders(): array { $search = "Group"; // 直接提取组名数组,比get()更高效 $groupNames = \App\Models\Group::where('name', 'LIKE', "%{$search}%")->pluck('name')->toArray(); array_unshift($groupNames, "User Name", "User Lastname"); return $groupNames; }
2. 重写headings()方法
复用抽离的表头逻辑:
public function headings(): array { return $this->getHeaders(); }
3. 修改array()方法生成对应行数据
遍历每个用户,按照表头顺序生成每行数据,判断用户是否属于当前组并填充X:
public function array(): array { $headers = $this->getHeaders(); // 提取表头中除前两列外的所有组列 $groupColumns = array_slice($headers, 2); $rows = []; $MyUsers = MyUser::with(['groupMatching'])->get(); foreach ($MyUsers as $MyUser) { // 将用户所属组转为键数组,提升存在性判断效率 $userGroups = collect($MyUser->groupMatching)->pluck('Group_name')->flip()->toArray(); $row = []; // 填充前两列:User Name(名)、User Lastname(姓) $row[] = $MyUser->firstname; $row[] = $MyUser->lastname; // 遍历所有组列,填充X或空值 foreach ($groupColumns as $groupName) { $row[] = isset($userGroups[$groupName]) ? 'X' : ''; } $rows[] = $row; } return $rows; }
代码说明
- 使用
pluck('name')直接获取组名数组,比get()后遍历更高效 flip()将用户所属组数组的键值互换,把组名作为键,判断用户是否属于该组时只需用isset(),性能更优- 严格按照表头顺序生成每行数据,保证Excel中列与数据完全对应
- 最终返回的二维数组
$rows完全符合maatwebsite/excel的要求,无需额外处理即可生成目标格式的Excel
内容的提问来源于stack exchange,提问作者STANISLAS PIERRE-ALEXANDRE
相关产品推荐
相关产品推荐

