Test Failed
Push — master ( 74ebd5...131fc3 )
by Serhii
03:40 queued 14s
created

SearchableListFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
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