Completed
Push — master ( ce0f45...969a46 )
by yuuki
01:36
created

RayAspectKernel::dispatch()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11
 * THE SOFTWARE.
12
 *
13
 * This software consists of voluntary contributions made by many individuals
14
 * and is licensed under the MIT license.
15
 *
16
 * Copyright (c) 2015-2017 Yuuki Takezawa
17
 *
18
 */
19
20
namespace Ytake\LaravelAspect;
21
22
use Illuminate\Contracts\Container\Container;
23
use Illuminate\Filesystem\Filesystem;
24
use Ray\Aop\Compiler;
25
use Ytake\LaravelAspect\Exception\ClassNotFoundException;
26
use Ytake\LaravelAspect\Modules\AspectModule;
27
28
/**
29
 * Class RayAspectKernel
30
 */
31
class RayAspectKernel implements AspectDriverInterface
32
{
33
    /** @var Container|\Illuminate\Container\Container */
34
    protected $app;
35
36
    /** @var array */
37
    protected $configure;
38
39
    /** @var Compiler */
40
    protected $compiler;
41
42
    /** @var Filesystem */
43
    protected $filesystem;
44
45
    /** @var bool */
46
    protected $cacheable = false;
47
48
    /** @var AspectModule */
49
    protected $aspectResolver;
50
51
    /** @var AspectModule[] */
52
    protected $registerModules = [];
53
54
    /** @var AspectModule[] */
55
    protected $modules = [];
56
57
    /** @var string */
58
    private $mapFile = 'aspect.map.serialize';
59
60
    /**
61
     * RayAspectKernel constructor.
62
     *
63
     * @param Container  $app
64
     * @param Filesystem $filesystem
65
     * @param array      $configure
66
     */
67
    public function __construct(Container $app, Filesystem $filesystem, array $configure)
68
    {
69
        $this->app = $app;
70
        $this->filesystem = $filesystem;
71
        $this->configure = $configure;
72
        $this->makeCompileDir();
73
        $this->makeCacheableDir();
74
        $this->registerAspectModule();
75
    }
76
77
    /**
78
     * @param string $module
79
     *
80
     * @throws ClassNotFoundException
81
     */
82
    public function register(string $module = null)
83
    {
84
        if (!class_exists($module)) {
85
            throw new ClassNotFoundException($module);
86
        }
87
        $this->modules[] = new $module;
88
    }
89
90
    /**
91
     * weaving
92
     */
93
    public function weave()
94
    {
95
        if (!count($this->modules)) {
96
            return;
97
        }
98
        $compiler = $this->getCompiler();
99
        $container = $this->containerAdaptor($this->app);
100
        foreach ($this->aspectConfiguration() as $class => $pointcuts) {
101
            $bind = (new AspectBind($this->filesystem, strval($this->configure['cache_dir']), $this->cacheable))
102
                ->bind($class, $pointcuts);
103
            $container->intercept($class, $bind, $compiler->compile($class, $bind));
104
        }
105
    }
106
107
    /**
108
     * @param Container $container
109
     *
110
     * @return ContainerInterceptor
111
     */
112
    protected function containerAdaptor(Container $container): ContainerInterceptor
113
    {
114
        return new ContainerInterceptor($container);
115
    }
116
117
    /**
118
     * @return Compiler
119
     */
120
    protected function getCompiler(): Compiler
121
    {
122
        return new Compiler((string)$this->configure['compile_dir']);
123
    }
124
125
    /**
126
     * make source compile file directory
127
     */
128
    protected function makeCompileDir()
129
    {
130
        $this->makeDirectories(strval($this->configure['compile_dir']), 0775);
131
    }
132
133
    /**
134
     * make aspect cache directory
135
     *
136
     * @codeCoverageIgnore
137
     */
138
    protected function makeCacheableDir()
139
    {
140
        if ($this->configure['cache']) {
141
            $this->makeDirectories(strval($this->configure['cache_dir']), 0775);
142
            $this->cacheable = true;
143
        }
144
    }
145
146
    /**
147
     * @param string $dir
148
     * @param int    $mode
149
     */
150
    private function makeDirectories(string $dir, int $mode = 0777)
151
    {
152
        // @codeCoverageIgnoreStart
153
        if (!$this->filesystem->exists($dir)) {
154
            $this->filesystem->makeDirectory($dir, $mode, true);
155
        }
156
        // @codeCoverageIgnoreEnd
157
    }
158
159
    /**
160
     * register Aspect Module
161
     */
162
    protected function registerAspectModule()
163
    {
164
        if (isset($this->configure['modules'])) {
165
            foreach ($this->configure['modules'] as $module) {
166
                $this->register($module);
167
            }
168
        }
169
    }
170
171
    /**
172
     * @return array
173
     * @codeCoverageIgnore
174
     */
175
    protected function aspectConfiguration(): array
176
    {
177
        $map = [];
178
        $file = $this->configure['cache_dir'] . "/{$this->mapFile}";
179
        if ($this->configure['cache']) {
180
            if ($this->filesystem->exists($file)) {
181
                foreach ($this->modules as $module) {
182
                    $module->registerPointCut()->configure($this->app);
183
                }
184
185
                return unserialize($this->filesystem->get($file));
186
            }
187
        }
188
        foreach ($this->modules as $module) {
189
            $pointcut = $module->registerPointCut()->configure($this->app);
190
            foreach ($module->target() as $class) {
191
                $map[$class][] = $pointcut;
192
            }
193
        }
194
195
        if ($this->configure['cache']) {
196
            $this->filesystem->put($file, serialize($map));
197
        }
198
199
        return $map;
200
    }
201
}
202