ContainerBuilder::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cakasim\Payone\Sdk;
6
7
use Cakasim\Payone\Sdk\Container\Container;
8
use Cakasim\Payone\Sdk\Container\ContainerException;
9
10
/**
11
 * Builds the container and applies SDK default dependencies.
12
 *
13
 * @author Fabian Böttcher <[email protected]>
14
 * @since 0.1.0
15
 */
16
class ContainerBuilder
17
{
18
    /**
19
     * A list of all required bindings.
20
     */
21
    protected const REQUIRED_BINDINGS = [
22
        \Psr\Log\LoggerInterface::class,
23
        \Psr\Http\Message\UriFactoryInterface::class,
24
        \Psr\Http\Message\StreamFactoryInterface::class,
25
        \Psr\Http\Message\RequestFactoryInterface::class,
26
        \Psr\Http\Message\ResponseFactoryInterface::class,
27
        \Psr\Http\Message\ServerRequestFactoryInterface::class,
28
        \Psr\Http\Client\ClientInterface::class,
29
        \Cakasim\Payone\Sdk\Http\Service::class,
30
        \Cakasim\Payone\Sdk\Api\Service::class,
31
        \Cakasim\Payone\Sdk\Notification\Service::class,
32
        \Cakasim\Payone\Sdk\Redirect\Service::class,
33
        \Cakasim\Payone\Sdk\Config\ConfigInterface::class,
34
        \Cakasim\Payone\Sdk\Api\Format\EncoderInterface::class,
35
        \Cakasim\Payone\Sdk\Api\Format\DecoderInterface::class,
36
        \Cakasim\Payone\Sdk\Api\Client\ClientInterface::class,
37
        \Cakasim\Payone\Sdk\Notification\Processor\ProcessorInterface::class,
38
        \Cakasim\Payone\Sdk\Notification\Handler\HandlerManagerInterface::class,
39
        \Cakasim\Payone\Sdk\Redirect\Token\TokenFactoryInterface::class,
40
        \Cakasim\Payone\Sdk\Redirect\Token\Format\EncoderInterface::class,
41
        \Cakasim\Payone\Sdk\Redirect\Token\Format\DecoderInterface::class,
42
        \Cakasim\Payone\Sdk\Redirect\Token\Format\SignerInterface::class,
43
        \Cakasim\Payone\Sdk\Redirect\UrlGenerator\UrlGeneratorInterface::class,
44
        \Cakasim\Payone\Sdk\Redirect\Handler\HandlerManagerInterface::class,
45
        \Cakasim\Payone\Sdk\Redirect\Processor\ProcessorInterface::class,
46
    ];
47
48
    /**
49
     * The SDK service bindings.
50
     */
51
    protected const SERVICE_BINDINGS = [
52
        \Cakasim\Payone\Sdk\Http\Service::class,
53
        \Cakasim\Payone\Sdk\Api\Service::class,
54
        \Cakasim\Payone\Sdk\Notification\Service::class,
55
        \Cakasim\Payone\Sdk\Redirect\Service::class,
56
    ];
57
58
    /**
59
     * The default bindings of the SDK.
60
     */
61
    protected const DEFAULT_BINDINGS = [
62
63
        // --- PSR Bindings ---
64
65
        // PSR-7
66
        // Concrete PSR-7 implementation is provided by PSR-17
67
        // factory bindings below.
68
69
        // PSR-11
70
        // Container binds itself within the container constructor.
71
72
        // --- SDK Bindings ---
73
74
        // Config
75
        \Cakasim\Payone\Sdk\Config\ConfigInterface::class => [\Cakasim\Payone\Sdk\Config\Config::class, true],
76
77
        // API Format
78
        \Cakasim\Payone\Sdk\Api\Format\EncoderInterface::class => [\Cakasim\Payone\Sdk\Api\Format\Encoder::class, true],
79
        \Cakasim\Payone\Sdk\Api\Format\DecoderInterface::class => [\Cakasim\Payone\Sdk\Api\Format\Decoder::class, true],
80
81
        // API Client
82
        \Cakasim\Payone\Sdk\Api\Client\ClientInterface::class => [\Cakasim\Payone\Sdk\Api\Client\Client::class, true],
83
84
        // Notification
85
        \Cakasim\Payone\Sdk\Notification\Processor\ProcessorInterface::class    => [\Cakasim\Payone\Sdk\Notification\Processor\Processor::class, true],
86
        \Cakasim\Payone\Sdk\Notification\Handler\HandlerManagerInterface::class => [\Cakasim\Payone\Sdk\Notification\Handler\HandlerManager::class, true],
87
88
        // Redirect
89
        \Cakasim\Payone\Sdk\Redirect\Token\TokenFactoryInterface::class        => [\Cakasim\Payone\Sdk\Redirect\Token\TokenFactory::class, true],
90
        \Cakasim\Payone\Sdk\Redirect\Token\Format\EncoderInterface::class      => [\Cakasim\Payone\Sdk\Redirect\Token\Format\Encoder::class, true],
91
        \Cakasim\Payone\Sdk\Redirect\Token\Format\DecoderInterface::class      => [\Cakasim\Payone\Sdk\Redirect\Token\Format\Decoder::class, true],
92
        \Cakasim\Payone\Sdk\Redirect\Token\Format\SignerInterface::class       => [\Cakasim\Payone\Sdk\Redirect\Token\Format\Signer::class, true],
93
        \Cakasim\Payone\Sdk\Redirect\UrlGenerator\UrlGeneratorInterface::class => [\Cakasim\Payone\Sdk\Redirect\UrlGenerator\UrlGenerator::class, true],
94
        \Cakasim\Payone\Sdk\Redirect\Handler\HandlerManagerInterface::class    => [\Cakasim\Payone\Sdk\Redirect\Handler\HandlerManager::class, true],
95
        \Cakasim\Payone\Sdk\Redirect\Processor\ProcessorInterface::class       => [\Cakasim\Payone\Sdk\Redirect\Processor\Processor::class, true],
96
    ];
97
98
    /**
99
     * A list of external bindings.
100
     */
101
    protected const EXTERNAL_BINDINGS = [
102
        // PSR-17 bindings, from cakasim/payone-sdk-http-message package
103
        \Psr\Http\Message\UriFactoryInterface::class           => ['Cakasim\Payone\Sdk\Http\Factory\UriFactory', true],
104
        \Psr\Http\Message\StreamFactoryInterface::class        => ['Cakasim\Payone\Sdk\Http\Factory\StreamFactory', true],
105
        \Psr\Http\Message\RequestFactoryInterface::class       => ['Cakasim\Payone\Sdk\Http\Factory\RequestFactory', true],
106
        \Psr\Http\Message\ResponseFactoryInterface::class      => ['Cakasim\Payone\Sdk\Http\Factory\ResponseFactory', true],
107
        \Psr\Http\Message\ServerRequestFactoryInterface::class => ['Cakasim\Payone\Sdk\Http\Factory\ServerRequestFactory', true],
108
109
        // PSR-18 bindings, from cakasim/payone-sdk-stream-client package
110
        \Psr\Http\Client\ClientInterface::class => ['Cakasim\Payone\Sdk\Http\StreamClient\StreamClient', true],
111
112
        // PSR-3 bindings, from cakasim/payone-sdk-silent-logger package
113
        \Psr\Log\LoggerInterface::class => ['Cakasim\Payone\Sdk\Log\SilentLogger\SilentLogger', true],
114
    ];
115
116
    /**
117
     * @var Container The container.
118
     */
119
    protected $container;
120
121
    /**
122
     * Returns a list of bindings that are required for the SDk to work.
123
     *
124
     * @return array List of required bindings.
125
     */
126
    protected static function getRequiredBindings(): array
127
    {
128
        return static::REQUIRED_BINDINGS;
129
    }
130
131
    /**
132
     * Returns a list of SDK service bindings.
133
     *
134
     * @return array List of SDK service bindings.
135
     */
136
    protected static function getServiceBindings(): array
137
    {
138
        return static::SERVICE_BINDINGS;
139
    }
140
141
    /**
142
     * Returns a list of default bindings.
143
     *
144
     * @return array List of default bindings.
145
     */
146
    protected static function getDefaultBindings(): array
147
    {
148
        return static::DEFAULT_BINDINGS;
149
    }
150
151
    /**
152
     * Returns a list of external bindings.
153
     *
154
     * @return array List of external bindings.
155
     */
156
    protected static function getExternalBindings(): array
157
    {
158
        return static::EXTERNAL_BINDINGS;
159
    }
160
161
    /**
162
     * Constructs the ContainerBuilder.
163
     *
164
     * @throws ContainerException
165
     */
166
    final public function __construct()
167
    {
168
        $this->container = new Container();
169
        $this->bindServices();
170
    }
171
172
    /**
173
     * Returns the container.
174
     *
175
     * @return Container The container.
176
     */
177
    public function getContainer(): Container
178
    {
179
        return $this->container;
180
    }
181
182
    /**
183
     * Binds the SDK services.
184
     *
185
     * @throws ContainerException
186
     */
187
    protected function bindServices(): void
188
    {
189
        foreach (static::getServiceBindings() as $service) {
190
            $this->container->bind($service, null, true);
191
        }
192
    }
193
194
    /**
195
     * Binds default SDK dependencies.
196
     *
197
     * @throws ContainerException
198
     */
199
    protected function bindDefaults(): void
200
    {
201
        foreach (static::getDefaultBindings() as $id => $binding) {
202
            if (!$this->container->has($id)) {
203
                $this->container->bind($id, $binding[0], $binding[1]);
204
            }
205
        }
206
    }
207
208
    /**
209
     * Binds external SDK dependencies.
210
     *
211
     * @throws ContainerException
212
     */
213
    protected function bindExternal(): void
214
    {
215
        foreach (static::getExternalBindings() as $id => $binding) {
216
            if (!$this->container->has($id) && class_exists($binding[0])) {
217
                $this->container->bind($id, $binding[0], $binding[1]);
218
            }
219
        }
220
    }
221
222
    /**
223
     * Verifies that the container holds all required bindings.
224
     */
225
    protected function verifyRequiredBindings(): void
226
    {
227
        foreach (static::getRequiredBindings() as $id) {
228
            if (!$this->container->has($id)) {
229
                throw new \RuntimeException("The SDK container is missing the following dependency: '{$id}'.");
230
            }
231
        }
232
    }
233
234
    /**
235
     * Builds the container.
236
     *
237
     * @return Container The container.
238
     * @throws ContainerException
239
     */
240
    public function buildContainer(): Container
241
    {
242
        $this->bindDefaults();
243
        $this->bindExternal();
244
        $this->verifyRequiredBindings();
245
        return $this->container;
246
    }
247
248
    /**
249
     * Builds the default container with all SDK dependencies.
250
     *
251
     * @return Container The container.
252
     * @throws ContainerException
253
     */
254
    public static function buildDefaultContainer(): Container
255
    {
256
        return (new static())->buildContainer();
257
    }
258
}
259