Completed
Push — feature/issue-41 ( 90ee1a...9015ef )
by Mikaël
25:01
created

AbstractModelFile::getMethodAnnotationBlock()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 1
ccs 0
cts 0
cp 0
nc 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 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 126
        $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 126
        $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 102
        }
162 156
        if (count($this->getModel()->getDocSubPackages()) > 0) {
163 156
            $block->addChild(new PhpAnnotation(self::ANNOTATION_SUB_PACKAGE, implode(',', $this->getModel()->getDocSubPackages())));
164 117
        }
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 124
        } elseif ($this->getGenerator()->getOptionSuffix() !== '') {
176 8
            $packageName = $this->getGenerator()->getOptionSuffix();
177 6
        }
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 117
        }
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 117
        $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 126
        $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 126
            $this
274 168
                ->getFile()
275 168
                    ->setNamespace($this->getModel()->getNamespace());
276 126
        }
277 168
        return $this;
278
    }
279
    /**
280
     * @return AbstractModelFile
281
     */
282 168
    protected function defineUseStatement()
283
    {
284 168
        if ($this->getModel()->getExtends() !== '') {
285 96
            $this
286 128
                ->getFile()
287 128
                    ->addUse($this->getModel()->getExtends(), null, true);
288 96
        }
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 36
            }
304 48
            $class->addConstantElement($constant);
305 126
        }
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 57
            }
321 76
            $class->addPropertyElement($property);
322 126
        }
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 126
            }
338 168
            $class->addMethodElement($method);
339 126
        }
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 117
        ));
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 21
        }
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 57
        }
420 76
        return $model;
421
    }
422
    /**
423
     * @param StructAttributeModel $attribute
424
     * @param bool $namespaced
425
     * @return string
426
     */
427 60
    protected function getStructAttributeType(StructAttributeModel $attribute = null, $namespaced = false)
428
    {
429 60
        $attribute = $this->getStructAttribute($attribute);
430 60
        $inheritance = $attribute->getInheritance();
431 60
        $type = empty($inheritance) ? $attribute->getType() : $inheritance;
432 60
        $model = $this->getModelFromStructAttribute($attribute);
433 60
        if ($model instanceof StructModel) {
434 52
            $modelInheritance = $model->getInheritance();
435 52
            if ($model->getIsStruct() === false) {
436 20
                $type = !empty($modelInheritance) ? $modelInheritance : $type;
437 52
            } elseif ($model->getIsRestriction() === true) {
438 40
                $type = !empty($modelInheritance) ? $modelInheritance : self::TYPE_STRING;
439 30
            } else {
440 40
                $type = $model->getPackagedName($namespaced);
441
            }
442 39
        }
443 60
        return $type;
444
    }
445
    /**
446
     * @param StructAttributeModel $attribute
447
     * @return string
448
     */
449 76
    protected function getStructAttributeTypeGetAnnotation(StructAttributeModel $attribute = null) {
450 76
        $attribute = $this->getStructAttribute($attribute);
451 76
        return sprintf('%s%s%s', $this->getStructAttributeType($attribute, true), $attribute->isArray() ? '[]' : '', $attribute->isRequired() ? '': '|null');
452
    }
453
    /**
454
     * @param StructAttributeModel $attribute
455
     * @return string
456
     */
457 76
    protected function getStructAttributeTypeSetAnnotation(StructAttributeModel $attribute = null) {
458 76
        $attribute = $this->getStructAttribute($attribute);
459 76
        return sprintf('%s%s', $this->getStructAttributeType($attribute, true), $attribute->isArray() ? '[]' : '');
460
    }
461
    /**
462
     * @param StructAttributeModel $attribute
463
     * @return string
464
     */
465 56
    protected function getStructAttributeTypeHint(StructAttributeModel $attribute = null) {
466 56
        $attribute = $this->getStructAttribute($attribute);
467 56
        return $attribute->isArray() ? self::TYPE_ARRAY : $this->getStructAttributeType($attribute, true);
468
    }
469
    /**
470
     * See http://php.net/manual/fr/language.oop5.typehinting.php for these cases
471
     * Also see http://www.w3schools.com/schema/schema_dtypes_numeric.asp
472
     * @param mixed $type
473
     * @param mixed $fallback
474
     * @return mixed
475
     */
476 56
    public static function getValidType($type, $fallback = null)
477
    {
478 56
        return XsdTypes::instance()->isXsd(str_replace('[]', '', $type)) ? $fallback : $type;
479
    }
480
    /**
481
     * See http://php.net/manual/fr/language.oop5.typehinting.php for these cases
482
     * Also see http://www.w3schools.com/schema/schema_dtypes_numeric.asp
483
     * @param mixed $type
484
     * @param mixed $fallback
485
     * @return mixed
486
     */
487 4
    public static function getPhpType($type, $fallback = self::TYPE_STRING)
488
    {
489 4
        return XsdTypes::instance()->isXsd(str_replace('[]', '', $type)) ? XsdTypes::instance()->phpType($type) : $fallback;
490
    }
491
}
492