DetectController::isControllerClass()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Lbil\LaravelGenerator\Http\Controllers\Detect;
4
5
use Illuminate\Routing\Controller;
6
use RecursiveDirectoryIterator;
7
use RecursiveIteratorIterator;
8
use ReflectionClass;
9
use ReflectionMethod;
10
11
class DetectController extends Controller
12
{
13
    /**
14
     * Get the type of all classes in the app folder.
15
     *
16
     * @return array[]
17
     */
18
    public function detect()
19
    {
20
        $recursiveDirectoryIterator = new RecursiveDirectoryIterator(app_path());
21
        $files = new RecursiveIteratorIterator($recursiveDirectoryIterator);
22
        $type = [];
23
24
        foreach ($files as $file) {
25
            if (!$file->isFile() || $file->getExtension() !== 'php') {
26
                continue;
27
            }
28
29
            $class = $this->getClassFromFile($file);
30
            if ($class !== null) {
31
                $type[] = $this->getClassType($class);
32
            }
33
        }
34
35
        return $type;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $type returns an array which contains values of type string which are incompatible with the documented value type array.
Loading history...
36
    }
37
38
    /**
39
     * @param $file
40
     * @return ReflectionClass|null
41
     */
42
    public function getClassFromFile($file)
43
    {
44
        $content = file_get_contents($file);
45
        $matches = [];
46
47
        // Match namespace and class name
48
        preg_match('/namespace\s+(.*?);.*?class\s+(\w+)/s', $content, $matches);
49
        if (!isset($matches[1]) || !isset($matches[2])) {
50
            return null;
51
        }
52
53
        $namespace = $matches[1];
54
        $class = $namespace.'\\'.$matches[2];
55
56
        return class_exists($class) ? new ReflectionClass($class) : null;
57
    }
58
59
    /**
60
     * Get the type of the given class.
61
     *
62
     * @param  ReflectionClass  $class
63
     * @return string
64
     */
65
    protected function getClassType(ReflectionClass $class)
66
    {
67
        $type = 'other';
68
69
        switch (true) {
70
            case $this->isRepositoryClass($class):
71
                $type = 'repository';
72
                break;
73
            case $this->isServiceClass($class):
74
                $type = 'service';
75
                break;
76
            case $this->isControllerClass($class):
77
                $type = 'controller';
78
                break;
79
            case $this->isActionClass($class):
80
                $type = 'action';
81
                break;
82
        }
83
84
        return $type;
85
    }
86
87
    /**
88
     * Check if the class is a repository class
89
     * A repository class must have a name ending with "Repository" or "EloquentRepository"
90
     * and implement the CRUD methods
91
     * and have a dependency on a model.
92
     *
93
     * @param  ReflectionClass  $class
94
     * @return bool
95
     */
96
    public function isRepositoryClass(ReflectionClass $class)
97
    {
98
        return $this->checkClassType($class, 'repository');
99
    }
100
101
    /**
102
     * Check if the class is a class of the given type
103
     * A class of the given type must have a name ending with the given type or "Eloquent" + the given type.
104
     *
105
     * @param  ReflectionClass  $class
106
     * @param $type
107
     * @return bool
108
     */
109
    protected function checkClassType(ReflectionClass $class, $type)
110
    {
111
        $type = ucfirst($type);
112
113
        return preg_match('/'.$type.'$/', $class->getName()) === 1
114
            || preg_match('/Eloquent'.$type.'$/', $class->getName()) === 1
115
            && $this->implementsCrudMethods($class)
116
            && $this->dependsOnModels($class);
117
    }
118
119
    /**
120
     * Check if the class implements the CRUD methods.
121
     *
122
     * @param  ReflectionClass  $class
123
     * @return bool
124
     */
125
    protected function implementsCrudMethods(ReflectionClass $class)
126
    {
127
        $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
128
        $crudMethods = [
129
            'create',
130
            'read',
131
            'update',
132
            'delete',
133
        ];
134
135
        foreach ($methods as $method) {
136
            if (in_array($method->name, $crudMethods)) {
137
                return true;
138
            }
139
        }
140
141
        return false;
142
    }
143
144
    /**
145
     * @param  ReflectionClass  $class
146
     * @return bool
147
     */
148
    private function dependsOnModels(ReflectionClass $class)
149
    {
150
        $dependencies = $class->getConstructor()->getParameters();
151
        foreach ($dependencies as $dependency) {
152
            if (preg_match('/Model$/', $dependency->getClass()->getName()) === 1) {
153
                return true;
154
            }
155
        }
156
157
        return false;
158
    }
159
160
    /**
161
     * Check if the class is a service class
162
     * A service class must have a name ending with "Service" or "EloquentService".
163
     *
164
     * @param  ReflectionClass  $class
165
     * @return bool
166
     */
167
    public function isServiceClass(ReflectionClass $class)
168
    {
169
        return $this->checkClassType($class, 'service');
170
    }
171
172
    /**
173
     * Check if the class is a controller class
174
     * A controller class must have a name ending with "Controller" or "EloquentController"
175
     * and implement the CRUD methods
176
     * and have a dependency on a model.
177
     *
178
     * @param  ReflectionClass  $class
179
     * @return bool
180
     */
181
    public function isControllerClass(ReflectionClass $class)
182
    {
183
        return $this->checkClassType($class, 'controller');
184
    }
185
186
    /**
187
     * Check if the class is an action class
188
     * An action class must have a name ending with "Action" or "EloquentAction".
189
     *
190
     * @param  ReflectionClass  $class
191
     * @return bool
192
     */
193
    public function isActionClass(ReflectionClass $class)
194
    {
195
        return $this->checkClassType($class, 'action');
196
    }
197
}
198