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    /**
104     * @param mixed $name
105     * @param mixed $arguments
106     * @throws \BadMethodCallException
107     */
108    public function __call($name, $arguments)
109    {
110        if (($prefix = 'getOption') === substr($name, 0, $length = strlen($prefix)) && empty($arguments)) {
111            $getMethod = 'get'.substr($name, $length);
112
113            return $this->options->{$getMethod}();
114        }
115        if (($prefix = 'setOption') === substr($name, 0, $length = strlen($prefix)) && 1 === (is_countable($arguments) ? count($arguments) : 0)) {
116            $setMethod = 'set'.substr($name, $length);
117            $this->options->{$setMethod}(array_shift($arguments));
118
119            return $this;
120        }
121
122        throw new \BadMethodCallException(sprintf('Method %s is undefined', $name));
123    }
124
125    public function getParsers(): GeneratorParsers
126    {
127        return $this->parsers;
128    }
129
130    public function getFiles(): GeneratorFiles
131    {
132        return $this->files;
133    }
134
135    public function generatePackage(): self
136    {
137        return $this
138            ->doSanityChecks()
139            ->parse()
140            ->initDirectory()
141            ->doGenerate()
142        ;
143    }
144
145    public function parse(): self
146    {
147        return $this->doParse();
148    }
149
150    /**
151     * Gets the struct by its name
152     * Starting from issue #157, we know call getVirtual secondly as structs are now betterly parsed and so is their inheritance/type is detected.
153     *
154     * @param string $structName the original struct name
155     *
156     * @uses Generator::getStructs()
157     */
158    public function getStructByName(string $structName): ?Struct
159    {
160        $struct = $this->getStructs()->getStructByName($structName);
161
162        return $struct ?: $this->getStructs()->getVirtual($structName);
163    }
164
165    public function getStructByNameAndType(string $structName, string $type): ?Struct
166    {
167        return $this->getStructs()->getStructByNameAndType($structName, $type);
168    }
169
170    public function getService(string $serviceName): ?Service
171    {
172        return $this->getServices()->getServiceByName($serviceName);
173    }
174
175    public function getServiceMethod(string $methodName): ?Method
176    {
177        return $this->getService($this->getServiceName($methodName)) instanceof Service ? $this->getService($this->getServiceName($methodName))->getMethod($methodName) : null;
178    }
179
180    public function getServices(bool $usingGatherMethods = false): ServiceContainer
181    {
182        $services = $this->containers->getServices();
183        if ($usingGatherMethods && GeneratorOptions::VALUE_NONE === $this->getOptionGatherMethods()) {
184            $serviceContainer = new ServiceContainer($this);
185            $serviceModel = new Service($this, Service::DEFAULT_SERVICE_CLASS_NAME);
186            foreach ($services as $service) {
187                foreach ($service->getMethods() as $method) {
188                    $serviceModel->getMethods()->add($method);
189                }
190            }
191            $serviceContainer->add($serviceModel);
192            $services = $serviceContainer;
193        }
194
195        return $services;
196    }
197
198    public function getStructs(): StructContainer
199    {
200        return $this->containers->getStructs();
201    }
202
203    public function getOptionNamespacePrefix(): string
204    {
205        return $this->options->getNamespace();
206    }
207
208    public function setOptionNamespacePrefix(string $namespace): self
209    {
210        $this->options->setNamespace($namespace);
211
212        return $this;
213    }
214
215    public function getOptionPrefix(bool $ucFirst = true): string
216    {
217        return $ucFirst ? ucfirst($this->getOptions()->getPrefix()) : $this->getOptions()->getPrefix();
218    }
219
220    public function getOptionSuffix(bool $ucFirst = true): string
221    {
222        return $ucFirst ? ucfirst($this->getOptions()->getSuffix()) : $this->getOptions()->getSuffix();
223    }
224
225    public function setOptionOrigin(string $optionOrigin): self
226    {
227        $this->options->setOrigin($optionOrigin);
228        $this->initWsdl();
229
230        return $this;
231    }
232
233    public function getOptionDestination(): string
234    {
235        $destination = $this->options->getDestination();
236        if (!empty($destination)) {
237            $destination = rtrim($destination, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
238        }
239
240        return $destination;
241    }
242
243    /**
244     * @throws \InvalidArgumentException
245     */
246    public function setOptionDestination(string $optionDestination): self
247    {
248        if (!empty($optionDestination)) {
249            $this->options->setDestination(rtrim($optionDestination, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR);
250        } else {
251            throw new \InvalidArgumentException('Package\'s destination can\'t be empty', __LINE__);
252        }
253
254        return $this;
255    }
256
257    public function setOptionSoapOptions(array $optionSoapOptions): self
258    {
259        $this->options->setSoapOptions($optionSoapOptions);
260
261        if ($this->soapClient) {
262            $this->soapClient->initSoapClient();
263        }
264
265        return $this;
266    }
267
268    /**
269     * @throws \InvalidArgumentException
270     */
271    public function setOptionComposerName(string $optionComposerName): self
272    {
273        if (!empty($optionComposerName)) {
274            $this->options->setComposerName($optionComposerName);
275        } else {
276            throw new \InvalidArgumentException('Package\'s composer name can\'t be empty', __LINE__);
277        }
278
279        return $this;
280    }
281
282    public function getWsdl(): ?Wsdl
283    {
284        return $this->wsdl;
285    }
286
287    public function addSchemaToWsdl(Wsdl $wsdl, string $schemaLocation): self
288    {
289        if (!empty($schemaLocation) && !$wsdl->hasSchema($schemaLocation)) {
290            $wsdl->addSchema(new Schema($wsdl->getGenerator(), $schemaLocation, $this->getUrlContent($schemaLocation)));
291        }
292
293        return $this;
294    }
295
296    public function getServiceName(string $methodName): string
297    {
298        return ucfirst($this->getGather(new EmptyModel($this, $methodName)));
299    }
300
301    public function getOptions(): ?GeneratorOptions
302    {
303        return $this->options;
304    }
305
306    public function getSoapClient(): GeneratorSoapClient
307    {
308        return $this->soapClient;
309    }
310
311    public function getUrlContent(string $url): ?string
312    {
313        if (false !== mb_strpos($url, '://')) {
314            $content = Utils::getContentFromUrl($url, $this->getOptionBasicLogin(), $this->getOptionBasicPassword(), $this->getOptionProxyHost(), $this->getOptionProxyPort(), $this->getOptionProxyLogin(), $this->getOptionProxyPassword(), $this->getSoapClient()->getSoapClientStreamContextOptions());
315            if ($this->getOptionSchemasSave()) {
316                Utils::saveSchemas($this->getOptionDestination(), $this->getOptionSchemasFolder(), $url, $content);
317            }
318
319            return $content;
320        }
321        if (is_file($url)) {
322            return file_get_contents($url);
323        }
324
325        return null;
326    }
327
328    public function getContainers(): GeneratorContainers
329    {
330        return $this->containers;
331    }
332
333    public function jsonSerialize(): array
334    {
335        return [
336            'containers' => $this->containers,
337            'options' => $this->options,
338        ];
339    }
340
341    /**
342     * @throws \InvalidArgumentException
343     */
344    public static function instanceFromSerializedJson(string $json): Generator
345    {
346        $decodedJson = json_decode($json, true);
347        if (JSON_ERROR_NONE === json_last_error()) {
348            // load options first
349            $options = GeneratorOptions::instance();
350            foreach ($decodedJson['options'] as $name => $value) {
351                $options->setOptionValue($name, $value);
352            }
353            // create generator instance with options
354            $instance = new self($options);
355            // load services
356            foreach ($decodedJson['containers']['services'] as $service) {
357                $instance->getContainers()->getServices()->add(self::getModelInstanceFromJsonArrayEntry($instance, $service));
358            }
359            // load structs
360            foreach ($decodedJson['containers']['structs'] as $struct) {
361                $instance->getContainers()->getStructs()->add(self::getModelInstanceFromJsonArrayEntry($instance, $struct));
362            }
363        } else {
364            throw new \InvalidArgumentException(sprintf('Json is invalid, please check error %s', json_last_error()));
365        }
366
367        return $instance;
368    }
369
370    protected function initialize(): self
371    {
372        return $this
373            ->initContainers()
374            ->initParsers()
375            ->initFiles()
376            ->initSoapClient()
377            ->initWsdl()
378        ;
379    }
380
381    protected function initSoapClient(): self
382    {
383        if (!isset($this->soapClient)) {
384            $this->soapClient = new GeneratorSoapClient($this);
385        }
386
387        return $this;
388    }
389
390    protected function initContainers(): self
391    {
392        if (!isset($this->containers)) {
393            $this->containers = new GeneratorContainers($this);
394        }
395
396        return $this;
397    }
398
399    protected function initParsers(): self
400    {
401        if (!isset($this->parsers)) {
402            $this->parsers = new GeneratorParsers($this);
403        }
404
405        return $this;
406    }
407
408    protected function initFiles(): self
409    {
410        if (!isset($this->files)) {
411            $this->files = new GeneratorFiles($this);
412        }
413
414        return $this;
415    }
416
417    /**
418     * @throws \InvalidArgumentException
419     */
420    protected function initDirectory(): self
421    {
422        Utils::createDirectory($this->getOptions()->getDestination());
423        if (!is_writable($this->getOptionDestination())) {
424            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__);
425        }
426
427        return $this;
428    }
429
430    protected function initWsdl(): self
431    {
432        $this->setWsdl(new Wsdl($this, $this->getOptionOrigin(), $this->getUrlContent($this->getOptionOrigin())));
433
434        return $this;
435    }
436
437    /**
438     * @throws \InvalidArgumentException
439     */
440    protected function doSanityChecks(): self
441    {
442        $destination = $this->getOptionDestination();
443        if (empty($destination)) {
444            throw new \InvalidArgumentException('Package\'s destination must be defined', __LINE__);
445        }
446
447        $composerName = $this->getOptionComposerName();
448        if ($this->getOptionStandalone() && empty($composerName)) {
449            throw new \InvalidArgumentException('Package\'s composer name must be defined', __LINE__);
450        }
451
452        return $this;
453    }
454
455    protected function doParse(): self
456    {
457        $this->parsers->doParse();
458
459        return $this;
460    }
461
462    protected function doGenerate(): self
463    {
464        $this->files->doGenerate();
465
466        return $this;
467    }
468
469    protected function setWsdl(Wsdl $wsdl): self
470    {
471        $this->wsdl = $wsdl;
472
473        return $this;
474    }
475
476    protected function getGather(AbstractModel $model): string
477    {
478        return Utils::getPart($this->getOptionGatherMethods(), $model->getCleanName());
479    }
480
481    protected function setOptions(GeneratorOptions $options): self
482    {
483        $this->options = $options;
484
485        return $this;
486    }
487
488    protected static function getModelInstanceFromJsonArrayEntry(Generator $generator, array $jsonArrayEntry): AbstractModel
489    {
490        return AbstractModel::instanceFromSerializedJson($generator, $jsonArrayEntry);
491    }
492}