Passed
Pull Request — master (#4323)
by Owen
17:30 queued 06:07
created

NamedExpressions   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Test Coverage

Coverage 98.65%

Importance

Changes 0
Metric Value
wmc 18
eloc 70
c 0
b 0
f 0
dl 0
loc 124
rs 10
ccs 73
cts 74
cp 0.9865

6 Methods

Rating   Name   Duplication   Size   Complexity  
A writeExpressions() 0 14 3
B convertAddress() 0 54 9
A writeNamedFormula() 0 11 2
A writeNamedRange() 0 13 2
A __construct() 0 5 1
A write() 0 7 1
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Ods;
4
5
use Composer\Pcre\Preg;
6
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
7
use PhpOffice\PhpSpreadsheet\DefinedName;
8
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
9
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
10
use PhpOffice\PhpSpreadsheet\Spreadsheet;
11
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
12
13
class NamedExpressions
14
{
15
    private XMLWriter $objWriter;
16
17
    private Spreadsheet $spreadsheet;
18
19
    private Formula $formulaConvertor;
20
21 39
    public function __construct(XMLWriter $objWriter, Spreadsheet $spreadsheet, Formula $formulaConvertor)
22
    {
23 39
        $this->objWriter = $objWriter;
24 39
        $this->spreadsheet = $spreadsheet;
25 39
        $this->formulaConvertor = $formulaConvertor;
26
    }
27
28 39
    public function write(): string
29
    {
30 39
        $this->objWriter->startElement('table:named-expressions');
31 39
        $this->writeExpressions();
32 39
        $this->objWriter->endElement();
33
34 39
        return '';
35
    }
36
37 39
    private function writeExpressions(): void
38
    {
39 39
        $definedNames = $this->spreadsheet->getDefinedNames();
40
41 39
        foreach ($definedNames as $definedName) {
42 2
            if ($definedName->isFormula()) {
43 1
                $this->objWriter->startElement('table:named-expression');
44 1
                $this->writeNamedFormula($definedName, $this->spreadsheet->getActiveSheet());
45
            } else {
46 2
                $this->objWriter->startElement('table:named-range');
47 2
                $this->writeNamedRange($definedName);
48
            }
49
50 2
            $this->objWriter->endElement();
51
        }
52
    }
53
54 1
    private function writeNamedFormula(DefinedName $definedName, Worksheet $defaultWorksheet): void
55
    {
56 1
        $title = ($definedName->getWorksheet() !== null) ? $definedName->getWorksheet()->getTitle() : $defaultWorksheet->getTitle();
57 1
        $this->objWriter->writeAttribute('table:name', $definedName->getName());
58 1
        $this->objWriter->writeAttribute(
59 1
            'table:expression',
60 1
            $this->formulaConvertor->convertFormula($definedName->getValue(), $title)
61 1
        );
62 1
        $this->objWriter->writeAttribute('table:base-cell-address', $this->convertAddress(
63 1
            $definedName,
64 1
            "'" . $title . "'!\$A\$1"
65 1
        ));
66
    }
67
68 2
    private function writeNamedRange(DefinedName $definedName): void
69
    {
70 2
        $baseCell = '$A$1';
71 2
        $ws = $definedName->getWorksheet();
72 2
        if ($ws !== null) {
73 2
            $baseCell = "'" . $ws->getTitle() . "'!$baseCell";
74
        }
75 2
        $this->objWriter->writeAttribute('table:name', $definedName->getName());
76 2
        $this->objWriter->writeAttribute('table:base-cell-address', $this->convertAddress(
77 2
            $definedName,
78 2
            $baseCell
79 2
        ));
80 2
        $this->objWriter->writeAttribute('table:cell-range-address', $this->convertAddress($definedName, $definedName->getValue()));
81
    }
82
83 2
    private function convertAddress(DefinedName $definedName, string $address): string
84
    {
85 2
        $splitCount = Preg::matchAllWithOffsets(
86 2
            '/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/mui',
87 2
            $address,
88 2
            $splitRanges
89 2
        );
90
91 2
        $lengths = array_map([StringHelper::class, 'strlenAllowNull'], array_column($splitRanges[0], 0));
92 2
        $offsets = array_column($splitRanges[0], 1);
93
94 2
        $worksheets = $splitRanges[2];
95 2
        $columns = $splitRanges[6];
96 2
        $rows = $splitRanges[7];
97
98 2
        while ($splitCount > 0) {
99 2
            --$splitCount;
100 2
            $length = $lengths[$splitCount];
101 2
            $offset = $offsets[$splitCount];
102 2
            $worksheet = $worksheets[$splitCount][0];
103 2
            $column = $columns[$splitCount][0];
104 2
            $row = $rows[$splitCount][0];
105
106 2
            $newRange = '';
107 2
            if (empty($worksheet)) {
108 1
                if (($offset === 0) || ($address[$offset - 1] !== ':')) {
109
                    // We need a worksheet
110 1
                    $ws = $definedName->getWorksheet();
111 1
                    if ($ws !== null) {
112 1
                        $worksheet = $ws->getTitle();
113
                    }
114
                }
115
            } else {
116 2
                $worksheet = str_replace("''", "'", trim($worksheet, "'"));
117
            }
118 2
            if (!empty($worksheet)) {
119 2
                $newRange = "'" . str_replace("'", "''", $worksheet) . "'.";
120
            }
121
122
            //if (!empty($column)) { // phpstan says always true
123 2
            $newRange .= $column;
124
            //}
125 2
            if (!empty($row)) {
126 2
                $newRange .= $row;
127
            }
128
129 2
            $address = substr($address, 0, $offset) . $newRange . substr($address, $offset + $length);
130
        }
131
132 2
        if (str_starts_with($address, '=')) {
133
            $address = substr($address, 1);
134
        }
135
136 2
        return $address;
137
    }
138
}
139