Test Failed
Pull Request — master (#719)
by
unknown
06:13
created

Application::bootstrap()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 9
nc 8
nop 0
dl 0
loc 15
ccs 2
cts 2
cp 1
crap 7
rs 8.2222
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the overtrue/wechat.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
/**
13
 * Application.php.
14
 *
15
 * Part of Overtrue\WeChat.
16
 *
17
 * For the full copyright and license information, please view the LICENSE
18
 * file that was distributed with this source code.
19
 *
20
 * @author    overtrue <[email protected]>
21
 * @copyright 2015
22
 *
23
 * @see      https://github.com/overtrue
24
 * @see      http://overtrue.me
25
 */
26
27
namespace EasyWeChat\Foundation;
28
29
use Doctrine\Common\Cache\Cache as CacheInterface;
30
use Doctrine\Common\Cache\FilesystemCache;
31
use EasyWeChat\Core\AccessToken;
32
use EasyWeChat\Core\Http;
33
use EasyWeChat\Support\Log;
34
use Monolog\Handler\HandlerInterface;
35
use Monolog\Handler\NullHandler;
36
use Monolog\Handler\StreamHandler;
37
use Monolog\Logger;
38
use Pimple\Container;
39
use Symfony\Component\HttpFoundation\Request;
40
41
/**
42
 * Class Application.
43
 *
44
 * @property \EasyWeChat\Core\AccessToken $access_token
45
 * @property \EasyWeChat\Server\Guard $server
46
 * @property \EasyWeChat\User\User $user
47
 * @property \EasyWeChat\User\Tag $user_tag
48
 * @property \EasyWeChat\User\Group $user_group
49
 * @property \EasyWeChat\Js\Js $js
50
 * @property \Overtrue\Socialite\Providers\WeChatProvider $oauth
51
 * @property \EasyWeChat\Menu\Menu $menu
52
 * @property \EasyWeChat\Notice\Notice $notice
53
 * @property \EasyWeChat\Material\Material $material
54
 * @property \EasyWeChat\Material\Temporary $material_temporary
55
 * @property \EasyWeChat\Staff\Staff $staff
56
 * @property \EasyWeChat\Url\Url $url
57
 * @property \EasyWeChat\QRCode\QRCode $qrcode
58
 * @property \EasyWeChat\Semantic\Semantic $semantic
59
 * @property \EasyWeChat\Stats\Stats $stats
60
 * @property \EasyWeChat\Payment\Merchant $merchant
61
 * @property \EasyWeChat\Payment\Payment $payment
62
 * @property \EasyWeChat\Payment\LuckyMoney\LuckyMoney $lucky_money
63
 * @property \EasyWeChat\Payment\MerchantPay\MerchantPay $merchant_pay
64
 * @property \EasyWeChat\Payment\CashCoupon\CashCoupon $cash_coupon
65
 * @property \EasyWeChat\Reply\Reply $reply
66
 * @property \EasyWeChat\Broadcast\Broadcast $broadcast
67
 * @property \EasyWeChat\Card\Card $card
68
 * @property \EasyWeChat\Device\Device $device
69
 * @property \EasyWeChat\Comment\Comment $comment
70
 * @property \EasyWeChat\ShakeAround\ShakeAround $shakearound
71
 * @property \EasyWeChat\OpenPlatform\OpenPlatform $open_platform
72
 * @property \EasyWeChat\MiniProgram\MiniProgram $mini_program
73
 *
74
 * @method \EasyWeChat\Support\Collection clearQuota()
75
 * @method \EasyWeChat\Support\Collection getCallbackIp()
76
 */
77
class Application extends Container
78
{
79
    /**
80
     * Service Providers.
81
     *
82
     * @var array
83
     */
84
    protected $providers = [
85
        ServiceProviders\FundamentalServiceProvider::class,
86
        ServiceProviders\ServerServiceProvider::class,
87
        ServiceProviders\UserServiceProvider::class,
88
        ServiceProviders\JsServiceProvider::class,
89
        ServiceProviders\OAuthServiceProvider::class,
90
        ServiceProviders\MenuServiceProvider::class,
91
        ServiceProviders\NoticeServiceProvider::class,
92
        ServiceProviders\MaterialServiceProvider::class,
93
        ServiceProviders\StaffServiceProvider::class,
94
        ServiceProviders\UrlServiceProvider::class,
95
        ServiceProviders\QRCodeServiceProvider::class,
96
        ServiceProviders\SemanticServiceProvider::class,
97
        ServiceProviders\StatsServiceProvider::class,
98
        ServiceProviders\PaymentServiceProvider::class,
99
        ServiceProviders\POIServiceProvider::class,
100
        ServiceProviders\ReplyServiceProvider::class,
101
        ServiceProviders\BroadcastServiceProvider::class,
102
        ServiceProviders\CardServiceProvider::class,
103
        ServiceProviders\DeviceServiceProvider::class,
104
        ServiceProviders\ShakeAroundServiceProvider::class,
105
        ServiceProviders\OpenPlatformServiceProvider::class,
106
        ServiceProviders\MiniProgramServiceProvider::class,
107
        ServiceProviders\CommentServiceProvider::class,
108
    ];
109
110
    /**
111
     * @var array list of installed wechat extensions. Each array element represents a single extension
112
     * with the following structure:
113
     *
114
     * ```php
115 8
     * [
116
     *     'name' => 'extension name',
117 8
     *     'version' => 'version number',
118
     *     'bootstrap' => 'BootstrapClassName',  // optional, may also be a configuration array
119
     * ]
120 8
     * ```
121
     *
122
     * The "bootstrap" class listed above will be instantiated during the application
123 8
     * [[bootstrap()|bootstrapping process]]. If the class implements [[BootstrapInterface]],
124
     * its [[BootstrapInterface::bootstrap()|bootstrap()]] method will be also be called.
125
     *
126
     * If not set explicitly in the application config, this property will be populated with the contents of
127 8
     * `vendor/overtrue/extensions.php`.
128 8
     */
129 8
    public $extensions;
130
131 8
    /**
132
     * Application constructor.
133 8
     *
134 8
     * @param array $config
135
     */
136
    public function __construct($config)
137
    {
138
        parent::__construct();
139
140
        $this['config'] = function () use ($config) {
141 8
            return new Config($config);
142
        };
143 8
144
        if ($this['config']['debug']) {
145 8
            error_reporting(E_ALL);
146 8
        }
147 8
148 8
        $this->registerProviders();
149
        $this->registerBase();
150 8
        $this->initializeLogger();
151 8
152
        Http::setDefaultOptions($this['config']->get('guzzle', ['timeout' => 5.0]));
153
154
        $this->logConfiguration($config);
155
156
        $this->bootstrap();
157
    }
158
159
    /**
160 1
     * Log configuration.
161
     *
162 1
     * @param array $config
163
     */
164 1
    public function logConfiguration($config)
165
    {
166
        $config = new Config($config);
167
168
        $keys = ['app_id', 'secret', 'open_platform.app_id', 'open_platform.secret', 'mini_program.app_id', 'mini_program.secret'];
169
        foreach ($keys as $key) {
170
            !$config->has($key) || $config[$key] = '***' . substr($config[$key], -5);
171
        }
172 1
173
        Log::debug('Current config:', $config->toArray());
174 1
    }
175
176 1
    /**
177 1
     * Initializes extensions and executes bootstrap extensions.
178 1
     * This method is called by [[__construct()]] after the application has been fully configured.
179 1
     * If you override this method, make sure you also call the parent implementation.
180
     */
181
    protected function bootstrap()
182
    {
183
        if ($this->extensions === null  && isset($this['config']['vendor'])) {
184
            $file = $this['config']['vendor'] . '/overtrue/extensions.php';
185
            $this->extensions = is_file($file) ? include($file) : [];
186 2
        }
187
        foreach ($this->extensions as $extension) {
188 2
            if (isset($extension['bootstrap'])) {
189
                $ext = new $extension['bootstrap'];
190
                if ($ext instanceof BootstrapInterface) {
191
                    $ext->bootstrap($this);
192
                }
193
            }
194
        }
195
    }
196
197
    /**
198 4
     * Add a provider.
199
     *
200 4
     * @param string $provider
201
     *
202
     * @return Application
203
     */
204
    public function addProvider($provider)
205
    {
206
        array_push($this->providers, $provider);
207
208
        return $this;
209 1
    }
210
211 1
    /**
212 1
     * Set providers.
213
     *
214
     * @param array $providers
215
     */
216
    public function setProviders(array $providers)
217 8
    {
218
        $this->providers = [];
219 8
220 8
        foreach ($providers as $provider) {
221 8
            $this->addProvider($provider);
222 8
        }
223
    }
224
225
    /**
226
     * Return all providers.
227 8
     *
228
     * @return array
229
     */
230 2
    public function getProviders()
231
    {
232
        return $this->providers;
233 8
    }
234
235
    /**
236
     * Magic get access.
237 4
     *
238
     * @param string $id
239
     *
240
     * @return mixed
241 1
     */
242 1
    public function __get($id)
243 1
    {
244 1
        return $this->offsetGet($id);
245 1
    }
246 1
247
    /**
248 8
     * Magic set access.
249
     *
250
     * @param string $id
251
     * @param mixed $value
252
     */
253 8
    public function __set($id, $value)
254
    {
255 8
        $this->offsetSet($id, $value);
256 8
    }
257
258
    /**
259
     * Register providers.
260
     */
261
    private function registerProviders()
262
    {
263
        foreach ($this->providers as $provider) {
264
            $this->register(new $provider());
265
        }
266
    }
267
268
    /**
269
     * Register basic providers.
270
     */
271
    private function registerBase()
272
    {
273
        $this['request'] = function () {
274
            return Request::createFromGlobals();
275
        };
276
277
        if (!empty($this['config']['cache']) && $this['config']['cache'] instanceof CacheInterface) {
278
            $this['cache'] = $this['config']['cache'];
279
        } else {
280
            $this['cache'] = function () {
281
                return new FilesystemCache(sys_get_temp_dir());
282
            };
283
        }
284
285
        $this['access_token'] = function () {
286
            return new AccessToken(
287
                $this['config']['app_id'],
288
                $this['config']['secret'],
289
                $this['cache']
290
            );
291
        };
292
    }
293
294
    /**
295
     * Initialize logger.
296
     */
297
    private function initializeLogger()
298
    {
299
        if (Log::hasLogger()) {
300
            return;
301
        }
302
303
        $logger = new Logger('easywechat');
304
305
        if (!$this['config']['debug'] || defined('PHPUNIT_RUNNING')) {
306
            $logger->pushHandler(new NullHandler());
307
        } elseif ($this['config']['log.handler'] instanceof HandlerInterface) {
308
            $logger->pushHandler($this['config']['log.handler']);
309
        } elseif ($logFile = $this['config']['log.file']) {
310
            $logger->pushHandler(new StreamHandler(
311
                    $logFile,
312
                    $this['config']->get('log.level', Logger::WARNING),
313
                    true,
314
                    $this['config']->get('log.permission', null))
315
            );
316
        }
317
318
        Log::setLogger($logger);
319
    }
320
321
    /**
322
     * Magic call.
323
     *
324
     * @param string $method
325
     * @param array $args
326
     *
327
     * @return mixed
328
     *
329
     * @throws \Exception
330
     */
331
    public function __call($method, $args)
332
    {
333
        if (is_callable([$this['fundamental.api'], $method])) {
334
            return call_user_func_array([$this['fundamental.api'], $method], $args);
335
        }
336
337
        throw new \Exception("Call to undefined method {$method}()");
338
    }
339
}
340