Completed
Push — master ( 4fafa1...e65f27 )
by Nicolas
12:12
created

src/Commands/SeedCommand.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Nwidart\Modules\Commands;
4
5
use Illuminate\Console\Command;
6
use Illuminate\Contracts\Debug\ExceptionHandler;
7
use Illuminate\Support\Str;
8
use Nwidart\Modules\Contracts\RepositoryInterface;
9
use Nwidart\Modules\Module;
10
use Nwidart\Modules\Support\Config\GenerateConfigReader;
11
use Nwidart\Modules\Traits\ModuleCommandTrait;
12
use RuntimeException;
13
use Symfony\Component\Console\Input\InputArgument;
14
use Symfony\Component\Console\Input\InputOption;
15
16
class SeedCommand extends Command
17
{
18
    use ModuleCommandTrait;
19
20
    /**
21
     * The console command name.
22
     *
23
     * @var string
24
     */
25
    protected $name = 'module:seed';
26
27
    /**
28
     * The console command description.
29
     *
30
     * @var string
31
     */
32
    protected $description = 'Run database seeder from the specified module or from all modules.';
33
34
    /**
35
     * Execute the console command.
36
     * @throws FatalThrowableError
37
     */
38
    public function handle()
39
    {
40
        try {
41
            if ($name = $this->argument('module')) {
42
                $name = Str::studly($name);
0 ignored issues
show
It seems like $name can also be of type array; however, Illuminate\Support\Str::studly() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
43
                $this->moduleSeed($this->getModuleByName($name));
0 ignored issues
show
It seems like $this->getModuleByName($name) can be null; however, moduleSeed() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
44
            } else {
45
                $modules = $this->getModuleRepository()->getOrdered();
46
                array_walk($modules, [$this, 'moduleSeed']);
47
                $this->info('All modules seeded.');
48
            }
49
        } catch (\Throwable $e) {
50
            $this->reportException($e);
51
52
            $this->renderException($this->getOutput(), $e);
53
54
            return 1;
55
        }
56
    }
57
58
    /**
59
     * @throws RuntimeException
60
     * @return RepositoryInterface
61
     */
62
    public function getModuleRepository(): RepositoryInterface
63
    {
64
        $modules = $this->laravel['modules'];
65
        if (!$modules instanceof RepositoryInterface) {
66
            throw new RuntimeException('Module repository not found!');
67
        }
68
69
        return $modules;
70
    }
71
72
    /**
73
     * @param $name
74
     *
75
     * @throws RuntimeException
76
     *
77
     * @return Module
78
     */
79
    public function getModuleByName($name)
80
    {
81
        $modules = $this->getModuleRepository();
82
        if ($modules->has($name) === false) {
83
            throw new RuntimeException("Module [$name] does not exists.");
84
        }
85
86
        return $modules->find($name);
87
    }
88
89
    /**
90
     * @param Module $module
91
     *
92
     * @return void
93
     */
94
    public function moduleSeed(Module $module)
95
    {
96
        $seeders = [];
97
        $name = $module->getName();
98
        $config = $module->get('migration');
99
        if (is_array($config) && array_key_exists('seeds', $config)) {
100
            foreach ((array)$config['seeds'] as $class) {
101
                if (class_exists($class)) {
102
                    $seeders[] = $class;
103
                }
104
            }
105
        } else {
106
            $class = $this->getSeederName($name); //legacy support
107
            if (class_exists($class)) {
108
                $seeders[] = $class;
109
            } else {
110
                //look at other namespaces
111
                $classes = $this->getSeederNames($name);
112
                foreach ($classes as $class) {
113
                    if (class_exists($class)) {
114
                        $seeders[] = $class;
115
                    }
116
                }
117
            }
118
        }
119
120
        if (count($seeders) > 0) {
121
            array_walk($seeders, [$this, 'dbSeed']);
122
            $this->info("Module [$name] seeded.");
123
        }
124
    }
125
126
    /**
127
     * Seed the specified module.
128
     *
129
     * @param string $className
130
     */
131
    protected function dbSeed($className)
132
    {
133
        if ($option = $this->option('class')) {
134
            $params['--class'] = Str::finish(substr($className, 0, strrpos($className, '\\')), '\\') . $option;
135
        } else {
136
            $params = ['--class' => $className];
137
        }
138
139
        if ($option = $this->option('database')) {
140
            $params['--database'] = $option;
141
        }
142
143
        if ($option = $this->option('force')) {
144
            $params['--force'] = $option;
145
        }
146
147
        $this->call('db:seed', $params);
148
    }
149
150
    /**
151
     * Get master database seeder name for the specified module.
152
     *
153
     * @param string $name
154
     *
155
     * @return string
156
     */
157
    public function getSeederName($name)
158
    {
159
        $name = Str::studly($name);
160
161
        $namespace = $this->laravel['modules']->config('namespace');
162
        $config = GenerateConfigReader::read('seeder');
163
        $seederPath = str_replace('/', '\\', $config->getPath());
164
165
        return $namespace . '\\' . $name . '\\' . $config->getNamespace() . '\\' . $name . 'DatabaseSeeder';
166
    }
167
168
    /**
169
     * Get master database seeder name for the specified module under a different namespace than Modules.
170
     *
171
     * @param string $name
172
     *
173
     * @return array $foundModules array containing namespace paths
174
     */
175
    public function getSeederNames($name)
176
    {
177
        $name = Str::studly($name);
178
179
        $seederPath = GenerateConfigReader::read('seeder');
180
        $seederPath = str_replace('/', '\\', $seederPath->getPath());
181
182
        $foundModules = [];
183
        foreach ($this->laravel['modules']->config('scan.paths') as $path) {
184
            $namespace = array_slice(explode('/', $path), -1)[0];
185
            $foundModules[] = $namespace . '\\' . $name . '\\' . $seederPath . '\\' . $name . 'DatabaseSeeder';
186
        }
187
188
        return $foundModules;
189
    }
190
191
    /**
192
     * Report the exception to the exception handler.
193
     *
194
     * @param  \Symfony\Component\Console\Output\OutputInterface  $output
195
     * @param  \Throwable  $e
196
     * @return void
197
     */
198
    protected function renderException($output, \Throwable $e)
199
    {
200
        $this->laravel[ExceptionHandler::class]->renderForConsole($output, $e);
201
    }
202
203
    /**
204
     * Report the exception to the exception handler.
205
     *
206
     * @param  \Throwable  $e
207
     * @return void
208
     */
209
    protected function reportException(\Throwable $e)
210
    {
211
        $this->laravel[ExceptionHandler::class]->report($e);
212
    }
213
214
    /**
215
     * Get the console command arguments.
216
     *
217
     * @return array
218
     */
219 120
    protected function getArguments()
220
    {
221
        return [
222 120
            ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
223
        ];
224
    }
225
226
    /**
227
     * Get the console command options.
228
     *
229
     * @return array
230
     */
231 120 View Code Duplication
    protected function getOptions()
232
    {
233
        return [
234 120
            ['class', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder.'],
235
            ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed.'],
236
            ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
237
        ];
238
    }
239
}
240