Completed
Push — feature/issue-43 ( 7fc434 )
by Mikaël
02:48
created

getRestrictionFromStructAttribute()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

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