Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
95.56% |
129 / 135 |
|
84.00% |
21 / 25 |
CRAP | |
0.00% |
0 / 1 |
Service | |
95.56% |
129 / 135 |
|
84.00% |
21 / 25 |
58 | |
0.00% |
0 / 1 |
getOperationMethodReturnType | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
7 | |||
setModel | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
getModel | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
fillClassConstants | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getConstantAnnotationBlock | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
fillClassProperties | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getPropertyAnnotationBlock | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
defineUseStatements | |
85.71% |
12 / 14 |
|
0.00% |
0 / 1 |
6.10 | |||
getClassDeclarationLineText | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
fillClassMethods | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
addSoapHeaderMethods | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
addSoapHeaderFromMethod | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
8 | |||
getSoapHeaderMethod | |
86.67% |
13 / 15 |
|
0.00% |
0 / 1 |
3.02 | |||
getTypeFromName | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getSoapHeaderMethodName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addOperationsMethods | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
addGetResultMethod | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
addMainMethod | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getMethodAnnotationBlock | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
addAnnotationBlockForSoapHeaderMethod | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
4 | |||
addAnnotationBlockForOperationMethod | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
addAnnotationBlockForgetResultMethod | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getServiceReturnTypes | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
getModelFromMethod | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
setModelFromMethod | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace WsdlToPhp\PackageGenerator\File; |
6 | |
7 | use WsdlToPhp\PackageGenerator\ConfigurationReader\GeneratorOptions; |
8 | use WsdlToPhp\PackageGenerator\Container\PhpElement\Constant as ConstantContainer; |
9 | use WsdlToPhp\PackageGenerator\Container\PhpElement\Property as PropertyContainer; |
10 | use WsdlToPhp\PackageGenerator\File\Element\PhpFunctionParameter; |
11 | use WsdlToPhp\PackageGenerator\File\Validation\Rules; |
12 | use WsdlToPhp\PackageGenerator\Generator\Generator; |
13 | use WsdlToPhp\PackageGenerator\Model\AbstractModel; |
14 | use WsdlToPhp\PackageGenerator\Model\Method; |
15 | use WsdlToPhp\PackageGenerator\Model\Method as MethodModel; |
16 | use WsdlToPhp\PackageGenerator\Model\Service as ServiceModel; |
17 | use WsdlToPhp\PackageGenerator\Model\Struct as StructModel; |
18 | use WsdlToPhp\PackageGenerator\Model\StructAttribute as StructAttributeModel; |
19 | use WsdlToPhp\PackageGenerator\Parser\Wsdl\TagHeader; |
20 | use WsdlToPhp\PhpGenerator\Element\PhpAnnotation; |
21 | use WsdlToPhp\PhpGenerator\Element\PhpAnnotationBlock; |
22 | use WsdlToPhp\PhpGenerator\Element\PhpConstant; |
23 | use WsdlToPhp\PhpGenerator\Element\PhpFunctionParameter as PhpFunctionParameterBase; |
24 | use WsdlToPhp\PhpGenerator\Element\PhpMethod; |
25 | use WsdlToPhp\PhpGenerator\Element\PhpProperty; |
26 | |
27 | final class Service extends AbstractModelFile |
28 | { |
29 | public const METHOD_SET_HEADER_PREFIX = 'setSoapHeader'; |
30 | public const PARAM_SET_HEADER_NAMESPACE = 'namespace'; |
31 | public const PARAM_SET_HEADER_MUSTUNDERSTAND = 'mustUnderstand'; |
32 | public const PARAM_SET_HEADER_ACTOR = 'actor'; |
33 | public const METHOD_GET_RESULT = 'getResult'; |
34 | |
35 | /** |
36 | * Method model can't be found in case the original method's name is unclean: |
37 | * - ex: my.operation.name becomes my_operation_name |
38 | * thus the Model from Model\Service::getMethod() can't be found |
39 | * So we store the generated name associated to the original method object. |
40 | */ |
41 | protected array $methodNames = []; |
42 | |
43 | public static function getOperationMethodReturnType(MethodModel $method, Generator $generator): string |
44 | { |
45 | $returnType = $method->getReturnType(); |
46 | |
47 | if (is_null($returnType)) { |
48 | return 'null'; |
49 | } |
50 | |
51 | if ((($struct = $generator->getStructByName($returnType)) instanceof StructModel) && !$struct->isRestriction()) { |
52 | if ($struct->isStruct()) { |
53 | $returnType = $struct->getPackagedName(true); |
54 | } elseif ($struct->isArray()) { |
55 | if (($structInheritance = $struct->getInheritanceStruct()) instanceof StructModel) { |
56 | $returnType = sprintf('%s[]', $structInheritance->getPackagedName(true)); |
57 | } else { |
58 | $returnType = $struct->getInheritance(); |
59 | } |
60 | } |
61 | } |
62 | |
63 | return $returnType; |
64 | } |
65 | |
66 | public function setModel(AbstractModel $model): self |
67 | { |
68 | if (!$model instanceof ServiceModel) { |
69 | throw new \InvalidArgumentException('Model must be an instance of a Service', __LINE__); |
70 | } |
71 | |
72 | return parent::setModel($model); |
73 | } |
74 | |
75 | public function getModel(): ?ServiceModel |
76 | { |
77 | return parent::getModel(); |
78 | } |
79 | |
80 | protected function fillClassConstants(ConstantContainer $constants): void |
81 | { |
82 | } |
83 | |
84 | protected function getConstantAnnotationBlock(PhpConstant $constant): ?PhpAnnotationBlock |
85 | { |
86 | return null; |
87 | } |
88 | |
89 | protected function fillClassProperties(PropertyContainer $properties): void |
90 | { |
91 | } |
92 | |
93 | protected function getPropertyAnnotationBlock(PhpProperty $property): ?PhpAnnotationBlock |
94 | { |
95 | return null; |
96 | } |
97 | |
98 | protected function defineUseStatements(): AbstractModelFile |
99 | { |
100 | $this->getFile()->addUse(\SoapFault::class); |
101 | |
102 | /** @var Method $method */ |
103 | foreach ($this->getModel()->getMethods() as $method) { |
104 | $soapHeaderTypes = $method->getMetaValue(TagHeader::META_SOAP_HEADER_TYPES, []); |
105 | if (!is_array($soapHeaderTypes)) { |
106 | continue; |
107 | } |
108 | foreach ($soapHeaderTypes as $soapHeaderType) { |
109 | $model = $this->getModelByName($soapHeaderType); |
110 | if (!$model instanceof StructModel) { |
111 | continue; |
112 | } |
113 | if (!$model->isRestriction()) { |
114 | continue; |
115 | } |
116 | |
117 | $this->getFile()->addUse(\InvalidArgumentException::class); |
118 | |
119 | break 2; |
120 | } |
121 | } |
122 | |
123 | return parent::defineUseStatements(); |
124 | } |
125 | |
126 | protected function getClassDeclarationLineText(): string |
127 | { |
128 | return GeneratorOptions::VALUE_NONE === $this->getGenerator()->getOptionGatherMethods() ? 'This class stands for all operations' : parent::getClassDeclarationLineText(); |
129 | } |
130 | |
131 | protected function fillClassMethods(): void |
132 | { |
133 | $this |
134 | ->addSoapHeaderMethods() |
135 | ->addOperationsMethods() |
136 | ->addGetResultMethod() |
137 | ; |
138 | } |
139 | |
140 | protected function addSoapHeaderMethods(): self |
141 | { |
142 | foreach ($this->getModel()->getMethods() as $method) { |
143 | $this->addSoapHeaderFromMethod($method); |
144 | } |
145 | |
146 | return $this; |
147 | } |
148 | |
149 | protected function addSoapHeaderFromMethod(MethodModel $method): self |
150 | { |
151 | $soapHeaderNames = $method->getMetaValue(TagHeader::META_SOAP_HEADER_NAMES, []); |
152 | $soapHeaderNamespaces = $method->getMetaValue(TagHeader::META_SOAP_HEADER_NAMESPACES, []); |
153 | $soapHeaderTypes = $method->getMetaValue(TagHeader::META_SOAP_HEADER_TYPES, []); |
154 | if (is_array($soapHeaderNames) && is_array($soapHeaderNamespaces) && is_array($soapHeaderTypes)) { |
155 | foreach ($soapHeaderNames as $index => $soapHeaderName) { |
156 | $methodName = $this->getSoapHeaderMethodName($soapHeaderName); |
157 | if (is_null($this->methods->get($methodName))) { |
158 | $soapHeaderNamespace = array_key_exists($index, $soapHeaderNamespaces) ? $soapHeaderNamespaces[$index] : null; |
159 | $soapHeaderType = array_key_exists($index, $soapHeaderTypes) ? $soapHeaderTypes[$index] : null; |
160 | $this->methods->add($this->getSoapHeaderMethod($methodName, $soapHeaderName, $soapHeaderNamespace, $soapHeaderType)); |
161 | } |
162 | } |
163 | } |
164 | |
165 | return $this; |
166 | } |
167 | |
168 | protected function getSoapHeaderMethod(string $methodName, string $soapHeaderName, string $soapHeaderNamespace, string $soapHeaderType): PhpMethod |
169 | { |
170 | try { |
171 | $method = new PhpMethod($methodName, [ |
172 | $firstParameter = new PhpFunctionParameter(lcfirst($soapHeaderName), PhpFunctionParameterBase::NO_VALUE, $this->getTypeFromName($soapHeaderType)), |
173 | new PhpFunctionParameterBase(self::PARAM_SET_HEADER_NAMESPACE, $soapHeaderNamespace, self::TYPE_STRING), |
174 | new PhpFunctionParameterBase(self::PARAM_SET_HEADER_MUSTUNDERSTAND, false, self::TYPE_BOOL), |
175 | new PhpFunctionParameterBase(self::PARAM_SET_HEADER_ACTOR, null, '?'.self::TYPE_STRING), |
176 | ], self::TYPE_SELF); |
177 | |
178 | $model = $this->getModelByName($soapHeaderType); |
179 | if ($model instanceof StructModel) { |
180 | $rules = new Rules($this, $method, new StructAttributeModel($model->getGenerator(), $soapHeaderType, $model->getName(), $model), $this->methods); |
181 | $rules->applyRules(lcfirst($soapHeaderName)); |
182 | $firstParameter->setModel($model); |
183 | } |
184 | $method->addChild(sprintf('return $this->%s($%s, \'%s\', $%s, $%s, $%s);', self::METHOD_SET_HEADER_PREFIX, self::PARAM_SET_HEADER_NAMESPACE, $soapHeaderName, lcfirst($soapHeaderName), self::PARAM_SET_HEADER_MUSTUNDERSTAND, self::PARAM_SET_HEADER_ACTOR)); |
185 | } catch (\InvalidArgumentException $exception) { |
186 | throw new \InvalidArgumentException(sprintf('Unable to create function parameter for service "%s" with type "%s"', $this->getModel()->getName(), var_export($this->getTypeFromName($soapHeaderName), true)), __LINE__, $exception); |
187 | } |
188 | |
189 | return $method; |
190 | } |
191 | |
192 | protected function getTypeFromName(string $name): ?string |
193 | { |
194 | return self::getPhpType( |
195 | $this->getStructAttributeTypeAsPhpType(new StructAttributeModel($this->generator, 'any', $name)), |
196 | $this->getGenerator()->getOptionXsdTypesPath(), |
197 | $this->getStructAttributeTypeAsPhpType(new StructAttributeModel($this->generator, 'any', $name)) |
198 | ); |
199 | } |
200 | |
201 | protected function getSoapHeaderMethodName(string $soapHeaderName): string |
202 | { |
203 | return sprintf('%s%s', self::METHOD_SET_HEADER_PREFIX, ucfirst($soapHeaderName)); |
204 | } |
205 | |
206 | protected function addOperationsMethods(): self |
207 | { |
208 | foreach ($this->getModel()->getMethods() as $method) { |
209 | $this->addMainMethod($method); |
210 | } |
211 | |
212 | return $this; |
213 | } |
214 | |
215 | protected function addGetResultMethod(): self |
216 | { |
217 | $method = new PhpMethod(self::METHOD_GET_RESULT); |
218 | $method->addChild('return parent::getResult();'); |
219 | $this->methods->add($method); |
220 | |
221 | return $this; |
222 | } |
223 | |
224 | protected function addMainMethod(MethodModel $method): self |
225 | { |
226 | $methodFile = new Operation($method, $this->getGenerator()); |
227 | $mainMethod = $methodFile->getMainMethod(); |
228 | $this->methods->add($mainMethod); |
229 | $this->setModelFromMethod($mainMethod, $method); |
230 | |
231 | return $this; |
232 | } |
233 | |
234 | protected function getMethodAnnotationBlock(PhpMethod $method): PhpAnnotationBlock |
235 | { |
236 | $annotationBlock = new PhpAnnotationBlock(); |
237 | if (0 === mb_stripos($method->getName(), self::METHOD_SET_HEADER_PREFIX)) { |
238 | $this->addAnnotationBlockForSoapHeaderMethod($annotationBlock, $method); |
239 | } elseif (self::METHOD_GET_RESULT === $method->getName()) { |
240 | $this->addAnnotationBlockForgetResultMethod($annotationBlock); |
241 | } else { |
242 | $this->addAnnotationBlockForOperationMethod($annotationBlock, $method); |
243 | } |
244 | |
245 | return $annotationBlock; |
246 | } |
247 | |
248 | protected function addAnnotationBlockForSoapHeaderMethod(PhpAnnotationBlock $annotationBlock, PhpMethod $method): self |
249 | { |
250 | $methodParameters = $method->getParameters(); |
251 | $firstParameter = array_shift($methodParameters); |
252 | if ($firstParameter instanceof PhpFunctionParameter) { |
253 | $annotationBlock->addChild(sprintf('Sets the %s SoapHeader param', ucfirst($firstParameter->getName()))); |
254 | $firstParameterType = $firstParameter->getType(); |
255 | if ($firstParameter->getModel() instanceof StructModel) { |
256 | $firstParameterType = $this->getStructAttributeTypeAsPhpType(new StructAttributeModel($firstParameter->getModel()->getGenerator(), $firstParameter->getName(), $firstParameter->getModel()->getName(), $firstParameter->getModel())); |
257 | if ($firstParameter->getModel()->isRestriction()) { |
258 | $annotationBlock |
259 | ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $firstParameter->getModel()->getPackagedName(true), StructEnum::METHOD_VALUE_IS_VALID))) |
260 | ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $firstParameter->getModel()->getPackagedName(true), StructEnum::METHOD_GET_VALID_VALUES))) |
261 | ->addChild(new PhpAnnotation(self::ANNOTATION_THROWS, \InvalidArgumentException::class)) |
262 | ; |
263 | } |
264 | } |
265 | $annotationBlock |
266 | ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $this->getModel()->getExtends(true), self::METHOD_SET_HEADER_PREFIX))) |
267 | ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', $firstParameterType, $firstParameter->getName()))) |
268 | ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', self::TYPE_STRING, self::PARAM_SET_HEADER_NAMESPACE))) |
269 | ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', self::TYPE_BOOL, self::PARAM_SET_HEADER_MUSTUNDERSTAND))) |
270 | ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s|null $%s', self::TYPE_STRING, self::PARAM_SET_HEADER_ACTOR))) |
271 | ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $this->getModel()->getPackagedName(true))) |
272 | ; |
273 | } |
274 | |
275 | return $this; |
276 | } |
277 | |
278 | protected function addAnnotationBlockForOperationMethod(PhpAnnotationBlock $annotationBlock, PhpMethod $method): self |
279 | { |
280 | if (($model = $this->getModelFromMethod($method)) instanceof MethodModel) { |
281 | $operationAnnotationBlock = new OperationAnnotationBlock($model, $this->getGenerator()); |
282 | $operationAnnotationBlock->addAnnotationBlockForOperationMethod($annotationBlock); |
283 | } |
284 | |
285 | return $this; |
286 | } |
287 | |
288 | protected function addAnnotationBlockForgetResultMethod(PhpAnnotationBlock $annotationBlock): self |
289 | { |
290 | $annotationBlock |
291 | ->addChild('Returns the result')->addChild(new PhpAnnotation(self::ANNOTATION_SEE, sprintf('%s::getResult()', $this->getModel()->getExtends(true)))) |
292 | ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $this->getServiceReturnTypes())) |
293 | ; |
294 | |
295 | return $this; |
296 | } |
297 | |
298 | protected function getServiceReturnTypes(): string |
299 | { |
300 | $returnTypes = []; |
301 | foreach ($this->getModel()->getMethods() as $method) { |
302 | $returnTypes[] = self::getOperationMethodReturnType($method, $this->getGenerator()); |
303 | } |
304 | natcasesort($returnTypes); |
305 | |
306 | return implode('|', array_unique($returnTypes)); |
307 | } |
308 | |
309 | protected function getModelFromMethod(PhpMethod $method): ?MethodModel |
310 | { |
311 | $model = $this->getGenerator()->getServiceMethod($method->getName()); |
312 | if (!$model instanceof MethodModel) { |
313 | $model = array_key_exists($method->getName(), $this->methodNames) ? $this->methodNames[$method->getName()] : null; |
314 | } |
315 | |
316 | return $model; |
317 | } |
318 | |
319 | protected function setModelFromMethod(PhpMethod $phpMethod, MethodModel $methodModel): self |
320 | { |
321 | $this->methodNames[$phpMethod->getName()] = $methodModel; |
322 | |
323 | return $this; |
324 | } |
325 | } |