Completed
Push — injector ( 82c90d )
by Akihito
02:38
created

AppInjector::cleanupDir()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 5
cts 7
cp 0.7143
rs 9.4285
cc 3
eloc 6
nc 1
nop 1
crap 3.2098
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\Package\Exception\InvalidContextException;
12
use Ray\Compiler\DiCompiler;
13
use Ray\Compiler\Exception\NotCompiled;
14
use Ray\Compiler\ScriptInjector;
15
use Ray\Di\AbstractModule;
16
use Ray\Di\InjectorInterface;
17
use Ray\Di\Name;
18
19
final class AppInjector implements InjectorInterface
20
{
21
    /**
22
     * @var InjectorInterface
23
     */
24
    private $injector;
25
26
    /**
27
     * @var AppMeta
28
     */
29
    private $appMeta;
30
31 8
    public function __construct($name, $contexts)
32
    {
33 8
        $this->appMeta = new AppMeta($name, $contexts);
34 8
        $this->injector = $this->getInjector($this->appMeta, $contexts);
35 6
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 6
    public function getInstance($interface, $name = Name::ANY)
41
    {
42
        try {
43 6
            return $this->injector->getInstance($interface, $name);
44 1
        } catch (NotCompiled $e) {
45 1
            file_put_contents(sprintf('%s/%s', $this->appMeta->logDir, 'compile-err.log'), (string) $e);
46
47 1
            throw $e;
48
        }
49
    }
50
51
    /**
52
     * @param AbstractAppMeta $appMeta
53
     * @param string          $contexts
54
     *
55
     * @return InjectorInterface
56
     */
57 8
    private function getInjector(AbstractAppMeta $appMeta, $contexts)
58
    {
59 8
        $module = $this->newModule($appMeta, $contexts);
60 6
        $module->override(new AppMetaModule($appMeta));
61 6
        $scriptDir = $appMeta->tmpDir;
62 6
        $scriptInjector = new ScriptInjector($scriptDir);
63
        try {
64 6
            $injector = $scriptInjector->getInstance(InjectorInterface::class);
65 4
        } catch (NotCompiled $e) {
66 4
            $this->compile($module, $appMeta, $scriptDir);
0 ignored issues
show
Bug introduced by
It seems like $module defined by $this->newModule($appMeta, $contexts) on line 59 can be null; however, BEAR\Package\AppInjector::compile() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
67 4
            $injector = $scriptInjector->getInstance(InjectorInterface::class);
68
        }
69
70 6
        return $injector;
71
    }
72
73
    /**
74
     * Compile dependencies
75
     *
76
     * @param AbstractModule  $module
77
     * @param AbstractAppMeta $appMeta
78
     * @param string          $contexts
0 ignored issues
show
Bug introduced by
There is no parameter named $contexts. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
Coding Style introduced by
Doc comment for parameter $contexts does not match actual variable name $scriptDir
Loading history...
79
     */
80 4
    private function compile(AbstractModule $module, AbstractAppMeta $appMeta, $scriptDir)
81
    {
82 4
        $hashFile = $appMeta->tmpDir . '/compile_hash';
83 4
        $moduleHash = md5(serialize($module));
84 4
        $isUnchanged = file_exists($hashFile) && (file_get_contents($hashFile) === $moduleHash);
85 4
        if ($isUnchanged) {
86
            return;
87
        }
88 4
        $this->cleanupDir($scriptDir);
89 4
        $compiler = new DiCompiler($module, $scriptDir);
90 4
        $compiler->compile();
91 4
        file_put_contents($hashFile, $moduleHash);
92 4
    }
93
94
    /**
95
     * Return configured module
96
     *
97
     * @param AbstractAppMeta $appMeta
98
     * @param string          $contexts
99
     *
100
     * @return AbstractModule
101
     */
102 8
    private function newModule(AbstractAppMeta $appMeta, $contexts)
103
    {
104 8
        $contextsArray = array_reverse(explode('-', $contexts));
105 8
        $module = null;
106 8
        foreach ($contextsArray as $context) {
107 8
            $class = $appMeta->name . '\Module\\' . ucwords($context) . 'Module';
108 8
            if (! class_exists($class)) {
109 6
                $class = 'BEAR\Package\Context\\' . ucwords($context) . 'Module';
110
            }
111 8
            if (! is_a($class, AbstractModule::class, true)) {
112 2
                throw new InvalidContextException($class);
113
            }
114
            /* @var $module AbstractModule */
115 6
            $module = new $class($module);
116
        }
117
118 6
        return $module;
119
    }
120
121
    /**
122
     * @param string $tmpDir Cleanup directory
123
     */
124
    private function cleanupDir($tmpDir)
125
    {
126 4
        $unlink = function ($path) use (&$unlink) {
127 4
            foreach (glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*') as $file) {
128
                is_dir($file) ? $unlink($file) : unlink($file);
129
                @rmdir($file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
130
            }
131 4
        };
132 4
        $unlink($tmpDir);
133 4
    }
134
}
135