Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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