GroupHandler   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 64
c 0
b 0
f 0
dl 0
loc 152
rs 10
wmc 24

4 Methods

Rating   Name   Duplication   Size   Complexity  
C processGroupLeft() 0 72 13
A arrayCount() 0 18 3
A groupDataByTwoFields() 0 9 4
A groupDataByOneField() 0 15 4
1
<?php
2
/**
3
 * @name: GroupHandler
4
 * @author: JiaMeng <[email protected]>
5
 * @file: GroupHandler.php
6
 * @Date: 2025/01/XX
7
 */
8
namespace tinymeng\spreadsheet\Excel\Handler;
9
10
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
11
use tinymeng\spreadsheet\Util\WorkSheetHelper;
12
use tinymeng\tools\exception\StatusCode;
13
use tinymeng\tools\exception\TinymengException;
14
15
class GroupHandler
16
{
17
    /**
18
     * 处理左侧分组数据
19
     * @param Worksheet $worksheet
20
     * @param array $data 分组后的数据
21
     * @param int $groupLeftCount 分组级别数
22
     * @param array $groupLeft 分组字段列表
23
     * @param array $fields 所有字段列表
24
     * @param array $mergeColumns 需要合并的列
25
     * @param int $row 当前行
26
     * @param callable $setCellValueFunc 设置单元格值的函数(用于递归调用)
27
     * @return int 返回更新后的行号
28
     */
29
    public static function processGroupLeft(
30
        Worksheet $worksheet,
31
        array $data,
32
        int $groupLeftCount,
33
        array $groupLeft,
34
        array $fields,
35
        array $mergeColumns,
36
        int $row,
37
        callable $setCellValueFunc
38
    ): int {
39
        // 获取分组字段在field中的实际位置
40
        $group_field_positions = [];
41
        foreach ($groupLeft as $group_field) {
42
            $position = array_search($group_field, $fields);
43
            if ($position !== false) {
44
                $group_field_positions[] = $position;
45
            }
46
        }
47
48
        if (empty($group_field_positions)) {
49
            throw new TinymengException(StatusCode::COMMON_PARAM_INVALID, '分组字段未在标题中定义');
50
        }
51
52
        $group_start = $row;
53
        foreach ($data as $key => $val) {
54
            // 第一级分组的合并单元格
55
            $rowName = WorkSheetHelper::cellName($group_field_positions[0]); // 使用第一个分组字段的实际位置
56
            $coordinate = $rowName . $row . ':' . $rowName . ($row + $val['count'] - 1);
57
            $worksheet->mergeCells($coordinate);
58
            $worksheet->setCellValue($rowName . $row, $key);
59
60
            // 合并mergeColumns指定的其它列
61
            if (!empty($mergeColumns)) {
62
                foreach ($mergeColumns as $field) {
63
                    // 跳过分组字段本身
64
                    if (in_array($field, $groupLeft)) continue;
65
                    $colIdx = array_search($field, $fields);
66
                    if ($colIdx !== false) {
67
                        $colLetter = WorkSheetHelper::cellName($colIdx);
0 ignored issues
show
Bug introduced by
It seems like $colIdx can also be of type string; however, parameter $columnIndex of tinymeng\spreadsheet\Uti...SheetHelper::cellName() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

67
                        $colLetter = WorkSheetHelper::cellName(/** @scrutinizer ignore-type */ $colIdx);
Loading history...
68
                        $worksheet->mergeCells($colLetter . $row . ':' . $colLetter . ($row + $val['count'] - 1));
69
                        // 取本组第一个数据的值
70
                        $worksheet->setCellValue($colLetter . $row, $val['data'][0][$field] ?? '');
71
                    }
72
                }
73
            }
74
75
            if ($groupLeftCount == 1) {
76
                foreach ($val['data'] as $dataRow) {
77
                    $setCellValueFunc($dataRow);
78
                }
79
            } else {
80
                $sub_group_start = $row;
81
                $rowName = WorkSheetHelper::cellName($group_field_positions[1]); // 使用第二个分组字段的实际位置
82
83
                foreach ($val['data'] as $k => $v) {
84
                    $coordinate = $rowName . $sub_group_start . ':' . $rowName . ($sub_group_start + $v['count'] - 1);
85
                    $worksheet->mergeCells($coordinate);
86
                    $worksheet->setCellValue($rowName . $sub_group_start, $k);
87
88
                    foreach ($v['data'] as $data) {
89
                        $setCellValueFunc($data);
90
                    }
91
92
                    $sub_group_start = $sub_group_start + $v['count'];
93
                }
94
            }
95
96
            $row = $group_start + $val['count'];
97
            $group_start = $row;
98
        }
99
        
100
        return $row;
101
    }
102
103
    /**
104
     * 数据分组(一级分组)
105
     * @param array $data 原始数据
106
     * @param string $groupField 分组字段
107
     * @return array
108
     */
109
    public static function groupDataByOneField(array $data, string $groupField): array
110
    {
111
        $grouped = [];
112
        foreach ($data as $k => $v) {
113
            if (isset($v[$groupField])) {
114
                $grouped[$v[$groupField]][] = $v;
115
            }
116
        }
117
        foreach ($grouped as $k => $v) {
118
            $grouped[$k] = [
119
                'data' => $v,
120
                'count' => count($v)
121
            ];
122
        }
123
        return $grouped;
124
    }
125
126
    /**
127
     * 数据分组(二级分组)
128
     * @param array $data 原始数据
129
     * @param string $firstGroupField 第一级分组字段
130
     * @param string $secondGroupField 第二级分组字段
131
     * @return array
132
     */
133
    public static function groupDataByTwoFields(array $data, string $firstGroupField, string $secondGroupField): array
134
    {
135
        $grouped = [];
136
        foreach ($data as $v) {
137
            if (isset($v[$firstGroupField]) && isset($v[$secondGroupField])) {
138
                $grouped[$v[$firstGroupField]][$v[$secondGroupField]][] = $v;
139
            }
140
        }
141
        return self::arrayCount($grouped);
142
    }
143
144
    /**
145
     * 二位数组获取每一级别数量
146
     * @param array $data 二维数组原始数据
147
     * @return array
148
     */
149
    private static function arrayCount(array $data): array
150
    {
151
        foreach ($data as $key => $val) {
152
            $num = 0;
153
            foreach ($val as $k => $v) {
154
                $sub_num = count($v);
155
                $num = $num + $sub_num;
156
                $val[$k] = [
157
                    'count' => $sub_num,
158
                    'data' => $v
159
                ];
160
            }
161
            $data[$key] = [
162
                'count' => $num,
163
                'data' => $val
164
            ];
165
        }
166
        return $data;
167
    }
168
}
169
170