Completed
Pull Request — feature/issue-45 (#46)
by
unknown
26:03
created

AbstractModel::replaceReservedPhpKeyword()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 8.125

Importance

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