Passed
Push — master ( 51dcfe...4ee661 )
by Ryuichi
02:30
created

anonymous//Modules/ClassLoader/ClassLoader.php$0   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 1
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
rs 10
c 0
b 0
f 0
wmc 1
1
<?php
2
namespace WebStream\ClassLoader;
3
4
use WebStream\DI\Injector;
5
use WebStream\IO\File;
6
use WebStream\IO\FileInputStream;
7
8
/**
9
 * クラスローダ
10
 * @author Ryuichi TANAKA.
11
 * @since 2013/09/02
12
 * @version 0.7
13
 */
14
class ClassLoader
15
{
16
    use Injector;
17
18
    /**
19
     * @var Psr\Log\LoggerInterface
0 ignored issues
show
Bug introduced by
The type WebStream\ClassLoader\Psr\Log\LoggerInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
     */
21
    private $logger;
22
23
    /**
24
     * @var string アプリケーションルートパス
25
     */
26
    private $applicationRoot;
27
28
    /**
29
     * constructor
30
     * @param string アプリケーションルートパス
31
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment アプリケーションルートパス at position 0 could not be parsed: Unknown type name 'アプリケーションルートパス' at position 0 in アプリケーションルートパス.
Loading history...
32
    public function __construct(string $applicationRoot)
33
    {
34
        $this->logger = new class() { function __call($name, $args) {} };
0 ignored issues
show
Documentation Bug introduced by
It seems like new ClassNode() of type anonymous//Modules/ClassLoader/ClassLoader.php$0 is incompatible with the declared type WebStream\ClassLoader\Psr\Log\LoggerInterface of property $logger.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
35
        $this->applicationRoot = $applicationRoot;
36
    }
37
38
    /**
39
     * クラスをロードする
40
     * @param mixed クラスまたはクラスリスト
41
     * @return array<string> ロード済みクラスリスト
42
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment クラスまたはクラスリスト at position 0 could not be parsed: Unknown type name 'クラスまたはクラスリスト' at position 0 in クラスまたはクラスリスト.
Loading history...
43
    public function load($target): array
44
    {
45
        return is_array($target) ? $this->loadClassList($target) : $this->loadClass($target);
46
    }
47
48
    /**
49
     * ファイルをインポートする
50
     * @param string ファイルパス
51
     * @param callable フィルタリング無名関数 trueを返すとインポート
52
     * @return bool インポート結果
53
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment ファイルパス at position 0 could not be parsed: Unknown type name 'ファイルパス' at position 0 in ファイルパス.
Loading history...
54
    public function import($filepath, callable $filter = null): bool
55
    {
56
        $file = new File($this->applicationRoot . "/" . $filepath);
57 View Code Duplication
        if ($file->isFile()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
58
            if ($file->getFileExtension() === 'php') {
59
                if ($filter === null || (is_callable($filter) && $filter($file->getFilePath()) === true)) {
60
                    include_once $file->getFilePath();
61
                    $this->logger->debug($file->getFilePath() . " import success.");
62
                }
63
            }
64
65
            return true;
66
        }
67
68
        return false;
69
    }
70
71
    /**
72
     * 指定ディレクトリのファイルをインポートする
73
     * @param string ディレクトリパス
74
     * @param callable フィルタリング無名関数 trueを返すとインポート
75
     * @return bool インポート結果
76
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment ディレクトリパス at position 0 could not be parsed: Unknown type name 'ディレクトリパス' at position 0 in ディレクトリパス.
Loading history...
77
    public function importAll($dirPath, callable $filter = null): bool
78
    {
79
        $dir = new File($this->applicationRoot . "/" . $dirPath);
80
        $isSuccess = true;
81
        if ($dir->isDirectory()) {
82
            $iterator = $this->getFileSearchIterator($dir->getFilePath());
83
            foreach ($iterator as $filepath => $fileObject) {
84
                if (preg_match("/(?:\/\.|\/\.\.|\.DS_Store)$/", $filepath)) {
85
                    continue;
86
                }
87
                $file = new File($filepath);
88
                if ($file->isFile()) {
89 View Code Duplication
                    if ($file->getFileExtension() === 'php') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
                        if ($filter === null || (is_callable($filter) && $filter($file->getFilePath()) === true)) {
91
                            include_once $file->getFilePath();
92
                            $this->logger->debug($file->getFilePath() . " import success.");
93
                        }
94
                    }
95
                } else {
96
                    $this->logger->warn($filepath . " import failure.");
97
                    $isSuccess = false;
98
                }
99
            }
100
        }
101
102
        return $isSuccess;
103
    }
104
105
    /**
106
     * 名前空間リストを返却する
107
     * @param string ファイル名
108
     * @return array<string> 名前空間リスト
109
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment ファイル名 at position 0 could not be parsed: Unknown type name 'ファイル名' at position 0 in ファイル名.
Loading history...
110
    public function getNamespaces($fileName)
111
    {
112
        $dir = new File($this->applicationRoot);
113
        $namespaces = [];
114
        if ($dir->isDirectory()) {
115
            $iterator = $this->getFileSearchIterator($dir->getFilePath());
116
            foreach ($iterator as $filepath => $fileObject) {
117
                if (preg_match("/(?:\/\.|\/\.\.|\.DS_Store)$/", $filepath)) {
118
                    continue;
119
                }
120
                $file = new File($filepath);
121
                if ($file->isFile() && $file->getFileName() === $fileName) {
122
                    $fis = new FileInputStream($file);
123
                    while (($line = $fis->readLine()) !== null) {
124
                        if (preg_match("/^namespace\s(.*);$/", $line, $matches)) {
125
                            $namespace = $matches[1];
126
                            if (substr($namespace, 0) !== '\\') {
127
                                $namespace = '\\' . $namespace;
128
                            }
129
                            $namespaces[] = $namespace;
130
                        }
131
                    }
132
                    $fis->close();
133
                }
134
            }
135
        }
136
137
        return $namespaces;
138
    }
139
140
    /**
141
    * ロード可能なクラスを返却する
142
    * @param string クラス名(フルパス指定の場合はクラスパス)
143
    * @return array<string> ロード可能クラス
144
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment ... at position 0 could not be parsed: Unknown type name 'クラス名' at position 0 in クラス名(フルパス指定の場合はクラスパス).
Loading history...
145
    private function loadClass(string $className): array
146
    {
147
        $rootDir = $this->applicationRoot;
148
        $logger = $this->logger;
149
150
        // 名前空間セパレータをパスセパレータに置換
151
        if (DIRECTORY_SEPARATOR === '/') {
152
            $className = str_replace("\\", DIRECTORY_SEPARATOR, $className);
153
        }
154
155
        $search = function ($dirPath, $searchFilePath) use ($logger) {
156
            $includeList = [];
157
            $dir = new File($dirPath);
158
            if (!$dir->isDirectory()) {
159
                $logger->error("Invalid search directory path: " . $dir->getFilePath());
160
                return $includeList;
161
            }
162
            $iterator = $this->getFileSearchIterator($dir->getFilePath());
163
            foreach ($iterator as $filepath => $fileObject) {
164
                if (!$fileObject->isFile()) {
165
                    continue;
166
                }
167
                if (strpos($filepath, $searchFilePath) !== false) {
168
                    $file = new File($filepath);
169
                    $absoluteFilePath = $file->getAbsoluteFilePath();
170
                    include_once $absoluteFilePath;
171
                    $includeList[] = $absoluteFilePath;
172
                    $logger->debug($absoluteFilePath . " load success. (search from " . $dir->getFilePath());
173
                }
174
            }
175
176
            return $includeList;
177
        };
178
179
        return $search("${rootDir}", DIRECTORY_SEPARATOR . "${className}.php");
180
    }
181
182
    /**
183
     * ロード可能なクラスを複数返却する
184
     * @param array クラス名
185
     * @return array<string> ロード済みクラスリスト
186
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment クラス名 at position 0 could not be parsed: Unknown type name 'クラス名' at position 0 in クラス名.
Loading history...
187
    private function loadClassList(array $classList): array
188
    {
189
        $includedlist = [];
190
        foreach ($classList as $className) {
191
            $result = $this->loadClass($className);
192
            if (is_array($result)) {
193
                $includedlist = array_merge($includedlist, $result);
194
            }
195
        }
196
197
        return $includedlist;
198
    }
199
200
    /**
201
     * ファイル検索イテレータを返却する
202
     * @param string ディレクトリパス
203
     * @return RecursiveIteratorIterator イテレータ
204
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment ディレクトリパス at position 0 could not be parsed: Unknown type name 'ディレクトリパス' at position 0 in ディレクトリパス.
Loading history...
205
    private function getFileSearchIterator(string $path): \RecursiveIteratorIterator
206
    {
207
        $iterator = [];
208
        $file = new File($path);
209
        if ($file->isDirectory()) {
210
            $iterator = new \RecursiveIteratorIterator(
211
                new \RecursiveDirectoryIterator($path),
212
                \RecursiveIteratorIterator::LEAVES_ONLY,
213
                \RecursiveIteratorIterator::CATCH_GET_CHILD // for Permission deny
214
            );
215
        }
216
        return $iterator;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $iterator could return the type array which is incompatible with the type-hinted return RecursiveIteratorIterator. Consider adding an additional type-check to rule them out.
Loading history...
217
    }
218
}
219