Completed
Push — master ( 959f72...e1ca15 )
by Nenad
01:44 queued 11s
created

StatusCommand::handle()   B

Complexity

Conditions 5
Paths 13

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 8.9368
c 0
b 0
f 0
cc 5
nc 13
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
            $rowsTotal = $model->count();
67
            $recordsDifference = $rowsTotal - $rowsIndexed;
68
69
            $indexedColumns = $rowsTotal ? implode(",", array_keys($model->first()->toSearchableArray())) : '';
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);
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
                try {
96
                    require_once $file;
97
                } catch (\Exception $e) {
98
                    //skiping if the file cannot be loaded
99
                } catch (\Throwable $e) {
100
                    //skiping if the file cannot be loaded
101
                }
102
            }
103
104
            self::$declaredClasses = get_declared_classes();
105
        }
106
107
        return self::$declaredClasses;
108
    }
109
110
    /**
111
     * @return array|void
112
     */
113
    private function getSearchableModelsFromClasses($trait = 'Laravel\Scout\Searchable')
114
    {
115
        $projectClasses = $this->getProjectClasses();
116
        $classes = array_filter(
117
            $projectClasses,
118
            $this->isSearchableModel($trait)
119
        );
120
121
        return $classes;
122
    }
123
124
    /**
125
     * @return array
126
     */
127
    private function getSearchableModels()
128
    {
129
        $searchableModels = (array)$this->argument('model');
130
        if (empty($searchableModels)) {
131
            $searchableModels = $this->getSearchableModelsFromClasses();
132
        }
133
134
        return $searchableModels;
135
    }
136
137
    /**
138
     * @param $trait
139
     * @return \Closure
140
     */
141
    private function isSearchableModel($trait)
142
    {
143
        return function ($className) use ($trait) {
144
            $traits = class_uses($className);
145
146
            return isset($traits[$trait]);
147
        };
148
    }
149
150
    /**
151
     * @param $model
152
     * @return TNTSearch
153
     */
154
    private function loadTNTEngine($model)
155
    {
156
        $tnt = new TNTSearch();
157
158
        $driver = $model->getConnectionName() ?: config('database.default');
159
        $config = config('scout.tntsearch') + config("database.connections.$driver");
160
        $tnt->loadConfig($config);
161
162
        return $tnt;
163
    }
164
}
165