Completed
Push — master ( 916455...a9a34e )
by
unknown
01:23
created

StatusCommand::getSearchableModelsFromClasses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace TeamTNT\Scout\Console;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Contracts\Events\Dispatcher;
7
use TeamTNT\TNTSearch\Exceptions\IndexNotFoundException;
8
use TeamTNT\TNTSearch\Indexer\TNTIndexer;
9
use TeamTNT\TNTSearch\TNTSearch;
10
use Illuminate\Support\Facades\Schema;
11
use Symfony\Component\Finder\Finder;
12
13
class StatusCommand extends Command
14
{
15
    /**
16
     * The name and signature of the console command.
17
     *
18
     * @var string
19
     */
20
    protected $signature = 'scout:status {model? : The name of the model}';
21
22
    /**
23
     * The console command description.
24
     *
25
     * @var string
26
     */
27
    protected $description = 'Status of the search index by TNTSeach';
28
29
    /**
30
     * @var array
31
     */
32
    private static $declaredClasses;
33
34
35
    /**
36
     * Execute the console command.
37
     *
38
     * @param \Illuminate\Contracts\Events\Dispatcher $events
39
     *
40
     * @return void
41
     */
42
    public function handle(Dispatcher $events)
0 ignored issues
show
Unused Code introduced by
The parameter $events is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
43
    {
44
45
        $searchableModels = $this->getSearchableModels();
46
47
        $this->output->text('🔎 Analysing information from: <info>['.implode(',', $searchableModels).']</info>');
48
        $this->output->newLine();
49
        $this->output->progressStart(count($searchableModels));
50
51
        $headers = ['Searchable', 'Index', 'Indexed Columns', 'Index Records', 'DB Records', 'Records difference'];
52
        $rows = [];
53
        foreach ($searchableModels as $class) {
0 ignored issues
show
Bug introduced by
The expression $searchableModels of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
54
            $model = new $class();
55
56
            $tnt = $this->loadTNTEngine($model);
57
            $indexName = $model->searchableAs().'.index';
58
59
            try {
60
                $tnt->selectIndex($indexName);
61
                $rowsIndexed = $tnt->totalDocumentsInCollection();
62
            } catch (IndexNotFoundException $e) {
63
                $rowsIndexed = 0;
64
            }
65
66
            $indexedColumns = implode(",", array_keys($model->toSearchableArray()));
67
68
            $rowsTotal = $model->count();
69
            $recordsDifference = $rowsTotal - $rowsIndexed;
70
71
            if($recordsDifference == 0) {
72
                $recordsDifference = '<fg=green>Synchronized</>';
73
            } else {
74
                $recordsDifference = "<fg=red>$recordsDifference</>";
75
            }
76
77
            array_push($rows, [$class, $indexName, $indexedColumns, $rowsIndexed, $rowsTotal, $recordsDifference]);
78
79
        }
80
81
        $this->output->progressFinish();
82
        $this->output->table($headers, $rows, $tableStyle = 'default', $columnStyles = []);
0 ignored issues
show
Unused Code introduced by
The call to OutputStyle::table() has too many arguments starting with $tableStyle = 'default'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
83
    }
84
85
    /**
86
     * @return array
87
     */
88
    private function getProjectClasses(): array
89
    {
90
91
        if (self::$declaredClasses === null) {
92
            $configFiles = Finder::create()->files()->name('*.php')->notName('*.blade.php')->in(app()->path());
93
94
            foreach ($configFiles->files() as $file) {
95
                require_once $file;
96
            }
97
98
            self::$declaredClasses = get_declared_classes();
99
        }
100
101
        return self::$declaredClasses;
102
    }
103
104
    /**
105
     * @return array|void
106
     */
107
    private function getSearchableModelsFromClasses($trait = 'Laravel\Scout\Searchable')
108
    {
109
        $projectClasses = $this->getProjectClasses();
110
        $classes = array_filter(
111
            $projectClasses,
112
            $this->isSearchableModel($trait)
113
        );
114
115
        return $classes;
116
    }
117
118
    /**
119
     * @return array
120
     */
121
    private function getSearchableModels()
122
    {
123
        $searchableModels = (array)$this->argument('model');
124
        if (empty($searchableModels)) {
125
            $searchableModels = $this->getSearchableModelsFromClasses();
126
        }
127
128
        return $searchableModels;
129
    }
130
131
    /**
132
     * @param $trait
133
     * @return \Closure
134
     */
135
    private function isSearchableModel($trait)
136
    {
137
        return function ($className) use ($trait) {
138
            $traits = class_uses($className);
139
140
            return isset($traits[$trait]);
141
        };
142
    }
143
144
    /**
145
     * @param $model
146
     * @return TNTSearch
147
     */
148
    private function loadTNTEngine($model)
149
    {
150
        $tnt = new TNTSearch();
151
152
        $driver = $model->getConnectionName() ?: config('database.default');
153
        $config = config('scout.tntsearch') + config("database.connections.$driver");
154
        $tnt->loadConfig($config);
155
156
        return $tnt;
157
    }
158
}
159