feat: add CategoryImporter service and SeedCategoriesCommand for seeding category data
- Implemented CategoryImporter service to handle bulk export/import logic for categories. - Created SeedCategoriesCommand to seed category tables from JSON files in data/seed/. - Added validation and normalization for category data during import. - Ensured proper error handling and user feedback during the seeding process.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Category\Command;
|
||||
|
||||
use App\Category\Service\CategoryImporter;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Seeds the category tables from the JSON files in data/seed/.
|
||||
*
|
||||
* The data ships inside this repo (data/seed/) so a from-scratch database can be
|
||||
* populated with the canonical, valid categories without any external source.
|
||||
* Bundles are seeded in dependency order (provinces → cities, specialties →
|
||||
* doctor_services) and each is a strict wipe+replace via {@see CategoryImporter}.
|
||||
*
|
||||
* ddev exec php bin/console app:seed-categories
|
||||
*/
|
||||
#[AsCommand(name: 'app:seed-categories', description: 'Seed category tables (provinces, cities, specialties, doctor services) from data/seed/*.json')]
|
||||
class SeedCategoriesCommand extends Command
|
||||
{
|
||||
/** seed order matters: referenced tables first */
|
||||
private const ORDER = ['provinces', 'cities', 'specialties', 'doctor_services'];
|
||||
|
||||
public function __construct(
|
||||
private readonly CategoryImporter $importer,
|
||||
private readonly string $projectDir,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$seedDir = $this->projectDir . '/data/seed';
|
||||
|
||||
foreach (self::ORDER as $bundle) {
|
||||
$file = $seedDir . '/' . $bundle . '.json';
|
||||
if (!is_file($file)) {
|
||||
$io->error("فایل seed یافت نشد: {$file}");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$payload = json_decode((string) file_get_contents($file), true);
|
||||
if (!is_array($payload) || $payload === [] || array_keys($payload) !== range(0, count($payload) - 1)) {
|
||||
$io->error("{$bundle}: فایل باید یک آرایهی غیرخالی باشد");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$normalized = [];
|
||||
$errors = $this->importer->validate($bundle, $payload, $normalized);
|
||||
if ($errors !== []) {
|
||||
$io->error("{$bundle}: اعتبارسنجی ناموفق — " . count($errors) . ' خطا');
|
||||
foreach (array_slice($errors, 0, 10) as $e) {
|
||||
$io->writeln(" • {$e['message']}");
|
||||
}
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$this->importer->replace($bundle, $normalized);
|
||||
$io->success(sprintf('%s: %d رکورد seed شد', $bundle, count($normalized)));
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user