Completed
Push — feature/issue-54 ( 74298b...f633ee )
by Mikaël
32:39
created

AbstractModel::getCleanName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1
Metric Value
dl 0
loc 4
ccs 1
cts 1
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace WsdlToPhp\PackageGenerator\Model;
4
5
use WsdlToPhp\PackageGenerator\ConfigurationReader\GeneratorOptions;
6
use WsdlToPhp\PackageGenerator\ConfigurationReader\PhpReservedKeyword;
7
use WsdlToPhp\PackageGenerator\ConfigurationReader\AbstractReservedWord;
8
use WsdlToPhp\PackageGenerator\Generator\Generator;
9
use WsdlToPhp\PackageGenerator\Generator\Utils as GeneratorUtils;
10
use WsdlToPhp\PackageGenerator\Generator\AbstractGeneratorAware;
11
12
/**
13
 * Class AbstractModel defines the basic properties and methods to operations and structs extracted from the WSDL
14
 */
15
abstract class AbstractModel extends AbstractGeneratorAware
16
{
17
    /**
18
     * Constant used to define the key to store documentation value in meta
19
     * @var string
20
     */
21
    const META_DOCUMENTATION = 'documentation';
22
    /**
23
     * Original name od the element
24
     * @var string
25
     */
26
    private $name = '';
27
    /**
28
     * Values associated to the operation
29
     * @var string[]
30
     */
31
    private $meta = array();
32
    /**
33
     * Define the inheritance of a struct by the name of the parent struct or type
34
     * @var string
35
     */
36
    private $inheritance = '';
37
    /**
38
     * Store the object which owns the current model
39
     * @var AbstractModel
40
     */
41
    private $owner = null;
42
    /**
43
     * Indicates that the current elemen is an abstract element.
44
     * It allows to generated an abstract class.
45
     * This will happen for element/complexType that are defined with abstract="true"
46
     * @var bool
47
     */
48
    private $isAbstract = false;
49
    /**
50
     * Replaced keywords time in order to generate unique new keyword
51
     * @var array
52
     */
53
    private static $replacedPhpReservedKeywords = array();
54
    /**
55
     * Replaced methods time in order to generate unique new method
56
     * @var array
57
     */
58
    private $replacedReservedMethods = array();
59
    /**
60
     * Unique name generated in order to ensure unique naming (for struct constructor and setters/getters even for different case attribute name whith same value)
61
     * @var array
62
     */
63
    private static $uniqueNames = array();
64 716
    /**
65
     * Main constructor
66 716
     * @uses AbstractModel::setName()
67 716
     * @param Generator $generator
68 716
     * @param string $name the original name
69
     */
70
    public function __construct(Generator $generator, $name)
71
    {
72
        parent::__construct($generator);
73
        $this->setName($name);
74
    }
75
    /**
76 208
     * @uses AbstractModel::getInheritedMoel()
77
     * @uses AbstractModel::getPackagedName()
78 208
     * @uses AbstractModel::getExtends()
79 208
     * @uses Struct::getIsStruct()
80 20
     * @return string
81 15
     */
82 208
    public function getExtendsClassName()
83 196
    {
84 147
        $extends = '';
85 208
        if (($model = $this->getInheritedMoel()) instanceof Struct && $model->getIsStruct()) {
86
            $extends = $model->getPackagedName();
87
        }
88
        if (empty($extends)) {
89
            $extends = $this->getExtends(true);
90
        }
91 268
        return $extends;
92
    }
93 268
    /**
94
     * Returns the name of the class the current class inherits from
95
     * @return string
96
     */
97
    public function getInheritance()
98
    {
99 172
        return $this->inheritance;
100
    }
101 172
    /**
102 172
     * Sets the name of the class the current class inherits from
103
     * @param AbstractModel
104
     */
105
    public function setInheritance($inheritance = '')
106
    {
107
        $this->inheritance = $inheritance;
108
        return $this;
109
    }
110 208
    /**
111
     * @uses AbstractGeneratorAware::getGenerator()
112 208
     * @uses Generator::getStruct()
113
     * @uses AbstractModel::getInheritance()
114
     * @return Struct
115
     */
116
    public function getInheritedMoel()
117
    {
118 288
        return $this->getGenerator()->getStruct($this->getInheritance());
119
    }
120 288
    /**
121
     * Returns the meta
122
     * @return string[]
123
     */
124
    public function getMeta()
125
    {
126
        return $this->meta;
127 4
    }
128
    /**
129 4
     * Sets the meta
130 4
     * @param string[] $meta
131
     * @return AbstractModel
132
     */
133
    public function setMeta(array $meta = array())
134
    {
135
        $this->meta = $meta;
136
        return $this;
137
    }
138
    /**
139
     * Add meta information to the operation
140 364
     * @uses AbstractModel::getMeta()
141
     * @throws \InvalidArgumentException
142 364
     * @param string $metaName
143 8
     * @param mixed $metaValue
144
     * @return AbstractModel
145 356
     */
146 356
    public function addMeta($metaName, $metaValue)
147 356
    {
148 352
        if (!is_scalar($metaName) || (!is_scalar($metaValue) && !is_array($metaValue))) {
149 286
            throw new \InvalidArgumentException(sprintf('Invalid meta name "%s" or value "%s". Please provide scalar meta name and scalar or array meta value.', gettype($metaName), gettype($metaValue)), __LINE__);
150 56
        }
151 62
        $metaValue = is_scalar($metaValue) ? trim($metaValue) : $metaValue;
152 4
        if ((is_scalar($metaValue) && $metaValue !== '') || is_array($metaValue)) {
153 3
            if (!array_key_exists($metaName, $this->meta)) {
154 16
                $this->meta[$metaName] = $metaValue;
155
            } elseif (is_array($this->meta[$metaName]) && is_array($metaValue)) {
156 356
                $this->meta[$metaName] = array_merge($this->meta[$metaName], $metaValue);
157 267
            } elseif (is_array($this->meta[$metaName])) {
158 356
                array_push($this->meta[$metaName], $metaValue);
159
            } else {
160
                $this->meta[$metaName] = $metaValue;
161
            }
162
            ksort($this->meta);
163
        }
164
        return $this;
165
    }
166
    /**
167
     * Sets the documentation meta value.
168 104
     * Documentation is set as an array so if multiple documentation nodes are set for an unique element, it will gather them.
169
     * @uses AbstractModel::META_DOCUMENTATION
170 104
     * @uses AbstractModel::addMeta()
171
     * @param string $documentation the documentation from the WSDL
172
     * @return AbstractModel
173
     */
174
    public function setDocumentation($documentation)
175
    {
176
        return $this->addMeta(self::META_DOCUMENTATION, is_array($documentation) ? $documentation : array($documentation));
177
    }
178
    /**
179 232
     * Returns a meta value according to its name
180
     * @uses AbstractModel::getMeta()
181 232
     * @param string $metaName the meta information name
182 232
     * @param mixed $fallback the fallback value if unset
183
     * @return mixed the meta information value
184
     */
185
    public function getMetaValue($metaName, $fallback = null)
186
    {
187
        $meta = $this->getMeta();
188
        return array_key_exists($metaName, $meta) ? $meta[$metaName] : $fallback;
189
    }
190 104
    /**
191
     * Returns the value of the first meta value assigned to the name
192 104
     * @param array $names the meta names to check
193 104
     * @param mixed $fallback the fallback value if anyone is set
194 104
     * @return mixed the meta information value
195 86
     */
196
    public function getMetaValueFirstSet(array $names, $fallback = null)
197 57
    {
198 76
        $meta = $this->getMeta();
199
        foreach ($names as $name) {
200
            if (array_key_exists($name, $meta)) {
201
                return $meta[$name];
202
            }
203
        }
204 628
        return $fallback;
205
    }
206 628
    /**
207
     * Returns the original name extracted from the WSDL
208
     * @return string
209
     */
210
    public function getName()
211
    {
212
        return $this->name;
213 716
    }
214
    /**
215 716
     * Sets the original name extracted from the WSDL
216 716
     * @param string $name
217
     * @return AbstractModel
218
     */
219
    public function setName($name)
220
    {
221
        $this->name = $name;
222
        return $this;
223
    }
224
    /**
225 512
     * Returns a valid clean name for PHP
226
     * @uses AbstractModel::getName()
227 512
     * @uses AbstractModel::cleanString()
228
     * @param bool $keepMultipleUnderscores optional, allows to keep the multiple consecutive underscores
229
     * @return string
230
     */
231
    public function getCleanName($keepMultipleUnderscores = true)
232
    {
233 508
        return self::cleanString($this->getName(), $keepMultipleUnderscores);
234
    }
235 508
    /**
236
     * Returns the owner model object
237
     * @return AbstractModel
238
     */
239
    public function getOwner()
240
    {
241
        return $this->owner;
242 552
    }
243
    /**
244 552
     * Sets the owner model object
245 552
     * @param AbstractModel $owner object the owner of the current model
246
     * @return AbstractModel
247
     */
248
    public function setOwner(AbstractModel $owner)
249
    {
250 212
        $this->owner = $owner;
251
        return $this;
252 212
    }
253
    /**
254
     * @return bool
255
     */
256
    public function getIsAbstract()
257
    {
258 20
        return $this->isAbstract;
259
    }
260 20
    /**
261 20
     * @param bool $isAbstract
262
     * @return AbstractModel
263
     */
264
    public function setIsAbstract($isAbstract)
265
    {
266
        $this->isAbstract = $isAbstract;
267
        return $this;
268
    }
269 180
    /**
270
     * Returns true if the original name is safe to use as a PHP property, variable name or class name
271 180
     * @uses AbstractModel::getName()
272
     * @uses AbstractModel::getCleanName()
273
     * @return bool
274
     */
275
    public function nameIsClean()
276
    {
277
        return ($this->getName() !== '' && $this->getName() === $this->getCleanName());
278
    }
279
    /**
280
     * Returns the packaged name
281
     * @uses AbstractModel::getNamespace()
282
     * @uses AbstractModel::getCleanName()
283
     * @uses AbstractModel::getContextualPart()
284
     * @uses AbstractModel::uniqueName()
285
     * @uses AbstractModel::replacePhpReservedKeyword()
286 500
     * @uses AbstractGeneratorAware::getGenerator()
287
     * @uses Generator::getOptionPrefix()
288 500
     * @uses Generator::getOptionSuffix()
289 500
     * @uses AbstractModel::uniqueName() to ensure unique naming of struct case sensitively
290 196
     * @return string
291 147
     */
292 500
    public function getPackagedName($namespaced = false)
293 500
    {
294 268
        $nameParts = array();
295 201
        if ($namespaced && $this->getNamespace() !== '') {
296 260
            $nameParts[] = sprintf('\%s\\', $this->getNamespace());
297
        }
298 500
        $cleanName = $this->getCleanName();
299 500
        if ($this->getGenerator()->getOptionPrefix() !== '') {
300 24
            $nameParts[] = $this->getGenerator()->getOptionPrefix();
301 18
        } else {
302 500
            $cleanName = self::replacePhpReservedKeyword($cleanName);
303
        }
304
        $nameParts[] = ucfirst(self::uniqueName($cleanName, $this->getContextualPart()));
305
        if ($this->getGenerator()->getOptionSuffix() !== '') {
306
            $nameParts[] = $this->getGenerator()->getOptionSuffix();
307
        }
308 64
        return implode('', $nameParts);
309
    }
310 64
    /**
311
     * Allows to define the contextual part of the class name for the package
312
     * @return string
313
     */
314
    public function getContextualPart()
315
    {
316
        return '';
317 32
    }
318
    /**
319 32
     * Allows to define from which class the curent model extends
320
     * @param bool $short
321
     * @return string|null
322
     */
323
    public function getExtends($short = false)
324
    {
325
        return '';
326
    }
327
    /**
328
     * @uses AbstractGeneratorAware::getGenerator()
329 236
     * @uses Generator::getOptionNamespacePrefix()
330
     * @uses Generator::getOptionPrefix()
331 236
     * @uses Generator::getOptionSuffix()
332 236
     * @uses AbstractModel::getSubDirectory()
333 236
     * @return string
334 228
     */
335 184
    public function getNamespace()
336 182
    {
337 63
        $namespaces = array();
338 6
        $namespace = $this->getGenerator()->getOptionNamespacePrefix();
339 171
        if (empty($namespace)) {
340 8
            if ($this->getGenerator()->getOptionPrefix() !== '') {
341
                $namespaces[] = $this->getGenerator()->getOptionPrefix();
342 236
            } elseif ($this->getGenerator()->getOptionSuffix() !== '') {
343 232
                $namespaces[] = $this->getGenerator()->getOptionSuffix();
344 174
            }
345 236
        } else {
346
            $namespaces[] = $namespace;
347
        }
348
        if ($this->getSubDirectory() !== '') {
349
            $namespaces[] = $this->getSubDirectory();
350
        }
351
        return implode('\\', $namespaces);
352
    }
353
    /**
354
     * Returns directory where to store class and create it if needed
355 260
     * @uses AbstractGeneratorAware::getGenerator()
356
     * @uses AbstractModel::getOptionCategory()
357 260
     * @uses AbstractGeneratorAware::getContextualPart()
358 260
     * @uses GeneratorOptions::VALUE_CAT
359 260
     * @return string
360 195
     */
361 260
    public function getSubDirectory()
362
    {
363
        $subDirectory = '';
364
        if ($this->getGenerator()->getOptionCategory() === GeneratorOptions::VALUE_CAT) {
365
            $subDirectory = $this->getContextualPart();
366
        }
367
        return $subDirectory;
368 4
    }
369
    /**
370 4
     * Returns the sub package name which the model belongs to
371
     * Must be overridden by sub classes
372
     * @return array
373
     */
374
    public function getDocSubPackages()
375
    {
376
        return array();
377
    }
378
    /**
379 516
     * Clean a string to make it valid as PHP variable
380
     * @uses GeneratorUtils::cleanString()
381 516
     * @param string $string the string to clean
382
     * @param bool $keepMultipleUnderscores optional, allows to keep the multiple consecutive underscores
383
     * @return string
384
     */
385
    public static function cleanString($string, $keepMultipleUnderscores = true)
386
    {
387
        return GeneratorUtils::cleanString($string, $keepMultipleUnderscores);
388
    }
389
    /**
390
     * Returns a usable keyword for a original keyword
391 496
     * @uses PhpReservedKeyword::instance()
392
     * @uses PhpReservedKeyword::is()
393 496
     * @param string $keyword the keyword
394 496
     * @param string $context the context
395 112
     * @return string
396 60
     */
397 60
    public static function replacePhpReservedKeyword($keyword, $context = null)
398 32
    {
399 24
        if (PhpReservedKeyword::instance()->is($keyword)) {
400 28
            if ($context !== null) {
401
                $keywordKey = $keyword . '_' . $context;
402 60
                if (!array_key_exists($keywordKey, self::$replacedPhpReservedKeywords)) {
403
                    self::$replacedPhpReservedKeywords[$keywordKey] = 0;
404 88
                } else {
405
                    self::$replacedPhpReservedKeywords[$keywordKey]++;
406
                }
407 496
                return '_' . $keyword . (self::$replacedPhpReservedKeywords[$keywordKey] ? '_' . self::$replacedPhpReservedKeywords[$keywordKey] : '');
408
            } else {
409
                return '_' . $keyword;
410
            }
411
        } else {
412
            return $keyword;
413
        }
414
    }
415
    /**
416
     * @throws \InvalidArgumentException
417 504
     * @param $filename
418
     * @return AbstractReservedWord
419 504
     */
420 504
    public function getReservedMethodsInstance($filename = null)
421 504
    {
422 500
        throw new \InvalidArgumentException(sprintf('The method %s should be defined in the class %s', __FUNCTION__, get_called_class(), __LINE__));
423 432
    }
424 428
    /**
425 321
     * Returns a usable method for a original method
426 32
     * @uses PhpReservedKeywords::instance()
427
     * @uses PhpReservedKeywords::is()
428 432
     * @param string $keyword the keyword
0 ignored issues
show
Bug introduced by
There is no parameter named $keyword. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
429 432
     * @param string $context the context
430 432
     * @return string
431
     */
432
    public function replaceReservedMethod($methodName, $context = null)
433
    {
434
        if ($this->getReservedMethodsInstance()->is($methodName)) {
435
            if ($context !== null) {
436 284
                $methodKey = $methodName . '_' . $context;
437
                if (!array_key_exists($methodKey, $this->replacedReservedMethods)) {
438 284
                    $this->replacedReservedMethods[$methodKey] = 0;
439 284
                } else {
440
                    $this->replacedReservedMethods[$methodKey]++;
441
                }
442
                return '_' . $methodName . ($this->replacedReservedMethods[$methodKey] ? '_' . $this->replacedReservedMethods[$methodKey] : '');
443
            } else {
444 260
                return '_' . $methodName;
445
            }
446 260
        } else {
447 260
            return $methodName;
448
        }
449
    }
450
    /**
451
     * Static method wich returns a unique name case sensitively
452
     * Useful to name methods case sensitively distinct, see http://the-echoplex.net/log/php-case-sensitivity
453
     * @param string $name the original name
454
     * @param string $context the context where the name is needed unique
455
     * @return string
456
     */
457
    protected static function uniqueName($name, $context)
458
    {
459
        $insensitiveKey = strtolower($name . '_' . $context);
460
        $sensitiveKey = $name . '_' . $context;
461
        if (array_key_exists($sensitiveKey, self::$uniqueNames)) {
462
            return self::$uniqueNames[$sensitiveKey];
463
        } elseif (!array_key_exists($insensitiveKey, self::$uniqueNames)) {
464
            self::$uniqueNames[$insensitiveKey] = 0;
465
        } else {
466
            self::$uniqueNames[$insensitiveKey]++;
467
        }
468
        $uniqueName = $name . (self::$uniqueNames[$insensitiveKey] ? '_' . self::$uniqueNames[$insensitiveKey] : '');
469
        self::$uniqueNames[$sensitiveKey] = $uniqueName;
470
        return $uniqueName;
471
    }
472
    /**
473
     * Gives the availability for test purpose and multiple package generation to purge unique names
474
     * @todo see if it can be removed by reviewing how unique names are generated
475
     */
476
    public static function purgeUniqueNames()
477
    {
478
        self::$uniqueNames = array();
479
    }
480
    /**
481
     * Gives the availability for test purpose and multiple package generation to purge reserved keywords usage
482
     * @todo see if it can be removed by reviewing how reserved keywords are generated
483
     */
484
    public static function purgePhpReservedKeywords()
485
    {
486
        self::$replacedPhpReservedKeywords = array();
487
    }
488
    /**
489
     * Gives the availability for test purpose and multiple package generation to purge reserved methods usage
490
     * @todo see if it can be removed by reviewing how reserved methods are generated
491
     */
492
    public static function purgeReservedMethods()
493
    {
494
        self::$replacedReservedMethods = array();
495
    }
496
}
497