Passed
Push — master ( dcb10e...d87ef3 )
by Adrien
12:23
created

NamedExpressions::writeNamedRange()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

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