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

Pay::make()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 10
c 2
b 1
f 0
dl 0
loc 17
rs 9.6111
cc 5
nc 8
nop 2
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): Pay
103
    {
104
        if (self::hasContainer() && !($config['_force'] ?? false)) {
105
            return self::get(Pay::class);
106
        }
107
108
        return new self($config, $container);
109
    }
110
111
    /**
112
     * @param mixed $value
113
     *
114
     * @throws \Yansongda\Pay\Exception\ContainerException
115
     */
116
    public static function set(string $name, $value): void
117
    {
118
        try {
119
            $container = Pay::getContainer();
120
121
            if ($container instanceof Contract\ContainerInterface || method_exists($container, 'set')) {
122
                $container->set(...func_get_args());
123
124
                return;
125
            }
126
        } catch (ContainerNotFoundException $e) {
127
            throw $e;
128
        } catch (Throwable $e) {
129
            throw new ContainerException($e->getMessage());
130
        }
131
132
        throw new ContainerException('Current container does NOT support `set` method');
133
    }
134
135
    /**
136
     * @throws \Yansongda\Pay\Exception\ContainerException
137
     *
138
     * @return mixed
139
     */
140
    public static function make(string $service, array $parameters = [])
141
    {
142
        try {
143
            $container = Pay::getContainer();
144
145
            if ($container instanceof Contract\ContainerInterface || method_exists($container, 'make')) {
146
                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

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