Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.52% covered (success)
98.52%
133 / 135
95.45% covered (success)
95.45%
42 / 44
CRAP
0.00% covered (danger)
0.00%
0 / 1
Generator
98.52% covered (success)
98.52%
133 / 135
95.45% covered (success)
95.45%
42 / 44
78
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 __call
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
6.07
 getParsers
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFiles
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 generatePackage
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 parse
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getStructByName
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 getStructByNameAndType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getService
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getServiceMethod
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getServices
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 getStructs
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOptionNamespacePrefix
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setOptionNamespacePrefix
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getOptionPrefix
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getOptionSuffix
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 setOptionOrigin
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getOptionDestination
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setOptionDestination
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setOptionSoapOptions
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setOptionComposerName
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getWsdl
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addSchemaToWsdl
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 getServiceName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOptions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSoapClient
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUrlContent
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 getContainers
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 jsonSerialize
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 instanceFromSerializedJson
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 initialize
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 initSoapClient
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 initContainers
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 initParsers
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 initFiles
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 initDirectory
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 initWsdl
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 doSanityChecks
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 doParse
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 doGenerate
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setWsdl
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getGather
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setOptions
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getModelInstanceFromJsonArrayEntry
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace WsdlToPhp\PackageGenerator\Generator;
6
7use WsdlToPhp\PackageGenerator\ConfigurationReader\GeneratorOptions;
8use WsdlToPhp\PackageGenerator\Container\Model\Service as ServiceContainer;
9use WsdlToPhp\PackageGenerator\Container\Model\Struct as StructContainer;
10use WsdlToPhp\PackageGenerator\Model\AbstractModel;
11use WsdlToPhp\PackageGenerator\Model\EmptyModel;
12use WsdlToPhp\PackageGenerator\Model\Method;
13use WsdlToPhp\PackageGenerator\Model\Schema;
14use WsdlToPhp\PackageGenerator\Model\Service;
15use WsdlToPhp\PackageGenerator\Model\Struct;
16use WsdlToPhp\PackageGenerator\Model\Wsdl;
17
18/**
19 * @method string getOptionCategory()
20 * @method self   setOptionCategory(string $category)
21 * @method string getOptionGatherMethods()
22 * @method self   setOptionGatherMethods(string $gatherMethods)
23 * @method bool   getOptionGenericConstantsNames()
24 * @method self   setOptionGenericConstantsNames(bool $genericConstantsNames)
25 * @method bool   getOptionGenerateTutorialFile()
26 * @method self   setOptionGenerateTutorialFile(bool $generateTutorialFile)
27 * @method string getOptionNamespace()
28 * @method self   setOptionNamespace(string $namespace)
29 * @method bool   getOptionNamespaceDictatesDirectories()
30 * @method self   setOptionNamespaceDictatesDirectories(bool $namespaceDictatesDirectories)
31 * @method array  getOptionAddComments()
32 * @method self   setOptionAddComments(array $addComments)
33 * @method bool   getOptionStandalone()
34 * @method self   setOptionStandalone(bool $standalone)
35 * @method bool   getOptionValidation()
36 * @method self   setOptionValidation(bool $validation)
37 * @method string getOptionStructClass()
38 * @method self   setOptionStructClass(string $structClass)
39 * @method string getOptionStructArrayClass()
40 * @method self   setOptionStructArrayClass(string $structArrayClass)
41 * @method string getOptionStructEnumClass()
42 * @method self   setOptionStructEnumClass(string $structEnumClass)
43 * @method string getOptionSoapClientClass()
44 * @method self   setOptionSoapClientClass(string $soapClientClass)
45 * @method self   setOptionPrefix(string $optionPrefix)
46 * @method self   setOptionSuffix(string $optionSuffix)
47 * @method string getOptionBasicLogin()
48 * @method self   setOptionBasicLogin(string $optionBasicLogin)
49 * @method string getOptionBasicPassword()
50 * @method self   setOptionBasicPassword(string $optionBasicPassword)
51 * @method string getOptionProxyHost()
52 * @method self   setOptionProxyHost(string $optionProxyHost)
53 * @method string getOptionProxyPort()
54 * @method self   setOptionProxyPort(string $optionProxyPort)
55 * @method string getOptionProxyLogin()
56 * @method self   setOptionProxyLogin(string $optionProxyLogin)
57 * @method string getOptionProxyPassword()
58 * @method self   setOptionProxyPassword(string $optionProxyPassword)
59 * @method string getOptionOrigin()
60 * @method string getOptionSrcDirname()
61 * @method self   setOptionSrcDirname(string $optionSrcDirname)
62 * @method array  getOptionSoapOptions()
63 * @method string getOptionComposerName()
64 * @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 * @method self   setOptionSchemasSave(bool $optionSchemasSave)
76 * @method string getOptionSchemasFolder()
77 * @method self   setOptionSchemasFolder(string $optionSchemasFolder)
78 * @method string getOptionXsdTypesPath()
79 * @method self   setOptionXsdTypesPath(string $xsdTypesPath)
80 */
81class Generator implements \JsonSerializable
82{
83    protected Wsdl $wsdl;
84
85    protected GeneratorOptions $options;
86
87    protected GeneratorParsers $parsers;
88
89    protected GeneratorFiles $files;
90
91    protected GeneratorContainers $containers;
92
93    protected ?GeneratorSoapClient $soapClient = null;
94
95    public function __construct(GeneratorOptions $options)
96    {
97        $this
98            ->setOptions($options)
99            ->initialize()
100        ;
101    }
102
103    public function __call($name, $arguments)
104    {
105        if (($prefix = 'getOption') === substr($name, 0, $length = strlen($prefix)) && empty($arguments)) {
106            $getMethod = 'get'.substr($name, $length);
107
108            return $this->options->{$getMethod}();
109        }
110        if (($prefix = 'setOption') === substr($name, 0, $length = strlen($prefix)) && 1 === (is_countable($arguments) ? count($arguments) : 0)) {
111            $setMethod = 'set'.substr($name, $length);
112            $this->options->{$setMethod}(array_shift($arguments));
113
114            return $this;
115        }
116
117        throw new \BadMethodCallException(sprintf('Method %s is undefined', $name));
118    }
119
120    public function getParsers(): GeneratorParsers
121    {
122        return $this->parsers;
123    }
124
125    public function getFiles(): GeneratorFiles
126    {
127        return $this->files;
128    }
129
130    public function generatePackage(): self
131    {
132        return $this
133            ->doSanityChecks()
134            ->parse()
135            ->initDirectory()
136            ->doGenerate()
137        ;
138    }
139
140    public function parse(): self
141    {
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     * @param string $structName the original struct name
150     *
151     * @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    {
162        return $this->getStructs()->getStructByNameAndType($structName, $type);
163    }
164
165    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    }
174
175    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            }
186            $serviceContainer->add($serviceModel);
187            $services = $serviceContainer;
188        }
189
190        return $services;
191    }
192
193    public function getStructs(): StructContainer
194    {
195        return $this->containers->getStructs();
196    }
197
198    public function getOptionNamespacePrefix(): string
199    {
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
210    public function getOptionPrefix(bool $ucFirst = true): string
211    {
212        return $ucFirst ? ucfirst($this->getOptions()->getPrefix()) : $this->getOptions()->getPrefix();
213    }
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    {
222        $this->options->setOrigin($optionOrigin);
223        $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        }
234
235        return $destination;
236    }
237
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
246        return $this;
247    }
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        return $this;
258    }
259
260    public function setOptionComposerName(string $optionComposerName): self
261    {
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    }
270
271    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)));
280        }
281
282        return $this;
283    }
284
285    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    }
294
295    public function getSoapClient(): GeneratorSoapClient
296    {
297        return $this->soapClient;
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                Utils::saveSchemas($this->getOptionDestination(), $this->getOptionSchemasFolder(), $url, $content);
306            }
307
308            return $content;
309        }
310        if (is_file($url)) {
311            return file_get_contents($url);
312        }
313
314        return null;
315    }
316
317    public function getContainers(): GeneratorContainers
318    {
319        return $this->containers;
320    }
321
322    public function jsonSerialize(): array
323    {
324        return [
325            'containers' => $this->containers,
326            'options' => $this->options,
327        ];
328    }
329
330    public static function instanceFromSerializedJson(string $json): Generator
331    {
332        $decodedJson = json_decode($json, true);
333        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);
338            }
339            // create generator instance with options
340            $instance = new self($options);
341            // load services
342            foreach ($decodedJson['containers']['services'] as $service) {
343                $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        return $instance;
354    }
355
356    protected function initialize(): self
357    {
358        return $this
359            ->initContainers()
360            ->initParsers()
361            ->initFiles()
362            ->initSoapClient()
363            ->initWsdl()
364        ;
365    }
366
367    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    {
378        if (!isset($this->containers)) {
379            $this->containers = new GeneratorContainers($this);
380        }
381
382        return $this;
383    }
384
385    protected function initParsers(): self
386    {
387        if (!isset($this->parsers)) {
388            $this->parsers = new GeneratorParsers($this);
389        }
390
391        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    }
402
403    protected function initDirectory(): self
404    {
405        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        $this->setWsdl(new Wsdl($this, $this->getOptionOrigin(), $this->getUrlContent($this->getOptionOrigin())));
416
417        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        $composerName = $this->getOptionComposerName();
428        if ($this->getOptionStandalone() && empty($composerName)) {
429            throw new \InvalidArgumentException('Package\'s composer name must be defined', __LINE__);
430        }
431
432        return $this;
433    }
434
435    protected function doParse(): self
436    {
437        $this->parsers->doParse();
438
439        return $this;
440    }
441
442    protected function doGenerate(): self
443    {
444        $this->files->doGenerate();
445
446        return $this;
447    }
448
449    protected function setWsdl(Wsdl $wsdl): self
450    {
451        $this->wsdl = $wsdl;
452
453        return $this;
454    }
455
456    protected function getGather(AbstractModel $model): string
457    {
458        return Utils::getPart($this->getOptionGatherMethods(), $model->getCleanName());
459    }
460
461    protected function setOptions(GeneratorOptions $options): self
462    {
463        $this->options = $options;
464
465        return $this;
466    }
467
468    protected static function getModelInstanceFromJsonArrayEntry(Generator $generator, array $jsonArrayEntry): AbstractModel
469    {
470        return AbstractModel::instanceFromSerializedJson($generator, $jsonArrayEntry);
471    }
472}