Completed
Pull Request — master (#175)
by
unknown
24:47 queued 20:09
created

SearchableFinder   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Test Coverage

Coverage 95.24%

Importance

Changes 0
Metric Value
eloc 34
dl 0
loc 122
ccs 20
cts 21
cp 0.9524
rs 10
c 0
b 0
f 0
wmc 12

6 Methods

Rating   Name   Duplication   Size   Complexity  
A find() 0 6 2
A fromCommand() 0 9 3
A __construct() 0 3 1
A getProjectClasses() 0 17 3
A inferProjectSourcePaths() 0 20 2
A isSearchableModel() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Scout Extended.
7
 *
8
 * (c) Algolia Team <[email protected]>
9
 *
10
 *  For the full copyright and license information, please view the LICENSE
11
 *  file that was distributed with this source code.
12
 */
13
14
namespace Algolia\ScoutExtended\Helpers;
15
16
use Composer\Factory as ComposerFactory;
17
use Composer\IO\NullIO;
18
use Illuminate\Support\Arr;
19
use function in_array;
20
use Illuminate\Support\Str;
21
use Laravel\Scout\Searchable;
22
use Illuminate\Console\Command;
23
use RuntimeException;
24
use Symfony\Component\Finder\Finder;
25
use Symfony\Component\Console\Exception\InvalidArgumentException;
26
27
/**
28
 * @internal
29
 */
30
final class SearchableFinder
31
{
32
    /**
33
     * @var array
34
     */
35
    private static $declaredClasses;
36
37
    /**
38
     * @var \Illuminate\Contracts\Foundation\Application
39
     */
40
    private $app;
41
42
    /**
43
     * @var array
44 17
     */
45
    private $projectNamespaces;
46 17
47 17
    /**
48
     * @var array
49
     */
50
    private $projectSources;
51
52
    /**
53
     * SearchableModelsFinder constructor.
54
     *
55
     * @param \Illuminate\Contracts\Foundation\Application $app
56 17
     * @return void
57
     */
58 17
    public function __construct($app)
59
    {
60 17
        $this->app = $app;
61
    }
62
63
    /**
64 17
     * Get a list of searchable models from the given command.
65
     *
66
     * @param \Illuminate\Console\Command $command
67
     *
68
     * @return array
69
     */
70
    public function fromCommand(Command $command): array
71
    {
72 2
        $searchables = (array) $command->argument('searchable');
73
74 2
        if (empty($searchables) && empty($searchables = $this->find())) {
75
            throw new InvalidArgumentException('No searchable classes found.');
76
        }
77 2
78 2
        return $searchables;
79
    }
80
81
    /**
82
     * Get a list of searchable models.
83
     *
84
     * @return string[]
85
     */
86 2
    public function find(): array
87
    {
88 2
        $this->inferProjectSourcePaths();
89
90
        return array_values(array_filter($this->getProjectClasses(), function (string $class) {
91
            return Str::startsWith($class, $this->projectNamespaces) && $this->isSearchableModel($class);
92
        }));
93
    }
94 2
95
    /**
96 2
     * @param  string $class
97 1
     *
98
     * @return bool
99 1
     */
100 1
    private function isSearchableModel($class): bool
101
    {
102
        return in_array(Searchable::class, class_uses_recursive($class), true);
103 1
    }
104
105
    /**
106 2
     * @return array
107
     */
108
    private function getProjectClasses(): array
109
    {
110
        if (self::$declaredClasses === null) {
0 ignored issues
show
introduced by
The condition self::declaredClasses === null is always false.
Loading history...
111
            $configFiles = Finder::create()
112
                ->files()
113
                ->notName('*.blade.php')
114
                ->name('*.php')
115
                ->in($this->projectSources);
116
117
            foreach ($configFiles->files() as $file) {
118
                require_once $file;
119
            }
120
121
            self::$declaredClasses = get_declared_classes();
122
        }
123
124
        return self::$declaredClasses;
125
    }
126
127
    /**
128
     * Using Composer retrieve the autoload config from the root package.
129
     *
130
     * @return void
131
     */
132
    private function inferProjectSourcePaths(): void
133
    {
134
        $rootPackage = ComposerFactory::create(new NullIO(), null,null)->getPackage();
135
        $autoload = array_merge_recursive(
136
            $rootPackage->getAutoload(),
137
            $rootPackage->getDevAutoload()
138
        );
139
140
        if (!isset($autoload['psr-4'])) {
141
            throw new RuntimeException('psr-4 autoload mappings are not present in composer.json');
142
        }
143
144
        // Remove this package and the test path
145
        $psr4 = collect($autoload['psr-4'])->diff([
146
            'Algolia\\ScoutExtended\\' => 'src/',
147
            'Tests\\' => 'tests/',
148
        ]);
149
150
        $this->projectSources = $psr4->values()->toArray();
151
        $this->projectNamespaces = $psr4->keys()->toArray();
152
    }
153
}
154