SeedCommand   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 227
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 28
eloc 79
dl 0
loc 227
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getSeederName() 0 9 1
A getArguments() 0 4 1
A renderException() 0 3 1
B domainSeed() 0 29 9
A getSeederNames() 0 14 2
A getDomainByName() 0 8 2
A handle() 0 25 4
A reportException() 0 3 1
A dbSeed() 0 17 4
A getOptions() 0 6 1
A getDomainRepository() 0 8 2
1
<?php
2
3
namespace Salah3id\Domains\Commands;
4
5
use ErrorException;
6
use Illuminate\Console\Command;
7
use Illuminate\Contracts\Debug\ExceptionHandler;
8
use Illuminate\Support\Str;
9
use Salah3id\Domains\Contracts\RepositoryInterface;
10
use Salah3id\Domains\Domain;
11
use Salah3id\Domains\Support\Config\GenerateConfigReader;
12
use Salah3id\Domains\Traits\DomainCommandTrait;
13
use RuntimeException;
14
use Symfony\Component\Console\Input\InputArgument;
15
use Symfony\Component\Console\Input\InputOption;
16
17
class SeedCommand extends Command
18
{
19
    use DomainCommandTrait;
20
21
    /**
22
     * The console command name.
23
     *
24
     * @var string
25
     */
26
    protected $name = 'domain:seed';
27
28
    /**
29
     * The console command description.
30
     *
31
     * @var string
32
     */
33
    protected $description = 'Run database seeder from the specified domain or from all domains.';
34
35
    /**
36
     * Execute the console command.
37
     */
38
    public function handle(): int
39
    {
40
        try {
41
            if ($name = $this->argument('domain')) {
42
                $name = Str::studly($name);
43
                $this->domainSeed($this->getDomainByName($name));
44
            } else {
45
                $domains = $this->getDomainRepository()->getOrdered();
46
                array_walk($domains, [$this, 'domainSeed']);
47
                $this->info('All domains seeded.');
48
            }
49
        } catch (\Error $e) {
50
            $e = new ErrorException($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), $e);
0 ignored issues
show
Bug introduced by
$e of type Error is incompatible with the type Exception expected by parameter $previous of ErrorException::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

50
            $e = new ErrorException($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), /** @scrutinizer ignore-type */ $e);
Loading history...
51
            $this->reportException($e);
52
            $this->renderException($this->getOutput(), $e);
53
54
            return E_ERROR;
55
        } catch (\Exception $e) {
56
            $this->reportException($e);
57
            $this->renderException($this->getOutput(), $e);
58
59
            return E_ERROR;
60
        }
61
62
        return 0;
63
    }
64
65
    /**
66
     * @throws RuntimeException
67
     * @return RepositoryInterface
68
     */
69
    public function getDomainRepository(): RepositoryInterface
70
    {
71
        $domains = $this->laravel['domains'];
72
        if (!$domains instanceof RepositoryInterface) {
73
            throw new RuntimeException('Domain repository not found!');
74
        }
75
76
        return $domains;
77
    }
78
79
    /**
80
     * @param $name
81
     *
82
     * @throws RuntimeException
83
     *
84
     * @return Domain
85
     */
86
    public function getDomainByName($name)
87
    {
88
        $domains = $this->getDomainRepository();
89
        if ($domains->has($name) === false) {
0 ignored issues
show
Bug introduced by
The method has() does not exist on Salah3id\Domains\Contracts\RepositoryInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Salah3id\Domains\Contracts\RepositoryInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

89
        if ($domains->/** @scrutinizer ignore-call */ has($name) === false) {
Loading history...
90
            throw new RuntimeException("Domain [$name] does not exists.");
91
        }
92
93
        return $domains->find($name);
94
    }
95
96
    /**
97
     * @param Domain $domain
98
     *
99
     * @return void
100
     */
101
    public function domainSeed(Domain $domain)
102
    {
103
        $seeders = [];
104
        $name = $domain->getName();
105
        $config = $domain->get('migration');
106
        if (is_array($config) && array_key_exists('seeds', $config)) {
107
            foreach ((array)$config['seeds'] as $class) {
108
                if (class_exists($class)) {
109
                    $seeders[] = $class;
110
                }
111
            }
112
        } else {
113
            $class = $this->getSeederName($name); //legacy support
114
            if (class_exists($class)) {
115
                $seeders[] = $class;
116
            } else {
117
                //look at other namespaces
118
                $classes = $this->getSeederNames($name);
119
                foreach ($classes as $class) {
120
                    if (class_exists($class)) {
121
                        $seeders[] = $class;
122
                    }
123
                }
124
            }
125
        }
126
127
        if (count($seeders) > 0) {
128
            array_walk($seeders, [$this, 'dbSeed']);
129
            $this->info("Domain [$name] seeded.");
130
        }
131
    }
132
133
    /**
134
     * Seed the specified domain.
135
     *
136
     * @param string $className
137
     */
138
    protected function dbSeed($className)
139
    {
140
        if ($option = $this->option('class')) {
141
            $params['--class'] = Str::finish(substr($className, 0, strrpos($className, '\\')), '\\') . $option;
0 ignored issues
show
Bug introduced by
Are you sure $option of type array|string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

141
            $params['--class'] = Str::finish(substr($className, 0, strrpos($className, '\\')), '\\') . /** @scrutinizer ignore-type */ $option;
Loading history...
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
142
        } else {
143
            $params = ['--class' => $className];
144
        }
145
146
        if ($option = $this->option('database')) {
147
            $params['--database'] = $option;
148
        }
149
150
        if ($option = $this->option('force')) {
151
            $params['--force'] = $option;
152
        }
153
154
        $this->call('db:seed', $params);
155
    }
156
157
    /**
158
     * Get master database seeder name for the specified domain.
159
     *
160
     * @param string $name
161
     *
162
     * @return string
163
     */
164
    public function getSeederName($name)
165
    {
166
        $name = Str::studly($name);
167
168
        $namespace = $this->laravel['domains']->config('namespace');
169
        $config = GenerateConfigReader::read('seeder');
170
        $seederPath = str_replace('/', '\\', $config->getPath());
171
172
        return $namespace . '\\' . $name . '\\' . $seederPath . '\\' . $name . 'DatabaseSeeder';
173
    }
174
175
    /**
176
     * Get master database seeder name for the specified domain under a different namespace than Domains.
177
     *
178
     * @param string $name
179
     *
180
     * @return array $foundDomains array containing namespace paths
181
     */
182
    public function getSeederNames($name)
183
    {
184
        $name = Str::studly($name);
185
186
        $seederPath = GenerateConfigReader::read('seeder');
187
        $seederPath = str_replace('/', '\\', $seederPath->getPath());
188
189
        $foundDomains = [];
190
        foreach ($this->laravel['domains']->config('scan.paths') as $path) {
191
            $namespace = array_slice(explode('/', $path), -1)[0];
192
            $foundDomains[] = $namespace . '\\' . $name . '\\' . $seederPath . '\\' . $name . 'DatabaseSeeder';
193
        }
194
195
        return $foundDomains;
196
    }
197
198
    /**
199
     * Report the exception to the exception handler.
200
     *
201
     * @param  \Symfony\Component\Console\Output\OutputInterface  $output
202
     * @param  \Throwable  $e
203
     * @return void
204
     */
205
    protected function renderException($output, \Exception $e)
206
    {
207
        $this->laravel[ExceptionHandler::class]->renderForConsole($output, $e);
208
    }
209
210
    /**
211
     * Report the exception to the exception handler.
212
     *
213
     * @param  \Throwable  $e
214
     * @return void
215
     */
216
    protected function reportException(\Exception $e)
217
    {
218
        $this->laravel[ExceptionHandler::class]->report($e);
219
    }
220
221
    /**
222
     * Get the console command arguments.
223
     *
224
     * @return array
225
     */
226
    protected function getArguments()
227
    {
228
        return [
229
            ['domain', InputArgument::OPTIONAL, 'The name of domain will be used.'],
230
        ];
231
    }
232
233
    /**
234
     * Get the console command options.
235
     *
236
     * @return array
237
     */
238
    protected function getOptions()
239
    {
240
        return [
241
            ['class', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder.'],
242
            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed.'],
243
            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
244
        ];
245
    }
246
}
247