Сидеры
Внимание
Данная статья документации написана нейросетью. Возможны некоторые расхождения и неточность информации!
Полное руководство по созданию и использованию сидеров в IO7 фреймворке.
Содержание
Обзор
Сидеры используются для заполнения базы данных начальными данными:
- Административные учётные записи
- Справочники (роли, категории, настройки)
- Тестовые данные для разработки
- Данные для staging-окружения
Пространство имён: IO\Database
Файл: src/modules/io7/php/Database/Seeder.php
Seeder
Абстрактный базовый класс сидера. Каждый сидер должен наследоваться от этого класса и реализовывать метод run().
run()
abstract public function run(): void
Основной метод сидера — содержит логику заполнения данных. Вызывается автоматически при выполнении сидера.
public function run(): void
{
$this->insert('users', [
'login' => 'admin',
'name' => 'Администратор',
'email' => 'admin@example.com',
]);
}
insert()
protected function insert(string $table, array $data): void
Вставить одну запись в таблицу.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$data | array | Ассоциативный массив данных | — | Да |
$this->insert('users', [
'login' => 'admin',
'name' => 'Администратор',
'email' => 'admin@example.com',
'password_hash' => password_hash('admin123', PASSWORD_DEFAULT),
'role' => 'admin',
'active' => true,
]);
call()
protected function call(string $seederClass): void
Выполнить другой сидер по имени класса. Позволяет организовать порядок выполнения сидеров.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$seederClass | string | Полное имя класса сидера | — | Да |
$this->call(RolesSeeder::class);
$this->call(SettingsSeeder::class);
$this->call(UserSeeder::class);
DatabaseManager
seed()
public static function seed(?string $seederClass = null): int
Выполнить сидер(ы). Если класс не указан — выполняются все найденные сидеры из директории seeders.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$seederClass | ?\string | Имя класса сидера. null — выполнить все | null | Нет |
Возвращает: int — количество выполненных сидеров
use IO\Database\DatabaseManager;
// Один сидер
DatabaseManager::seed(UserSeeder::class);
// Все сидеры
DatabaseManager::seed();
Примеры
Простой сидер
Файл: database/seeders/RoleSeeder.php
<?php
use IO\Database\Seeder;
class RoleSeeder extends Seeder
{
public function run(): void
{
$roles = [
['name' => 'admin', 'description' => 'Администратор'],
['name' => 'manager', 'description' => 'Менеджер'],
['name' => 'user', 'description' => 'Пользователь'],
['name' => 'guest', 'description' => 'Гость'],
];
foreach ($roles as $role) {
$this->insert('roles', $role);
}
}
}
Сидер с вызовом других сидеров
Файл: database/seeders/DatabaseSeeder.php
<?php
use IO\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
$this->call(RolesSeeder::class);
$this->call(SettingsSeeder::class);
$this->call(UserSeeder::class);
}
}
Сидер пользователей
Файл: database/seeders/UserSeeder.php
<?php
use IO\Database\Seeder;
class UserSeeder extends Seeder
{
public function run(): void
{
$this->insert('users', [
'login' => 'admin',
'name' => 'Администратор',
'email' => 'admin@example.com',
'password_hash' => password_hash('admin123', PASSWORD_DEFAULT),
'role' => 'admin',
'active' => true,
]);
$this->insert('users', [
'login' => 'manager',
'name' => 'Менеджер',
'email' => 'manager@example.com',
'password_hash' => password_hash('manager123', PASSWORD_DEFAULT),
'role' => 'manager',
'active' => true,
]);
// Тестовые пользователи
for ($i = 1; $i <= 10; $i++) {
$this->insert('users', [
'login' => "user_{$i}",
'name' => "Пользователь {$i}",
'email' => "user{$i}@example.com",
'password_hash' => password_hash('password', PASSWORD_DEFAULT),
'role' => 'user',
'active' => true,
]);
}
}
}
Сидер настроек
Файл: database/seeders/SettingsSeeder.php
<?php
use IO\Database\Seeder;
class SettingsSeeder extends Seeder
{
public function run(): void
{
$settings = [
['key' => 'site_name', 'value' => 'Мой сайт'],
['key' => 'site_email', 'value' => 'info@example.com'],
['key' => 'timezone', 'value' => 'Europe/Moscow'],
['key' => 'items_per_page', 'value' => '25'],
['key' => 'allow_registration', 'value' => 'true'],
];
foreach ($settings as $setting) {
$this->insert('settings', $setting);
}
}
}
Сидер с фабрикой
Файл: database/seeders/ProductSeeder.php
<?php
use IO\Database\Seeder;
class ProductSeeder extends Seeder
{
public function run(): void
{
$faker = \Faker\Factory::create('ru_RU');
$categories = ['Электроника', 'Одежда', 'Книги', 'Продукты'];
foreach ($categories as $category) {
$this->insert('categories', ['name' => $category]);
$categoryId = \IO\Database\SqlConnection::connection()
->getPdo()->lastInsertId();
for ($i = 0; $i < 20; $i++) {
$this->insert('products', [
'category_id' => $categoryId,
'name' => $faker->words(3, true),
'description' => $faker->paragraph,
'price' => $faker->randomFloat(2, 10, 10000),
'in_stock' => $faker->boolean(80),
]);
}
}
}
}
Идемпотентный сидер
<?php
use IO\Database\Seeder;
use IO\Database\SqlConnection;
class RoleSeeder extends Seeder
{
public function run(): void
{
$roles = [
['name' => 'admin', 'description' => 'Администратор'],
['name' => 'manager', 'description' => 'Менеджер'],
['name' => 'user', 'description' => 'Пользователь'],
];
foreach ($roles as $role) {
$exists = SqlConnection::table('roles')
->where('name', $role['name'])
->exists();
if (!$exists) {
$this->insert('roles', $role);
}
}
}
}
Сидер с параметрами
<?php
use IO\Database\Seeder;
class UserSeeder extends Seeder
{
private int $count;
public function __construct(int $count = 10)
{
$this->count = $count;
}
public function run(): void
{
for ($i = 1; $i <= $this->count; $i++) {
$this->insert('users', [
'login' => "user_{$i}",
'name' => "Пользователь {$i}",
'email' => "user{$i}@example.com",
'password_hash' => password_hash('password', PASSWORD_DEFAULT),
'role' => 'user',
'active' => true,
]);
}
}
}
// Использование
$seeder = new UserSeeder(50);
$seeder->run();
Сидер только для dev-окружения
<?php
use IO\Database\Seeder;
class TestDataSeeder extends Seeder
{
public function run(): void
{
if (getenv('CLOUD_ENV') !== 'dev') {
return;
}
$faker = \Faker\Factory::create('ru_RU');
for ($i = 0; $i < 100; $i++) {
$this->insert('users', [
'login' => $faker->unique()->userName,
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password_hash' => password_hash('password', PASSWORD_DEFAULT),
'role' => 'user',
'active' => true,
]);
}
}
}
Запуск
# Все сидеры
php iocli db:seed
# Один сидер
php iocli db:seed --class=UserSeeder
Через PHP
use IO\Database\DatabaseManager;
DatabaseManager::init('/path/to/project');
// Все сидеры
DatabaseManager::seed();
// Один сидер
DatabaseManager::seed(UserSeeder::class);
// Цепочка
DatabaseManager::seed(RolesSeeder::class);
DatabaseManager::seed(SettingsSeeder::class);
DatabaseManager::seed(UserSeeder::class);
Рекомендации
- Создайте
DatabaseSeederкак точку входа для всех сидеров - Используйте
call()для организации порядка выполнения - Проверяйте существование записей перед вставкой (идемпотентность)
- Не используйте сидеры для продакшен-данных (кроме начальных)
- Используйте фабрики для генерации тестовых данных
- Храните сидеры в
database/seeders/ - Именование:
ModelNameSeeder.phpилиDescriptiveNameSeeder.php - Передавайте параметры через конструктор для гибкости
FAQ
Как сделать сидер идемпотентным?
public function run(): void
{
$exists = \IO\Database\SqlConnection::table('roles')
->where('name', 'admin')
->exists();
if (!$exists) {
$this->insert('roles', ['name' => 'admin', 'description' => 'Администратор']);
}
}
Как передать параметры в сидер?
class UserSeeder extends Seeder
{
private int $count;
public function __construct(int $count = 10)
{
$this->count = $count;
}
public function run(): void
{
for ($i = 0; $i < $this->count; $i++) {
$this->insert('users', [...]);
}
}
}
// Использование
$seeder = new UserSeeder(50);
$seeder->run();
Как выполнить сидер только в dev?
public function run(): void
{
if (getenv('CLOUD_ENV') !== 'dev') {
return;
}
// Тестовые данные только для dev
...
}
Чем сидер отличается от фабрики?
- Сидер — заполняет БД реальными/тестовыми данными (выполняет
insert()в БД) - Фабрика — генерирует структурированные данные программно (может не сохранять в БД)
Как получить ID последней вставленной записи в сидере?
$this->insert('categories', ['name' => 'Electronics']);
$categoryId = \IO\Database\SqlConnection::connection()
->getPdo()->lastInsertId();
Можно ли использовать сидер без класса?
Да, через DatabaseManager::seed() без параметров выполняются все сидеры из директории database/seeders/.