Completed
Branch master (62d6ee)
by Adrian Florin
05:11 queued 02:52
created

ClassFinder::identifyClasses()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

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