Skip to content

Commit d82d82a

Browse files
authored
Merge pull request #6 from blitz-php/1.x-devs
chore: Refactorisation du système Seeder
2 parents f4ee1bc + 8f07ca8 commit d82d82a

12 files changed

Lines changed: 814 additions & 930 deletions

File tree

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"require-dev": {
2424
"blitz-php/coding-standard": "^1.5",
2525
"blitz-php/framework": "^1.0.0-rc",
26+
"fakerphp/faker": "^1.24",
2627
"kahlan/kahlan": "^6.1.0",
2728
"phpstan/phpstan": "^2.1.36"
2829
},

src/Commands/Seed.php

Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace BlitzPHP\Database\Commands;
1313

14-
use BlitzPHP\Container\Services;
14+
use BlitzPHP\Database\Connection\BaseConnection;
1515
use BlitzPHP\Database\Seeder\Seeder;
1616
use InvalidArgumentException;
1717

@@ -34,55 +34,138 @@ class Seed extends DatabaseCommand
3434
* {@inheritDoc}
3535
*/
3636
protected array $arguments = [
37-
'name' => 'Nom du seedr a executer',
37+
'name' => 'Nom du seeder à exécuter (ex: DatabaseSeeder ou Users\\UserSeeder)',
3838
];
3939

40+
/**
41+
* {@inheritDoc}
42+
*/
43+
protected array $options = [
44+
'--group' => 'Groupe de connexion à utiliser',
45+
'--silent' => 'Mode silencieux (pas de sortie)',
46+
'--locale' => 'Langue à utiliser pour Faker (ex: fr_FR, en_US)',
47+
];
48+
49+
protected ?BaseConnection $db = null;
50+
4051
/**
4152
* {@inheritDoc}
4253
*/
4354
public function handle()
4455
{
45-
if (empty($name = $this->argument('name'))) {
46-
$name = $this->prompt(lang('Migrations.migSeeder'), null, static function ($val) {
56+
$group = $this->option('group');
57+
$silent = $this->option('silent') !== null;
58+
$locale = $this->option('locale', config('app.language', 'fr_FR'));
59+
60+
$this->db = $this->resolver->connect($group);
61+
62+
$name = $this->getSeederName();
63+
64+
$seeder = $this->resolveSeeder($name);
65+
66+
$this->configureSeeder($seeder, $locale, $silent);
67+
68+
$this->runSeeder($seeder);
69+
70+
return EXIT_SUCCESS;
71+
}
72+
73+
/**
74+
* Récupère le nom du seeder
75+
*/
76+
protected function getSeederName(): string
77+
{
78+
if (null !== $name = $this->argument('name')) {
79+
return $name;
80+
}
81+
82+
return $this->prompt(
83+
'Quel seeder souhaitez-vous exécuter ?',
84+
'DatabaseSeeder',
85+
function ($val) {
4786
if (empty($val)) {
4887
throw new InvalidArgumentException('Veuillez entrer le nom du seeder.');
4988
}
50-
5189
return $val;
52-
});
53-
}
90+
}
91+
);
92+
}
5493

55-
$seedClass = APP_NAMESPACE . '\Database\Seeds\\';
56-
$seedClass .= str_replace($seedClass, '', $name);
94+
/**
95+
* Résout la classe du seeder
96+
*/
97+
protected function resolveSeeder(string $name): Seeder
98+
{
99+
// Chemins possibles
100+
$paths = [
101+
APP_NAMESPACE . '\\Database\\Seeds\\',
102+
APP_NAMESPACE . '\\Database\\Seeders\\',
103+
'Database\\Seeds\\',
104+
'Database\\Seeders\\',
105+
];
106+
107+
$className = $name;
57108

58-
/**
59-
* @var Seeder
60-
*/
61-
$seeder = new $seedClass($this->db);
109+
// Si le nom ne contient pas de namespace, on essaie les chemins standards
110+
if (!str_contains($name, '\\')) {
111+
foreach ($paths as $path) {
112+
$fullClass = $path . $name;
113+
if (class_exists($fullClass)) {
114+
$className = $fullClass;
115+
break;
116+
}
117+
}
118+
}
62119

63-
if ($seeder->getLocale() === '') {
64-
$seeder->setLocale(config('app.language'));
120+
if (!class_exists($className)) {
121+
throw new InvalidArgumentException(
122+
"Le seeder '{$name}' n'a pas été trouvé.\n" .
123+
"Chemins recherchés :\n" .
124+
implode("\n", array_map(fn($p) => "- {$p}{$name}", $paths))
125+
);
65126
}
66127

67-
$this->task('Demarrage du seed')->eol();
68-
sleep(2);
69-
$this->info('Remplissage en cours de traitement');
128+
return new $className($this->db);
129+
}
70130

71-
if (method_exists($seeder, 'run')) {
72-
Services::container()->call([$seeder, 'run']);
131+
/**
132+
* Configure le seeder
133+
*/
134+
protected function configureSeeder(Seeder $seeder, ?string $locale, bool $silent): void
135+
{
136+
if ($locale !== null) {
137+
$seeder->setLocale($locale);
138+
} elseif ($seeder->getLocale() === '') {
139+
$seeder->setLocale(config('app.language', 'fr_FR'));
73140
}
74141

75-
$usedSeed = [
76-
Services::container()->call([$seeder, 'execute']),
77-
...$seeder->getSeeded(),
142+
if ($silent) {
143+
$seeder->setSilent(true);
144+
}
145+
}
146+
147+
/**
148+
* Exécute le seeder
149+
*/
150+
protected function runSeeder(Seeder $seeder): void
151+
{
152+
$this->task('Démarrage du seed')->eol();
153+
154+
$this->info('Remplissage en cours...');
155+
156+
$seeder->setCommand($this)->execute();
157+
158+
$executed = [
159+
$seeder::class,
160+
...$seeder->getCalled(),
78161
];
79162

80-
$this->eol()->success('Opération terminée.');
163+
$this->eol()->success('Opération terminée avec succès !');
81164

82-
foreach ($usedSeed as $seeded) {
83-
$this->eol()->write('- ')->writer->yellow($seeded);
84-
}
165+
$this->eol()->write('Seeders exécutés :');
85166

86-
return EXIT_SUCCESS;
167+
foreach (array_unique($executed) as $seeded) {
168+
$this->eol()->write('')->writer->green($seeded);
169+
}
87170
}
88171
}

src/Config/Services.php

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace BlitzPHP\Database\Config;
1313

1414
use BlitzPHP\Container\Services as BaseServices;
15+
use BlitzPHP\Contracts\Database\BuilderInterface;
16+
use BlitzPHP\Contracts\Database\ConnectionInterface;
1517
use BlitzPHP\Database\Builder\BaseBuilder;
1618
use BlitzPHP\Database\Connection\BaseConnection;
1719
use BlitzPHP\Database\DatabaseManager;
@@ -32,7 +34,7 @@ class Services extends BaseServices
3234
/**
3335
* Récupère le gestionnaire de base de données
3436
*/
35-
protected static function manager(): DatabaseManager
37+
public static function dbManager(): DatabaseManager
3638
{
3739
if (static::$manager === null) {
3840
static::$manager = new DatabaseManager(static::logger(), static::event());
@@ -43,10 +45,12 @@ protected static function manager(): DatabaseManager
4345

4446
/**
4547
* Récupère une connexion à la base de données
48+
*
49+
* @return BaseConnection
4650
*/
47-
public static function database(?string $group = null, bool $shared = true): BaseConnection
51+
public static function database(?string $group = null, bool $shared = true): ConnectionInterface
4852
{
49-
$connection = static::manager()->connect($group, $shared);
53+
$connection = static::dbManager()->connect($group, $shared);
5054

5155
if (!$connection instanceof BaseConnection) {
5256
throw new InvalidArgumentException('La connexion retournée n\'est pas une instance de BaseConnection');
@@ -57,16 +61,20 @@ public static function database(?string $group = null, bool $shared = true): Bas
5761

5862
/**
5963
* Récupère un query builder
64+
*
65+
* @return BaseBuilder
66+
*
67+
* @deprecated 1.0 use static::database()->table($tablename) instead
6068
*/
61-
public static function builder(?string $group = null, bool $shared = true): BaseBuilder
69+
public static function builder(?string $group = null, bool $shared = true): BuilderInterface
6270
{
6371
$key = 'builder_' . ($group ?? 'default');
6472

6573
if ($shared && isset(static::$instances[$key])) {
6674
return static::$instances[$key];
6775
}
6876

69-
$builder = static::manager()->builder(static::database($group, $shared));
77+
$builder = static::dbManager()->builder(static::database($group, $shared));
7078

7179
if ($shared) {
7280
static::$instances[$key] = $builder;
@@ -78,7 +86,7 @@ public static function builder(?string $group = null, bool $shared = true): Base
7886
/**
7987
* Récupère un exportateur de base de données
8088
*/
81-
public static function dbExporter(?BaseConnection $db = null, array $config = [], bool $shared = true): Exporter
89+
public static function dbExporter(?ConnectionInterface $db = null, array $config = [], bool $shared = true): Exporter
8290
{
8391
if ($shared) {
8492
return static::sharedInstance('dbExporter', $db, $config);
@@ -102,7 +110,7 @@ public static function dbExporter(?BaseConnection $db = null, array $config = []
102110
/**
103111
* Récupère un importateur de base de données
104112
*/
105-
public static function dbImporter(?BaseConnection $db = null, array $config = [], bool $shared = true): Importer
113+
public static function dbImporter(?ConnectionInterface $db = null, array $config = [], bool $shared = true): Importer
106114
{
107115
if ($shared) {
108116
return static::sharedInstance('dbImporter', $db, $config);

src/Exceptions/DatabaseException.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,9 @@ class DatabaseException extends Error implements ExceptionInterface
2121
* @var int
2222
*/
2323
protected $code = 8;
24+
25+
protected static function t(string $message, array $args = []): string
26+
{
27+
return sprintf($message, $args);
28+
}
2429
}

src/Exceptions/SeederException.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace BlitzPHP\Database\Exceptions;
4+
5+
class SeederException extends DatabaseException
6+
{
7+
public static function dataCannotBeEmpty()
8+
{
9+
return new static(static::t('Les données ne peuvent pas être vides.'));
10+
}
11+
12+
public static function unspecifiedFakerMethod()
13+
{
14+
return new static(static::t('Méthode Faker non spécifiée.'));
15+
}
16+
17+
public static function relationTableNotFound(string $table)
18+
{
19+
return new static(static::t("Table de relation '%s' non trouvée.", [$table]));
20+
}
21+
22+
public static function propertyNotFound(string $property)
23+
{
24+
return new static(static::t("Propriété '%s' non trouvée.", [$property]));
25+
}
26+
27+
public static function seederClassDoesNotExist(string $class)
28+
{
29+
return new static(static::t("La classe de seeder '%s' n'existe pas.", [$class]));
30+
}
31+
}

src/Seeder/Factory.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
/**
4+
* This file is part of Blitz PHP framework - Database Layer.
5+
*
6+
* (c) 2022 Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace BlitzPHP\Database\Seeder;
13+
14+
use Faker\Factory as FakerFactory;
15+
use Faker\Generator as FakerGenerator;
16+
17+
/**
18+
* Générateur de configurations pour les seeders
19+
*
20+
* @mixin FakerGenerator
21+
*/
22+
class Factory
23+
{
24+
/**
25+
* Instance Faker
26+
*/
27+
protected FakerGenerator $faker;
28+
29+
/**
30+
* Constructeur
31+
*/
32+
public function __construct(string $locale = 'fr_FR')
33+
{
34+
$this->faker = FakerFactory::create($locale);
35+
}
36+
37+
/**
38+
* Appel Faker (retourne une configuration)
39+
*/
40+
public function __call(string $name, array $arguments): array
41+
{
42+
if ($name === 'unique') {
43+
return ['faker:unique', $arguments[0] ?? null, array_slice($arguments, 1) ?? []];
44+
}
45+
46+
return ['faker', $name, $arguments];
47+
}
48+
49+
/**
50+
* Propriété Faker (retourne une configuration)
51+
*/
52+
public function __get(string $name): array
53+
{
54+
return ['faker', $name, []];
55+
}
56+
57+
/**
58+
* Relation avec une autre table
59+
*/
60+
public function relation(string $table, string $column = 'id'): array
61+
{
62+
return ['relation', $table, $column];
63+
}
64+
65+
/**
66+
* Valeur optionnelle
67+
*/
68+
public function optional(float $weight = 0.5, mixed $default = null, mixed $value = null): array
69+
{
70+
if ($value === null) {
71+
// Si pas de valeur fournie, on utilisera une closure
72+
return ['optional', $weight, $default];
73+
}
74+
return ['optional', $weight, $default, $value];
75+
}
76+
77+
/**
78+
* Valeur fixe (pour compatibilité)
79+
*/
80+
public function raw(mixed $value): mixed
81+
{
82+
return $value;
83+
}
84+
}

0 commit comments

Comments
 (0)