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

AbstractModel::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
crap 1
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 12
        }
78 168
        if (empty($extends)) {
79 164
            $extends = $this->getExtends(true);
80 164
        }
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 300
            } elseif (is_array($this->meta[$metaName]) && is_array($metaValue)) {
143 40
                $this->meta[$metaName] = array_merge($this->meta[$metaName], $metaValue);
144 60
            } elseif (is_array($this->meta[$metaName])) {
145 4
                array_push($this->meta[$metaName], $metaValue);
146 4
            } else {
147 24
                $this->meta[$metaName] = $metaValue;
148
            }
149 300
            ksort($this->meta);
150 300
        }
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 68
                return $this->meta[$name];
187
            }
188 48
        }
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::cleanString($this->getName(), $keepMultipleUnderscores);
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 156
        }
278 428
        $cleanName = $this->getCleanName();
279 228
        if ($this->getGenerator()->getOptionPrefix() !== '') {
280 228
            $nameParts[] = $this->getGenerator()->getOptionPrefix();
281 428
        } else {
282 428
            $cleanName = self::replaceReservedPhpKeyword($cleanName, null);
283 24
        }
284 24
285 428
        $nameParts[] = ucfirst(self::uniqueName($cleanName, $this->getContextualPart()));
286
        if ($this->getGenerator()->getOptionSuffix() !== '') {
287
            $nameParts[] = $this->getGenerator()->getOptionSuffix();
288
        }
289
        return implode('', $nameParts);
290
    }
291 64
    /**
292
     * Allows to define the contextual part of the class name for the package
293 64
     * @return string
294
     */
295
    public function getContextualPart()
296
    {
297
        return '';
298
    }
299
    /**
300 32
     * Allows to define from which class the curent model extends
301
     * @param bool $short
302 32
     * @return string|null
303
     */
304
    public function getExtends($short = false)
305
    {
306
        return '';
307 196
    }
308
    /**
309 196
     * @return string
310 196
     */
311 196
    public function getNamespace()
312 188
    {
313 156
        $namespaces = array();
314 188
        $namespace = $this->getGenerator()->getOptionNamespacePrefix();
315 8
        if (empty($namespace)) {
316 8
            if ($this->getGenerator()->getOptionPrefix() !== '') {
317 188
                $namespaces[] = $this->getGenerator()->getOptionPrefix();
318 8
            } elseif ($this->getGenerator()->getOptionSuffix() !== '') {
319
                $namespaces[] = $this->getGenerator()->getOptionSuffix();
320 196
            }
321 192
        } else {
322 192
            $namespaces[] = $namespace;
323 196
        }
324
        if ($this->getSubDirectory() !== '') {
325
            $namespaces[] = $this->getSubDirectory();
326
        }
327
        return implode('\\', $namespaces);
328
    }
329 220
    /**
330
     * Returns directory where to store class and create it if needed
331 220
     * @return string
332 220
     */
333 220
    public function getSubDirectory()
334 220
    {
335 220
        $subDirectory = '';
336
        if ($this->getGenerator()->getOptionCategory() === GeneratorOptions::VALUE_CAT) {
337
            $subDirectory = $this->getContextualPart();
338
        }
339
        return $subDirectory;
340
    }
341
    /**
342 4
     * Returns the sub package name which the model belongs to
343
     * Must be overridden by sub classes
344 4
     * @return array
345
     */
346
    public function getDocSubPackages()
347
    {
348
        return array();
349
    }
350
    /**
351
     * Clean a string to make it valid as PHP variable
352 440
     * @param string $string the string to clean
353
     * @param bool $keepMultipleUnderscores optional, allows to keep the multiple consecutive underscores
354 440
     * @return string
355
     */
356
    public static function cleanString($string, $keepMultipleUnderscores = true)
357
    {
358
        return GeneratorUtils::cleanString($string, $keepMultipleUnderscores);
359
    }
360
    /**
361
     * Returns a usable keyword for a original keyword
362 424
     * @param string $keyword the keyword
363
     * @param string $context the context
364 424
     * @return string
365 424
     */
366 52
    public static function replaceReservedPhpKeyword($keyword, $context = null)
367 52
    {
368 36
        $phpReservedKeywordFound = '';
369 36
        if (ReservedKeywords::instance()->is($keyword)) {
370 16
            if ($context !== null) {
371
                $keywordKey = $phpReservedKeywordFound . '_' . $context;
372 52
                if (!array_key_exists($keywordKey, self::$replacedReservedPhpKeywords)) {
373
                    self::$replacedReservedPhpKeywords[$keywordKey] = 0;
374 424
                } else {
375
                    self::$replacedReservedPhpKeywords[$keywordKey]++;
376
                }
377
                return '_' . $keyword . (self::$replacedReservedPhpKeywords[$keywordKey] ? '_' . self::$replacedReservedPhpKeywords[$keywordKey] : '');
378
            } else {
379
                return '_' . $keyword;
380
            }
381
        } else {
382
            return $keyword;
383
        }
384 432
    }
385
    /**
386 432
     * Static method wich returns a unique name case sensitively
387 432
     * Useful to name methods case sensitively distinct, see http://the-echoplex.net/log/php-case-sensitivity
388 432
     * @param string $name the original name
389 428
     * @param string $context the context where the name is needed unique
390 372
     * @return string
391 368
     */
392 368
    protected static function uniqueName($name, $context)
393 32
    {
394
        $insensitiveKey = strtolower($name . '_' . $context);
395 372
        $sensitiveKey = $name . '_' . $context;
396 372
        if (array_key_exists($sensitiveKey, self::$uniqueNames)) {
397 372
            return self::$uniqueNames[$sensitiveKey];
398
        } elseif (!array_key_exists($insensitiveKey, self::$uniqueNames)) {
399
            self::$uniqueNames[$insensitiveKey] = 0;
400
        } else {
401
            self::$uniqueNames[$insensitiveKey]++;
402
        }
403 244
        $uniqueName = $name . (self::$uniqueNames[$insensitiveKey] ? '_' . self::$uniqueNames[$insensitiveKey] : '');
404
        self::$uniqueNames[$sensitiveKey] = $uniqueName;
405 244
        return $uniqueName;
406 244
    }
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 220
    public static function purgeUniqueNames()
412
    {
413 220
        self::$uniqueNames = array();
414 220
    }
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
    public static function purgeReservedKeywords()
420
    {
421
        self::$replacedReservedPhpKeywords = array();
422
    }
423
}
424