Completed
Push — develop ( 2afd17...8aece3 )
by Mikaël
24:19
created

AbstractModelFile::setModel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

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