Completed
Push — develop ( ecfe6e...c28702 )
by Fabian
02:09
created

ContainerBuilder   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 243
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 79
dl 0
loc 243
rs 10
c 6
b 0
f 0
wmc 20

12 Methods

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