Failed Conditions
Pull Request — master (#3876)
by Abdul Malik
17:26 queued 02:15
created

DefinedName::testIfFormula()   A

Complexity

Conditions 6
Paths 8

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 23
rs 9.2222
ccs 12
cts 12
cp 1
cc 6
nc 8
nop 1
crap 6
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet;
4
5
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
6
7
abstract class DefinedName
8
{
9
    protected const REGEXP_IDENTIFY_FORMULA = '[^_\p{N}\p{L}:, \$\'!]';
10
11
    /**
12
     * Worksheet on which the defined name can be resolved.
13
     */
14
    protected ?Worksheet $worksheet;
15
16
    /**
17
     * Value of the named object.
18
     */
19
    protected string $value;
20
21
    /**
22
     * Scope.
23
     */
24
    protected ?Worksheet $scope;
25
26
    /**
27
     * Whether this is a named range or a named formula.
28
     */
29
    protected bool $isFormula;
30
31
    /**
32
     * Create a new Defined Name.
33
     */
34 340
    public function __construct(
35
        /**
36
         * Name.
37
         */
38
        protected string $name,
39
        ?Worksheet $worksheet = null,
40
        ?string $value = null,
41
        /**
42
         * Is the defined named local? (i.e. can only be used on $this->worksheet).
43
         */
44
        protected bool $localOnly = false,
45
        ?Worksheet $scope = null
46
    ) {
47 340
        if ($worksheet === null) {
48 40
            $worksheet = $scope;
49
        }
50 340
        $this->worksheet = $worksheet;
51 340
        $this->value = (string) $value;
52
        // If local only, then the scope will be set to worksheet unless a scope is explicitly set
53 340
        $this->scope = ($this->localOnly === true) ? ($scope ?? $worksheet) : null;
54
        // If the range string contains characters that aren't associated with the range definition (A-Z,1-9
55
        //      for cell references, and $, or the range operators (colon comma or space), quotes and ! for
56
        //      worksheet names
57
        //  then this is treated as a named formula, and not a named range
58 340
        $this->isFormula = self::testIfFormula($this->value);
59
    }
60
61 38
    public function __destruct()
62
    {
63 38
        $this->worksheet = null;
64 38
        $this->scope = null;
65
    }
66
67
    /**
68
     * Create a new defined name, either a range or a formula.
69
     */
70 121
    public static function createInstance(
71
        string $name,
72
        ?Worksheet $worksheet = null,
73
        ?string $value = null,
74
        bool $localOnly = false,
75
        ?Worksheet $scope = null
76
    ): self {
77 121
        $value = (string) $value;
78 121
        $isFormula = self::testIfFormula($value);
79 121
        if ($isFormula) {
80 71
            return new NamedFormula($name, $worksheet, $value, $localOnly, $scope);
81
        }
82
83 87
        return new NamedRange($name, $worksheet, $value, $localOnly, $scope);
84
    }
85
86 362
    public static function testIfFormula(string $value): bool
87
    {
88 362
        if (str_starts_with($value, '=')) {
89 57
            $value = substr($value, 1);
90
        }
91
92 362
        if (is_numeric($value)) {
93 6
            return true;
94
        }
95
96 359
        $segMatcher = false;
97 359
        foreach (explode("'", $value) as $subVal) {
98
            //    Only test in alternate array entries (the non-quoted blocks)
99 359
            $segMatcher = $segMatcher === false;
100
            if (
101 359
                $segMatcher
102 359
                && (preg_match('/' . self::REGEXP_IDENTIFY_FORMULA . '/miu', $subVal))
103
            ) {
104 93
                return true;
105
            }
106
        }
107
108 320
        return false;
109
    }
110
111
    /**
112
     * Get name.
113
     */
114 338
    public function getName(): string
115
    {
116 338
        return $this->name;
117
    }
118
119
    /**
120
     * Set name.
121
     */
122 1
    public function setName(string $name): self
123
    {
124 1
        if (!empty($name)) {
125
            // Old title
126 1
            $oldTitle = $this->name;
127
128
            // Re-attach
129 1
            if ($this->worksheet !== null) {
130 1
                $this->worksheet->getParentOrThrow()->removeNamedRange($this->name, $this->worksheet);
131
            }
132 1
            $this->name = $name;
133
134 1
            if ($this->worksheet !== null) {
135 1
                $this->worksheet->getParentOrThrow()->addDefinedName($this);
136
            }
137
138 1
            if ($this->worksheet !== null) {
139
                // New title
140 1
                $newTitle = $this->name;
141 1
                ReferenceHelper::getInstance()->updateNamedFormulae($this->worksheet->getParentOrThrow(), $oldTitle, $newTitle);
0 ignored issues
show
Bug introduced by
The type PhpOffice\PhpSpreadsheet\ReferenceHelper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
142
            }
143
        }
144
145 1
        return $this;
146
    }
147
148
    /**
149
     * Get worksheet.
150
     */
151 136
    public function getWorksheet(): ?Worksheet
152
    {
153 136
        return $this->worksheet;
154
    }
155
156
    /**
157
     * Set worksheet.
158
     */
159 2
    public function setWorksheet(?Worksheet $worksheet): self
160
    {
161 2
        $this->worksheet = $worksheet;
162
163 2
        return $this;
164
    }
165
166
    /**
167
     * Get range or formula value.
168
     */
169 155
    public function getValue(): string
170
    {
171 155
        return $this->value;
172
    }
173
174
    /**
175
     * Set range or formula  value.
176
     */
177 12
    public function setValue(string $value): self
178
    {
179 12
        $this->value = $value;
180
181 12
        return $this;
182
    }
183
184
    /**
185
     * Get localOnly.
186
     */
187 35
    public function getLocalOnly(): bool
188
    {
189 35
        return $this->localOnly;
190
    }
191
192
    /**
193
     * Set localOnly.
194
     */
195 1
    public function setLocalOnly(bool $localScope): self
196
    {
197 1
        $this->localOnly = $localScope;
198 1
        $this->scope = $localScope ? $this->worksheet : null;
199
200 1
        return $this;
201
    }
202
203
    /**
204
     * Get scope.
205
     */
206 338
    public function getScope(): ?Worksheet
207
    {
208 338
        return $this->scope;
209
    }
210
211
    /**
212
     * Set scope.
213
     */
214 1
    public function setScope(?Worksheet $worksheet): self
215
    {
216 1
        $this->scope = $worksheet;
217 1
        $this->localOnly = $worksheet !== null;
218
219 1
        return $this;
220
    }
221
222
    /**
223
     * Identify whether this is a named range or a named formula.
224
     */
225 143
    public function isFormula(): bool
226
    {
227 143
        return $this->isFormula;
228
    }
229
230
    /**
231
     * Resolve a named range to a regular cell range or formula.
232
     */
233 235
    public static function resolveName(string $definedName, Worksheet $worksheet, string $sheetName = ''): ?self
234
    {
235 235
        if ($sheetName === '') {
236 214
            $worksheet2 = $worksheet;
237
        } else {
238 27
            $worksheet2 = $worksheet->getParentOrThrow()->getSheetByName($sheetName);
239 27
            if ($worksheet2 === null) {
240 3
                return null;
241
            }
242
        }
243
244 233
        return $worksheet->getParentOrThrow()->getDefinedName($definedName, $worksheet2);
245
    }
246
247
    /**
248
     * Implement PHP __clone to create a deep clone, not just a shallow copy.
249
     */
250 1
    public function __clone()
251
    {
252 1
        $vars = get_object_vars($this);
253 1
        foreach ($vars as $key => $value) {
254 1
            if (is_object($value)) {
255 1
                $this->$key = clone $value;
256
            } else {
257 1
                $this->$key = $value;
258
            }
259
        }
260
    }
261
}
262