Passed
Pull Request — master (#675)
by Songda
02:35 queued 47s
created

Pay::get()   A

Complexity

Conditions 5
Paths 11

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 18
rs 9.5222
cc 5
nc 11
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yansongda\Pay;
6
7
use Closure;
8
use Illuminate\Container\Container as LaravelContainer;
0 ignored issues
show
Bug introduced by
The type Illuminate\Container\Container was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Psr\Container\ContainerInterface;
10
use Psr\Container\NotFoundExceptionInterface;
11
use think\Container as ThinkPHPContainer;
0 ignored issues
show
Bug introduced by
The type think\Container was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Throwable;
13
use Yansongda\Pay\Contract\ServiceProviderInterface;
14
use Yansongda\Pay\Exception\ContainerException;
15
use Yansongda\Pay\Exception\ContainerNotFoundException;
16
use Yansongda\Pay\Exception\ServiceNotFoundException;
17
use Yansongda\Pay\Provider\Alipay;
18
use Yansongda\Pay\Provider\Wechat;
19
use Yansongda\Pay\Service\AlipayServiceProvider;
20
use Yansongda\Pay\Service\ConfigServiceProvider;
21
use Yansongda\Pay\Service\ContainerServiceProvider;
22
use Yansongda\Pay\Service\EventServiceProvider;
23
use Yansongda\Pay\Service\HttpServiceProvider;
24
use Yansongda\Pay\Service\LoggerServiceProvider;
25
use Yansongda\Pay\Service\WechatServiceProvider;
26
27
/**
28
 * @method static Alipay alipay(array $config = [], $container = null)
29
 * @method static Wechat wechat(array $config = [], $container = null)
30
 */
31
class Pay
32
{
33
    /**
34
     * 正常模式.
35
     */
36
    public const MODE_NORMAL = 0;
37
38
    /**
39
     * 沙箱模式.
40
     */
41
    public const MODE_SANDBOX = 1;
42
43
    /**
44
     * 服务商模式.
45
     */
46
    public const MODE_SERVICE = 2;
47
48
    /**
49
     * @var string[]
50
     */
51
    protected array $service = [
52
        AlipayServiceProvider::class,
53
        WechatServiceProvider::class,
54
    ];
55
56
    /**
57
     * @var string[]
58
     */
59
    private array $coreService = [
60
        ContainerServiceProvider::class,
61
        ConfigServiceProvider::class,
62
        LoggerServiceProvider::class,
63
        EventServiceProvider::class,
64
        HttpServiceProvider::class,
65
    ];
66
67
    /**
68
     * @var \Closure|\Psr\Container\ContainerInterface|null
69
     */
70
    private static $container = null;
71
72
    /**
73
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
74
     *
75
     * @throws \Yansongda\Pay\Exception\ContainerException
76
     */
77
    private function __construct(array $config, $container = null)
78
    {
79
        $this->registerServices($config, $container);
80
    }
81
82
    /**
83
     * @return mixed
84
     *
85
     * @throws \Yansongda\Pay\Exception\ContainerException
86
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
87
     */
88
    public static function __callStatic(string $service, array $config)
89
    {
90
        if (!empty($config)) {
91
            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

91
            self::config(/** @scrutinizer ignore-type */ ...$config);
Loading history...
92
        }
93
94
        return self::get($service);
95
    }
96
97
    /**
98
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
99
     *
100
     * @throws \Yansongda\Pay\Exception\ContainerException
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
     * @codeCoverageIgnore
115
     *
116
     * @param mixed $value
117
     *
118
     * @throws \Yansongda\Pay\Exception\ContainerException
119
     */
120
    public static function set(string $name, $value): void
121
    {
122
        try {
123
            $container = Pay::getContainer();
124
125
            switch (true) {
126
                case $container instanceof LaravelContainer:
127
                    $container->singleton($name, $value instanceof Closure ? $value : static fn () => $value);
0 ignored issues
show
Bug introduced by
The method singleton() does not exist on Psr\Container\ContainerInterface. ( Ignorable by Annotation )

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

127
                    $container->/** @scrutinizer ignore-call */ 
128
                                singleton($name, $value instanceof Closure ? $value : static fn () => $value);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
128
                    break;
129
                case $container instanceof ThinkPHPContainer:
130
                    $container->delete($name);
0 ignored issues
show
Bug introduced by
The method delete() does not exist on Psr\Container\ContainerInterface. ( Ignorable by Annotation )

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

130
                    $container->/** @scrutinizer ignore-call */ 
131
                                delete($name);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
131
                    $container->bind($name, $value instanceof Closure ? $value : static fn () => $value);
0 ignored issues
show
Bug introduced by
The method bind() does not exist on Psr\Container\ContainerInterface. ( Ignorable by Annotation )

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

131
                    $container->/** @scrutinizer ignore-call */ 
132
                                bind($name, $value instanceof Closure ? $value : static fn () => $value);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
132
                    break;
133
                default:
134
                    if (!method_exists($container, 'set')) {
135
                        throw new ContainerException('Current container does NOT support `set` method');
136
                    }
137
138
                    $container->set($name, $value);
139
            }
140
        } catch (ContainerNotFoundException $e) {
141
            throw $e;
142
        } catch (Throwable $e) {
143
            throw new ContainerException($e->getMessage());
144
        }
145
    }
146
147
    /**
148
     * @return mixed
149
     *
150
     * @throws \Yansongda\Pay\Exception\ContainerException
151
     */
152
    public static function make(string $service, array $parameters = [])
153
    {
154
        try {
155
            $container = Pay::getContainer();
156
157
            if (method_exists($container, 'make')) {
158
                return $container->make(...func_get_args());
159
            }
160
        } catch (ContainerNotFoundException $e) {
161
            throw $e;
162
        } catch (Throwable $e) {
163
            throw new ContainerException($e->getMessage());
164
        }
165
166
        $parameters = array_values($parameters);
167
168
        return new $service(...$parameters);
169
    }
170
171
    /**
172
     * @codeCoverageIgnore
173
     *
174
     * @return mixed
175
     *
176
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
177
     * @throws \Yansongda\Pay\Exception\ContainerException
178
     */
179
    public static function get(string $service)
180
    {
181
        try {
182
            $container = Pay::getContainer();
183
184
            // thinkphp 在 `get` 中必须是已经 bind 的,否则会报错,所以这里用其 make 替代
185
            switch (true) {
186
                case $container instanceof ThinkPHPContainer:
187
                    return $container->make($service);
0 ignored issues
show
Bug introduced by
The method make() does not exist on Psr\Container\ContainerInterface. It seems like you code against a sub-type of Psr\Container\ContainerInterface such as Yansongda\Pay\Contract\ContainerInterface. ( Ignorable by Annotation )

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

187
                    return $container->/** @scrutinizer ignore-call */ make($service);
Loading history...
188
                default:
189
                    return $container->get($service);
190
            }
191
        } catch (NotFoundExceptionInterface $e) {
192
            throw new ServiceNotFoundException($e->getMessage());
193
        } catch (ContainerNotFoundException $e) {
194
            throw $e;
195
        } catch (Throwable $e) {
196
            throw new ContainerException($e->getMessage());
197
        }
198
    }
199
200
    /**
201
     * @throws \Yansongda\Pay\Exception\ContainerNotFoundException
202
     */
203
    public static function has(string $service): bool
204
    {
205
        return Pay::getContainer()->has($service);
206
    }
207
208
    /**
209
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
210
     */
211
    public static function setContainer($container): void
212
    {
213
        self::$container = $container;
214
    }
215
216
    /**
217
     * @throws \Yansongda\Pay\Exception\ContainerNotFoundException
218
     */
219
    public static function getContainer(): ContainerInterface
220
    {
221
        if (self::$container instanceof ContainerInterface) {
222
            return self::$container;
223
        }
224
225
        if (self::$container instanceof Closure) {
226
            return (self::$container)();
227
        }
228
229
        throw new ContainerNotFoundException('`getContainer()` failed! Maybe you should `setContainer()` first', Exception\Exception::CONTAINER_NOT_FOUND);
230
    }
231
232
    public static function hasContainer(): bool
233
    {
234
        return self::$container instanceof ContainerInterface || self::$container instanceof Closure;
235
    }
236
237
    public static function clear(): void
238
    {
239
        self::$container = null;
240
    }
241
242
    /**
243
     * @param mixed $data
244
     *
245
     * @throws \Yansongda\Pay\Exception\ContainerException
246
     */
247
    public static function registerService(string $service, $data): void
248
    {
249
        $var = new $service();
250
251
        if ($var instanceof ServiceProviderInterface) {
252
            $var->register($data);
253
        }
254
    }
255
256
    /**
257
     * @param \Closure|\Psr\Container\ContainerInterface|null $container
258
     *
259
     * @throws \Yansongda\Pay\Exception\ContainerException
260
     */
261
    private function registerServices(array $config, $container = null): void
262
    {
263
        foreach (array_merge($this->coreService, $this->service) as $service) {
264
            self::registerService($service, ContainerServiceProvider::class == $service ? $container : $config);
265
        }
266
    }
267
}
268