Completed
Push — master ( 060bfa...009823 )
by Mikaël
50:16 queued 31:14
created

Service   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 333
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 96.71%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 51
lcom 1
cbo 15
dl 0
loc 333
ccs 147
cts 152
cp 0.9671
rs 7.1582
c 1
b 0
f 1

24 Methods

Rating   Name   Duplication   Size   Complexity  
A addSoapHeaderMethods() 0 7 2
B addSoapHeaderFromMethod() 0 15 5
A getClassConstants() 0 3 1
A getConstantAnnotationBlock() 0 3 1
A getClassProperties() 0 3 1
A getPropertyAnnotationBlock() 0 3 1
A getClassDeclarationLineText() 0 4 2
A getClassMethods() 0 4 1
A getSoapHeaderMethod() 0 21 3
A getTypeFromName() 0 13 4
A getSoapHeaderMethodName() 0 4 1
A addOperationsMethods() 0 7 2
A addGetResultMethod() 0 7 1
A addMainMethod() 0 8 1
A getMethodAnnotationBlock() 0 12 3
B addAnnotationBlockForSoapHeaderMethod() 0 26 4
A addAnnotationBlockForOperationMethod() 0 8 2
A addAnnnotationBlockForgetResultMethod() 0 7 1
A getServiceReturnTypes() 0 9 2
B getOperationMethodReturnType() 0 16 6
A getModelFromMethod() 0 8 3
A setModelFromMethod() 0 5 1
A getModel() 0 4 1
A setModel() 0 7 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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\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 $methods = array();
55
    /**
56
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getClassConstants()
57
     */
58 115
    protected function getClassConstants(ConstantContainer $constants)
59
    {
60 115
    }
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 115
    protected function getClassProperties(PropertyContainer $properties)
71
    {
72 115
    }
73
    /**
74
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getPropertyAnnotationBlock()
75
     */
76
    protected function getPropertyAnnotationBlock(PhpProperty $property)
77
    {
78
    }
79
    /**
80
     * @return string
81
     */
82 115
    protected function getClassDeclarationLineText()
83
    {
84 115
        return $this->getGenerator()->getOptionGatherMethods() === GeneratorOptions::VALUE_NONE ? 'This class stands for all operations' : parent::getClassDeclarationLineText();
85
    }
86
    /**
87
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getClassMethods()
88
     */
89 115
    protected function getClassMethods(MethodContainer $methods)
90
    {
91 115
        $this->addSoapHeaderMethods($methods)->addOperationsMethods($methods)->addGetResultMethod($methods);
92 115
    }
93
    /**
94
     * @param MethodContainer $methods
95
     * @return Service
96
     */
97 115
    protected function addSoapHeaderMethods(MethodContainer $methods)
98
    {
99 115
        foreach ($this->getModel()->getMethods() as $method) {
100 115
            $this->addSoapHeaderFromMethod($methods, $method);
101 69
        }
102 115
        return $this;
103
    }
104
    /**
105
     * @param MethodContainer $methods
106
     * @param MethodModel $method
107
     * @return Service
108
     */
109 115
    protected function addSoapHeaderFromMethod(MethodContainer $methods, MethodModel $method)
110
    {
111 115
        $soapHeaderNames = $method->getMetaValue(TagHeader::META_SOAP_HEADER_NAMES, array());
112 115
        $soapHeaderNamespaces = $method->getMetaValue(TagHeader::META_SOAP_HEADER_NAMESPACES, array());
113 115
        $soapHeaderTypes = $method->getMetaValue(TagHeader::META_SOAP_HEADER_TYPES, array());
114 115
        foreach ($soapHeaderNames as $index => $soapHeaderName) {
115 30
            $methodName = $this->getSoapHeaderMethodName($soapHeaderName);
116 30
            if ($methods->get($methodName) === null) {
117 30
                $soapHeaderNamespace = array_key_exists($index, $soapHeaderNamespaces) ? $soapHeaderNamespaces[$index] : null;
118 30
                $soapHeaderType = array_key_exists($index, $soapHeaderTypes) ? $soapHeaderTypes[$index] : null;
119 30
                $methods->add($this->getSoapHeaderMethod($methodName, $soapHeaderName, $soapHeaderNamespace, $soapHeaderType));
120 18
            }
121 69
        }
122 115
        return $this;
123
    }
124
    /**
125
     * @param string $methodName
126
     * @param string $soapHeaderName
127
     * @param string $soapHeaderNamespace
128
     * @param string $soapHeaderType
129
     * @return PhpMethod
130
     */
131 30
    protected function getSoapHeaderMethod($methodName, $soapHeaderName, $soapHeaderNamespace, $soapHeaderType)
132
    {
133
        try {
134 30
            $method = new PhpMethod($methodName, array(
135 30
                $firstParameter = new PhpFunctionParameter(lcfirst($soapHeaderName), PhpFunctionParameterBase::NO_VALUE, $this->getTypeFromName($soapHeaderType)),
136 30
                new PhpFunctionParameterBase(self::PARAM_SET_HEADER_NAMESPACE, $soapHeaderNamespace),
137 30
                new PhpFunctionParameterBase(self::PARAM_SET_HEADER_MUSTUNDERSTAND, false),
138 30
                new PhpFunctionParameterBase(self::PARAM_SET_HEADER_ACTOR, null),
139 18
            ));
140 30
            $model = $this->getModelByName($soapHeaderType);
141 30
            if ($model instanceof StructModel) {
142 30
                $rules = new Rules($this, $method, new StructAttributeModel($model->getGenerator(), $soapHeaderType, $model->getName(), $model));
143 30
                $rules->applyRules(lcfirst($soapHeaderName));
144 30
                $firstParameter->setModel($model);
145 18
            }
146 30
            $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));
147 18
        } catch (\InvalidArgumentException $exception) {
148
            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);
149
        }
150 30
        return $method;
151
    }
152
    /**
153
     * @param string $name
154
     * @return string
155
     */
156 30
    protected function getTypeFromName($name)
157
    {
158 30
        $type = $name;
159 30
        $model = $this->getModelByName($name);
160 30
        if ($model instanceof StructModel) {
161 30
            if ($model->isRestriction() || $model->isUnion()) {
162 5
                $type = self::TYPE_STRING;
163 3
            } else {
164 30
                $type = $model->getPackagedName(true);
165
            }
166 18
        }
167 30
        return self::getValidType($type);
168
    }
169
    /**
170
     * @param string $soapHeaderName
171
     * @return string
172
     */
173 30
    protected function getSoapHeaderMethodName($soapHeaderName)
174
    {
175 30
        return sprintf('%s%s', self::METHOD_SET_HEADER_PREFIX, ucfirst($soapHeaderName));
176
    }
177
    /**
178
     * @param MethodContainer $methods
179
     * @return Service
180
     */
181 115
    protected function addOperationsMethods(MethodContainer $methods)
182
    {
183 115
        foreach ($this->getModel()->getMethods() as $method) {
184 115
            $this->addMainMethod($methods, $method);
185 69
        }
186 115
        return $this;
187
    }
188
    /**
189
     * @param MethodContainer $methods
190
     * @return Service
191
     */
192 115
    protected function addGetResultMethod(MethodContainer $methods)
193
    {
194 115
        $method = new PhpMethod(self::METHOD_GET_RESULT);
195 115
        $method->addChild('return parent::getResult();');
196 115
        $methods->add($method);
197 115
        return $this;
198
    }
199
    /**
200
     * @param MethodContainer $methods
201
     * @param MethodModel $method
202
     * @return Service
203
     */
204 115
    protected function addMainMethod(MethodContainer $methods, MethodModel $method)
205
    {
206 115
        $methodFile = new Operation($method, $this->getGenerator());
207 115
        $mainMethod = $methodFile->getMainMethod();
208 115
        $methods->add($mainMethod);
209 115
        $this->setModelFromMethod($mainMethod, $method);
210 115
        return $this;
211
    }
212
    /**
213
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getMethodAnnotationBlock()
214
     */
215 115
    protected function getMethodAnnotationBlock(PhpMethod $method)
216
    {
217 115
        $annotationBlock = new PhpAnnotationBlock();
218 115
        if (stripos($method->getName(), self::METHOD_SET_HEADER_PREFIX) === 0) {
219 30
            $this->addAnnotationBlockForSoapHeaderMethod($annotationBlock, $method);
220 115
        } elseif ($method->getName() === self::METHOD_GET_RESULT) {
221 115
            $this->addAnnnotationBlockForgetResultMethod($annotationBlock);
222 69
        } else {
223 115
            $this->addAnnotationBlockForOperationMethod($annotationBlock, $method);
224
        }
225 115
        return $annotationBlock;
226
    }
227
    /**
228
     * @param PhpAnnotationBlock $annotationBlock
229
     * @param PhpMethod $method
230
     * @return Service
231
     */
232 30
    protected function addAnnotationBlockForSoapHeaderMethod(PhpAnnotationBlock $annotationBlock, PhpMethod $method)
233
    {
234 30
        $methodParameters = $method->getParameters();
235 30
        $firstParameter = array_shift($methodParameters);
236 30
        if ($firstParameter instanceof PhpFunctionParameter) {
237 30
            $annotationBlock->addChild(sprintf('Sets the %s SoapHeader param', ucfirst($firstParameter->getName())));
238 30
            $firstParameterType = $firstParameter->getType();
239 30
            if ($firstParameter->getModel() instanceof StructModel) {
240 30
                $firstParameterType = $this->getStructAttributeTypeAsPhpType(new StructAttributeModel($firstParameter->getModel()->getGenerator(), $firstParameter->getName(), $firstParameter->getModel()->getName(), $firstParameter->getModel()));
241 30
                if ($firstParameter->getModel()->isRestriction()) {
242
                    $annotationBlock
243 5
                        ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $firstParameter->getModel()->getPackagedName(true), StructEnum::METHOD_VALUE_IS_VALID)))
244 5
                        ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::%s()', $firstParameter->getModel()->getPackagedName(true), StructEnum::METHOD_GET_VALID_VALUES)))
245 5
                        ->addChild(new PhpAnnotation(self::ANNOTATION_THROWS, '\InvalidArgumentException'));
246 3
                }
247 18
            }
248
            $annotationBlock
249 30
                ->addChild(new PhpAnnotation(self::ANNOTATION_USES, sprintf('%s::setSoapHeader()', $this->getModel()->getExtends(true))))
250 30
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('%s $%s', $firstParameterType, $firstParameter->getName())))
251 30
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('string $%s', self::PARAM_SET_HEADER_NAMESPACE)))
252 30
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('bool $%s', self::PARAM_SET_HEADER_MUSTUNDERSTAND)))
253 30
                ->addChild(new PhpAnnotation(self::ANNOTATION_PARAM, sprintf('string $%s', self::PARAM_SET_HEADER_ACTOR)))
254 30
                ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, 'bool'));
255 18
        }
256 30
        return $this;
257
    }
258
    /**
259
     * @param PhpAnnotationBlock $annotationBlock
260
     * @param PhpMethod $method
261
     * @return Service
262
     */
263 115
    protected function addAnnotationBlockForOperationMethod(PhpAnnotationBlock $annotationBlock, PhpMethod $method)
264
    {
265 115
        if (($model = $this->getModelFromMethod($method)) instanceof MethodModel) {
266 115
            $operationAnnotationBlock = new OperationAnnotationBlock($model, $this->getGenerator());
267 115
            $operationAnnotationBlock->addAnnotationBlockForOperationMethod($annotationBlock);
268 69
        }
269 115
        return $this;
270
    }
271
    /**
272
     * @param PhpAnnotationBlock $annotationBlock
273
     * @return Service
274
     */
275 115
    protected function addAnnnotationBlockForgetResultMethod(PhpAnnotationBlock $annotationBlock)
276
    {
277
        $annotationBlock
278 115
            ->addChild('Returns the result')->addChild(new PhpAnnotation(self::ANNOTATION_SEE, sprintf('%s::getResult()', $this->getModel()->getExtends(true))))
279 115
            ->addChild(new PhpAnnotation(self::ANNOTATION_RETURN, $this->getServiceReturnTypes()));
280 115
        return $this;
281
    }
282
    /**
283
     * @return string
284
     */
285 115
    protected function getServiceReturnTypes()
286
    {
287 115
        $returnTypes = array();
288 115
        foreach ($this->getModel()->getMethods() as $method) {
289 115
            $returnTypes[] = self::getOperationMethodReturnType($method, $this->getGenerator());
290 69
        }
291 115
        natcasesort($returnTypes);
292 115
        return implode('|', array_unique($returnTypes));
293
    }
294
    /**
295
     * @param MethodModel $method
296
     * @return string
297
     */
298 115
    public static function getOperationMethodReturnType(MethodModel $method, Generator $generator)
299
    {
300 115
        $returnType = $method->getReturnType();
301 115
        if ((($struct = $generator->getStruct($returnType)) instanceof StructModel) && !$struct->isRestriction()) {
302 100
            if ($struct->isStruct()) {
303 100
                $returnType = $struct->getPackagedName(true);
304 68
            } elseif ($struct->isArray()) {
305 20
                if (($structInheritance = $struct->getInheritanceStruct()) instanceof StructModel) {
306 20
                    $returnType = sprintf('%s[]', $structInheritance->getPackagedName(true));
307 12
                } else {
308 10
                    $returnType = $struct->getInheritance();
309
                }
310 12
            }
311 60
        }
312 115
        return $returnType;
313
    }
314
    /**
315
     * @param PhpMethod $method
316
     * @return MethodModel|null
317
     */
318 115
    protected function getModelFromMethod(PhpMethod $method)
319
    {
320 115
        $model = $this->getGenerator()->getServiceMethod($method->getName());
321 115
        if (!$model instanceof MethodModel) {
322 20
            $model = array_key_exists($method->getName(), $this->methods) ? $this->methods[$method->getName()] : null;
323 12
        }
324 115
        return $model;
325
    }
326
    /**
327
     * @param PhpMethod $phpMethod
328
     * @param MethodModel $methodModel
329
     * @return Service
330
     */
331 115
    protected function setModelFromMethod(PhpMethod $phpMethod, MethodModel $methodModel)
332
    {
333 115
        $this->methods[$phpMethod->getName()] = $methodModel;
334 115
        return $this;
335
    }
336
    /**
337
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::getModel()
338
     * @return ServiceModel
339
     */
340 120
    public function getModel()
341
    {
342 120
        return parent::getModel();
343
    }
344
    /**
345
     * @see \WsdlToPhp\PackageGenerator\File\AbstractModelFile::setModel()
346
     * @throws \InvalidaArgumentException
347
     * @param AbstractModel $model
348
     * @return Service
349
     */
350 125
    public function setModel(AbstractModel $model)
351
    {
352 125
        if (!$model instanceof ServiceModel) {
353 5
            throw new \InvalidArgumentException('Model must be an instance of a Service', __LINE__);
354
        }
355 120
        return parent::setModel($model);
356
    }
357
}
358