1
|
|
|
<?php |
2
|
|
|
namespace EngineWorks\Pivot; |
3
|
|
|
|
4
|
|
|
/** |
5
|
|
|
* Class to present Groups of results |
6
|
|
|
* |
7
|
|
|
* @property string $fieldname |
8
|
|
|
* @property string $caption |
9
|
|
|
* @property bool $isrow |
10
|
|
|
* @property array $values |
11
|
|
|
* @property Results|Result[] $children |
12
|
|
|
* @property Result $parent |
13
|
|
|
*/ |
14
|
|
|
class Result |
15
|
|
|
{ |
16
|
|
|
/** @var string */ |
17
|
|
|
private $privFieldname; |
18
|
|
|
|
19
|
|
|
/** @var string */ |
20
|
|
|
private $privCaption; |
21
|
|
|
|
22
|
|
|
/** @var array|null */ |
23
|
|
|
private $privValues; |
24
|
|
|
|
25
|
|
|
/** @var Results|Result[] */ |
26
|
|
|
private $privChildren; |
27
|
|
|
|
28
|
|
|
/** @var Result */ |
29
|
|
|
private $privParent; |
30
|
|
|
|
31
|
|
|
/** @var bool */ |
32
|
|
|
private $privIsRow; |
33
|
|
|
|
34
|
11 |
|
public function __construct($fieldname, $caption, $values = null, $isrow = true) |
35
|
|
|
{ |
36
|
11 |
|
$this->fieldname = $fieldname; |
37
|
11 |
|
$this->caption = $caption; |
38
|
11 |
|
$this->values = $values; |
39
|
11 |
|
$this->isrow = $isrow; |
40
|
11 |
|
$this->privChildren = null; |
41
|
11 |
|
} |
42
|
|
|
|
43
|
|
|
public function __clone() |
44
|
|
|
{ |
45
|
|
|
throw new PivotException('Result cannot be cloned'); |
46
|
|
|
} |
47
|
|
|
|
48
|
11 |
|
public function __set($name, $value) |
49
|
|
|
{ |
50
|
11 |
|
if ('fieldname' == $name) { |
51
|
11 |
|
$this->privFieldname = (string) $value; |
52
|
11 |
|
} elseif ('caption' == $name) { |
53
|
11 |
|
$this->privCaption = (string) $value; |
54
|
11 |
|
} elseif ('values' == $name) { |
55
|
11 |
|
if (! is_null($value) && ! is_array($value)) { |
56
|
|
|
throw new PivotException('Property values must be null or array'); |
57
|
|
|
} else { |
58
|
11 |
|
$this->privValues = $value; |
59
|
|
|
} |
60
|
11 |
|
} elseif ('isrow' == $name) { |
61
|
11 |
|
$this->privIsRow = (bool) $value; |
62
|
8 |
|
} elseif ('children' == $name) { |
63
|
|
|
throw new PivotException('Property children is read only'); |
64
|
8 |
|
} elseif ('parent' == $name) { |
65
|
8 |
|
if (! is_null($this->privParent)) { |
66
|
|
|
throw new PivotException('Property parent has been set already'); |
67
|
|
|
} |
68
|
8 |
|
if (! ($value instanceof self)) { |
69
|
|
|
throw new PivotException('Property parent must be a Result'); |
70
|
|
|
} |
71
|
8 |
|
$this->privParent = $value; |
72
|
|
|
} else { |
73
|
|
|
throw new PivotException("Property $name does not exists"); |
74
|
|
|
} |
75
|
11 |
|
return null; |
76
|
|
|
} |
77
|
|
|
|
78
|
10 |
|
public function __get($name) |
79
|
|
|
{ |
80
|
10 |
|
if ('isrow' === $name) { |
81
|
2 |
|
$propname = 'privIsRow'; |
82
|
|
|
} else { |
83
|
10 |
|
$propname = 'priv' . ucfirst($name); |
84
|
|
|
} |
85
|
10 |
|
if (! property_exists($this, $propname)) { |
86
|
|
|
throw new PivotException("Property $name does not exists"); |
87
|
|
|
} |
88
|
|
|
// late creation of children property, created only when used |
89
|
10 |
|
if ($name == 'children' && is_null($this->privChildren)) { |
90
|
10 |
|
$this->privChildren = new Results($this); |
91
|
|
|
} |
92
|
10 |
|
return $this->{$propname}; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @param array $path |
97
|
|
|
* @return array|null |
98
|
|
|
*/ |
99
|
1 |
|
public function searchValue(array $path) |
100
|
|
|
{ |
101
|
|
|
// if this is the element |
102
|
1 |
|
if (count($path) == 0) { |
103
|
1 |
|
return $this->privValues; |
104
|
|
|
} |
105
|
|
|
// get the first part to check in |
106
|
1 |
|
$search = array_shift($path); |
107
|
|
|
// if exists then search inside |
108
|
1 |
|
if ($this->children->exists($search)) { // if found |
109
|
1 |
|
return $this->children->value($search)->searchValue($path); |
110
|
|
|
} |
111
|
1 |
|
return null; |
112
|
|
|
} |
113
|
|
|
|
114
|
1 |
|
public function getPath($excludeRoot = true) |
115
|
|
|
{ |
116
|
|
|
// I'm the root and is required to exclude |
117
|
1 |
|
if ($excludeRoot && is_null($this->privParent)) { |
118
|
1 |
|
return []; |
119
|
|
|
} |
120
|
|
|
// define me as an array |
121
|
1 |
|
$me = [$this->privCaption]; |
122
|
1 |
|
if (! is_null($this->privParent)) { |
123
|
1 |
|
return array_merge($this->privParent->getPath($excludeRoot), $me); |
124
|
|
|
} |
125
|
|
|
// I'm not the root |
126
|
|
|
return $me; |
127
|
|
|
} |
128
|
|
|
|
129
|
9 |
|
public function hasChildren() |
130
|
|
|
{ |
131
|
9 |
|
return (null !== $this->privChildren && $this->privChildren->Count() > 0); |
132
|
|
|
} |
133
|
|
|
|
134
|
5 |
|
public function setAsNotRow($childrenLevels = 0) |
135
|
|
|
{ |
136
|
5 |
|
$this->privIsRow = false; |
137
|
5 |
|
if ($this->hasChildren() && $childrenLevels > 0) { |
138
|
5 |
|
foreach ($this->children as $child) { |
139
|
5 |
|
$child->setAsNotRow($childrenLevels - 1); |
140
|
|
|
} |
141
|
|
|
} |
142
|
5 |
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* @param bool|null $asrows |
146
|
|
|
* @return int |
147
|
|
|
*/ |
148
|
|
View Code Duplication |
public function getDepth($asrows = null) |
|
|
|
|
149
|
|
|
{ |
150
|
|
|
if (! $this->hasChildren()) { |
151
|
|
|
return 0; |
152
|
|
|
} |
153
|
|
|
$level = 0; |
154
|
|
|
foreach ($this->children as $child) { |
155
|
|
|
if (null === $asrows || $asrows == $child->isrow) { |
156
|
|
|
$level = max($level, $child->getDepth() + 1); |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
return $level; |
160
|
|
|
} |
161
|
|
|
|
162
|
1 |
|
public function getCurrentDepth() |
163
|
|
|
{ |
164
|
1 |
|
if (null === $this->parent) { |
165
|
1 |
|
return 0; |
166
|
|
|
} |
167
|
1 |
|
return $this->parent->getCurrentDepth() + 1; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param bool|null $asrows |
172
|
|
|
* @return int |
173
|
|
|
*/ |
174
|
1 |
View Code Duplication |
public function getHorizontalDepth($asrows = null) |
|
|
|
|
175
|
|
|
{ |
176
|
1 |
|
if (! $this->hasChildren()) { |
177
|
1 |
|
return 1; |
178
|
|
|
} |
179
|
|
|
$sum = 0; |
180
|
|
|
foreach ($this->children as $child) { |
181
|
|
|
if (null === $asrows || $asrows === $child->isrow) { |
182
|
|
|
$sum += $child->getHorizontalDepth(); |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
return $sum; |
186
|
|
|
} |
187
|
|
|
|
188
|
1 |
|
public function copy($childrenLevels) |
189
|
|
|
{ |
190
|
1 |
|
$tree = new self($this->fieldname, $this->caption, $this->values, $this->isrow); |
191
|
1 |
|
if ($childrenLevels > 0 && $this->hasChildren()) { |
192
|
1 |
|
foreach ($this->children as $key => $child) { |
193
|
1 |
|
$tree->children->addItem($child->copy($childrenLevels - 1), $key); |
194
|
|
|
} |
195
|
|
|
} |
196
|
1 |
|
return $tree; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
public function toText($includevalues = false) |
200
|
|
|
{ |
201
|
|
|
$textvalues = []; |
202
|
|
|
if ($includevalues) { |
203
|
|
|
if (is_array($this->values)) { |
204
|
|
|
foreach ($this->values as $key => $value) { |
205
|
|
|
$textvalues[] = $key . ' => ' . $value; |
206
|
|
|
} |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
return implode(', ', [ |
210
|
|
|
$this->privFieldname, |
211
|
|
|
$this->privCaption, |
212
|
|
|
'children: ' . (($this->hasChildren()) ? $this->children->count() : 'NO'), |
213
|
|
|
'[' . implode(', ', $textvalues) . ']', |
214
|
|
|
]); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
public function toTextTree($includevalues = false, $level = 0) |
218
|
|
|
{ |
219
|
|
|
$tabs = str_repeat("\t", $level); |
220
|
|
|
$chtext = $tabs . $this->toText($includevalues); |
221
|
|
|
if ($this->hasChildren()) { |
222
|
|
|
foreach ($this->children as $child) { |
223
|
|
|
$chtext .= "\n" . $tabs . '' . $child->toTextTree($includevalues, $level + 1); |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
return $chtext; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* @return Result[] |
231
|
|
|
*/ |
232
|
1 |
|
public function getLastChildrenArray() |
233
|
|
|
{ |
234
|
|
|
// no children |
235
|
1 |
|
if (! $this->hasChildren()) { |
236
|
1 |
|
return [$this]; |
237
|
|
|
} |
238
|
1 |
|
$array = []; |
239
|
1 |
|
foreach ($this->children as $child) { |
240
|
1 |
|
$array = array_merge($array, $child->getLastChildrenArray()); |
241
|
|
|
} |
242
|
1 |
|
return $array; |
243
|
|
|
} |
244
|
|
|
|
245
|
9 |
|
public function getCurrentValue(string $key) |
246
|
|
|
{ |
247
|
9 |
View Code Duplication |
if (is_array($this->privValues) && array_key_exists($key, $this->privValues)) { |
248
|
9 |
|
return $this->privValues[$key]; |
249
|
|
|
} |
250
|
|
|
return null; |
251
|
|
|
} |
252
|
|
|
|
253
|
9 |
|
public function setCurrentValue(string $key, $value) |
254
|
|
|
{ |
255
|
9 |
View Code Duplication |
if (is_array($this->privValues) && array_key_exists($key, $this->privValues)) { |
|
|
|
|
256
|
9 |
|
$this->privValues[$key] = $value; |
257
|
|
|
} |
258
|
9 |
|
} |
259
|
|
|
|
260
|
4 |
|
public function orderBy(ResultOrdering $ordering) |
261
|
|
|
{ |
262
|
4 |
|
$this->children->orderBy($ordering); |
263
|
4 |
|
foreach ($this->children as $child) { |
264
|
3 |
|
$child->orderBy($ordering); |
265
|
|
|
} |
266
|
4 |
|
} |
267
|
|
|
} |
268
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.