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

AbstractModelFile   F

Complexity

Total Complexity 78

Size/Duplication

Total Lines 486
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 78
lcom 1
cbo 17
dl 0
loc 486
ccs 186
cts 186
cp 1
rs 2.1126
c 0
b 0
f 0

40 Methods

Rating   Name   Duplication   Size   Complexity  
A getFileDestination() 0 4 2
A getDestinationFolder() 0 5 3
A writeFile() 0 9 2
A addAnnotationBlock() 0 5 1
A setModel() 0 6 1
A getModel() 0 4 1
A getModelByName() 0 4 1
A definePackageAnnotations() 0 11 3
A getPackageName() 0 10 3
A defineGeneralAnnotations() 0 7 2
A getClassAnnotationBlock() 0 7 1
A getClassDeclarationLine() 0 4 1
A getClassDeclarationLineText() 0 4 1
A defineModelAnnotationsFromWsdl() 0 5 2
A addClassElement() 0 11 2
A defineNamespace() 0 7 2
A defineUseStatement() 0 7 2
A defineConstants() 0 13 3
A defineProperties() 0 13 3
A defineMethods() 0 13 3
getClassConstants() 0 1 ?
getConstantAnnotationBlock() 0 1 ?
getClassProperties() 0 1 ?
getPropertyAnnotationBlock() 0 1 ?
getClassMethods() 0 1 ?
getMethodAnnotationBlock() 0 1 ?
A defineStringMethod() 0 6 1
A getToStringMethodAnnotationBlock() 0 7 1
A getToStringMethod() 0 6 1
A getStructAttribute() 0 8 4
A getModelFromStructAttribute() 0 9 2
A getRestrictionFromStructAttribute() 0 8 3
C getStructAttributeType() 0 29 11
A getStructAttributeTypeGetAnnotation() 0 5 3
A getStructAttributeTypeSetAnnotation() 0 5 2
A useBrackets() 0 4 2
A getStructAttributeTypeHint() 0 5 3
A getStructAttributeTypeAsPhpType() 0 9 2
A getValidType() 0 4 2
A getPhpType() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like AbstractModelFile 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 AbstractModelFile, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace WsdlToPhp\PackageGenerator\File;
4
5
use WsdlToPhp\PackageGenerator\Container\PhpElement\Method;
6
use WsdlToPhp\PackageGenerator\Container\PhpElement\Property;
7
use WsdlToPhp\PackageGenerator\Container\PhpElement\Constant;
8
use WsdlToPhp\PackageGenerator\Model\Struct as StructModel;
9
use WsdlToPhp\PackageGenerator\Model\StructAttribute as StructAttributeModel;
10
use WsdlToPhp\PackageGenerator\Model\AbstractModel;
11
use WsdlToPhp\PackageGenerator\File\Utils as FileUtils;
12
use WsdlToPhp\PackageGenerator\Generator\Utils as GeneratorUtils;
13
use WsdlToPhp\PhpGenerator\Element\PhpAnnotationBlock;
14
use WsdlToPhp\PhpGenerator\Element\PhpAnnotation;
15
use WsdlToPhp\PhpGenerator\Element\PhpMethod;
16
use WsdlToPhp\PhpGenerator\Element\PhpProperty;
17
use WsdlToPhp\PhpGenerator\Element\PhpConstant;
18
use WsdlToPhp\PhpGenerator\Component\PhpClass;
19
use WsdlToPhp\PackageGenerator\ConfigurationReader\XsdTypes;
20
21
abstract class AbstractModelFile extends AbstractFile
22
{
23
    /**
24
     * @var string Meta annotation length
25
     */
26
    const ANNOTATION_META_LENGTH = '250';
27
    /**
28
     * @var string Long annotation string
29
     */
30
    const ANNOTATION_LONG_LENGTH = '1000';
31
    /**
32
     * @var string
33
     */
34
    const ANNOTATION_PACKAGE = 'package';
35
    /**
36
     * @var string
37
     */
38
    const ANNOTATION_SUB_PACKAGE = 'subpackage';
39
    /**
40
     * @var string
41
     */
42
    const ANNOTATION_RETURN = 'return';
43
    /**
44
     * @var string
45
     */
46
    const ANNOTATION_USES = 'uses';
47
    /**
48
     * @var string
49
     */
50
    const ANNOTATION_PARAM = 'param';
51
    /**
52
     * @var string
53
     */
54
    const ANNOTATION_VAR = 'var';
55
    /**
56
     * @var string
57
     */
58
    const ANNOTATION_SEE = 'see';
59
    /**
60
     * @var string
61
     */
62
    const ANNOTATION_THROWS = 'throws';
63
    /**
64
     * @var string
65
     */
66
    const METHOD_CONSTRUCT = '__construct';
67
    /**
68
     * @var string
69
     */
70
    const METHOD_SET_STATE = '__set_state';
71
    /**
72
     * @var string
73
     */
74
    const TYPE_STRING = 'string';
75
    /**
76
     * @var string
77
     */
78
    const TYPE_ARRAY = 'array';
79
    /**
80
     * @var AbstractModel
81
     */
82
    protected $model;
83
    /**
84
     * @param bool $withSrc
85
     * @return string
86
     */
87 330
    public function getFileDestination($withSrc = true)
88
    {
89 330
        return sprintf('%s%s%s', $this->getDestinationFolder($withSrc), $this->getModel()->getSubDirectory(), $this->getModel()->getSubDirectory() !== '' ? '/' : '');
90
    }
91
    /**
92
     * @param bool $withSrc
93
     * @return string
94
     */
95 330
    public function getDestinationFolder($withSrc = true)
96
    {
97 330
        $src = rtrim($this->generator->getOptionSrcDirname(), DIRECTORY_SEPARATOR);
98 330
        return sprintf('%s%s', $this->getGenerator()->getOptionDestination(), (bool) $withSrc && !empty($src) ? $src . DIRECTORY_SEPARATOR : '');
99
    }
100
    /**
101
     * @see \WsdlToPhp\PackageGenerator\File\AbstractFile::writeFile()
102
     * @param bool $withSrc
103
     * @return int|bool
104
     */
105 305
    public function writeFile($withSrc = true)
106
    {
107 305
        if (!$this->getModel() instanceof AbstractModel) {
108 5
            throw new \InvalidArgumentException('You MUST define the model before begin able to generate the file', __LINE__);
109
        }
110 300
        GeneratorUtils::createDirectory($this->getFileDestination($withSrc));
111 300
        $this->defineNamespace()->defineUseStatement()->addAnnotationBlock()->addClassElement();
112 300
        return parent::writeFile();
113
    }
114
    /**
115
     * @return AbstractModelFile
116
     */
117 300
    protected function addAnnotationBlock()
118
    {
119 300
        $this->getFile()->addAnnotationBlockElement($this->getClassAnnotationBlock());
120 300
        return $this;
121
    }
122
    /**
123
     * @param AbstractModel $model
124
     * @return AbstractModelFile
125
     */
126 360
    public function setModel(AbstractModel $model)
127
    {
128 360
        $this->model = $model;
129 360
        $this->getFile()->getMainElement()->setName($model->getPackagedName());
130 360
        return $this;
131
    }
132
    /**
133
     * @return AbstractModel
134
     */
135 405
    public function getModel()
136
    {
137 405
        return $this->model;
138
    }
139
    /**
140
     * @param string $name
141
     * @return StructModel|null
142
     */
143 30
    protected function getModelByName($name)
144
    {
145 30
        return $this->getGenerator()->getStruct($name);
146
    }
147
    /**
148
     * @param PhpAnnotationBlock $block
149
     * @return AbstractModelFile
150
     */
151 275
    protected function definePackageAnnotations(PhpAnnotationBlock $block)
152
    {
153 275
        $packageName = $this->getPackageName();
154 275
        if (!empty($packageName)) {
155 230
            $block->addChild(new PhpAnnotation(self::ANNOTATION_PACKAGE, $packageName));
156 138
        }
157 275
        if (count($this->getModel()->getDocSubPackages()) > 0) {
158 275
            $block->addChild(new PhpAnnotation(self::ANNOTATION_SUB_PACKAGE, implode(',', $this->getModel()->getDocSubPackages())));
159 165
        }
160 275
        return $this;
161
    }
162
    /**
163
     * @return string
164
     */
165 275
    protected function getPackageName()
166
    {
167 275
        $packageName = '';
168 275
        if ($this->getGenerator()->getOptionPrefix() !== '') {
169 220
            $packageName = $this->getGenerator()->getOptionPrefix();
170 187
        } elseif ($this->getGenerator()->getOptionSuffix() !== '') {
171 10
            $packageName = $this->getGenerator()->getOptionSuffix();
172 6
        }
173 275
        return $packageName;
174
    }
175
    /**
176
     * @param PhpAnnotationBlock $block
177
     * @return AbstractModelFile
178
     */
179 275
    protected function defineGeneralAnnotations(PhpAnnotationBlock $block)
180
    {
181 275
        foreach ($this->getGenerator()->getOptionAddComments() as $tagName => $tagValue) {
182 245
            $block->addChild(new PhpAnnotation($tagName, $tagValue));
183 165
        }
184 275
        return $this;
185
    }
186
    /**
187
     * @return PhpAnnotationBlock
188
     */
189 275
    protected function getClassAnnotationBlock()
190
    {
191 275
        $block = new PhpAnnotationBlock();
192 275
        $block->addChild($this->getClassDeclarationLine());
193 275
        $this->defineModelAnnotationsFromWsdl($block)->definePackageAnnotations($block)->defineGeneralAnnotations($block);
194 275
        return $block;
195
    }
196
    /**
197
     * @return string
198
     */
199 275
    protected function getClassDeclarationLine()
200
    {
201 275
        return sprintf($this->getClassDeclarationLineText(), $this->getModel()->getName(), $this->getModel()->getContextualPart());
202
    }
203
    /**
204
     * @return string
205
     */
206 255
    protected function getClassDeclarationLineText()
207
    {
208 255
        return 'This class stands for %s %s';
209
    }
210
    /**
211
     * @param PhpAnnotationBlock $block
212
     * @param AbstractModel $model
213
     * @return AbstractModelFile
214
     */
215 275
    protected function defineModelAnnotationsFromWsdl(PhpAnnotationBlock $block, AbstractModel $model = null)
216
    {
217 275
        FileUtils::defineModelAnnotationsFromWsdl($block, $model instanceof AbstractModel ? $model : $this->getModel());
218 275
        return $this;
219
    }
220
    /**
221
     * @return AbstractModelFile
222
     */
223 300
    protected function addClassElement()
224
    {
225 300
        $class = new PhpClass($this->getModel()->getPackagedName(), $this->getModel()->isAbstract(), $this->getModel()->getExtendsClassName() === '' ? null : $this->getModel()->getExtendsClassName());
226 300
        $this->defineConstants($class)
227 300
            ->defineProperties($class)
228 300
            ->defineMethods($class)
229 300
            ->defineStringMethod($class)
230 300
            ->getFile()
231 300
            ->addClassComponent($class);
232 300
        return $this;
233
    }
234
    /**
235
     * @return AbstractModelFile
236
     */
237 300
    protected function defineNamespace()
238
    {
239 300
        if ($this->getModel()->getNamespace() !== '') {
240 290
            $this->getFile()->setNamespace($this->getModel()->getNamespace());
241 174
        }
242 300
        return $this;
243
    }
244
    /**
245
     * @return AbstractModelFile
246
     */
247 300
    protected function defineUseStatement()
248
    {
249 300
        if ($this->getModel()->getExtends() !== '') {
250 240
            $this->getFile()->addUse($this->getModel()->getExtends(), null, true);
251 144
        }
252 300
        return $this;
253
    }
254
    /**
255
     * @param PhpClass $class
256
     * @return AbstractModelFile
257
     */
258 300
    protected function defineConstants(PhpClass $class)
259
    {
260 300
        $constants = new Constant($this->getGenerator());
261 300
        $this->getClassConstants($constants);
262 300
        foreach ($constants as $constant) {
263 65
            $annotationBlock = $this->getConstantAnnotationBlock($constant);
264 65
            if (!empty($annotationBlock)) {
265 65
                $class->addAnnotationBlockElement($annotationBlock);
266 39
            }
267 65
            $class->addConstantElement($constant);
268 180
        }
269 300
        return $this;
270
    }
271
    /**
272
     * @param PhpClass $class
273
     * @return AbstractModelFile
274
     */
275 300
    protected function defineProperties(PhpClass $class)
276
    {
277 300
        $properties = new Property($this->getGenerator());
278 300
        $this->getClassProperties($properties);
279 300
        foreach ($properties as $property) {
280 155
            $annotationBlock = $this->getPropertyAnnotationBlock($property);
281 155
            if (!empty($annotationBlock)) {
282 155
                $class->addAnnotationBlockElement($annotationBlock);
283 93
            }
284 155
            $class->addPropertyElement($property);
285 180
        }
286 300
        return $this;
287
    }
288
    /**
289
     * @param PhpClass $class
290
     * @return AbstractModelFile
291
     */
292 300
    protected function defineMethods(PhpClass $class)
293
    {
294 300
        $methods = new Method($this->getGenerator());
295 300
        $this->getClassMethods($methods);
296 300
        foreach ($methods as $method) {
297 300
            $annotationBlock = $this->getMethodAnnotationBlock($method);
298 300
            if (!empty($annotationBlock)) {
299 300
                $class->addAnnotationBlockElement($annotationBlock);
300 180
            }
301 300
            $class->addMethodElement($method);
302 180
        }
303 300
        return $this;
304
    }
305
    /**
306
     * @param Constant $constants
307
     */
308
    abstract protected function getClassConstants(Constant $constants);
309
    /**
310
     * @param PhpConstant $constant
311
     * @return PhpAnnotationBlock|null
312
     */
313
    abstract protected function getConstantAnnotationBlock(PhpConstant $constant);
314
    /**
315
     * @param Property $properties
316
     */
317
    abstract protected function getClassProperties(Property $properties);
318
    /**
319
     * @param PhpProperty $property
320
     * @return PhpAnnotationBlock|null
321
     */
322
    abstract protected function getPropertyAnnotationBlock(PhpProperty $property);
323
    /**
324
     * @param Method $methods
325
     */
326
    abstract protected function getClassMethods(Method $methods);
327
    /**
328
     * @param PhpMethod $method
329
     * @return PhpAnnotationBlock|null
330
     */
331
    abstract protected function getMethodAnnotationBlock(PhpMethod $method);
332
    /**
333
     * @param PhpClass $class
334
     * @return AbstractModelFile
335
     */
336 275
    protected function defineStringMethod(PhpClass $class)
337
    {
338 275
        $class->addAnnotationBlockElement($this->getToStringMethodAnnotationBlock());
339 275
        $class->addMethodElement($this->getToStringMethod());
340 275
        return $this;
341
    }
342
    /**
343
     * @return PhpAnnotationBlock
344
     */
345 275
    protected function getToStringMethodAnnotationBlock()
346
    {
347 275
        return new PhpAnnotationBlock(array(
348 275
            'Method returning the class name',
349 275
            new PhpAnnotation(self::ANNOTATION_RETURN, 'string __CLASS__'),
350 165
        ));
351
    }
352
    /**
353
     * @return PhpMethod
354
     */
355 275
    protected function getToStringMethod()
356
    {
357 275
        $method = new PhpMethod('__toString');
358 275
        $method->addChild('return __CLASS__;');
359 275
        return $method;
360
    }
361
    /**
362
     * @param StructAttributeModel $attribute
363
     * @return StructAttributeModel
364
     */
365 225
    protected function getStructAttribute(StructAttributeModel $attribute = null)
366
    {
367 225
        $struct = $this->getModel();
368 225
        if (empty($attribute) && $struct instanceof StructModel && $struct->getAttributes()->count() === 1) {
369 40
            $attribute = $struct->getAttributes()->offsetGet(0);
370 24
        }
371 225
        return $attribute;
372
    }
373
    /**
374
     * @param StructAttributeModel $attribute
375
     * @return StructModel|null
376
     */
377 225
    public function getModelFromStructAttribute(StructAttributeModel $attribute = null)
378
    {
379 225
        $model = null;
380 225
        $attribute = $this->getStructAttribute($attribute);
381 225
        if ($attribute instanceof StructAttributeModel) {
382 225
            $model = $attribute->getTypeStruct();
383 135
        }
384 225
        return $model;
385
    }
386
    /**
387
     * @param StructAttributeModel $attribute
388
     * @return StructModel|null
389
     */
390 185
    public function getRestrictionFromStructAttribute(StructAttributeModel $attribute = null)
391
    {
392 185
        $model = $this->getModelFromStructAttribute($attribute);
393 185
        if ($model instanceof StructModel && !$model->isRestriction()) {
394 160
            $model = null;
395 96
        }
396 185
        return $model;
397
    }
398
    /**
399
     * @param StructAttributeModel $attribute
400
     * @param bool $namespaced
401
     * @return string
402
     */
403 225
    public function getStructAttributeType(StructAttributeModel $attribute = null, $namespaced = false)
404
    {
405 225
        $attribute = $this->getStructAttribute($attribute);
406 225
        $inheritance = $attribute->getInheritance();
407 225
        if (empty($inheritance)) {
408 225
            $type = $attribute->getType();
409 135
        } else {
410 10
            $type = $inheritance;
411
        }
412 225
        if (!empty($type) && ($struct = $this->getGenerator()->getStruct($type))) {
413 170
            $inheritance = $struct->getTopInheritance();
414 170
            if (!empty($inheritance)) {
415 75
                $type = str_replace('[]', '', $inheritance);
416 45
            }
417 102
        }
418 225
        $model = $this->getModelFromStructAttribute($attribute);
419 225
        if ($model instanceof StructModel) {
420
            // issue #84: union is considered as string as it would be difficult to have a method that accepts multiple object types.
421
            // If the property has to be an object of multiple types => new issue...
422 170
            if ($model->isRestriction() || $model->isUnion()) {
423 95
                $type = self::TYPE_STRING;
424 166
            } elseif ($model->isStruct()) {
425 145
                $type = $model->getPackagedName($namespaced);
426 118
            } elseif ($model->isArray() && ($inheritanceStruct = $model->getInheritanceStruct()) instanceof StructModel) {
427 15
                $type = $inheritanceStruct->getPackagedName($namespaced);
428 9
            }
429 102
        }
430 225
        return $type;
431
    }
432
    /**
433
     * @param StructAttributeModel $attribute
434
     * @param bool $returnArrayType
435
     * @return string
436
     */
437 155
    protected function getStructAttributeTypeGetAnnotation(StructAttributeModel $attribute = null, $returnArrayType = true)
438
    {
439 155
        $attribute = $this->getStructAttribute($attribute);
440 155
        return sprintf('%s%s%s', $this->getStructAttributeTypeAsPhpType($attribute), $this->useBrackets($attribute, $returnArrayType) ? '[]' : '', $attribute->isRequired() ? '' : '|null');
441
    }
442
    /**
443
     * @param StructAttributeModel $attribute
444
     * @param bool $returnArrayType
445
     * @return string
446
     */
447 155
    protected function getStructAttributeTypeSetAnnotation(StructAttributeModel $attribute = null, $returnArrayType = true)
448
    {
449 155
        $attribute = $this->getStructAttribute($attribute);
450 155
        return sprintf('%s%s', $this->getStructAttributeTypeAsPhpType($attribute), $this->useBrackets($attribute, $returnArrayType) ? '[]' : '');
451
    }
452
    /**
453
     * @param StructAttributeModel $attribute
454
     * @param bool $returnArrayType
455
     * @return bool
456
     */
457 155
    protected function useBrackets(StructAttributeModel $attribute, $returnArrayType = true)
458
    {
459 155
        return $returnArrayType && $attribute->isArray();
460
    }
461
    /**
462
     * @param StructAttributeModel $attribute
463
     * @param bool $returnArrayType
464
     * @return string
465
     */
466 155
    protected function getStructAttributeTypeHint(StructAttributeModel $attribute = null, $returnArrayType = true)
467
    {
468 155
        $attribute = $this->getStructAttribute($attribute);
469 155
        return ($returnArrayType && $attribute->isArray()) ? self::TYPE_ARRAY : $this->getStructAttributeType($attribute, true);
470
    }
471
    /**
472
     * @param StructAttributeModel $attribute
473
     * @return string
474
     */
475 185
    public function getStructAttributeTypeAsPhpType(StructAttributeModel $attribute = null)
476
    {
477 185
        $attribute = $this->getStructAttribute($attribute);
478 185
        $attributeType = $this->getStructAttributeType($attribute, true);
479 185
        if (XsdTypes::instance()->isXsd($attributeType)) {
480 140
            $attributeType = self::getPhpType($attributeType);
481 84
        }
482 185
        return $attributeType;
483
    }
484
    /**
485
     * See http://php.net/manual/fr/language.oop5.typehinting.php for these cases
486
     * Also see http://www.w3schools.com/schema/schema_dtypes_numeric.asp
487
     * @param mixed $type
488
     * @param mixed $fallback
489
     * @return mixed
490
     */
491 185
    public static function getValidType($type, $fallback = null)
492
    {
493 185
        return XsdTypes::instance()->isXsd(str_replace('[]', '', $type)) ? $fallback : $type;
494
    }
495
    /**
496
     * See http://php.net/manual/fr/language.oop5.typehinting.php for these cases
497
     * Also see http://www.w3schools.com/schema/schema_dtypes_numeric.asp
498
     * @param mixed $type
499
     * @param mixed $fallback
500
     * @return mixed
501
     */
502 180
    public static function getPhpType($type, $fallback = self::TYPE_STRING)
503
    {
504 180
        return XsdTypes::instance()->isXsd(str_replace('[]', '', $type)) ? XsdTypes::instance()->phpType($type) : $fallback;
505
    }
506
}
507