Passed
Push — 2.x ( 270e0d...5f9cdf )
by Mikaël
24:20
created

AbstractModelFile::isAttributeAList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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