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

AbstractModel::replaceReservedPhpKeyword()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
ccs 12
cts 12
cp 1
rs 8.8571
cc 5
eloc 14
nc 6
nop 2
crap 5
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 648
    public function __construct(Generator $generator, $name)
65
    {
66 648
        parent::__construct($generator);
67 648
        $this->setName($name);
68 648
    }
69
    /**
70
     * @return string
71
     */
72 172
    public function getExtendsClassName()
73
    {
74 172
        $extends = '';
75 172
        if (($model = $this->getInheritedMoel()) instanceof Struct && $model->getIsStruct()) {
76 12
            $extends = $model->getPackagedName();
77 9
        }
78 172
        if (empty($extends)) {
79 168
            $extends = $this->getExtends(true);
80 126
        }
81 172
        return $extends;
82
    }
83
    /**
84
     * Returns the name of the class the current class inherits from
85
     * @return string
86
     */
87 196
    public function getInheritance()
88
    {
89 196
        return $this->inheritance;
90
    }
91
    /**
92
     * Sets the name of the class the current class inherits from
93
     * @param AbstractModel
94
     */
95 128
    public function setInheritance($inheritance = '')
96
    {
97 128
        $this->inheritance = $inheritance;
98 128
        return $this;
99
    }
100
    /**
101
     * @return Struct
102
     */
103 172
    public function getInheritedMoel()
104
    {
105 172
        return $this->getGenerator()->getStruct($this->getInheritance());
106
    }
107
    /**
108
     * Returns the meta
109
     * @return array
110
     */
111 304
    public function getMeta()
112
    {
113 304
        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 312
    public function addMeta($metaName, $metaValue)
134
    {
135 312
        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 304
        $metaValue = is_scalar($metaValue) ? trim($metaValue) : $metaValue;
139 304
        if ((is_scalar($metaValue) && $metaValue !== '') || is_array($metaValue)) {
140 304
            if (!array_key_exists($metaName, $this->getMeta())) {
141 300
                $this->meta[$metaName] = $metaValue;
142 244
            } elseif (is_array($this->meta[$metaName]) && is_array($metaValue)) {
143 44
                $this->meta[$metaName] = array_merge($this->meta[$metaName], $metaValue);
144 56
            } elseif (is_array($this->meta[$metaName])) {
145 4
                array_push($this->meta[$metaName], $metaValue);
146 3
            } else {
147 28
                $this->meta[$metaName] = $metaValue;
148
            }
149 304
            ksort($this->meta);
150 228
        }
151 304
        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 84
    public function setDocumentation($documentation)
162
    {
163 84
        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 192
    public function getMetaValue($metaName, $fallback = null)
173
    {
174 192
        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 556
    public function getName()
196
    {
197 556
        return $this->name;
198
    }
199
    /**
200
     * Sets the original name extracted from the WSDL
201
     * @param string $name
202
     * @return AbstractModel
203
     */
204 648
    public function setName($name)
205
    {
206 648
        $this->name = $name;
207 648
        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 444
    public function getCleanName($keepMultipleUnderscores = true)
217
    {
218 444
        return self::cleanString($this->getName(), $keepMultipleUnderscores);
219
    }
220
    /**
221
     * Returns the owner model object
222
     * @return AbstractModel
223
     */
224 436
    public function getOwner()
225
    {
226 436
        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 480
    public function setOwner(AbstractModel $owner)
234
    {
235 480
        $this->owner = $owner;
236 480
        return $this;
237
    }
238
    /**
239
     * @return bool
240
     */
241 176
    public function getIsAbstract()
242
    {
243 176
        return $this->isAbstract;
244
    }
245
    /**
246
     * @param bool $isAbstract
247
     * @return AbstractModel
248
     */
249 16
    public function setIsAbstract($isAbstract)
250
    {
251 16
        $this->isAbstract = $isAbstract;
252 16
        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 144
    public function nameIsClean()
261
    {
262 144
        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 432
    public function getPackagedName($namespaced = false)
273
    {
274 432
        $nameParts = array();
275 432
        if ($namespaced && $this->getNamespace() !== '') {
276 160
            $nameParts[] = sprintf('\%s\\', $this->getNamespace());
277 120
        }
278 432
        $cleanName = $this->getCleanName();
279 432
        if ($this->getGenerator()->getOptionPrefix() !== '') {
280 232
            $nameParts[] = $this->getGenerator()->getOptionPrefix();
281 174
        } else {
282 220
            $cleanName = self::replaceReservedPhpKeyword($cleanName, null);
283
        }
284
285 432
        $nameParts[] = ucfirst(self::uniqueName($cleanName, $this->getContextualPart()));
286 432
        if ($this->getGenerator()->getOptionSuffix() !== '') {
287 24
            $nameParts[] = $this->getGenerator()->getOptionSuffix();
288 18
        }
289 432
        return implode('', $nameParts);
290
    }
291
    /**
292
     * Allows to define the contextual part of the class name for the package
293
     * @return string
294
     */
295 64
    public function getContextualPart()
296
    {
297 64
        return '';
298
    }
299
    /**
300
     * Allows to define from which class the curent model extends
301
     * @param bool $short
302
     * @return string|null
303
     */
304 32
    public function getExtends($short = false)
305
    {
306 32
        return '';
307
    }
308
    /**
309
     * @return string
310
     */
311 200
    public function getNamespace()
312
    {
313 200
        $namespaces = array();
314 200
        $namespace = $this->getGenerator()->getOptionNamespacePrefix();
315 200
        if (empty($namespace)) {
316 192
            if ($this->getGenerator()->getOptionPrefix() !== '') {
317 156
                $namespaces[] = $this->getGenerator()->getOptionPrefix();
318 153
            } elseif ($this->getGenerator()->getOptionSuffix() !== '') {
319 54
                $namespaces[] = $this->getGenerator()->getOptionSuffix();
320 6
            }
321 144
        } else {
322 8
            $namespaces[] = $namespace;
323
        }
324 200
        if ($this->getSubDirectory() !== '') {
325 196
            $namespaces[] = $this->getSubDirectory();
326 147
        }
327 200
        return implode('\\', $namespaces);
328
    }
329
    /**
330
     * Returns directory where to store class and create it if needed
331
     * @return string
332
     */
333 224
    public function getSubDirectory()
334
    {
335 224
        $subDirectory = '';
336 224
        if ($this->getGenerator()->getOptionCategory() === GeneratorOptions::VALUE_CAT) {
337 224
            $subDirectory = $this->getContextualPart();
338 168
        }
339 224
        return $subDirectory;
340
    }
341
    /**
342
     * Returns the sub package name which the model belongs to
343
     * Must be overridden by sub classes
344
     * @return array
345
     */
346 4
    public function getDocSubPackages()
347
    {
348 4
        return array();
349
    }
350
    /**
351
     * Clean a string to make it valid as PHP variable
352
     * @param string $string the string to clean
353
     * @param bool $keepMultipleUnderscores optional, allows to keep the multiple consecutive underscores
354
     * @return string
355
     */
356 444
    public static function cleanString($string, $keepMultipleUnderscores = true)
357
    {
358 444
        return GeneratorUtils::cleanString($string, $keepMultipleUnderscores);
359
    }
360
    /**
361
     * Returns a usable keyword for a original keyword
362
     * @param string $keyword the keyword
363
     * @param string $context the context
364
     * @return string
365
     */
366 428
    public static function replaceReservedPhpKeyword($keyword, $context = null)
367
    {
368 428
        $phpReservedKeywordFound = '';
369 428
        if (ReservedKeywords::instance()->is($keyword)) {
370 100
            if ($context !== null) {
371 52
                $keywordKey = $phpReservedKeywordFound . '_' . $context;
372 52
                if (!array_key_exists($keywordKey, self::$replacedReservedPhpKeywords)) {
373 36
                    self::$replacedReservedPhpKeywords[$keywordKey] = 0;
374 27
                } else {
375 16
                    self::$replacedReservedPhpKeywords[$keywordKey]++;
376
                }
377 52
                return '_' . $keyword . (self::$replacedReservedPhpKeywords[$keywordKey] ? '_' . self::$replacedReservedPhpKeywords[$keywordKey] : '');
378
            } else {
379 72
                return '_' . $keyword;
380
            }
381
        } else {
382 428
            return $keyword;
383
        }
384
    }
385
    /**
386
     * Static method wich returns a unique name case sensitively
387
     * Useful to name methods case sensitively distinct, see http://the-echoplex.net/log/php-case-sensitivity
388
     * @param string $name the original name
389
     * @param string $context the context where the name is needed unique
390
     * @return string
391
     */
392 436
    protected static function uniqueName($name, $context)
393
    {
394 436
        $insensitiveKey = strtolower($name . '_' . $context);
395 436
        $sensitiveKey = $name . '_' . $context;
396 436
        if (array_key_exists($sensitiveKey, self::$uniqueNames)) {
397 432
            return self::$uniqueNames[$sensitiveKey];
398 376
        } elseif (!array_key_exists($insensitiveKey, self::$uniqueNames)) {
399 372
            self::$uniqueNames[$insensitiveKey] = 0;
400 279
        } else {
401 32
            self::$uniqueNames[$insensitiveKey]++;
402
        }
403 376
        $uniqueName = $name . (self::$uniqueNames[$insensitiveKey] ? '_' . self::$uniqueNames[$insensitiveKey] : '');
404 376
        self::$uniqueNames[$sensitiveKey] = $uniqueName;
405 376
        return $uniqueName;
406
    }
407
    /**
408
     * Gives the availability for test purpose and multiple package generation to purge unique names
409
     * @todo see if it can be removed by reviewing how unique names are generated
410
     */
411 248
    public static function purgeUniqueNames()
412
    {
413 248
        self::$uniqueNames = array();
414 248
    }
415
    /**
416
     * Gives the availability for test purpose and multiple package generation to purge reserved keywords usage
417
     * @todo see if it can be removed by reviewing how reserved keywords are generated
418
     */
419 224
    public static function purgeReservedKeywords()
420
    {
421 224
        self::$replacedReservedPhpKeywords = array();
422 224
    }
423
}
424