Passed
Branch master (afcd62)
by Songda
02:00
created

Pay::setContainer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
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 = [], $container = null)
27
 * @method static Wechat wechat(array $config = [], $container = null)
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 array $service = [
50
        AlipayServiceProvider::class,
51
        WechatServiceProvider::class,
52
    ];
53
54
    /**
55
     * @var string[]
56
     */
57
    private array $coreService = [
58
        ContainerServiceProvider::class,
59
        ConfigServiceProvider::class,
60
        LoggerServiceProvider::class,
61
        EventServiceProvider::class,
62
        HttpServiceProvider::class,
63
    ];
64
65
    /**
66
     * @var \Closure|\Psr\Container\ContainerInterface|null
67
     */
68
    private static $container = null;
69
70
    /**
71
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
72
     *
73
     * @throws \Yansongda\Pay\Exception\ContainerException
74
     */
75
    private function __construct(array $config, $container = null)
76
    {
77
        $this->registerServices($config, $container);
78
    }
79
80
    /**
81
     * @throws \Yansongda\Pay\Exception\ContainerException
82
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
83
     *
84
     * @return mixed
85
     */
86
    public static function __callStatic(string $service, array $config)
87
    {
88
        if (!empty($config)) {
89
            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

89
            self::config(/** @scrutinizer ignore-type */ ...$config);
Loading history...
90
        }
91
92
        return self::get($service);
93
    }
94
95
    /**
96
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
97
     *
98
     * @throws \Yansongda\Pay\Exception\ContainerException
99
     */
100
    public static function config(array $config = [], $container = null): bool
101
    {
102
        if (self::hasContainer() && !($config['_force'] ?? false)) {
103
            return false;
104
        }
105
106
        new self($config, $container);
107
108
        return true;
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 (method_exists($container, 'set')) {
122
                $container->set(...func_get_args());
123
124
                return;
125
            }
126
127
            // laravel
128
            if (method_exists($container, 'singleton')) {
129
                $container->singleton($name, $value instanceof Closure ? $value : static function () use ($value) {
130
                    return $value;
131
                });
132
133
                return;
134
            }
135
        } catch (ContainerNotFoundException $e) {
136
            throw $e;
137
        } catch (Throwable $e) {
138
            throw new ContainerException($e->getMessage());
139
        }
140
141
        throw new ContainerException('Current container does NOT support `set` method');
142
    }
143
144
    /**
145
     * @throws \Yansongda\Pay\Exception\ContainerException
146
     *
147
     * @return mixed
148
     */
149
    public static function make(string $service, array $parameters = [])
150
    {
151
        try {
152
            $container = Pay::getContainer();
153
154
            if (method_exists($container, 'make')) {
155
                return $container->make(...func_get_args());
156
            }
157
        } catch (ContainerNotFoundException $e) {
158
            throw $e;
159
        } catch (Throwable $e) {
160
            throw new ContainerException($e->getMessage());
161
        }
162
163
        $parameters = array_values($parameters);
164
165
        return new $service(...$parameters);
166
    }
167
168
    /**
169
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
170
     * @throws \Yansongda\Pay\Exception\ContainerException
171
     *
172
     * @return mixed
173
     */
174
    public static function get(string $service)
175
    {
176
        try {
177
            return Pay::getContainer()->get($service);
178
        } catch (NotFoundExceptionInterface $e) {
179
            throw new ServiceNotFoundException($e->getMessage());
180
        } catch (Throwable $e) {
181
            throw new ContainerException($e->getMessage());
182
        }
183
    }
184
185
    /**
186
     * @throws \Yansongda\Pay\Exception\ContainerNotFoundException
187
     */
188
    public static function has(string $service): bool
189
    {
190
        return Pay::getContainer()->has($service);
191
    }
192
193
    /**
194
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
195
     */
196
    public static function setContainer($container): void
197
    {
198
        self::$container = $container;
199
    }
200
201
    /**
202
     * @throws \Yansongda\Pay\Exception\ContainerNotFoundException
203
     */
204
    public static function getContainer(): ContainerInterface
205
    {
206
        if (self::$container instanceof ContainerInterface) {
207
            return self::$container;
208
        }
209
210
        if (self::$container instanceof Closure) {
211
            return (self::$container)();
212
        }
213
214
        throw new ContainerNotFoundException('`getContainer()` failed! Maybe you should `setContainer()` first', Exception\Exception::CONTAINER_NOT_FOUND);
215
    }
216
217
    public static function hasContainer(): bool
218
    {
219
        return self::$container instanceof ContainerInterface || self::$container instanceof Closure;
220
    }
221
222
    public static function clear(): void
223
    {
224
        self::$container = null;
225
    }
226
227
    /**
228
     * @param mixed $data
229
     *
230
     * @throws \Yansongda\Pay\Exception\ContainerException
231
     */
232
    public static function registerService(string $service, $data): void
233
    {
234
        $var = new $service();
235
236
        if ($var instanceof ServiceProviderInterface) {
237
            $var->register($data);
238
        }
239
    }
240
241
    /**
242
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
243
     *
244
     * @throws \Yansongda\Pay\Exception\ContainerException
245
     */
246
    private function registerServices(array $config, $container = null): void
247
    {
248
        foreach (array_merge($this->coreService, $this->service) as $service) {
249
            self::registerService($service, ContainerServiceProvider::class == $service ? $container : $config);
250
        }
251
    }
252
}
253