Completed
Push — master ( c9e623...1bff5d )
by Mikaël
55:40 queued 34:00
created

AbstractModel::getMetaValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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