Files
testRestApi/config/Seeds/DatabaseSeed.php
T
2026-10-21 18:34:35 +02:00

217 lines
8.7 KiB
PHP

<?php
declare(strict_types=1);
use Authentication\PasswordHasher\DefaultPasswordHasher;
use Faker\Factory;
use Faker\Generator;
use Migrations\BaseSeed;
/**
* Seeds test data: 2 accounts, 100 customers and 1-5 cars per customer.
*
* Run: bin/cake seeds run DatabaseSeed
* Existing data in users, customers and cars is removed first.
*/
class DatabaseSeed extends BaseSeed
{
private const CARS = [
'Toyota' => ['Corolla', 'Yaris', 'RAV4', 'Auris', 'C-HR', 'Camry'],
'Volkswagen' => ['Golf', 'Passat', 'Polo', 'Tiguan', 'T-Roc', 'Arteon'],
'Skoda' => ['Octavia', 'Fabia', 'Superb', 'Kodiaq', 'Karoq', 'Scala'],
'Ford' => ['Focus', 'Fiesta', 'Mondeo', 'Kuga', 'Puma'],
'Opel' => ['Astra', 'Corsa', 'Insignia', 'Mokka', 'Grandland'],
'BMW' => ['Seria 3', 'Seria 5', 'X1', 'X3', 'X5'],
'Audi' => ['A3', 'A4', 'A6', 'Q3', 'Q5'],
'Mercedes-Benz' => ['Klasa A', 'Klasa C', 'Klasa E', 'GLC', 'GLA'],
'Renault' => ['Clio', 'Megane', 'Captur', 'Kadjar'],
'Kia' => ['Ceed', 'Sportage', 'Rio', 'Niro'],
'Hyundai' => ['i20', 'i30', 'Tucson', 'Kona'],
'Tesla' => ['Model 3', 'Model Y', 'Model S'],
'Fiat' => ['Panda', '500', 'Tipo'],
'Dacia' => ['Duster', 'Sandero', 'Logan'],
];
private const COLORS = ['czarny', 'biały', 'srebrny', 'szary', 'niebieski', 'czerwony', 'zielony', 'grafitowy', 'beżowy'];
private const PLATE_PREFIXES = ['WA', 'WE', 'WI', 'KR', 'KK', 'PO', 'PZ', 'GD', 'GA', 'WR', 'DW', 'LU', 'SK', 'SC', 'EL', 'BI', 'OP', 'RZ', 'TK', 'NO', 'ZS', 'CB', 'FZ'];
private const CUSTOMER_NOTES = [
'Preferuje kontakt telefoniczny po godzinie 16.',
'Stały klient, przysługuje rabat 10% na usługi serwisowe.',
'Prosi o przypomnienia SMS przed terminem przeglądu.',
'Faktury wysyłać wyłącznie na adres e-mail.',
'Klient flotowy - rozliczenie zbiorcze na koniec miesiąca.',
'Zainteresowany wymianą auta na nowsze w przyszłym roku.',
'Kontakt tylko w dni robocze.',
];
private const CAR_NOTES = [
'Wymiana oleju przy 15 000 km.',
'Do sprawdzenia klocki hamulcowe przy następnej wizycie.',
'Opony zimowe przechowywane w serwisie.',
'Auto po szkodzie parkingowej - naprawiony tylny zderzak.',
'Gwarancja producenta do końca roku.',
'Klient zgłaszał stuki w zawieszeniu.',
'Zalecana wymiana rozrządu.',
];
private const VIN_CHARS = 'ABCDEFGHJKLMNPRSTUVWXYZ0123456789';
/**
* The seed truncates its tables first, so it can safely be re-run.
*
* @return bool
*/
public function isIdempotent(): bool
{
return true;
}
/**
* @return void
*/
public function run(): void
{
$faker = Factory::create('pl_PL');
$faker->seed(20261019);
$now = date('Y-m-d H:i:s');
$hasher = new DefaultPasswordHasher();
$this->execute('SET FOREIGN_KEY_CHECKS=0');
foreach (['cars', 'customers', 'users'] as $table) {
$this->execute("TRUNCATE TABLE `{$table}`");
}
$this->execute('SET FOREIGN_KEY_CHECKS=1');
$this->table('users')->insert([
[
'email' => 'admin@example.com',
'password' => $hasher->hash('Admin123!'),
'first_name' => 'Adam',
'last_name' => 'Administrator',
'role' => 'admin',
'active' => true,
'created' => $now,
'modified' => $now,
],
[
'email' => 'user@example.com',
'password' => $hasher->hash('User1234!'),
'first_name' => 'Jan',
'last_name' => 'Użytkownik',
'role' => 'user',
'active' => true,
'created' => $now,
'modified' => $now,
],
])->saveData();
$customers = [];
$emails = [];
for ($i = 1; $i <= 100; $i++) {
$isCompany = $faker->boolean(25);
$firstName = $faker->firstName();
$lastName = $faker->lastName();
do {
$email = $this->slug($firstName) . '.' . $this->slug($lastName) . $faker->numberBetween(1, 999)
. '@' . $faker->freeEmailDomain();
} while (isset($emails[$email]));
$emails[$email] = true;
$created = $faker->dateTimeBetween('-3 years', '-1 day')->format('Y-m-d H:i:s');
$customers[] = [
'type' => $isCompany ? 'company' : 'individual',
'first_name' => $firstName,
'last_name' => $lastName,
'email' => $email,
'phone' => '+48 ' . $faker->numerify('### ### ###'),
'company_name' => $isCompany ? $faker->company() : null,
'tax_id' => $isCompany ? $faker->numerify('##########') : null,
'street' => $faker->boolean(90) ? $faker->streetAddress() : null,
'city' => $faker->city(),
'postal_code' => $faker->numerify('##-###'),
'country' => 'PL',
'birth_date' => $isCompany ? null : $faker->dateTimeBetween('-80 years', '-18 years')->format('Y-m-d'),
'notes' => $faker->boolean(20) ? $faker->randomElement(self::CUSTOMER_NOTES) : null,
'created_by' => $faker->randomElement([1, 2]),
'created' => $created,
'modified' => $created,
];
}
$this->table('customers')->insert($customers)->saveData();
$cars = [];
$vins = [];
$plates = [];
for ($customerId = 1; $customerId <= 100; $customerId++) {
$count = $faker->numberBetween(1, 5);
for ($j = 0; $j < $count; $j++) {
$make = $faker->randomElement(array_keys(self::CARS));
$isTesla = $make === 'Tesla';
$fuel = $isTesla ? 'electric' : $faker->randomElement(['petrol', 'petrol', 'diesel', 'diesel', 'lpg', 'hybrid']);
do {
$vin = $this->randomVin($faker);
} while (isset($vins[$vin]));
$vins[$vin] = true;
do {
$plate = $faker->randomElement(self::PLATE_PREFIXES)
. $faker->numberBetween(10000, 99999);
$plate = substr($plate, 0, 2) . $faker->bothify('?') . substr($plate, 3);
$plate = strtoupper($plate);
} while (isset($plates[$plate]));
$plates[$plate] = true;
$year = $faker->numberBetween(2005, 2026);
$created = $faker->dateTimeBetween('-3 years', '-1 day')->format('Y-m-d H:i:s');
$cars[] = [
'customer_id' => $customerId,
'make' => $make,
'model' => $faker->randomElement(self::CARS[$make]),
'production_year' => $year,
'vin' => $vin,
'registration_number' => $plate,
'fuel_type' => $fuel,
'color' => $faker->randomElement(self::COLORS),
'engine_capacity' => $fuel === 'electric' ? null : $faker->randomElement([999, 1197, 1395, 1498, 1598, 1968, 1995, 2494, 2993]),
'power_hp' => $faker->numberBetween(70, $isTesla ? 500 : 300),
'transmission' => $isTesla ? 'automatic' : $faker->randomElement(['manual', 'manual', 'automatic']),
'mileage' => max(0, (2026 - $year) * $faker->numberBetween(5000, 25000) + $faker->numberBetween(0, 5000)),
'notes' => $faker->boolean(15) ? $faker->randomElement(self::CAR_NOTES) : null,
'created' => $created,
'modified' => $created,
];
}
}
$this->table('cars')->insert($cars)->saveData();
$this->getIo()?->out(sprintf('Seeded 2 users, %d customers and %d cars.', count($customers), count($cars)));
}
/**
* @param \Faker\Generator $faker Faker
* @return string
*/
private function randomVin(Generator $faker): string
{
$vin = '';
for ($i = 0; $i < 17; $i++) {
$vin .= self::VIN_CHARS[$faker->numberBetween(0, strlen(self::VIN_CHARS) - 1)];
}
return $vin;
}
/**
* ASCII slug for e-mail addresses (strips Polish diacritics).
*
* @param string $text Text
* @return string
*/
private function slug(string $text): string
{
$map = ['ą' => 'a', 'ć' => 'c', 'ę' => 'e', 'ł' => 'l', 'ń' => 'n', 'ó' => 'o', 'ś' => 's', 'ź' => 'z', 'ż' => 'z'];
return preg_replace('/[^a-z]/', '', strtr(mb_strtolower($text), $map)) ?? '';
}
}