Skip to content

Commit 2192533

Browse files
committed
refactor: improve seeder with namespace
1 parent aae89b8 commit 2192533

File tree

6 files changed

+291
-86
lines changed

6 files changed

+291
-86
lines changed

src/core/class_map/Database/Commands/Seeders/BaseCommand.php

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/core/class_map/Database/Migrations/Migration.php

Lines changed: 0 additions & 36 deletions
This file was deleted.

src/core/src/ConfigProvider.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@
1313
use Hyperf\Database\Commands\Migrations\ResetCommand;
1414
use Hyperf\Database\Commands\Migrations\RollbackCommand;
1515
use Hyperf\Database\Commands\Migrations\StatusCommand;
16-
use Hyperf\Database\Commands\Seeders\BaseCommand as SeederBaseCommand;
17-
use Hyperf\Database\Commands\Seeders\SeedCommand;
18-
use Hyperf\Database\Migrations\Migration;
1916
use Hyperf\Database\Model\Factory as HyperfDatabaseFactory;
2017
use Hyperf\Redis\Pool\RedisPool as HyperfRedisPool;
2118
use Hyperf\ViewEngine\Compiler\CompilerInterface;
19+
use Hypervel\Database\Console\SeedCommand;
2220
use Hypervel\Database\Eloquent\Factories\FactoryInvoker as DatabaseFactoryInvoker;
23-
use Hypervel\Database\Migrations\MigrationCreator;
2421
use Hypervel\Database\Migrations\MigrationCreator as HyperfMigrationCreator;
22+
use Hypervel\Database\Migrations\MigrationCreator;
2523
use Hypervel\Database\TransactionListener;
2624
use Hypervel\Redis\RedisPool;
2725
use Hypervel\View\CompilerFactory;
@@ -53,9 +51,7 @@ public function __invoke(): array
5351
'annotations' => [
5452
'scan' => [
5553
'class_map' => [
56-
Migration::class => __DIR__ . '/../class_map/Database/Migrations/Migration.php', // TODO: this will be removed in the future version
5754
MigrationBaseCommand::class => __DIR__ . '/../class_map/Database/Commands/Migrations/BaseCommand.php',
58-
SeederBaseCommand::class => __DIR__ . '/../class_map/Database/Commands/Seeders/BaseCommand.php',
5955
Confirmable::class => __DIR__ . '/../class_map/Command/Concerns/Confirmable.php',
6056
],
6157
],
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypervel\Database\Console;
6+
7+
use Hyperf\Command\Concerns\Prohibitable;
8+
use Hyperf\Contract\ConfigInterface;
9+
use Hyperf\Database\ConnectionResolverInterface;
10+
use Hypervel\Console\Command;
11+
use Hypervel\Console\ConfirmableTrait;
12+
use Hypervel\Database\Eloquent\Model;
13+
use Hypervel\Database\Seeder;
14+
use Symfony\Component\Console\Input\InputArgument;
15+
use Symfony\Component\Console\Input\InputOption;
16+
17+
class SeedCommand extends Command
18+
{
19+
use ConfirmableTrait, Prohibitable;
20+
21+
/**
22+
* The console command name.
23+
*/
24+
protected ?string $name = 'db:seed';
25+
26+
/**
27+
* The console command description.
28+
*/
29+
protected string $description = 'Seed the database with records';
30+
31+
/**
32+
* Create a new database seed command instance.
33+
*
34+
* @param ConnectionResolverInterface $resolver The connection resolver instance.
35+
*/
36+
public function __construct(
37+
protected ConnectionResolverInterface $resolver
38+
) {
39+
parent::__construct();
40+
}
41+
42+
/**
43+
* Execute the console command.
44+
*/
45+
public function handle(): int
46+
{
47+
if ($this->isProhibited() ||
48+
! $this->confirmToProceed()
49+
) {
50+
return Command::FAILURE;
51+
}
52+
53+
$this->components->info('Seeding database.');
54+
55+
$previousConnection = $this->resolver->getDefaultConnection();
56+
57+
$this->resolver->setDefaultConnection($this->getDatabase());
58+
59+
Model::unguarded(function () {
60+
$this->getSeeder()->__invoke();
61+
});
62+
63+
if ($previousConnection) {
64+
$this->resolver->setDefaultConnection($previousConnection);
65+
}
66+
67+
return 0;
68+
}
69+
70+
/**
71+
* Get a seeder instance from the container.
72+
*/
73+
protected function getSeeder(): Seeder
74+
{
75+
$class = $this->input->getArgument('class') ?? $this->input->getOption('class');
76+
77+
if (! str_contains($class, '\\')) {
78+
$class = 'Database\\Seeders\\' . $class;
79+
}
80+
81+
if ($class === 'Database\\Seeders\\DatabaseSeeder'
82+
&& ! class_exists($class)) {
83+
$class = 'DatabaseSeeder';
84+
}
85+
86+
return $this->app->get($class)
87+
->setContainer($this->app)
88+
->setCommand($this);
89+
}
90+
91+
/**
92+
* Get the name of the database connection to use.
93+
*/
94+
protected function getDatabase(): string
95+
{
96+
$database = $this->input->getOption('database');
97+
98+
return $database
99+
?: $this->app->get(ConfigInterface::class)
100+
->get('database.default');
101+
}
102+
103+
/**
104+
* Get the console command arguments.
105+
*/
106+
protected function getArguments(): array
107+
{
108+
return [
109+
['class', InputArgument::OPTIONAL, 'The class name of the root seeder', null],
110+
];
111+
}
112+
113+
/**
114+
* Get the console command options.
115+
*/
116+
protected function getOptions(): array
117+
{
118+
return [
119+
['class', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder', 'Database\\Seeders\\DatabaseSeeder'],
120+
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed'],
121+
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'],
122+
];
123+
}
124+
}

src/core/src/Database/Seeder.php

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypervel\Database;
6+
7+
use FriendsOfHyperf\PrettyConsole\View\Components\TwoColumnDetail;
8+
use Hypervel\Console\Command;
9+
use Hypervel\Container\Contracts\Container as ContainerContract;
10+
use Hypervel\Support\Arr;
11+
use InvalidArgumentException;
12+
13+
use function Hyperf\Support\with;
14+
15+
abstract class Seeder
16+
{
17+
/**
18+
* The container instance.
19+
*/
20+
protected ContainerContract $container;
21+
22+
/**
23+
* The console command instance.
24+
*/
25+
protected Command $command;
26+
27+
/**
28+
* Seeders that have been called at least one time.
29+
*/
30+
protected static array $called = [];
31+
32+
/**
33+
* Run the given seeder class.
34+
*/
35+
public function call(array|string $class, bool $silent = false, array $parameters = []): static
36+
{
37+
$classes = Arr::wrap($class);
38+
39+
foreach ($classes as $class) {
40+
$seeder = $this->resolve($class);
41+
42+
$name = get_class($seeder);
43+
44+
if ($silent === false && isset($this->command)) {
45+
with(new TwoColumnDetail($this->command->getOutput()))->render(
46+
$name,
47+
'<fg=yellow;options=bold>RUNNING</>'
48+
);
49+
}
50+
51+
$startTime = microtime(true);
52+
53+
$seeder->__invoke($parameters);
54+
55+
if ($silent === false && isset($this->command)) {
56+
$runTime = number_format((microtime(true) - $startTime) * 1000);
57+
58+
with(new TwoColumnDetail($this->command->getOutput()))->render(
59+
$name,
60+
"<fg=gray>$runTime ms</> <fg=green;options=bold>DONE</>"
61+
);
62+
63+
$this->command->getOutput()->writeln('');
64+
}
65+
66+
static::$called[] = $class;
67+
}
68+
69+
return $this;
70+
}
71+
72+
/**
73+
* Run the given seeder class.
74+
*/
75+
public function callWith(array|string $class, array $parameters = []): void
76+
{
77+
$this->call($class, false, $parameters);
78+
}
79+
80+
/**
81+
* Silently run the given seeder class.
82+
*/
83+
public function callSilent(array|string $class, array $parameters = []): void
84+
{
85+
$this->call($class, true, $parameters);
86+
}
87+
88+
/**
89+
* Run the given seeder class once.
90+
*/
91+
public function callOnce(array|string $class, bool $silent = false, array $parameters = []): void
92+
{
93+
$classes = Arr::wrap($class);
94+
95+
foreach ($classes as $class) {
96+
if (in_array($class, static::$called)) {
97+
continue;
98+
}
99+
100+
$this->call($class, $silent, $parameters);
101+
}
102+
}
103+
104+
/**
105+
* Resolve an instance of the given seeder class.
106+
*/
107+
protected function resolve(string $class): Seeder
108+
{
109+
if (isset($this->container)) {
110+
$instance = $this->container->get($class);
111+
112+
$instance->setContainer($this->container);
113+
} else {
114+
$instance = new $class;
115+
}
116+
117+
if (isset($this->command)) {
118+
$instance->setCommand($this->command);
119+
}
120+
121+
return $instance;
122+
}
123+
124+
/**
125+
* Set the IoC container instance.
126+
*/
127+
public function setContainer(ContainerContract $container): static
128+
{
129+
$this->container = $container;
130+
131+
return $this;
132+
}
133+
134+
/**
135+
* Set the console command instance.
136+
*/
137+
public function setCommand(Command $command): static
138+
{
139+
$this->command = $command;
140+
141+
return $this;
142+
}
143+
144+
/**
145+
* Run the database seeds.
146+
*
147+
* @throws InvalidArgumentException
148+
*/
149+
public function __invoke(array $parameters = []): mixed
150+
{
151+
if (! method_exists($this, 'run')) {
152+
throw new InvalidArgumentException('Method [run] missing from ' . get_class($this));
153+
}
154+
155+
$callback = fn () => isset($this->container)
156+
? $this->container->call([$this, 'run'], $parameters)
157+
: $this->run(...$parameters); // @phpstan-ignore-line
158+
159+
return $callback();
160+
}
161+
}

0 commit comments

Comments
 (0)