Completed
Push — develop ( ded088...9a12a6 )
by Mikaël
28:59
created

Service   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 322
Duplicated Lines 0 %

Test Coverage

Coverage 96.64%

Importance

Changes 0
Metric Value
eloc 116
dl 0
loc 322
ccs 144
cts 149
cp 0.9664
rs 7.92
c 0
b 0
f 0
wmc 51

24 Methods

Rating   Name   Duplication   Size   Complexity  
A getSoapHeaderMethod() 0 20 3
A fillClassMethods() 0 6 1
A addSoapHeaderMethods() 0 6 2
A getClassConstants() 0 2 1
A getClassDeclarationLineText() 0 3 2
B addSoapHeaderFromMethod() 0 16 8
A getClassProperties() 0 2 1
A getPropertyAnnotationBlock() 0 2 1
A getConstantAnnotationBlock() 0 2 1
A getServiceReturnTypes() 0 8 2
A getModel() 0 3 1
A getSoapHeaderMethodName() 0 3 1
A getModelFromMethod() 0 7 3
A addAnnnotationBlockForgetResultMethod() 0 6 1
A getOperationMethodReturnType() 0 15 6
A getMethodAnnotationBlock() 0 11 3
A getTypeFromName() 0 3 1
A addMainMethod() 0 7 1
A setModel() 0 6 2
A addAnnotationBlockForOperationMethod() 0 7 2
A addAnnotationBlockForSoapHeaderMethod() 0 25 4
A addGetResultMethod() 0 6 1
A setModelFromMethod() 0 4 1
A addOperationsMethods() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like Service often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Service, and based on these observations, apply Extract Interface, too.

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

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