ClassFinder   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 2
dl 0
loc 147
ccs 58
cts 58
cp 1
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A findClasses() 0 9 1
A log() 0 9 2
A getFiles() 0 25 5
A isRequiredFile() 0 4 1
A loadFiles() 0 6 2
A identifyClasses() 0 12 3
A isA() 0 9 1
1
<?php
2
/**
3
 * This file is part of the NeedleProject\Common package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
namespace NeedleProject\Common;
9
10
use Psr\Log\LoggerAwareTrait;
11
use Psr\Log\LogLevel;
12
13
/**
14
 * Class ErrorToExceptionConverter
15
 *
16
 * @package NeedleProject\Common
17
 * @author Adrian Tilita <[email protected]>
18
 * @copyright 2017 Adrian Tilita
19
 * @license https://opensource.org/licenses/MIT MIT Licence
20
 */
21
class ClassFinder
22
{
23
    use LoggerAwareTrait;
24
25
    /**
26
     * @const string
27
     */
28
    const BASE_EXTENSION = '.php';
29
30
    /**
31
     * @var null|string Fully qualified path
32
     */
33
    private $searchPath = null;
34
35
    /**
36
     * @var null|string Fully qualified namespace
37
     */
38
    private $classType = null;
39
40
    /**
41
     * @var null|string The extension of a file in format ".ext"
42
     */
43
    private $extension = null;
44
45
    /**
46
     * ClassSearchService constructor.
47
     * @param string $searchPath    Fully qualified path
48
     * @param string $classType     Fully qualified path
49
     */
50 4
    public function __construct($searchPath, $classType)
51
    {
52 4
        $this->searchPath = $searchPath;
53 4
        $this->classType = $classType;
54 4
        $this->extension = static::BASE_EXTENSION;
55 4
    }
56
57
    /**
58
     * Start searching for files
59
     * @return array
60
     */
61 4
    public function findClasses()
62
    {
63 4
        $files = $this->getFiles($this->searchPath);
64
65
        // if class are not loaded they will ne be caught by "declared_classes"
66 4
        $this->loadFiles($files);
67
68 4
        return $this->identifyClasses();
69
    }
70
71
    /**
72
     * Log Messages
73
     * @param string $message
74
     */
75 4
    private function log($message)
76
    {
77 4
        if (!is_null($this->logger)) {
78 1
            $this->logger->log(
79 1
                LogLevel::DEBUG,
80 1
                sprintf("[%s] - %s", date('Y-m-d H:i:s'), $message)
81 1
            );
82 1
        }
83 4
    }
84
85
    /**
86
     * Scan a directory and list all files that correspond to given criteria
87
     * @param string $directory
88
     * @return array
89
     */
90 4
    private function getFiles($directory)
91
    {
92 4
        $fileList = [];
93 4
        $files = scandir($directory);
94 4
        $this->log(sprintf("Scanning dir %s, found %d files", $directory, count($files)));
95 4
        foreach ($files as $index => $file) {
96
            // recursive retrieve files in subdirectories
97 4
            if (true === is_dir($directory . DIRECTORY_SEPARATOR . $file) && !in_array($file, [".", ".."])) {
98 4
                $fileList = array_merge(
99 4
                    $fileList,
100 4
                    $this->getFiles($directory . DIRECTORY_SEPARATOR . $file)
101 4
                );
102 4
                continue;
103
            }
104
105
            // not the file we want
106 4
            if (false === $this->isRequiredFile($file)) {
107 4
                $this->log(sprintf("Files %s is not required", $directory . DIRECTORY_SEPARATOR . $file));
108 4
                continue;
109
            }
110 4
            $this->log(sprintf("Collected %s", $directory . DIRECTORY_SEPARATOR . $file));
111 4
            $fileList[] = $directory . DIRECTORY_SEPARATOR . $file;
112 4
        }
113 4
        return $fileList;
114
    }
115
116
    /**
117
     * @param string $file
118
     * @return bool
119
     */
120 4
    private function isRequiredFile($file)
121
    {
122 4
        return substr($file, strlen($this->extension) * -1) === $this->extension;
123
    }
124
125
    /**
126
     * Load all files that are not caught by auto-loader
127
     * @param array $files
128
     */
129 4
    private function loadFiles($files)
130
    {
131 4
        foreach ($files as $file) {
132 4
            require_once $file;
133 4
        }
134 4
    }
135
136
    /**
137
     * @return array
138
     */
139 4
    private function identifyClasses()
140
    {
141 4
        $definedClasses = get_declared_classes();
142 4
        $models = [];
143 4
        foreach ($definedClasses as $className) {
144 4
            if (false === $this->isA($className, $this->classType)) {
145 4
                continue;
146
            }
147 4
            $models[] = $className;
148 4
        }
149 4
        return $models;
150
    }
151
152
    /**
153
     * Identify if a class-name extends a type or implements an interface
154
     * @param string $className
155
     * @param string $classType
156
     * @return bool
157
     */
158 4
    private function isA($className, $classType)
159
    {
160 4
        $types = array_merge(
161 4
            class_parents($className),
162 4
            class_implements($className)
163 4
        );
164 4
        $this->log(sprintf("Class %s is a %s", $className, implode(', ', $types)));
165 4
        return in_array($classType, $types);
166
    }
167
}
168