Completed
Push — feature/issue-158 ( 8b9ab6...25acf9 )
by Mikaël
23:05 queued 36s
created

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