Completed
Push — 1.x ( 378c34...640f8a )
by Akihito
12s
created

Bootstrap::newApp()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 6
Bugs 0 Features 0
Metric Value
c 6
b 0
f 0
dl 0
loc 23
ccs 12
cts 12
cp 1
rs 8.5906
cc 6
eloc 17
nc 16
nop 3
crap 6
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
     * @return AbstractApp
45
     */
46 3
    public function getApp($name, $contexts, $appDir = null)
47
    {
48
        return $this->newApp(new AppMeta($name, $contexts, $appDir), $contexts);
49
    }
50
51
    /**
52
     * Return cached contextual application instance
53
     *
54
     * @param AbstractAppMeta $appMeta
55
     * @param string          $contexts
56
     * @param Cache           $cache
57
     *
58 5
     * @return AbstractApp
59
     */
60 5
    public function newApp(AbstractAppMeta $appMeta, $contexts, Cache $cache = null)
61 5
    {
62 5
        $isCacheable = is_int(strpos($contexts, 'prod-')) || is_int(strpos($contexts, 'stage-'));
63 5
        $cache = $cache ?: ($isCacheable ? new ChainCache([new ApcuCache, new FilesystemCache($appMeta->tmpDir)]) : new VoidCache);
64 1
        $appId = $appMeta->name . $contexts . filemtime($appMeta->appDir . '/src');
65
        list($app) = $cache->fetch($appId); // $scriptInjector set cached single instance in wakeup
66 5
        if ($app && $app instanceof AbstractApp) {
67 4
            return $app;
68
        }
69 4
        $app = (new AppInjector($appMeta->name, $contexts))->getInstance(AppInterface::class);
70 4
        $injector = new ScriptInjector($appMeta->tmpDir);
71 4
        // save singleton instance cache
72 4
        $injector->getInstance(Reader::class);
73
        $injector->getInstance(Cache::class);
74 4
        $injector->getInstance(LoggerInterface::class);
75
        $injector->getInstance(ResourceInterface::class);
76
        $log = sprintf('%s/context.%s.log', $appMeta->logDir, $contexts);
77
        file_put_contents($log, print_r($app, true));
78
        // save $app with injector to save singleton instance (in ScriptInjector::$singletons)
79
        $cache->save($appId, [$app, $injector]);
80
81
        return $app;
82
    }
83
}
84