Completed
Branch 1.x (abde83)
by Akihito
05:39 queued 04:04
created

Bootstrap   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 49
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%

Importance

Changes 8
Bugs 0 Features 0
Metric Value
wmc 8
c 8
b 0
f 0
lcom 1
cbo 9
dl 0
loc 49
ccs 22
cts 22
cp 1
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getApp() 0 4 1
B newApp() 0 14 6
A getInstance() 0 14 1
1
<?php
2
/**
3
 * This file is part of the BEAR.Package package.
4
 *
5
 * @license http://opensource.org/licenses/MIT MIT
6
 */
7
namespace BEAR\Package;
8
9
use BEAR\AppMeta\AbstractAppMeta;
10
use BEAR\AppMeta\AppMeta;
11
use BEAR\Resource\ResourceInterface;
12
use BEAR\Sunday\Extension\Application\AbstractApp;
13
use BEAR\Sunday\Extension\Application\AppInterface;
14
use Doctrine\Common\Annotations\Reader;
15
use Doctrine\Common\Cache\ApcuCache;
16
use Doctrine\Common\Cache\Cache;
17
use Doctrine\Common\Cache\ChainCache;
18
use Doctrine\Common\Cache\FilesystemCache;
19
use Doctrine\Common\Cache\VoidCache;
20
use Psr\Log\LoggerInterface;
21
use Ray\Compiler\ScriptInjector;
22
23
/**
24
 * Bootstrap
25
 *
26
 * Create an app object that contains all the objects used in the bootstrap script The bootstrap script uses the public
27
 * property of $ app to run the application.
28
 *
29
 * AppModule knows the binding of all interfaces. Other context modules override bindings on the interface. For example,
30
 * `app` binds JsonRenderer and outputs JSON. In` html-prod`, HtmlModule overwrites the binding on TwigRenderer and
31
 * outputs html.
32
 */
33
final class Bootstrap
34
{
35
    /**
36
     * Return application instance by name and contexts
37
     *
38
     * Use newApp() instead for your own AppMeta and Cache.
39
     *
40
     * @param string $name     application name    'koriym\blog' (vendor\package)
41
     * @param string $contexts application context 'prd-html-app'
42
     * @param string $appDir   application path
43
     */
44 3
    public function getApp(string $name, string $contexts, string $appDir = null) : AbstractApp
45
    {
46 3
        return $this->newApp(new AppMeta($name, $contexts, $appDir), $contexts);
47
    }
48
49
    /**
50
     * Return cached contextual application instance
51
     */
52 6
    public function newApp(AbstractAppMeta $appMeta, string $contexts, Cache $cache = null) : AbstractApp
53
    {
54 6
        $isCacheable = is_int(strpos($contexts, 'prod-')) || is_int(strpos($contexts, 'stage-'));
55 6
        $cache = $cache ?: ($isCacheable ? new ChainCache([new ApcuCache, new FilesystemCache($appMeta->tmpDir)]) : new VoidCache);
56 6
        $appId = $appMeta->name . $contexts . filemtime($appMeta->appDir . '/src');
57 6
        list($app) = $cache->fetch($appId); // $scriptInjector set cached single instance in wakeup
58 6
        if ($app && $app instanceof AbstractApp) {
59 1
            return $app;
60
        }
61 6
        list($app, $injector) = $this->getInstance($appMeta, $contexts);
62 5
        $cache->save($appId, [$app, $injector]); // save $app with injector to save singleton instance (in ScriptInjector::$singletons)
63
64 5
        return $app;
65
    }
66
67 6
    private function getInstance(AbstractAppMeta $appMeta, string $contexts) : array
68
    {
69 6
        $app = (new AppInjector($appMeta->name, $contexts))->getInstance(AppInterface::class);
70 5
        $injector = new ScriptInjector($appMeta->tmpDir);
71
        // save singleton instance cache
72 5
        $injector->getInstance(Reader::class);
73 5
        $injector->getInstance(Cache::class);
74 5
        $injector->getInstance(LoggerInterface::class);
75 5
        $injector->getInstance(ResourceInterface::class);
76 5
        $log = sprintf('%s/context.%s.log', $appMeta->logDir, $contexts);
77 5
        file_put_contents($log, print_r($app, true));
78
79 5
        return [$app, $injector];
80
    }
81
}
82