Completed
Push — feature/issue-165 ( 83f642...d66719 )
by Mikaël
23:02 queued 18s
created

Service::getClassProperties()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 1
dl 0
loc 2
ccs 1
cts 1
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace WsdlToPhp\PackageGenerator\File;
4
5
use WsdlToPhp\PackageGenerator\Parser\Wsdl\TagHeader;
6
use WsdlToPhp\PackageGenerator\Generator\Generator;
7
use WsdlToPhp\PackageGenerator\Container\PhpElement\Method as MethodContainer;
8
use WsdlToPhp\PackageGenerator\Container\PhpElement\Property as PropertyContainer;
9
use WsdlToPhp\PackageGenerator\Container\PhpElement\Constant as ConstantContainer;
10
use WsdlToPhp\PackageGenerator\Model\AbstractModel;
11
use WsdlToPhp\PackageGenerator\Model\Service as ServiceModel;
12
use WsdlToPhp\PackageGenerator\Model\Method as MethodModel;
13
use WsdlToPhp\PackageGenerator\Model\Struct as StructModel;
14
use WsdlToPhp\PackageGenerator\Model\StructAttribute as StructAttributeModel;
15
use WsdlToPhp\PhpGenerator\Element\PhpConstant;
16
use WsdlToPhp\PhpGenerator\Element\PhpProperty;
17
use WsdlToPhp\PhpGenerator\Element\PhpMethod;
18
use WsdlToPhp\PhpGenerator\Element\PhpAnnotation;
19
use WsdlToPhp\PhpGenerator\Element\PhpAnnotationBlock;
20
use WsdlToPhp\PhpGenerator\Element\PhpFunctionParameter as PhpFunctionParameterBase;
21
use WsdlToPhp\PackageGenerator\File\Element\PhpFunctionParameter;
22
use WsdlToPhp\PackageGenerator\ConfigurationReader\GeneratorOptions;
23
use WsdlToPhp\PackageGenerator\File\Validation\Rules;
24
25
class Service extends AbstractModelFile
26
{
27
    /**
28
     * @var string
29
     */
30
    const METHOD_SET_HEADER_PREFIX = 'setSoapHeader';
31
    /**
32
     * @var string
33
     */
34
    const PARAM_SET_HEADER_NAMESPACE = 'nameSpace';
35
    /**
36
     * @var string
37
     */
38
    const PARAM_SET_HEADER_MUSTUNDERSTAND = 'mustUnderstand';
39
    /**
40
     * @var string
41
     */
42
    const PARAM_SET_HEADER_ACTOR = 'actor';
43
    /**
44
     * @var string
45
     */
46
    const METHOD_GET_RESULT = 'getResult';
47
    /**
48
     * Method model can't be found in case the original method's name is unclean:
49
     * - ex: my.operation.name becomes my_operation_name
50
     * thus the Model from Model\Service::getMethod() can't be found
51
     * So we store the generated name associated to the original method object
52
     * @var array
53
     */
54
    protected $methodNames = [];
55
    /**
56
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getClassConstants()
57
     */
58 138
    protected function getClassConstants(ConstantContainer $constants)
59
    {
60 138
    }
61
    /**
62
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getConstantAnnotationBlock()
63
     */
64
    protected function getConstantAnnotationBlock(PhpConstant $constant)
65
    {
66
    }
67
    /**
68
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getClassProperties()
69
     */
70 138
    protected function getClassProperties(PropertyContainer $properties)
71
    {
72 138
    }
73
    /**
74
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getPropertyAnnotationBlock()
75
     */
76
    protected function getPropertyAnnotationBlock(PhpProperty $property)
77
    {
78
    }
79
    /**
80
     * @return string
81
     */
82 138
    protected function getClassDeclarationLineText()
83
    {
84 138
        return $this->getGenerator()->getOptionGatherMethods() === GeneratorOptions::VALUE_NONE ? 'This class stands for all operations' : parent::getClassDeclarationLineText();
85
    }
86
    /**
87
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::fillClassMethods()
88
     */
89 138
    protected function fillClassMethods()
90
    {
91 69
        $this
92 138
            ->addSoapHeaderMethods()
93 138
            ->addOperationsMethods()
94 138
            ->addGetResultMethod();
95 138
    }
96
    /**
97
     * @return Service
98
     */
99 138
    protected function addSoapHeaderMethods()
100
    {
101 138
        foreach ($this->getModel()->getMethods() as $method) {
102 138
            $this->addSoapHeaderFromMethod($method);
103 69
        }
104 138
        return $this;
105
    }
106
    /**
107
     * @param MethodModel $method
108
     * @return Service
109
     */
110 138
    protected function addSoapHeaderFromMethod(MethodModel $method)
111
    {
112 138
        $soapHeaderNames = $method->getMetaValue(TagHeader::META_SOAP_HEADER_NAMES, []);
113 138
        $soapHeaderNamespaces = $method->getMetaValue(TagHeader::META_SOAP_HEADER_NAMESPACES, []);
114 138
        $soapHeaderTypes = $method->getMetaValue(TagHeader::META_SOAP_HEADER_TYPES, []);
115 138
        if (is_array($soapHeaderNames) && is_array($soapHeaderNamespaces) && is_array($soapHeaderTypes)) {
116 138
            foreach ($soapHeaderNames as $index => $soapHeaderName) {
117 36
                $methodName = $this->getSoapHeaderMethodName($soapHeaderName);
118 36
                if ($this->methods->get($methodName) === null) {
119 36
                    $soapHeaderNamespace = array_key_exists($index, $soapHeaderNamespaces) ? $soapHeaderNamespaces[$index] : null;
120 36
                    $soapHeaderType = array_key_exists($index, $soapHeaderTypes) ? $soapHeaderTypes[$index] : null;
121 36
                    $this->methods->add($this->getSoapHeaderMethod($methodName, $soapHeaderName, $soapHeaderNamespace, $soapHeaderType));
122 18
                }
123 69
            }
124 69
        }
125 138
        return $this;
126
    }
127
    /**
128
     * @param string $methodName
129
     * @param string $soapHeaderName
130
     * @param string $soapHeaderNamespace
131
     * @param string $soapHeaderType
132
     * @return PhpMethod
133
     */
134 36
    protected function getSoapHeaderMethod($methodName, $soapHeaderName, $soapHeaderNamespace, $soapHeaderType)
135
    {
136
        try {
137 36
            $method = new PhpMethod($methodName, [
138 36
                $firstParameter = new PhpFunctionParameter(lcfirst($soapHeaderName), PhpFunctionParameterBase::NO_VALUE, $this->getTypeFromName($soapHeaderType)),
139 36
                new PhpFunctionParameterBase(self::PARAM_SET_HEADER_NAMESPACE, $soapHeaderNamespace),
140 36
                new PhpFunctionParameterBase(self::PARAM_SET_HEADER_MUSTUNDERSTAND, false),
141 36
                new PhpFunctionParameterBase(self::PARAM_SET_HEADER_ACTOR, null),
142 18
            ]);
143 36
            $model = $this->getModelByName($soapHeaderType);
144 36
            if ($model instanceof StructModel) {
145 36
                $rules = new Rules($this, $method, new StructAttributeModel($model->getGenerator(), $soapHeaderType, $model->getName(), $model), $this->methods);
146 36
                $rules->applyRules(lcfirst($soapHeaderName));
147 36
                $firstParameter->setModel($model);
148 18
            }
149 36
            $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));
150 18
        } catch (\InvalidArgumentException $exception) {
151
            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);
152
        }
153 36
        return $method;
154
    }
155
    /**
156
     * @param string $name
157
     * @return string
158
     */
159 36
    protected function getTypeFromName($name)
160
    {
161 36
        $type = $name;
162 36
        $model = $this->getModelByName($name);
163 36
        if ($model instanceof StructModel) {
164 36
            if ($model->isRestriction() || $model->isUnion()) {
165 6
                $type = self::TYPE_STRING;
166 3
            } else {
167 36
                $type = $model->getPackagedName(true);
168
            }
169 18
        }
170 36
        return self::getValidType($type, $this->getGenerator()->getOptionXsdTypesPath());
171
    }
172
    /**
173
     * @param string $soapHeaderName
174
     * @return string
175
     */
176 36
    protected function getSoapHeaderMethodName($soapHeaderName)
177
    {
178 36
        return sprintf('%s%s', self::METHOD_SET_HEADER_PREFIX, ucfirst($soapHeaderName));
179
    }
180
    /**
181
     * @return Service
182
     */
183 138
    protected function addOperationsMethods()
184
    {
185 138
        foreach ($this->getModel()->getMethods() as $method) {
186 138
            $this->addMainMethod($method);
187 69
        }
188 138
        return $this;
189
    }
190
    /**
191
     * @return Service
192
     */
193 138
    protected function addGetResultMethod()
194
    {
195 138
        $method = new PhpMethod(self::METHOD_GET_RESULT);
196 138
        $method->addChild('return parent::getResult();');
197 138
        $this->methods->add($method);
198 138
        return $this;
199
    }
200
    /**
201
     * @param MethodModel $method
202
     * @return Service
203
     */
204 138
    protected function addMainMethod(MethodModel $method)
205
    {
206 138
        $methodFile = new Operation($method, $this->getGenerator());
207 138
        $mainMethod = $methodFile->getMainMethod();
208 138
        $this->methods->add($mainMethod);
209 138
        $this->setModelFromMethod($mainMethod, $method);
210 138
        return $this;
211
    }
212
    /**
213
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getMethodAnnotationBlock()
214
     */
215 138
    protected function getMethodAnnotationBlock(PhpMethod $method)
216
    {
217 138
        $annotationBlock = new PhpAnnotationBlock();
218 138
        if (stripos($method->getName(), self::METHOD_SET_HEADER_PREFIX) === 0) {
219 36
            $this->addAnnotationBlockForSoapHeaderMethod($annotationBlock, $method);
220 138
        } elseif ($method->getName() === self::METHOD_GET_RESULT) {
221 138
            $this->addAnnnotationBlockForgetResultMethod($annotationBlock);
222 69
        } else {
223 138
            $this->addAnnotationBlockForOperationMethod($annotationBlock, $method);
224
        }
225 138
        return $annotationBlock;
226
    }
227
    /**
228
     * @param PhpAnnotationBlock $annotationBlock
229
     * @param PhpMethod $method
230
     * @return Service
231
     */
232 36
    protected function addAnnotationBlockForSoapHeaderMethod(PhpAnnotationBlock $annotationBlock, PhpMethod $method)
233
    {
234 36
        $methodParameters = $method->getParameters();
235 36
        $firstParameter = array_shift($methodParameters);
236 36
        if ($firstParameter instanceof PhpFunctionParameter) {
237 36
            $annotationBlock->addChild(sprintf('Sets the %s SoapHeader param', ucfirst($firstParameter->getName())));
238 36
            $firstParameterType = $firstParameter->getType();
239 36
            if ($firstParameter->getModel()) {
240 36
                $firstParameterType = $this->getStructAttributeTypeAsPhpType(new StructAttributeModel($firstParameter->getModel()->getGenerator(), $firstParameter->getName(), $firstParameter->getModel()->getName(), $firstParameter->getModel()));
241 36
                if ($firstParameter->getModel()->isRestriction()) {
242
                    $annotationBlock
243 6
                        ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $firstParameter->getModel()->getPackagedName(true), StructEnum::METHOD_VALUE_IS_VALID)))
244 6
                        ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $firstParameter->getModel()->getPackagedName(true), StructEnum::METHOD_GET_VALID_VALUES)))
245 6
                        ->addChild(new PhpAnnotation(self::ANNOTATION_THROWS, '\InvalidArgumentException'));
246 3
                }
247 18
            }
248
            $annotationBlock
249 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::setSoapHeader()', $this->getModel()->getExtends(true))))
250 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', $firstParameterType, $firstParameter->getName())))
0 ignored issues
show
Bug introduced by
It seems like $firstParameterType can also be of type WsdlToPhp\PhpGenerator\Element\PhpClass; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

250
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', /** @scrutinizer ignore-type */ $firstParameterType, $firstParameter->getName())))
Loading history...
251 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('string $%s', self::PARAM_SET_HEADER_NAMESPACE)))
252 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('bool $%s', self::PARAM_SET_HEADER_MUSTUNDERSTAND)))
253 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('string $%s', self::PARAM_SET_HEADER_ACTOR)))
254 36
                ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, 'bool'));
255 18
        }
256 36
        return $this;
257
    }
258
    /**
259
     * @param PhpAnnotationBlock $annotationBlock
260
     * @param PhpMethod $method
261
     * @return Service
262
     */
263 138
    protected function addAnnotationBlockForOperationMethod(PhpAnnotationBlock $annotationBlock, PhpMethod $method)
264
    {
265 138
        if (($model = $this->getModelFromMethod($method)) instanceof MethodModel) {
266 138
            $operationAnnotationBlock = new OperationAnnotationBlock($model, $this->getGenerator());
267 138
            $operationAnnotationBlock->addAnnotationBlockForOperationMethod($annotationBlock);
268 69
        }
269 138
        return $this;
270
    }
271
    /**
272
     * @param PhpAnnotationBlock $annotationBlock
273
     * @return Service
274
     */
275 138
    protected function addAnnnotationBlockForgetResultMethod(PhpAnnotationBlock $annotationBlock)
276
    {
277
        $annotationBlock
278 138
            ->addChild('Returns the result')->addChild(new PhpAnnotation(self::ANNOTATION_SEE, sprintf('%s::getResult()', $this->getModel()->getExtends(true))))
279 138
            ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $this->getServiceReturnTypes()));
280 138
        return $this;
281
    }
282
    /**
283
     * @return string
284
     */
285 138
    protected function getServiceReturnTypes()
286
    {
287 138
        $returnTypes = [];
288 138
        foreach ($this->getModel()->getMethods() as $method) {
289 138
            $returnTypes[] = self::getOperationMethodReturnType($method, $this->getGenerator());
290 69
        }
291 138
        natcasesort($returnTypes);
292 138
        return implode('|', array_unique($returnTypes));
293
    }
294
    /**
295
     * @param MethodModel $method
296
     * @return string
297
     */
298 138
    public static function getOperationMethodReturnType(MethodModel $method, Generator $generator)
299
    {
300 138
        $returnType = $method->getReturnType();
301 138
        if ((($struct = $generator->getStructByName($returnType)) instanceof StructModel) && !$struct->isRestriction()) {
302 120
            if ($struct->isStruct()) {
303 120
                $returnType = $struct->getPackagedName(true);
304 72
            } elseif ($struct->isArray()) {
305 24
                if (($structInheritance = $struct->getInheritanceStruct()) instanceof StructModel) {
306 24
                    $returnType = sprintf('%s[]', $structInheritance->getPackagedName(true));
307 12
                } else {
308 12
                    $returnType = $struct->getInheritance();
309
                }
310 12
            }
311 60
        }
312 138
        return $returnType;
313
    }
314
    /**
315
     * @param PhpMethod $method
316
     * @return MethodModel|null
317
     */
318 138
    protected function getModelFromMethod(PhpMethod $method)
319
    {
320 138
        $model = $this->getGenerator()->getServiceMethod($method->getName());
321 138
        if (!$model instanceof MethodModel) {
322 24
            $model = array_key_exists($method->getName(), $this->methodNames) ? $this->methodNames[$method->getName()] : null;
323 12
        }
324 138
        return $model;
325
    }
326
    /**
327
     * @param PhpMethod $phpMethod
328
     * @param MethodModel $methodModel
329
     * @return Service
330
     */
331 138
    protected function setModelFromMethod(PhpMethod $phpMethod, MethodModel $methodModel)
332
    {
333 138
        $this->methodNames[$phpMethod->getName()] = $methodModel;
334 138
        return $this;
335
    }
336
    /**
337
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getModel()
338
     * @return ServiceModel
339
     */
340 144
    public function getModel()
341
    {
342 144
        return parent::getModel();
343
    }
344
    /**
345
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::setModel()
346
     * @throws \InvalidArgumentException
347
     * @param AbstractModel $model
348
     * @return Service
349
     */
350 150
    public function setModel(AbstractModel $model)
351
    {
352 150
        if (!$model instanceof ServiceModel) {
353 6
            throw new \InvalidArgumentException('Model must be an instance of a Service', __LINE__);
354
        }
355 144
        return parent::setModel($model);
356
    }
357
}
358