Passed
Push — master ( dba7cd...d89126 )
by Asmir
01:36
created

SoapContainerBuilder::fetchMetadata()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 10
rs 10
c 1
b 0
f 0
ccs 0
cts 5
cp 0
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GoetasWebservices\SoapServices\Metadata\Builder;
6
7
use GoetasWebservices\SoapServices\Metadata\DependencyInjection\Compiler\CleanupPass;
8
use GoetasWebservices\SoapServices\Metadata\Envelope\Envelope;
9
use GoetasWebservices\SoapServices\Metadata\Headers\Handler\HeaderHandler;
10
use GoetasWebservices\Xsd\XsdToPhpRuntime\Jms\Handler\BaseTypesHandler;
11
use GoetasWebservices\Xsd\XsdToPhpRuntime\Jms\Handler\XmlSchemaDateHandler;
12
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
13
use JMS\Serializer\Handler\HandlerRegistryInterface;
14
use JMS\Serializer\SerializerBuilder;
15
use Symfony\Component\Config\FileLocator;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Config\FileLocator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Symfony\Component\Config\Loader\DelegatingLoader;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Config\Loader\DelegatingLoader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Symfony\Component\Config\Loader\LoaderResolver;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Config\Loader\LoaderResolver was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...r\CompilerPassInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use Symfony\Component\DependencyInjection\ContainerBuilder;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...ection\ContainerBuilder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use Symfony\Component\DependencyInjection\ContainerInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...tion\ContainerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...ection\Dumper\PhpDumper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...sion\ExtensionInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...on\Loader\XmlFileLoader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Depend...n\Loader\YamlFileLoader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
26
abstract class SoapContainerBuilder
27
{
28
    /**
29
     * @var string
30
     */
31
    private $className = 'SoapContainer';
32
33
    /**
34
     * @var string
35
     */
36
    private $classNs = 'SoapServicesStub';
37
38
    /**
39
     * @var string
40
     */
41
    protected $configFile = 'config.yml';
42
43
    /**
44
     * @var string[]
45
     */
46
    protected $extensions = [];
47
48
    /**
49
     * @var string[]
50
     */
51
    protected $compilerPasses = [];
52
53
    public function __construct(?string $configFile = null)
54
    {
55
        $this->setConfigFile($configFile);
0 ignored issues
show
Bug introduced by
It seems like $configFile can also be of type null; however, parameter $configFile of GoetasWebservices\SoapSe...uilder::setConfigFile() 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

55
        $this->setConfigFile(/** @scrutinizer ignore-type */ $configFile);
Loading history...
56
        $this->addCompilerPass(new CleanupPass());
57
    }
58
59
    public function setConfigFile(string $configFile): void
60
    {
61
        $this->configFile = $configFile;
62
    }
63
64
    protected function addExtension(ExtensionInterface $extension): void
65
    {
66
        $this->extensions[] = $extension;
67
    }
68
69
    protected function addCompilerPass(CompilerPassInterface $pass): void
70
    {
71
        $this->compilerPasses[] = $pass;
72
    }
73
74
    public function setContainerClassName(string $fqcn): void
75
    {
76
        $fqcn = strtr($fqcn, [
77
            '.' => '\\',
78
            '/' => '\\',
79
        ]);
80
        $pos = strrpos($fqcn, '\\');
81
        $this->className = substr($fqcn, $pos + 1);
82
        $this->classNs = substr($fqcn, 0, $pos);
83
    }
84
85
    /**
86
     * @param array $metadata
87
     */
88
    protected function getContainerBuilder(array $metadata = []): ContainerBuilder
89
    {
90
        $container = new ContainerBuilder();
91
92
        foreach ($this->extensions as $extension) {
93
            $container->registerExtension($extension);
94
        }
95
96
        foreach ($this->compilerPasses as $pass) {
97
            $container->addCompilerPass($pass);
98
        }
99
100
        $locator = new FileLocator('.');
101
        $loaders = [
102
            new YamlFileLoader($container, $locator),
103
            new XmlFileLoader($container, $locator),
104
        ];
105
        $delegatingLoader = new DelegatingLoader(new LoaderResolver($loaders));
106
        $delegatingLoader->load($this->configFile);
107
108
        // set the production soap metadata
109
        $container->setParameter('goetas_webservices.soap.metadata', $metadata);
110
111
        $container->compile();
112
113
        return $container;
114
    }
115
116
    /**
117
     * @return array
118
     */
119
    protected function fetchMetadata(ContainerInterface $debugContainer): array
120
    {
121
        $metadataReader = $debugContainer->get('goetas_webservices.soap.metadata_loader.dev');
122
        $wsdlMetadata = $debugContainer->getParameter('goetas_webservices.soap.config')['metadata'];
123
        $metadata = [];
124
        foreach (array_keys($wsdlMetadata) as $uri) {
125
            $metadata[$uri] = $metadataReader->load($uri);
126
        }
127
128
        return $metadata;
129
    }
130
131
    public function getDebugContainer(): ContainerBuilder
132
    {
133
        return $this->getContainerBuilder();
134
    }
135
136
    public function getProdContainer(): ContainerInterface
137
    {
138
        $ref = new \ReflectionClass(sprintf('%s\\%s', $this->classNs, $this->className));
139
140
        return $ref->newInstance();
141
    }
142
143
    public function dumpContainerForProd(string $dir, ContainerInterface $debugContainer): void
144
    {
145
        $metadata = $this->fetchMetadata($debugContainer);
146
147
        if (!$metadata) {
148
            throw new \Exception('Empty metadata can not be used for production');
149
        }
150
151
        $forProdContainer = $this->getContainerBuilder($metadata);
152
        $this->dump($forProdContainer, $dir);
153
    }
154
155
    private function dump(ContainerBuilder $container, string $dir): void
156
    {
157
        $dumper = new PhpDumper($container);
158
        $options = [
159
            'debug' => false,
160
            'class' => $this->className,
161
            'namespace' => $this->classNs,
162
        ];
163
164
        if (!is_dir($dir)) {
165
            mkdir($dir, 0777, true);
166
        }
167
168
        file_put_contents($dir . '/' . $this->className . '.php', $dumper->dump($options));
169
    }
170
171
    public static function createSerializerBuilderFromContainer(ContainerInterface $container, ?callable $handlersCallback = null, ?callable $listenersCallback = null, ?string $metadataDirPrefix = null): SerializerBuilder
172
    {
173
        $destinations = $container->getParameter('goetas_webservices.soap.config')['destinations_jms'];
174
175
        if (null !== $metadataDirPrefix) {
176
            $destinations = array_map(static function ($dir) use ($metadataDirPrefix) {
177
                return rtrim($metadataDirPrefix, '/') . '/' . $dir;
178
            }, $destinations);
179
        }
180
181
        return self::createSerializerBuilder($destinations, $handlersCallback, $listenersCallback);
182
    }
183
184
    /**
185
     * @param array $jmsMetadata
186
     */
187
    public static function createSerializerBuilder(array $jmsMetadata, ?callable $handlersCallback = null, ?callable $listenersCallback = null): SerializerBuilder
188
    {
189
        $jmsMetadata = array_merge(self::getMetadataForSoapEnvelope(), $jmsMetadata);
190
191
        $serializerBuilder = SerializerBuilder::create();
192
193
        $h = new HeaderHandler();
194
        $serializerBuilder->configureHandlers(static function (HandlerRegistryInterface $handler) use ($handlersCallback, $serializerBuilder, $h): void {
195
            $serializerBuilder->addDefaultHandlers();
196
            $handler->registerSubscribingHandler(new BaseTypesHandler()); // XMLSchema List handling
197
            $handler->registerSubscribingHandler(new XmlSchemaDateHandler()); // XMLSchema date handling
198
            $handler->registerSubscribingHandler($h);
199
            if ($handlersCallback) {
200
                call_user_func($handlersCallback, $handler);
201
            }
202
        });
203
204
        $serializerBuilder->configureListeners(static function (EventDispatcherInterface $d) use ($serializerBuilder, $h, $listenersCallback): void {
205
            $serializerBuilder->addDefaultListeners();
206
            $d->addSubscriber($h);
207
            if ($listenersCallback) {
208
                call_user_func($listenersCallback, $d);
209
            }
210
        });
211
212
        foreach ($jmsMetadata as $php => $dir) {
213
            $serializerBuilder->addMetadataDir($dir, $php);
214
        }
215
216
        return $serializerBuilder;
217
    }
218
219
    /**
220
     * @return string[]
221
     */
222
    public static function getMetadataForSoapEnvelope(): array
223
    {
224
        $ref = new \ReflectionClass(Envelope::class);
225
226
        return [
227
            'GoetasWebservices\SoapServices\Metadata\Envelope\SoapEnvelope12' => dirname($ref->getFileName()) . '/../Resources/metadata/jms12',
228
            'GoetasWebservices\SoapServices\Metadata\Envelope\SoapEnvelope' => dirname($ref->getFileName()) . '/../Resources/metadata/jms',
229
        ];
230
    }
231
}
232