1
|
|
|
<?php declare(strict_types = 1); |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: root |
5
|
|
|
* Date: 02.08.16 |
6
|
|
|
* Time: 0:46. |
7
|
|
|
*/ |
8
|
|
|
namespace samsonframework\container\definition; |
9
|
|
|
|
10
|
|
|
use samsonframework\container\definition\reference\ReferenceInterface; |
11
|
|
|
use samsonframework\container\definition\scope\AbstractScope; |
12
|
|
|
use samsonframework\container\exception\MethodDefinitionAlreadyExistsException; |
13
|
|
|
use samsonframework\container\exception\PropertyDefinitionAlreadyExistsException; |
14
|
|
|
use samsonframework\container\exception\ScopeAlreadyExistsException; |
15
|
|
|
use samsonframework\container\exception\ScopeNotFoundException; |
16
|
|
|
use samsonframework\container\metadata\ClassMetadata; |
17
|
|
|
use samsonframework\container\metadata\MethodMetadata; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Class ClassDefinition |
21
|
|
|
* |
22
|
|
|
* @package samsonframework\container\definition |
23
|
|
|
*/ |
24
|
|
|
class ClassDefinition extends AbstractDefinition implements ClassBuilderInterface |
25
|
|
|
{ |
26
|
|
|
/** @var string Class name with namespace */ |
27
|
|
|
protected $className; |
28
|
|
|
/** @var string Class name space */ |
29
|
|
|
protected $nameSpace; |
30
|
|
|
/** @var string Service name */ |
31
|
|
|
protected $serviceName; |
32
|
|
|
/** @var array Class container scopes */ |
33
|
|
|
protected $scopes = []; |
34
|
|
|
|
35
|
|
|
/** @var MethodDefinition[] Methods collection */ |
36
|
|
|
protected $methodsCollection = []; |
37
|
|
|
/** @var PropertyDefinition[] Property collection */ |
38
|
|
|
protected $propertiesCollection = []; |
39
|
|
|
|
40
|
|
|
/** {@inheritdoc} */ |
41
|
2 |
|
public function defineConstructor(): MethodBuilderInterface |
42
|
|
|
{ |
43
|
|
|
/** Add constructor method manually */ |
44
|
2 |
|
return $this->defineMethod('__construct'); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** {@inheritdoc} */ |
48
|
4 |
|
public function defineMethod(string $methodName): MethodBuilderInterface |
49
|
|
|
{ |
50
|
4 |
|
if (array_key_exists($methodName, $this->methodsCollection)) { |
51
|
2 |
|
throw new MethodDefinitionAlreadyExistsException(); |
52
|
|
|
} |
53
|
|
|
|
54
|
4 |
|
$methodDefinition = new MethodDefinition($this, $methodName); |
|
|
|
|
55
|
4 |
|
$methodDefinition->setMethodName($methodName); |
56
|
|
|
|
57
|
4 |
|
$this->methodsCollection[$methodName] = $methodDefinition; |
58
|
|
|
|
59
|
4 |
|
return $methodDefinition; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** {@inheritdoc} */ |
63
|
2 |
|
public function defineProperty(string $propertyName): PropertyBuilderInterface |
64
|
|
|
{ |
65
|
2 |
|
if (array_key_exists($propertyName, $this->propertiesCollection)) { |
66
|
1 |
|
throw new PropertyDefinitionAlreadyExistsException(); |
67
|
|
|
} |
68
|
|
|
|
69
|
2 |
|
$propertyDefinition = new PropertyDefinition($this); |
70
|
2 |
|
$propertyDefinition->setPropertyName($propertyName); |
71
|
|
|
|
72
|
2 |
|
$this->propertiesCollection[$propertyName] = $propertyDefinition; |
73
|
|
|
|
74
|
2 |
|
return $propertyDefinition; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** {@inheritdoc} */ |
78
|
|
|
public function toMetadata(): ClassMetadata |
79
|
|
|
{ |
80
|
|
|
$classMetadata = new ClassMetadata(); |
81
|
|
|
$classMetadata->className = $this->className; |
82
|
|
|
$classMetadata->name = $this->serviceName ?? $this->className; |
83
|
|
|
|
84
|
|
|
// Resolve methods |
85
|
|
|
if (count($this->methodsCollection)) { |
86
|
|
|
foreach ($this->methodsCollection as $methodDefinition) { |
87
|
|
|
$classMetadata->methodsMetadata[$methodDefinition->getMethodName()] = |
88
|
|
|
$methodDefinition->toMethodMetadata($classMetadata); |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
// Resolve properties |
92
|
|
|
if (count($this->propertiesCollection)) { |
93
|
|
|
foreach ($this->propertiesCollection as $propertyDefinition) { |
94
|
|
|
$classMetadata->propertiesMetadata[$propertyDefinition->getPropertyName()] = |
95
|
|
|
$propertyDefinition->toPropertyMetadata($classMetadata); |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
return $classMetadata; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Get namespace |
103
|
|
|
* |
104
|
|
|
* @return string |
105
|
|
|
*/ |
106
|
|
|
public function getNameSpace(): string |
107
|
|
|
{ |
108
|
|
|
return $this->nameSpace; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Get class name |
113
|
|
|
* |
114
|
|
|
* @return string |
115
|
|
|
*/ |
116
|
1 |
|
public function getClassName(): string |
117
|
|
|
{ |
118
|
1 |
|
return $this->className; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Add scope to definition |
123
|
|
|
* |
124
|
|
|
* @param AbstractScope $scope |
125
|
|
|
* @return ClassDefinition |
126
|
|
|
* @throws ScopeAlreadyExistsException |
127
|
|
|
*/ |
128
|
1 |
|
public function addScope(AbstractScope $scope): ClassDefinition |
129
|
|
|
{ |
130
|
1 |
|
if ($this->hasScope($scope::getId())) { |
131
|
|
|
throw new ScopeAlreadyExistsException(); |
132
|
|
|
} |
133
|
|
|
|
134
|
1 |
|
$this->scopes[$scope::getId()] = $scope; |
135
|
|
|
|
136
|
1 |
|
return $this; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Remove scope from definition |
141
|
|
|
* |
142
|
|
|
* @param string $id |
143
|
|
|
* @return ClassDefinition |
144
|
|
|
* @throws ScopeNotFoundException |
145
|
|
|
*/ |
146
|
1 |
|
public function removeScope(string $id): ClassDefinition |
147
|
|
|
{ |
148
|
1 |
|
if (!$this->hasScope($id)) { |
149
|
|
|
throw new ScopeNotFoundException(); |
150
|
|
|
} |
151
|
|
|
|
152
|
1 |
|
unset($this->scopes[$id]); |
153
|
|
|
|
154
|
1 |
|
return $this; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Check if scope exists in definition |
159
|
|
|
* |
160
|
|
|
* @param string $id |
161
|
|
|
* @return bool |
162
|
|
|
*/ |
163
|
1 |
|
public function hasScope(string $id): bool |
164
|
|
|
{ |
165
|
1 |
|
return array_key_exists($id, $this->scopes); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Get scope from definition |
170
|
|
|
* |
171
|
|
|
* @param string $id |
172
|
|
|
* @return mixed |
173
|
|
|
* @throws ScopeNotFoundException |
174
|
|
|
*/ |
175
|
1 |
|
public function getScope(string $id): AbstractScope |
176
|
|
|
{ |
177
|
1 |
|
if (!$this->hasScope($id)) { |
178
|
1 |
|
throw new ScopeNotFoundException(); |
179
|
|
|
} |
180
|
1 |
|
return $this->scopes[$id]; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* Get all scopes |
185
|
|
|
* |
186
|
|
|
* @return AbstractScope[] |
187
|
|
|
*/ |
188
|
|
|
public function getScopes(): array |
189
|
|
|
{ |
190
|
|
|
return $this->scopes; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* @param string $className |
195
|
|
|
* @return ClassDefinition |
196
|
|
|
*/ |
197
|
9 |
|
public function setClassName(string $className): ClassDefinition |
198
|
|
|
{ |
199
|
9 |
|
$this->className = $className; |
200
|
|
|
|
201
|
9 |
|
return $this; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* @return string |
206
|
|
|
*/ |
207
|
1 |
|
public function getServiceName(): string |
208
|
|
|
{ |
209
|
1 |
|
return $this->serviceName; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* @param string $serviceName |
214
|
|
|
* @return ClassDefinition |
215
|
|
|
*/ |
216
|
2 |
|
public function setServiceName(string $serviceName): ClassDefinition |
217
|
|
|
{ |
218
|
2 |
|
$this->serviceName = $serviceName; |
219
|
|
|
|
220
|
2 |
|
return $this; |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.