Passed
Push — master ( 06c909...131fc3 )
by Serhii
04:37 queued 12s
created

SearchableListFactory::classNameFromFileContents()   C

Complexity

Conditions 16
Paths 7

Size

Total Lines 48
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 16.9313

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 16
eloc 25
c 3
b 0
f 0
nc 7
nop 1
dl 0
loc 48
ccs 22
cts 26
cp 0.8462
crap 16.9313
rs 5.5666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Matchish\ScoutElasticSearch\Searchable;
6
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Str;
9
use function in_array;
10
use Laravel\Scout\Searchable;
11
use Symfony\Component\Finder\Finder;
12
13
final class SearchableListFactory
14
{
15
    /**
16
     * @var array
17
     */
18
    private static $declaredClasses;
19
    /**
20
     * @var string
21
     */
22
    private $namespace;
23
    /**
24
     * @var string
25
     */
26
    private $appPath;
27
28
    /**
29
     * @param string $namespace
30
     */
31 12
    public function __construct(string $namespace, string $appPath)
32
    {
33 12
        $this->namespace = $namespace;
34 12
        $this->appPath = $appPath;
35 12
    }
36
37
    /**
38
     * Get a list of searchable models.
39
     *
40
     * @return string[]
41
     */
42 12
    private function find(): array
43
    {
44 12
        $appNamespace = $this->namespace;
45
46 12
        return array_values(array_filter($this->getProjectClasses(), function (string $class) use ($appNamespace) {
47 12
            return Str::startsWith($class, $appNamespace) && $this->isSearchableModel($class);
48 12
        }));
49
    }
50
51
    /**
52
     * @param  string $class
53
     *
54
     * @return bool
55
     */
56 12
    private function isSearchableModel($class): bool
57
    {
58 12
        return in_array(Searchable::class, class_uses_recursive($class), true);
59
    }
60
61
    /**
62
     * @return array
63
     */
64 12
    private function getProjectClasses(): array
65
    {
66 12
        if (self::$declaredClasses === null) {
0 ignored issues
show
introduced by
The condition self::declaredClasses === null is always false.
Loading history...
67 1
            self::$declaredClasses = [];
68
69 1
            $configFiles = Finder::create()->files()->name('*.php')->in($this->appPath);
70
71 1
            foreach ($configFiles->files() as $file) {
72 1
                if ($className = $this->classNameFromFileContents($file->getPathname())) {
73 1
                    self::$declaredClasses[] = $className;
74
                }
75
            }
76
        }
77
78 12
        return self::$declaredClasses;
79
    }
80
81
    /**
82
     * @param string $path
83
     * @return string|null
84
     * @link https://stackoverflow.com/a/7153391/1359273
85
     */
86 1
    private function classNameFromFileContents($path)
87
    {
88 1
        $fp = fopen($path, 'r');
89
90 1
        if (false === $fp) {
91
            return null;
92
        }
93
94 1
        $class = $namespace = $buffer = '';
95
96 1
        while (! $class) {
97 1
            if (feof($fp)) {
98
                break;
99
            }
100
101 1
            $buffer .= fread($fp, 512);
102 1
            $tokens = token_get_all($buffer);
103
104 1
            if (strpos($buffer, '{') === false) {
105
                continue;
106
            }
107
108 1
            for ($i = 0, $iMax = count($tokens); $i < $iMax; $i++) {
109 1
                if ($tokens[$i][0] === T_NAMESPACE) {
110 1
                    for ($j = $i + 1, $jMax = count($tokens); $j < $jMax; $j++) {
111 1
                        if ($tokens[$j][0] === T_STRING) {
112 1
                            $namespace .= $tokens[$j][1];
113 1
                        } elseif ($tokens[$j] === '{' || $tokens[$j] === ';') {
114 1
                            break;
115
                        }
116
                    }
117
                }
118
119 1
                if ($tokens[$i][0] === T_CLASS) {
120 1
                    for ($j = $i + 1, $jMax = count($tokens); $j < $jMax; $j++) {
121 1
                        if ($tokens[$j] === '{') {
122 1
                            $class = $tokens[$i + 2][1];
123
                        }
124
                    }
125
                }
126
            }
127
        }
128
129 1
        if (! $class) {
130
            return null;
131
        }
132
133 1
        return $namespace ? "{$namespace}\\{$class}" : $class;
134
    }
135
136
    /**
137
     * @return Collection
138
     */
139 12
    public function make(): Collection
140
    {
141 12
        return new Collection($this->find());
142
    }
143
}
144