Passed
Pull Request — master (#579)
by Songda
02:00
created

Pay::initContainer()   A

Complexity

Conditions 2
Paths 5

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
c 0
b 0
f 0
dl 0
loc 14
rs 9.9332
cc 2
nc 5
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yansongda\Pay;
6
7
use Closure;
8
use Psr\Container\ContainerInterface;
9
use Psr\Container\NotFoundExceptionInterface;
10
use Throwable;
11
use Yansongda\Pay\Contract\ServiceProviderInterface;
12
use Yansongda\Pay\Exception\ContainerException;
13
use Yansongda\Pay\Exception\ContainerNotFoundException;
14
use Yansongda\Pay\Exception\ServiceNotFoundException;
15
use Yansongda\Pay\Provider\Alipay;
16
use Yansongda\Pay\Provider\Wechat;
17
use Yansongda\Pay\Service\AlipayServiceProvider;
18
use Yansongda\Pay\Service\ConfigServiceProvider;
19
use Yansongda\Pay\Service\ContainerServiceProvider;
20
use Yansongda\Pay\Service\EventServiceProvider;
21
use Yansongda\Pay\Service\HttpServiceProvider;
22
use Yansongda\Pay\Service\LoggerServiceProvider;
23
use Yansongda\Pay\Service\WechatServiceProvider;
24
25
/**
26
 * @method static Alipay alipay(array $config = [])
27
 * @method static Wechat wechat(array $config = [])
28
 */
29
class Pay
30
{
31
    /**
32
     * 正常模式.
33
     */
34
    public const MODE_NORMAL = 0;
35
36
    /**
37
     * 沙箱模式.
38
     */
39
    public const MODE_SANDBOX = 1;
40
41
    /**
42
     * 服务商模式.
43
     */
44
    public const MODE_SERVICE = 2;
45
46
    /**
47
     * @var string[]
48
     */
49
    protected $service = [
50
        AlipayServiceProvider::class,
51
        WechatServiceProvider::class,
52
    ];
53
54
    /**
55
     * @var string[]
56
     */
57
    private $coreService = [
58
        ConfigServiceProvider::class,
59
        LoggerServiceProvider::class,
60
        EventServiceProvider::class,
61
        HttpServiceProvider::class,
62
    ];
63
64
    /**
65
     * @var \Closure|\Psr\Container\ContainerInterface|null
66
     */
67
    private static $container = null;
68
69
    /**
70
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
71
     *
72
     * @throws \Yansongda\Pay\Exception\ContainerException
73
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
74
     */
75
    private function __construct(array $config, $container = null)
76
    {
77
        $this->registerContainer($container);
78
        $this->registerServices($config);
79
    }
80
81
    /**
82
     * @throws \Yansongda\Pay\Exception\ContainerException
83
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
84
     *
85
     * @return mixed
86
     */
87
    public static function __callStatic(string $service, array $config)
88
    {
89
        if (!empty($config)) {
90
            self::config(...$config);
0 ignored issues
show
Bug introduced by
$config is expanded, but the parameter $config of Yansongda\Pay\Pay::config() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
            self::config(/** @scrutinizer ignore-type */ ...$config);
Loading history...
91
        }
92
93
        return self::get($service);
94
    }
95
96
    /**
97
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
98
     *
99
     * @throws \Yansongda\Pay\Exception\ContainerException
100
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
101
     */
102
    public static function config(array $config = [], $container = null): bool
103
    {
104
        if (self::hasContainer() && !($config['_force'] ?? false)) {
105
            return false;
106
        }
107
108
        new self($config, $container);
109
110
        return true;
111
    }
112
113
    /**
114
     * @param mixed $value
115
     *
116
     * @throws \Yansongda\Pay\Exception\ContainerException
117
     */
118
    public static function set(string $name, $value): void
119
    {
120
        try {
121
            $container = Pay::getContainer();
122
123
            if ($container instanceof Contract\ContainerInterface || method_exists($container, 'set')) {
124
                $container->set(...func_get_args());
125
126
                return;
127
            }
128
        } catch (ContainerNotFoundException $e) {
129
            throw $e;
130
        } catch (Throwable $e) {
131
            throw new ContainerException($e->getMessage());
132
        }
133
134
        throw new ContainerException('Current container does NOT support `set` method');
135
    }
136
137
    /**
138
     * @throws \Yansongda\Pay\Exception\ContainerException
139
     *
140
     * @return mixed
141
     */
142
    public static function make(string $service, array $parameters = [])
143
    {
144
        try {
145
            $container = Pay::getContainer();
146
147
            if ($container instanceof Contract\ContainerInterface || method_exists($container, 'make')) {
148
                return $container->make(...func_get_args());
0 ignored issues
show
Bug introduced by
func_get_args() is expanded, but the parameter $name of Yansongda\Pay\Contract\ContainerInterface::make() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

148
                return $container->make(/** @scrutinizer ignore-type */ ...func_get_args());
Loading history...
149
            }
150
        } catch (ContainerNotFoundException $e) {
151
            throw $e;
152
        } catch (Throwable $e) {
153
            throw new ContainerException($e->getMessage());
154
        }
155
156
        $parameters = array_values($parameters);
157
158
        return new $service(...$parameters);
159
    }
160
161
    /**
162
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
163
     * @throws \Yansongda\Pay\Exception\ContainerException
164
     *
165
     * @return mixed
166
     */
167
    public static function get(string $service)
168
    {
169
        try {
170
            return Pay::getContainer()->get($service);
171
        } catch (NotFoundExceptionInterface $e) {
172
            throw new ServiceNotFoundException($e->getMessage());
173
        } catch (Throwable $e) {
174
            throw new ContainerException($e->getMessage());
175
        }
176
    }
177
178
    /**
179
     * @throws \Yansongda\Pay\Exception\ContainerNotFoundException
180
     */
181
    public static function has(string $service): bool
182
    {
183
        return Pay::getContainer()->has($service);
184
    }
185
186
    /**
187
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
188
     */
189
    public static function setContainer($container): void
190
    {
191
        self::$container = $container;
192
    }
193
194
    /**
195
     * @throws \Yansongda\Pay\Exception\ContainerNotFoundException
196
     */
197
    public static function getContainer(): ContainerInterface
198
    {
199
        if (self::$container instanceof ContainerInterface) {
200
            return self::$container;
201
        }
202
203
        if (self::$container instanceof Closure) {
204
            return (self::$container)();
205
        }
206
207
        throw new ContainerNotFoundException('`getContainer()` failed! Maybe you should `setContainer()` first', Exception\Exception::CONTAINER_NOT_FOUND);
208
    }
209
210
    public static function hasContainer(): bool
211
    {
212
        return self::$container instanceof ContainerInterface || self::$container instanceof Closure;
213
    }
214
215
    public static function clear(): void
216
    {
217
        self::$container = null;
218
    }
219
220
    /**
221
     * @throws \Yansongda\Pay\Exception\ContainerException
222
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
223
     */
224
    public static function registerService(string $service, array $config): void
225
    {
226
        $var = self::get($service);
227
228
        if ($var instanceof ServiceProviderInterface) {
229
            $var->register($config);
230
        }
231
    }
232
233
    /**
234
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
235
     *
236
     * @throws \Yansongda\Pay\Exception\ContainerException
237
     */
238
    private function registerContainer($container = null): void
239
    {
240
        if ($container instanceof ContainerInterface || $container instanceof Closure) {
241
            self::$container = $container;
242
243
            return;
244
        }
245
246
        $this->tryRegisterContainer();
247
    }
248
249
    /**
250
     * @throws \Yansongda\Pay\Exception\ContainerException
251
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
252
     */
253
    private function registerServices(array $config): void
254
    {
255
        foreach (array_merge($this->coreService, $this->service) as $service) {
256
            self::registerService($service, $config);
257
        }
258
    }
259
260
    /**
261
     * @throws \Yansongda\Pay\Exception\ContainerException
262
     */
263
    private function tryRegisterContainer(): void
264
    {
265
        $cs = new ContainerServiceProvider();
266
267
        $cs->register();
268
    }
269
}
270