Completed
Push — 1.x ( 257780...f31d1d )
by Mikaël
42:33 queued 33:38
created

Service   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 323
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 96.53%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 46
c 1
b 0
f 0
lcom 1
cbo 12
dl 0
loc 323
ccs 139
cts 144
cp 0.9653
rs 8.3999

24 Methods

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