1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author: Viskov Sergey |
4
|
|
|
* @date : 19.03.16 |
5
|
|
|
* @time : 0:04 |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace LTDBeget\sphinx\configurator\configurationEntities\base; |
9
|
|
|
|
10
|
|
|
use InvalidArgumentException; |
11
|
|
|
use LogicException; |
12
|
|
|
use LTDBeget\sphinx\configurator\Configuration; |
13
|
|
|
use LTDBeget\sphinx\configurator\exceptions\SectionException; |
14
|
|
|
use LTDBeget\sphinx\enums\eSection; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Class Definition |
18
|
|
|
* |
19
|
|
|
* @package LTDBeget\sphinx\configurator\configurationEntities\base |
20
|
|
|
*/ |
21
|
|
|
abstract class Definition extends Section |
22
|
|
|
{ |
23
|
|
|
/** |
24
|
|
|
* Source constructor. |
25
|
|
|
* |
26
|
|
|
* @param Configuration $configuration |
27
|
|
|
* @param string $name |
28
|
|
|
* @param string|null $inheritance |
29
|
|
|
* |
30
|
|
|
* @throws InvalidArgumentException |
31
|
|
|
* @throws LogicException |
32
|
|
|
* @throws SectionException |
33
|
|
|
*/ |
34
|
15 |
|
public function __construct( |
35
|
|
|
Configuration $configuration, |
36
|
|
|
string $name, |
37
|
|
|
string $inheritance = NULL |
38
|
|
|
) |
39
|
|
|
{ |
40
|
15 |
|
parent::__construct($configuration); |
41
|
|
|
|
42
|
15 |
|
$this->defineName($this->sanitizeName($name)); |
43
|
|
|
|
44
|
14 |
|
if (!empty($inheritance)) { |
45
|
11 |
|
$this->setParent($this->sanitizeName($inheritance)); |
46
|
|
|
} |
47
|
13 |
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @return array |
51
|
|
|
* @throws \LogicException |
52
|
|
|
* @throws \LTDBeget\sphinx\configurator\exceptions\SectionException |
53
|
|
|
* @throws \InvalidArgumentException |
54
|
|
|
*/ |
55
|
1 |
|
public function toArray() |
56
|
|
|
{ |
57
|
|
|
return [ |
|
|
|
|
58
|
1 |
|
'type' => (string) $this->getType(), |
59
|
1 |
|
'name' => (string) $this->getName(), |
60
|
1 |
|
'inheritance' => $this->isHasInheritance() ? $this->getInheritance()->getName() : NULL, |
61
|
1 |
|
'options' => $this->toArrayOptions() |
62
|
|
|
]; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @return string |
67
|
|
|
* @throws \LTDBeget\sphinx\configurator\exceptions\SectionException |
68
|
|
|
* @throws \LogicException |
69
|
|
|
* @throws \InvalidArgumentException |
70
|
|
|
*/ |
71
|
2 |
|
protected function renderDefineBlock() : string |
72
|
|
|
{ |
73
|
2 |
|
$string = "{$this->getType()} {$this->getName()}"; |
74
|
2 |
|
if ($this->isHasInheritance()) { |
75
|
2 |
|
$string .= " : {$this->getInheritance()->getName()}"; |
76
|
|
|
} |
77
|
|
|
|
78
|
2 |
|
return $string; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @return bool |
83
|
|
|
*/ |
84
|
10 |
|
public function isHasInheritance() : bool |
85
|
|
|
{ |
86
|
10 |
|
return NULL !== $this->inheritance; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* @return Definition |
91
|
|
|
* @throws LogicException |
92
|
|
|
* @throws InvalidArgumentException |
93
|
|
|
* @throws SectionException |
94
|
|
|
*/ |
95
|
5 |
|
public function getInheritance() : Definition |
96
|
|
|
{ |
97
|
5 |
|
if (!$this->isHasInheritance()) { |
98
|
|
|
throw new SectionException("Trying to get inheritance for {$this->getType()} which doesn't' have it."); |
99
|
|
|
} |
100
|
|
|
|
101
|
5 |
|
return $this->inheritance; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @return string |
106
|
|
|
*/ |
107
|
12 |
|
public function getName() : string |
108
|
|
|
{ |
109
|
12 |
|
return $this->name; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Delete option and its child |
114
|
|
|
* |
115
|
|
|
* @throws LogicException |
116
|
|
|
* @throws SectionException |
117
|
|
|
* @throws InvalidArgumentException |
118
|
|
|
*/ |
119
|
2 |
|
public function delete() |
120
|
|
|
{ |
121
|
2 |
|
foreach ($this->getSelfTypeIterator() as $definition) { |
122
|
2 |
|
if ($definition->isHasInheritance() && $definition->getInheritance() === $this) { |
123
|
2 |
|
$definition->delete(); |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
|
127
|
2 |
|
parent::delete(); |
128
|
2 |
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* @internal |
132
|
|
|
* |
133
|
|
|
* @param string $name |
134
|
|
|
* |
135
|
|
|
* @throws LogicException |
136
|
|
|
* @throws SectionException |
137
|
|
|
* @throws \InvalidArgumentException |
138
|
|
|
*/ |
139
|
14 |
|
private function defineName(string $name) |
140
|
|
|
{ |
141
|
14 |
|
foreach ($this->getSelfTypeIterator() as $definition) { |
142
|
12 |
|
if ($definition->getName() === $name) { |
143
|
12 |
|
throw new SectionException("Duplicate name {$name} found in {$this->getType()} section"); |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
|
147
|
14 |
|
$this->name = $name; |
148
|
14 |
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @internal |
152
|
|
|
* |
153
|
|
|
* @param string $inheritance |
154
|
|
|
* |
155
|
|
|
* @throws SectionException |
156
|
|
|
* @throws LogicException |
157
|
|
|
* @throws \InvalidArgumentException |
158
|
|
|
*/ |
159
|
10 |
|
private function setParent(string $inheritance) |
160
|
|
|
{ |
161
|
10 |
|
foreach ($this->getSelfTypeIterator() as $definition) { |
162
|
10 |
|
if ($definition->getName() === $inheritance) { |
163
|
10 |
|
$this->inheritance = $definition; |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
10 |
|
if (!$this->isHasInheritance()) { |
168
|
2 |
|
throw new SectionException("Inheritance with name {$inheritance} of section {$this->getType()} doesn't exists in configuration"); |
169
|
|
|
} |
170
|
8 |
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @internal |
174
|
|
|
* |
175
|
|
|
* @param string $name |
176
|
|
|
* |
177
|
|
|
* @return string |
178
|
|
|
* @throws \LogicException |
179
|
|
|
* @throws \InvalidArgumentException |
180
|
|
|
* @throws SectionException |
181
|
|
|
*/ |
182
|
15 |
|
private function sanitizeName(string $name) : string |
183
|
|
|
{ |
184
|
15 |
|
$name = trim($name); |
185
|
|
|
|
186
|
15 |
|
if (empty($name)) { |
187
|
|
|
throw new SectionException("Name or inheritance of section {$this->getType()} can't be empty."); |
188
|
|
|
} |
189
|
|
|
|
190
|
15 |
|
if (!$this->isValidName($name)) { |
191
|
2 |
|
throw new SectionException("Name or inheritance of section {$this->getType()} must contains only A-Za-z and _ symbols"); |
192
|
|
|
} |
193
|
|
|
|
194
|
14 |
|
return $name; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* @internal |
199
|
|
|
* |
200
|
|
|
* @param $name |
201
|
|
|
* |
202
|
|
|
* @return bool |
203
|
|
|
*/ |
204
|
15 |
|
private function isValidName($name) : bool |
205
|
|
|
{ |
206
|
15 |
|
return (bool) preg_match("/^[A-Za-z_\d]*$/", $name); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* @internal |
211
|
|
|
* |
212
|
|
|
* @return Definition[] |
213
|
|
|
* @throws LogicException |
214
|
|
|
*/ |
215
|
14 |
|
private function getSelfTypeIterator() |
216
|
|
|
{ |
217
|
14 |
|
switch ($this->getType()) { |
218
|
14 |
|
case eSection::INDEX: |
219
|
8 |
|
$iterator = $this->getConfiguration()->iterateIndex(); |
220
|
8 |
|
break; |
221
|
11 |
|
case eSection::SOURCE: |
222
|
11 |
|
$iterator = $this->getConfiguration()->iterateSource(); |
223
|
11 |
|
break; |
224
|
|
|
default: |
225
|
|
|
throw new LogicException("Unknown type {$this->getType()}"); |
226
|
|
|
} |
227
|
|
|
|
228
|
14 |
|
return $iterator; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* @var string |
233
|
|
|
*/ |
234
|
|
|
private $name; |
235
|
|
|
/** |
236
|
|
|
* @var Definition |
237
|
|
|
*/ |
238
|
|
|
private $inheritance; |
239
|
|
|
} |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.