Passed
Push — feature/issue-262 ( cafbaa...b58e35 )
by Mikaël
07:31
created

Generator::setOptionStandalone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace WsdlToPhp\PackageGenerator\Generator;
6
7
use InvalidArgumentException;
8
use JsonSerializable;
9
use WsdlToPhp\PackageGenerator\ConfigurationReader\GeneratorOptions;
10
use WsdlToPhp\PackageGenerator\Container\Model\Service as ServiceContainer;
11
use WsdlToPhp\PackageGenerator\Container\Model\Struct as StructContainer;
12
use WsdlToPhp\PackageGenerator\Model\AbstractModel;
13
use WsdlToPhp\PackageGenerator\Model\EmptyModel;
14
use WsdlToPhp\PackageGenerator\Model\Method;
15
use WsdlToPhp\PackageGenerator\Model\Schema;
16
use WsdlToPhp\PackageGenerator\Model\Service;
17
use WsdlToPhp\PackageGenerator\Model\Struct;
18
use WsdlToPhp\PackageGenerator\Model\Wsdl;
19
20
/**
21
 * @method string getOptionCategory()
22
 * @method self   setOptionCategory(string $category)
23
 * @method string getOptionGatherMethods()
24
 * @method self   setOptionGatherMethods(string $gatherMethods)
25
 * @method bool   getOptionGenericConstantsNames()
26
 * @method self   setOptionGenericConstantsNames(bool $genericConstantsNames)
27
 * @method bool   getOptionGenerateTutorialFile()
28
 * @method self   setOptionGenerateTutorialFile(bool $generateTutorialFile)
29
 * @method string getOptionNamespace()
30
 * @method self   setOptionNamespace(string $namespace)
31
 * @method array  getOptionAddComments()
32
 * @method self   setOptionAddComments(array $addComments)
33
 * @method bool   getOptionStandalone()
34 448
 * @method self   setOptionStandalone(bool $standalone)
35
 * @method bool   getOptionValidation()
36
 * @method self   setOptionValidation(bool $validation)
37 448
 * @method string getOptionStructClass()
38 448
 * @method self   setOptionStructClass(string $structClass)
39
 * @method string getOptionStructArrayClass()
40 444
 * @method self   setOptionStructArrayClass(string $structArrayClass)
41
 * @method string getOptionStructEnumClass()
42 66
 * @method self   setOptionStructEnumClass(string $structEnumClass)
43
 * @method string getOptionSoapClientClass()
44 66
 * @method self   setOptionSoapClientClass(string $soapClientClass)
45
 * @method self   setOptionPrefix(string $optionPrefix)
46
 * @method self   setOptionSuffix(string $optionSuffix)
47 26
 * @method string getOptionBasicLogin()
48
 * @method self   setOptionBasicLogin(string $optionBasicLogin)
49 26
 * @method string getOptionBasicPassword()
50
 * @method self   setOptionBasicPassword(string $optionBasicPassword)
51
 * @method string getOptionProxyHost()
52 16
 * @method self   setOptionProxyHost(string $optionProxyHost)
53
 * @method string getOptionProxyPort()
54
 * @method self   setOptionProxyPort(string $optionProxyPort)
55 16
 * @method string getOptionProxyLogin()
56 12
 * @method self   setOptionProxyLogin(string $optionProxyLogin)
57 12
 * @method string getOptionProxyPassword()
58 12
 * @method self   setOptionProxyPassword(string $optionProxyPassword)
59
 * @method string getOptionOrigin()
60
 * @method string getOptionSrcDirname()
61
 * @method self   setOptionSrcDirname(string $optionSrcDirname)
62 14
 * @method array  getOptionSoapOptions()
63
 * @method string getOptionComposerName()
64 14
 * @method array  getOptionComposerSettings()
65
 * @method self   setOptionComposerSettings(array $optionComposerSettings)
66
 * @method string getOptionStructsFolder()
67
 * @method self   setOptionStructsFolder(string $optionStructsFolder)
68
 * @method string getOptionArraysFolder()
69
 * @method self   setOptionArraysFolder(string $optionArraysFolder)
70
 * @method string getOptionEnumsFolder()
71
 * @method self   setOptionEnumsFolder(string $optionEnumsFolder)
72
 * @method string getOptionServicesFolder()
73
 * @method self   setOptionServicesFolder(string $optionServicesFolder)
74
 * @method bool   getOptionSchemasSave()
75 442
 * @method self   setOptionSchemasSave(bool $optionSchemasSave)
76
 * @method string getOptionSchemasFolder()
77 442
 * @method self   setOptionSchemasFolder(string $optionSchemasFolder)
78
 * @method string getOptionXsdTypesPath()
79 442
 * @method self   setOptionXsdTypesPath(string $xsdTypesPath)
80
 */
81
class Generator implements JsonSerializable
82 164
{
83
    protected Wsdl $wsdl;
84 164
85
    protected GeneratorOptions $options;
86
87 74
    protected GeneratorParsers $parsers;
88
89 74
    protected GeneratorFiles $files;
90
91
    protected GeneratorContainers $containers;
92 70
93
    protected ?GeneratorSoapClient $soapClient = null;
94 70
95
    public function __construct(GeneratorOptions $options)
96
    {
97 176
        $this
98
            ->setOptions($options)
99 176
            ->initialize()
100 176
        ;
101 4
    }
102 4
103 4
    public function __call($name, $arguments)
104 4
    {
105 4
        if (($prefix = 'getOption') === substr($name, 0, $length = strlen($prefix)) && empty($arguments)) {
106
            $getMethod = 'get'.substr($name, $length);
107
108 4
            return $this->options->{$getMethod}();
109 4
        }
110
        if (($prefix = 'setOption') === substr($name, 0, $length = strlen($prefix)) && 1 === count($arguments)) {
111
            $setMethod = 'set'.substr($name, $length);
112 176
            $this->options->{$setMethod}(array_shift($arguments));
113
114
            return $this;
115 488
        }
116
117 488
        throw new \BadMethodCallException(sprintf('Method %s is undefined', $name));
118
    }
119
120
    public function getParsers(): GeneratorParsers
121
    {
122
        return $this->parsers;
123
    }
124
125 240
    public function getFiles(): GeneratorFiles
126
    {
127 240
        return $this->files;
128
    }
129
130
    public function generatePackage(): self
131
    {
132
        return $this
133
            ->doSanityChecks()
134
            ->parse()
135
            ->initDirectory()
136
            ->doGenerate()
137 4
        ;
138
    }
139 4
140
    public function parse(): self
141 4
    {
142
        return $this->doParse();
143
    }
144
145
    /**
146
     * Gets the struct by its name
147
     * Starting from issue #157, we know call getVirtual secondly as structs are now betterly parsed and so is their inheritance/type is detected.
148
     *
149 176
     * @param string $structName the original struct name
150
     *
151 176
     * @uses Generator::getStructs()
152
     */
153
    public function getStructByName(string $structName): ?Struct
154
    {
155
        $struct = $this->getStructs()->getStructByName($structName);
156
157
        return $struct ?: $this->getStructs()->getVirtual($structName);
158
    }
159
160
    public function getStructByNameAndType(string $structName, string $type): ?Struct
161 2
    {
162
        return $this->getStructs()->getStructByNameAndType($structName, $type);
163 2
    }
164
165 2
    public function getService(string $serviceName): ?Service
166
    {
167
        return $this->getServices()->getServiceByName($serviceName);
168
    }
169
170
    public function getServiceMethod(string $methodName): ?Method
171
    {
172
        return $this->getService($this->getServiceName($methodName)) instanceof Service ? $this->getService($this->getServiceName($methodName))->getMethod($methodName) : null;
173 48
    }
174
175 48
    public function getServices(bool $usingGatherMethods = false): ServiceContainer
176
    {
177
        $services = $this->containers->getServices();
178
        if ($usingGatherMethods && GeneratorOptions::VALUE_NONE === $this->getOptionGatherMethods()) {
179
            $serviceContainer = new ServiceContainer($this);
180
            $serviceModel = new Service($this, Service::DEFAULT_SERVICE_CLASS_NAME);
181
            foreach ($services as $service) {
182
                foreach ($service->getMethods() as $method) {
183
                    $serviceModel->getMethods()->add($method);
184
                }
185 4
            }
186
            $serviceContainer->add($serviceModel);
187 4
            $services = $serviceContainer;
188
        }
189 4
190
        return $services;
191
    }
192
193
    public function getStructs(): StructContainer
194
    {
195
        return $this->containers->getStructs();
196
    }
197 16
198
    public function getOptionNamespacePrefix(): string
199 16
    {
200
        return $this->options->getNamespace();
201
    }
202
203
    public function setOptionNamespacePrefix(string $namespace): self
204
    {
205
        $this->options->setNamespace($namespace);
206
207
        return $this;
208
    }
209 2
210
    public function getOptionPrefix(bool $ucFirst = true): string
211 2
    {
212
        return $ucFirst ? ucfirst($this->getOptions()->getPrefix()) : $this->getOptions()->getPrefix();
213 2
    }
214
215
    public function getOptionSuffix(bool $ucFirst = true): string
216
    {
217
        return $ucFirst ? ucfirst($this->getOptions()->getSuffix()) : $this->getOptions()->getSuffix();
218
    }
219
220
    public function setOptionOrigin(string $optionOrigin): self
221 240
    {
222
        $this->options->setOrigin($optionOrigin);
223 240
        $this->initWsdl();
224
225
        return $this;
226
    }
227
228
    public function getOptionDestination(): string
229
    {
230
        $destination = $this->options->getDestination();
231
        if (!empty($destination)) {
232
            $destination = rtrim($destination, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
233 14
        }
234
235 14
        return $destination;
236
    }
237 14
238
    public function setOptionDestination(string $optionDestination): self
239
    {
240
        if (!empty($optionDestination)) {
241
            $this->options->setDestination(rtrim($optionDestination, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR);
242
        } else {
243
            throw new InvalidArgumentException('Package\'s destination can\'t be empty', __LINE__);
244
        }
245 160
246
        return $this;
247 160
    }
248
249
    public function setOptionSoapOptions(array $optionSoapOptions): self
250
    {
251
        $this->options->setSoapOptions($optionSoapOptions);
252
253
        if ($this->soapClient) {
254
            $this->soapClient->initSoapClient();
255
        }
256
257 2
        return $this;
258
    }
259 2
260
    public function setOptionComposerName(string $optionComposerName): self
261 2
    {
262
        if (!empty($optionComposerName)) {
263
            $this->options->setComposerName($optionComposerName);
264
        } else {
265
            throw new InvalidArgumentException('Package\'s composer name can\'t be empty', __LINE__);
266
        }
267
268
        return $this;
269 32
    }
270
271 32
    public function getWsdl(): ?Wsdl
272
    {
273
        return $this->wsdl;
274
    }
275
276
    public function addSchemaToWsdl(Wsdl $wsdl, string $schemaLocation): self
277
    {
278
        if (!empty($schemaLocation) && !$wsdl->hasSchema($schemaLocation)) {
279
            $wsdl->addSchema(new Schema($wsdl->getGenerator(), $schemaLocation, $this->getUrlContent($schemaLocation)));
0 ignored issues
show
Bug introduced by
It seems like $this->getUrlContent($schemaLocation) can also be of type null; however, parameter $content of WsdlToPhp\PackageGenerat...l\Schema::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

279
            $wsdl->addSchema(new Schema($wsdl->getGenerator(), $schemaLocation, /** @scrutinizer ignore-type */ $this->getUrlContent($schemaLocation)));
Loading history...
280
        }
281 6
282
        return $this;
283 6
    }
284
285 6
    public function getServiceName(string $methodName): string
286
    {
287
        return ucfirst($this->getGather(new EmptyModel($this, $methodName)));
288
    }
289
290
    public function getOptions(): ?GeneratorOptions
291
    {
292
        return $this->options;
293 110
    }
294
295 110
    public function getSoapClient(): GeneratorSoapClient
296
    {
297
        return $this->soapClient;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->soapClient could return the type null which is incompatible with the type-hinted return WsdlToPhp\PackageGenerat...tor\GeneratorSoapClient. Consider adding an additional type-check to rule them out.
Loading history...
298
    }
299
300
    public function getUrlContent(string $url): ?string
301
    {
302
        if (false !== mb_strpos($url, '://')) {
303
            $content = Utils::getContentFromUrl($url, $this->getOptionBasicLogin(), $this->getOptionBasicPassword(), $this->getOptionProxyHost(), $this->getOptionProxyPort(), $this->getOptionProxyLogin(), $this->getOptionProxyPassword(), $this->getSoapClient()->getSoapClientStreamContextOptions());
304
            if ($this->getOptionSchemasSave()) {
305 20
                Utils::saveSchemas($this->getOptionDestination(), $this->getOptionSchemasFolder(), $url, $content);
306
            }
307 20
308
            return $content;
309 20
        }
310
        if (is_file($url)) {
311
            return file_get_contents($url);
312
        }
313
314
        return null;
315
    }
316
317 100
    public function getContainers(): GeneratorContainers
318
    {
319 100
        return $this->containers;
320
    }
321
322
    public function jsonSerialize(): array
323
    {
324
        return [
325
            'containers' => $this->containers,
326
            'options' => $this->options,
327
        ];
328
    }
329 6
330
    public static function instanceFromSerializedJson(string $json): Generator
331 6
    {
332
        $decodedJson = json_decode($json, true);
333 6
        if (JSON_ERROR_NONE === json_last_error()) {
334
            // load options first
335
            $options = GeneratorOptions::instance();
336
            foreach ($decodedJson['options'] as $name => $value) {
337
                $options->setOptionValue($name, $value);
0 ignored issues
show
Bug introduced by
The method setOptionValue() does not exist on WsdlToPhp\PackageGenerat...ader\AbstractYamlReader. It seems like you code against a sub-type of WsdlToPhp\PackageGenerat...ader\AbstractYamlReader such as WsdlToPhp\PackageGenerat...Reader\GeneratorOptions. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

337
                $options->/** @scrutinizer ignore-call */ 
338
                          setOptionValue($name, $value);
Loading history...
338
            }
339
            // create generator instance with options
340
            $instance = new self($options);
341 20
            // load services
342
            foreach ($decodedJson['containers']['services'] as $service) {
343 20
                $instance->getContainers()->getServices()->add(self::getModelInstanceFromJsonArrayEntry($instance, $service));
344
            }
345
            // load structs
346
            foreach ($decodedJson['containers']['structs'] as $struct) {
347
                $instance->getContainers()->getStructs()->add(self::getModelInstanceFromJsonArrayEntry($instance, $struct));
348
            }
349
        } else {
350
            throw new InvalidArgumentException(sprintf('Json is invalid, please check error %s', json_last_error()));
351
        }
352
353 2
        return $instance;
354
    }
355 2
356
    protected function initialize(): self
357 2
    {
358
        return $this
359
            ->initContainers()
360
            ->initParsers()
361
            ->initFiles()
362
            ->initSoapClient()
363
            ->initWsdl()
364
        ;
365 46
    }
366
367 46
    protected function initSoapClient(): self
368
    {
369
        if (!isset($this->soapClient)) {
370
            $this->soapClient = new GeneratorSoapClient($this);
371
        }
372
373
        return $this;
374
    }
375
376
    protected function initContainers(): self
377 2
    {
378
        if (!isset($this->containers)) {
379 2
            $this->containers = new GeneratorContainers($this);
380
        }
381 2
382
        return $this;
383
    }
384
385
    protected function initParsers(): self
386
    {
387
        if (!isset($this->parsers)) {
388
            $this->parsers = new GeneratorParsers($this);
389 50
        }
390
391 50
        return $this;
392
    }
393
394
    protected function initFiles(): self
395
    {
396
        if (!isset($this->files)) {
397
            $this->files = new GeneratorFiles($this);
398
        }
399
400
        return $this;
401 2
    }
402
403 2
    protected function initDirectory(): self
404
    {
405 2
        Utils::createDirectory($this->getOptions()->getDestination());
406
        if (!is_writable($this->getOptionDestination())) {
407
            throw new InvalidArgumentException(sprintf('Unable to use dir "%s" as dir does not exists, its creation has been impossible or it\'s not writable', $this->getOptionDestination()), __LINE__);
408
        }
409
410
        return $this;
411
    }
412
413
    protected function initWsdl(): self
414
    {
415 412
        $this->setWsdl(new Wsdl($this, $this->getOptionOrigin(), $this->getUrlContent($this->getOptionOrigin())));
0 ignored issues
show
Bug introduced by
It seems like $this->getUrlContent($this->getOptionOrigin()) can also be of type null; however, parameter $content of WsdlToPhp\PackageGenerat...del\Wsdl::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

415
        $this->setWsdl(new Wsdl($this, $this->getOptionOrigin(), /** @scrutinizer ignore-type */ $this->getUrlContent($this->getOptionOrigin())));
Loading history...
416
417 412
        return $this;
418
    }
419
420
    protected function doSanityChecks(): self
421
    {
422
        $destination = $this->getOptionDestination();
423
        if (empty($destination)) {
424
            throw new InvalidArgumentException('Package\'s destination must be defined', __LINE__);
425
        }
426
427 44
        $composerName = $this->getOptionComposerName();
428
        if ($this->getOptionStandalone() && empty($composerName)) {
429 44
            throw new InvalidArgumentException('Package\'s composer name must be defined', __LINE__);
430
        }
431 44
432
        return $this;
433
    }
434
435
    protected function doParse(): self
436
    {
437
        $this->parsers->doParse();
438
439
        return $this;
440
    }
441 408
442
    protected function doGenerate(): self
443 408
    {
444
        $this->files->doGenerate();
445
446
        return $this;
447
    }
448
449
    protected function setWsdl(Wsdl $wsdl): self
450
    {
451
        $this->wsdl = $wsdl;
452
453 16
        return $this;
454
    }
455 16
456
    protected function getGather(AbstractModel $model): string
457 16
    {
458
        return Utils::getPart($this->getOptionGatherMethods(), $model->getCleanName());
459
    }
460
461
    protected function setOptions(GeneratorOptions $options): self
462
    {
463
        $this->options = $options;
464
465 456
        return $this;
466
    }
467 456
468
    protected static function getModelInstanceFromJsonArrayEntry(Generator $generator, array $jsonArrayEntry): AbstractModel
469
    {
470
        return AbstractModel::instanceFromSerializedJson($generator, $jsonArrayEntry);
471
    }
472
}
473