Completed
Push — develop ( 695f05...cce551 )
by Mikaël
98:14 queued 95:30
created

defineModelAnnotationsFromInheritance()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

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