PHPackages                             timbrs/database-dumps - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. timbrs/database-dumps

ActiveLibrary[Database &amp; ORM](/categories/database)

timbrs/database-dumps
=====================

Framework-agnostic PHP package for managing database dumps with SQL exports/imports, supporting PostgreSQL and MySQL

v1.0.1(2mo ago)03MITPHPPHP ^7.2|^8.0

Since Mar 12Pushed 2w agoCompare

[ Source](https://github.com/timbrs/php-database-dumps)[ Packagist](https://packagist.org/packages/timbrs/database-dumps)[ RSS](/packages/timbrs-database-dumps/feed)WikiDiscussions master Synced 2w ago

READMEChangelogDependencies (26)Versions (3)Used By (0)

Database Dumps Package
======================

[](#database-dumps-package)

![Tests](https://camo.githubusercontent.com/d940ad7f0752e2cbe0d63c50dcebf329078807390051c41fe63258f1b5c4e182/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d70617373696e672d627269676874677265656e)![PHP Version](https://camo.githubusercontent.com/36b1af6536ce75dfb591b3c577035790c6842296193ef765a6bc8de44732705a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545372e32253230253743253230253545382e302d626c7565)![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)

**[Русский](#%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9)** | **[English](#english)**

---

Русский язык
============

[](#русский-язык)

PHP-пакет для экспорта и импорта дампов баз данных в SQL. Поддерживает PostgreSQL, MySQL и Oracle (12c+). Работает с Symfony, Laravel и любым PHP-проектом.

Оглавление
----------

[](#оглавление)

- [Описание](#%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5)
- [Возможности](#%D0%B2%D0%BE%D0%B7%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D0%B8)
- [Установка](#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0)
- [Быстрый запуск (LLM + OPENCODE)](#%D0%B1%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9-%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA-llm--opencode)
- [Быстрый старт](#%D0%B1%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9-%D1%81%D1%82%D0%B0%D1%80%D1%82)
    - [Symfony](#%D0%B1%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9-%D1%81%D1%82%D0%B0%D1%80%D1%82-symfony)
    - [Laravel](#%D0%B1%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9-%D1%81%D1%82%D0%B0%D1%80%D1%82-laravel)
- [Конфигурация](#%D0%BA%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D1%8F)
    - [Полный экспорт (full\_export)](#%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9-%D1%8D%D0%BA%D1%81%D0%BF%D0%BE%D1%80%D1%82-full_export)
    - [Частичный экспорт (partial\_export)](#%D1%87%D0%B0%D1%81%D1%82%D0%B8%D1%87%D0%BD%D1%8B%D0%B9-%D1%8D%D0%BA%D1%81%D0%BF%D0%BE%D1%80%D1%82-partial_export)
    - [Каскадные зависимости (cascade\_from)](#%D0%BA%D0%B0%D1%81%D0%BA%D0%B0%D0%B4%D0%BD%D1%8B%D0%B5-%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D0%BE%D1%81%D1%82%D0%B8-cascade_from)
    - [Замена персональных данных (faker)](#%D0%B7%D0%B0%D0%BC%D0%B5%D0%BD%D0%B0-%D0%BF%D0%B5%D1%80%D1%81%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-faker)
    - [Разделение конфига по схемам (includes)](#%D1%80%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D0%B0-%D0%BF%D0%BE-%D1%81%D1%85%D0%B5%D0%BC%D0%B0%D0%BC-includes)
    - [Несколько подключений](#%D0%BD%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9)
    - [Настройки (settings)](#%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B8-settings)
    - [Автогенерация конфигурации](#%D0%B0%D0%B2%D1%82%D0%BE%D0%B3%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F-%D0%BA%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D0%B8)
- [Углублённый анализ (LLM + OPENCODE)](#%D1%83%D0%B3%D0%BB%D1%83%D0%B1%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B9-%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7)
    - [Настройка LLM (интерактивно)](#%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-llm-%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE)
    - [LLM-детекция ПД и профилирование](#llm-%D0%B4%D0%B5%D1%82%D0%B5%D0%BA%D1%86%D0%B8%D1%8F-%D0%BF%D0%B4-%D0%B8-%D0%BF%D1%80%D0%BE%D1%84%D0%B8%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
    - [Анализ кода через OPENCODE](#%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7-%D0%BA%D0%BE%D0%B4%D0%B0-%D1%87%D0%B5%D1%80%D0%B5%D0%B7-opencode)
- [Настройка Symfony](#%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-symfony)
    - [Регистрация бандла](#%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D1%8F-%D0%B1%D0%B0%D0%BD%D0%B4%D0%BB%D0%B0)
    - [Структура каталогов (Symfony)](#%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0-%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE%D0%B2-symfony)
    - [Команды Symfony](#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B-symfony)
- [Настройка Laravel](#%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0-laravel)
    - [Регистрация провайдера](#%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D1%8F-%D0%BF%D1%80%D0%BE%D0%B2%D0%B0%D0%B9%D0%B4%D0%B5%D1%80%D0%B0)
    - [Публикация конфигурации](#%D0%BF%D1%83%D0%B1%D0%BB%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F-%D0%BA%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D0%B8)
    - [Команды Laravel](#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B-laravel)
- [Скрипты before/after](#%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D1%8B-beforeafter)
- [Поддержка IDE (JSON Schema)](#%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%BA%D0%B0-ide-json-schema)
- [Архитектура](#%D0%B0%D1%80%D1%85%D0%B8%D1%82%D0%B5%D0%BA%D1%82%D1%83%D1%80%D0%B0)
    - [Как работает экспорт](#%D0%BA%D0%B0%D0%BA-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82-%D1%8D%D0%BA%D1%81%D0%BF%D0%BE%D1%80%D1%82)
    - [Как работает импорт](#%D0%BA%D0%B0%D0%BA-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82-%D0%B8%D0%BC%D0%BF%D0%BE%D1%80%D1%82)
    - [Различия платформ](#%D1%80%D0%B0%D0%B7%D0%BB%D0%B8%D1%87%D0%B8%D1%8F-%D0%BF%D0%BB%D0%B0%D1%82%D1%84%D0%BE%D1%80%D0%BC)
    - [Структура исходного кода](#%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0-%D0%B8%D1%81%D1%85%D0%BE%D0%B4%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BA%D0%BE%D0%B4%D0%B0)
- [Безопасность](#%D0%B1%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C)
- [Тестирование](#%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
- [Локальная разработка](#%D0%BB%D0%BE%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0)
- [Требования](#%D1%82%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
- [Лицензия](#%D0%BB%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F)

---

Описание
--------

[](#описание)

**Database Dumps** — это PHP-пакет, который помогает разработчикам создавать и разворачивать дампы базы данных для локальной и тестовой среды.

**Какую проблему решает?** На проекте с большой боевой базой разработчику нужно иметь актуальные тестовые данные — но копировать всю базу долго, а персональные данные клиентов нельзя использовать в dev-окружении. Этот пакет позволяет настроить правила экспорта один раз: какие таблицы забирать целиком, какие — частично, и забыть о ручной подготовке дампов.

**Как работает?** Вы описываете в YAML-файле, какие таблицы и как экспортировать. Пакет сам:

- генерирует SQL-дампы из боевой (или staging) базы с учётом FK-зависимостей между таблицами
- заменяет персональные данные (ФИО, email, телефоны) на сгенерированные, чтобы дампы были безопасны
- разворачивает дампы в нужную базу одной командой, с защитой от случайного запуска на продакшене

**Где применим?** В любом PHP-проекте на Symfony или Laravel (или без фреймворка), где нужно:

- быстро разворачивать тестовую базу для разработчиков
- передавать дампы между командами без утечки персональных данных
- держать seed-данные в репозитории и обновлять их из реальной базы
- работать с несколькими базами данных одновременно

Возможности
-----------

[](#возможности)

- **Не привязан к фреймворку** — работает с Symfony, Laravel и любым PHP-проектом
- **PostgreSQL, MySQL и Oracle** — автоматически генерирует правильный SQL для каждой СУБД
- **Несколько подключений** — экспорт/импорт сразу из нескольких баз данных
- **Пакетные INSERT** — автоматическая группировка по 1000 строк на выражение
- **Откат при ошибках** — импорт выполняется в транзакции
- **Защита от продакшена** — импорт заблокирован при `APP_ENV=prod`
- **Скрипты до/после** — свои SQL-скрипты до и после импорта
- **Гибкая настройка** — YAML-файл с правилами полного и частичного экспорта
- **Сброс счётчиков** — автоматический сброс sequence / auto-increment после импорта
- **Автогенерация конфига** — команда `prepare-config` создаёт YAML по структуре БД
- **FK-сортировка** — автоматическая топологическая сортировка таблиц при экспорте и импорте (родители первыми)
- **Каскадные зависимости** — `cascade_from` генерирует WHERE-подзапросы для связности данных через FK
- **Замена ПД (faker)** — автоматическое обнаружение и замена персональных данных (ФИО, email, телефон, пол) при экспорте
- **Разделение конфига** — автоматическое разбиение конфигурации на отдельные файлы по схемам
- **Smart Cycle Breaking** — автоматический разрыв циклических FK-зависимостей (двухфазный INSERT NULL → UPDATE) вместо fallback на алфавитный порядок
- **Self-referential FK** — поддержка таблиц со ссылками на себя (деревья категорий, оргструктуры, комментарии)
- **Валидация схемы при импорте** — предупреждение при расхождении столбцов дампа и БД, опция `--ignore-schema-mismatch`
- **Настройки в конфиге** — секция `settings:` для batch\_size, sample\_size, max\_cascade\_depth
- **Dry-run экспорт** — опция `--dry-run` для просмотра плана экспорта без выполнения
- **ИИ-анализ данных (LLM)** — точная классификация ПД, профилирование колонок и подсказки по выборке через OpenAI-совместимый LLM; при первом запуске пакет интерактивно спрашивает URL/модель/token и запоминает их
- **ИИ-анализ кода (OPENCODE)** — обнаружение связей без FK и бизнес-сегментов в коде хост-приложения (Eloquent/Doctrine/сырые JOIN) → авто-обогащение `cascade_from` и `sample.criteria`
- **Выборка по критериям (sample)** — набор именованных «корзин» (red/new/inactive/vip…) с дедупом по PK — «все фломастеры»

Установка
---------

[](#установка)

```
composer require --dev timbrs/database-dumps
```

Быстрый запуск (LLM + OPENCODE)
-------------------------------

[](#быстрый-запуск-llm--opencode)

Рекомендуемый, основной сценарий — анализ **с участием ИИ**. Пакет использует два источника:

- **Прямой LLM** (OpenAI-совместимый API, например `openai/gpt-oss-120b`) — для анализа **данных**: точная классификация ПД (faker), профилирование колонок, подсказки по выборке.
- **OPENCODE** (внешний агент) — для анализа **кода** хост-приложения: связи без FK, бизнес-сегменты (scopes/репозитории) → `sample.criteria`, карта «колонка → код».

> Без настроенного LLM пакет тоже работает — анализ деградирует на regex-эвристики. Но рекомендуется именно LLM-сценарий.

### Шаг 1. Сгенерировать конфиг (при первом запуске пакет сам спросит про LLM)

[](#шаг-1-сгенерировать-конфиг-при-первом-запуске-пакет-сам-спросит-про-llm)

```
# Laravel
php artisan dbdump:prepare-config all
# Symfony
php bin/console app:dbdump:prepare-config all
```

**При первом запуске**, если настройки LLM ещё не заданы, команда спросит:

1. `Настроить LLM сейчас?` — да/нет (по умолчанию да);
2. `API URL` — базовый адрес OpenAI-совместимого API (например `https://gpt.example.com/v1`);
3. `Модель` — имя модели (по умолчанию `openai/gpt-oss-120b`);
4. `Token` — Bearer-токен; **можно оставить пустым** (Enter).

Ответы сохраняются в `database/dbdump_llm.json` и **применяются сразу в этом же запуске**. Повторно спрашивать не будет. Если откажетесь — выбор тоже запомнится (анализ пойдёт на regex); включить позже — командой `configure-llm` (см. ниже).

> ⚠️ Файл `database/dbdump_llm.json` может содержать token — добавьте его в `.gitignore`.

Результат: `dump_config.yaml` (+ per-schema файлы) с автоопределёнными `full_export`/`partial_export`, секцией `faker` (LLM-детекция ПД) и каскадами по FK.

### Шаг 2 (опционально). Обогатить конфиг анализом кода через OPENCODE

[](#шаг-2-опционально-обогатить-конфиг-анализом-кода-через-opencode)

Нужен установленный `opencode` в `PATH` и настроенный в нём провайдер LLM (`~/.config/opencode/opencode.json`).

```
# Одной командой: провижинит агента + инвентарь, прогонит opencode по схемам и применит результат
php artisan dbdump:prepare-analysis --run            # Laravel
php bin/console app:dbdump:prepare-analysis --run    # Symfony
```

Команда сгенерирует в хост-проект всё необходимое для связки с opencode:

- `.opencode/agents/dbdump-mapper.md` — готовый агент (read-only по коду, пишет только в `database/analysis/out/`);
- `database/analysis/schema_inventory.json` + `schema_inventory..json` — инвентарь БД для агента (**без значений данных** — PII не выгружается);
- `database/analysis/output_schema.json` — контракт JSON-вывода;
- `database/analysis/RUN.md` — точные команды для ручного прогона.

Результат (связи из кода → `cascade_from: source: code`, бизнес-сегменты → `sample.criteria`) дописывается в `dump_config.yaml`, отчёт — в `database/analysis/REPORT.md`. Пользовательские правки в YAML в приоритете. Если `opencode` не найден — команда не упадёт, а напечатает готовые к вставке строки запуска. Подробнее — в разделе [Анализ кода через OPENCODE](#%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7-%D0%BA%D0%BE%D0%B4%D0%B0-%D1%87%D0%B5%D1%80%D0%B5%D0%B7-opencode).

### Шаг 3. Экспортировать и импортировать дампы

[](#шаг-3-экспортировать-и-импортировать-дампы)

```
php artisan dbdump:export all      # экспорт (faker применяется автоматически)
php artisan dbdump:import          # импорт (заблокирован на проде)
```

### Переконфигурировать LLM в любой момент

[](#переконфигурировать-llm-в-любой-момент)

```
php artisan dbdump:configure-llm                 # Laravel
php bin/console app:dbdump:configure-llm         # Symfony
```

Интерактивно меняет URL/модель/token, умеет проверить соединение и пересохранить `database/dbdump_llm.json`.

Быстрый старт
-------------

[](#быстрый-старт)

### Symfony

[](#symfony)

1. Бандл регистрируется автоматически через Symfony Flex.
2. Создайте файл `config/dump_config.yaml`:

```
full_export:
  public:
    - users
    - roles

partial_export:
  public:
    clients:
      limit: 1000
      order_by: created_at DESC
```

3. Экспортируйте дампы:

```
php bin/console app:dbdump:export all
```

4. Импортируйте дампы:

```
php bin/console app:dbdump:import
```

### Laravel

[](#laravel)

1. Сервис-провайдер подключается автоматически. Файл `database/dump_config.yaml` создаётся при первом запуске.
2. Отредактируйте `database/dump_config.yaml` (формат тот же, что и для Symfony).
3. Экспортируйте дампы:

```
php artisan dbdump:export all
```

4. Импортируйте дампы:

```
php artisan dbdump:import
```

Конфигурация
------------

[](#конфигурация)

Экспорт настраивается через YAML-файл. В нём две секции: `full_export` (все строки) и `partial_export` (с ограничениями).

#### Полный экспорт (full\_export)

[](#полный-экспорт-full_export)

Экспортирует **все строки** из указанных таблиц:

```
full_export:
  public:          # имя схемы
    - users        # таблицы — все строки
    - roles
  system:
    - settings
```

#### Частичный экспорт (partial\_export)

[](#частичный-экспорт-partial_export)

Экспортирует **часть строк** с фильтрацией:

```
partial_export:
  public:
    clients:
      limit: 1000                    # максимум строк
      order_by: created_at DESC      # сортировка
      where: "is_active = true"      # условие WHERE
    orders:
      limit: 5000
      order_by: id DESC
```

**Доступные опции:**

ОпцияОписание`limit`Максимум строк (для `sample` — общий потолок на объединённую выборку)`order_by`Сортировка (должна заканчиваться на `ASC` или `DESC`)`where`Условие WHERE`cascade_from`Каскадная фильтрация по FK-родителю (см. ниже)`sample`Выборка по именованным критериям («все фломастеры», см. ниже)### Каскадные зависимости (cascade\_from)

[](#каскадные-зависимости-cascade_from)

При частичном экспорте связанных таблиц данные могут стать несогласованными: дочерняя таблица может ссылаться на строки, которые не попали в дамп родителя. Опция `cascade_from` решает эту проблему — она автоматически генерирует WHERE-подзапрос, ограничивающий выборку только теми строками, чей FK-родитель присутствует в дампе.

```
partial_export:
  public:
    users:
      limit: 500
      order_by: id DESC
    orders:
      limit: 1000
      order_by: created_at DESC
      cascade_from:
        - parent: public.users
          fk_column: user_id
          parent_column: id
    order_items:
      limit: 5000
      order_by: id DESC
      cascade_from:
        - parent: public.orders
          fk_column: order_id
          parent_column: id
```

В этом примере:

- `orders` экспортирует только те заказы, чей `user_id` есть среди экспортированных `users`
- `order_items` экспортирует только позиции заказов, попавших в дамп `orders`
- Подзапросы вложенные: `order_items` → `orders` → `users` (глубина до 10 уровней)

Команда `prepare-config` автоматически определяет FK-зависимости и генерирует `cascade_from`. Чтобы отключить: `--no-cascade`.

### Выборка по именованным критериям (sample)

[](#выборка-по-именованным-критериям-sample)

Иногда нужно набрать «все фломастеры» — по 10–100 строк каждого бизнес-сегмента (красные/жёлтые/зелёные по статусу, новые/старые по дате, неактивные, VIP…), часто по разным колонкам и кросс-таблично. Опция `sample` задаёт набор именованных «корзин», каждая со своим WHERE и квотой; итоговая выборка — объединение всех корзин **без дублей** (дедуп по первичному ключу).

```
partial_export:
  public:
    clients:
      order_by: id DESC
      limit: 100            # необяз.: общий потолок на объединённую выборку
      sample:
        criteria:           # именованные корзины; у каждой свой WHERE и квота
          - { name: red,      where: "status = 'red'",                            limit: 10 }
          - { name: new,      where: "created_at >= NOW() - INTERVAL '30 days'",   limit: 50 }
          - { name: inactive, where: "last_login_at < NOW() - INTERVAL '90 days'", limit: 20 }
          - { name: vip,      where: "EXISTS (SELECT 1 FROM public.client_flags f WHERE f.client_id = clients.id AND f.flag = 'vip')", limit: 30 }
        stratify_by: status   # сахар: развернуть в по-корзине-на-DISTINCT-значение
        per_value: 10         # квота для stratify_by
```

Как это работает:

- **Фаза 1** — по каждому критерию выбираются первичные ключи: `SELECT  FROM clients WHERE () AND () [ORDER BY ...] LIMIT `. `stratify_by` разворачивается в по-корзине на каждое DISTINCT-значение колонки.
- **Дедуп** — id всех корзин объединяются и дедуплицируются; при заданном `limit` объединённая выборка обрезается до него.
- **Фаза 2** — финальный `SELECT * FROM clients WHERE  IN (...)` (для составного PK — дизъюнкция равенств).

Требования и поведение:

- У таблицы должен быть первичный ключ (нужен для дедупа). `criteria[].where` проходит ту же проверку, что и обычный `where` (запрет `;` и SQL-комментариев, баланс кавычек/скобок) — корректные `EXISTS (...)` допускаются. `name` — идентификатор, `limit` — целое ≥ 1.
- **Cascade-консистентность:** если у родителя задан `sample`, дочерние таблицы (`cascade_from`) ссылаются на **фактически выбранные** id родителя, а не повторяют критерии подзапросом.
- `sample` и `cascade_from` на одной таблице несовместимы: при наличии `sample` экспорт идёт по нему (каскад для этой таблицы игнорируется). Поэтому авто-генерация добавляет `sample` только таблицам без `cascade_from`.

Авто-генерация: с флагом `--criteria` (или `--deep`) `prepare-config` профилирует категориальные колонки и сам предлагает `sample.criteria` (по корзине на топ-значение). Бизнес-сегменты из кода (Eloquent scopes, методы репозиториев) добавляются через ветку OPENCODE — см. [Углублённый анализ](#%D1%83%D0%B3%D0%BB%D1%83%D0%B1%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%B9-%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7).

### Замена персональных данных (faker)

[](#замена-персональных-данных-faker)

Пакет может автоматически обнаруживать и заменять персональные данные при экспорте. Это позволяет безопасно использовать дампы в dev/staging окружениях.

**Поддерживаемые паттерны:**

ПаттернОписаниеПример оригиналаПример замены`fio`ФИО полностьюИванов Иван ИвановичПетров Александр Сергеевич`fio_short`ФИО сокращённоИванов И.И.Козлов А.В.`name`Фамилия ИмяИванов ИванПетров Александр`firstname`Имя (кросс-корреляция с составной колонкой)ИванАлександр`lastname`Фамилия (кросс-корреляция с составной колонкой)ИвановПетров`patronymic`Отчество (кросс-корреляция с составной колонкой)ИвановичСергеевич`email`Email`phone`Телефон+79161234567+79234567890`gender`Пол (12 форматов: male/female, м/ж, муж/жен и др.)МужскойЖенский**Секция `faker` в конфигурации:**

```
faker:
  public:
    users:
      full_name: fio
      display_name: name
      first_name: firstname
      last_name: lastname
      middle_name: patronymic
      email: email
      phone: phone
      sex: gender
    employees:
      fio: fio
      short_fio: fio_short
      contact_email: email
```

Паттерны `firstname`, `lastname` и `patronymic` детектируются через кросс-корреляцию: если в таблице уже найдена составная колонка (fio, fio\_short, name), а рядом есть колонка с отдельными именами/фамилиями/отчествами — она будет обнаружена автоматически.

Паттерн `gender` определяется по совпадению имени колонки (`gender`, `sex`, `пол`) **и** содержимого (допустимые значения: `male`/`female`, `m`/`f`, `м`/`ж`, `мужской`/`женский`, `муж`/`жен`, `мужчина`/`женщина`). Регистр и формат оригинала сохраняются при замене.

Команда `prepare-config` автоматически анализирует содержимое таблиц и генерирует секцию `faker`, если в колонках обнаруживаются паттерны ПД (порог совпадения: 80% из 200 случайных строк). Чтобы отключить: `--no-faker`.

Замена детерминирована — seed основан на хеше значения ФИО (колонка с паттерном `fio`), если такая колонка есть в конфигурации таблицы. Если колонки `fio` нет — seed берётся от хеша комбинации всех faker-значений строки. Это гарантирует, что одна и та же персона всегда получает одинаковую замену независимо от таблицы и запуска.

### Разделение конфига по схемам (includes)

[](#разделение-конфига-по-схемам-includes)

При большом количестве таблиц конфигурация может стать громоздкой. Команда `prepare-config` по умолчанию разбивает конфиг на отдельные файлы по схемам:

```
config/
├── dump_config.yaml          # главный файл с includes
├── public.yaml               # конфигурация схемы public
├── system.yaml               # конфигурация схемы system
└── analytics/                # именованное подключение
    └── analytics.yaml

```

**Главный файл (`dump_config.yaml`):**

```
includes:
  public: public.yaml
  system: system.yaml

connections:
  analytics:
    includes:
      analytics: analytics/analytics.yaml
```

**Файл схемы (`public.yaml`):**

```
full_export:
  - users
  - roles
partial_export:
  clients:
    limit: 1000
    order_by: created_at DESC
faker:
  users:
    full_name: fio
    email: email
```

Чтобы генерировать единый файл без разделения: `--no-split`.

### Несколько подключений

[](#несколько-подключений)

Если нужно работать с несколькими базами данных, добавьте секцию `connections`:

```
# Основное подключение
full_export:
  public:
    - users
    - roles

partial_export:
  public:
    posts:
      limit: 100

# Дополнительные подключения
connections:
  analytics:                 # имя подключения (как в настройках фреймворка)
    full_export:
      analytics:
        - events
        - metrics
    partial_export:
      analytics:
        logs:
          limit: 50
          order_by: id DESC
```

**Куда сохраняются дампы:**

- Основное подключение: `database/dumps/{schema}/{table}.sql`
- Именованное подключение: `database/dumps/{connection}/{schema}/{table}.sql`

**Опция `--connection`:**

```
# Только основное подключение (по умолчанию)
php artisan dbdump:export all

# Только указанное подключение
php artisan dbdump:export all --connection=analytics

# Все подключения сразу
php artisan dbdump:export all --connection=all
```

### Настройки (settings)

[](#настройки-settings)

Секция `settings` позволяет изменять внутренние параметры пакета:

```
settings:
  batch_size: 1000        # строк на INSERT-выражение (по умолчанию: 1000)
  sample_size: 200        # строк для анализа ПД в PatternDetector (по умолчанию: 200)
  max_cascade_depth: 10   # макс. глубина cascade_from подзапросов (по умолчанию: 10)
```

### Автогенерация конфигурации

[](#автогенерация-конфигурации)

Команда `prepare-config` смотрит на структуру БД и создаёт или обновляет `dump_config.yaml`. Обязательный аргумент `mode` определяет область действия:

```
# Symfony
php bin/console app:dbdump:prepare-config all                    # Полная регенерация
php bin/console app:dbdump:prepare-config schema=billing         # Перегенерировать одну схему
php bin/console app:dbdump:prepare-config table=public.users     # Перегенерировать одну таблицу
php bin/console app:dbdump:prepare-config new                    # Добавить только новые таблицы

# Laravel
php artisan dbdump:prepare-config all
php artisan dbdump:prepare-config schema=billing
php artisan dbdump:prepare-config table=public.users
php artisan dbdump:prepare-config new
```

**Режимы:**

РежимОписание`all`Полная регенерация конфигурации (перезаписывает файл)`schema=`Перегенерация одной схемы, мёрж в существующий конфиг`table=`Перегенерация одной таблицы, мёрж в существующий конфиг`new`Обнаружение и дописывание новых таблиц (не затрагивает существующие)**Опции:**

ОпцияОписаниеПо умолчанию`--threshold`, `-t`Порог строк: таблицы с количеством строк &lt;= порога идут в full\_export, больше — в partial\_export500`--force`, `-f`Перезаписать файл без подтверждения (только для режима `all`)—`--no-cascade`Пропустить обнаружение FK и генерацию `cascade_from`—`--no-faker`Пропустить обнаружение персональных данных—`--no-split`Генерировать единый YAML без разделения по схемам—`--criteria`Авто-генерация `sample.criteria` из категориальных колонок—`--ai` / `--no-ai`Включить/отключить LLM-детекцию ПД (авто: включается, если LLM настроен — env `DBDUMP_LLM_URL` или `database/dbdump_llm.json`). `--no-ai` также подавляет авто-запрос настройки LLM при первом запускеавто`--deep`Глубокий анализ: профилирование + ИИ + `sample.criteria` + отчёт `database/analysis/REPORT.md`—**Как распределяются таблицы:**

- Строк &lt;= порога — `full_export`
- Строк &gt; порога — `partial_export` (с limit, автоопределённой сортировкой и шаблоном `where: "1=1"` для удобства редактирования)
- Пустые таблицы — пропускаются
- Служебные таблицы (migrations, sessions, cache\_*, telescope\_*, oauth\_*, audit\_*) — пропускаются

Углублённый анализ (--deep / --ai / --criteria)
-----------------------------------------------

[](#углублённый-анализ---deep----ai----criteria)

Анализ с участием ИИ — **основной сценарий** пакета. Опирается на два источника:

- **Прямой LLM** (`openai/gpt-oss-120b` по OpenAI-совместимому API) — анализ **данных**: PII-классификация точнее regex, профилирование, подсказки по выборке. Запросы ограничены по размеру.
- **OPENCODE** (внешний агент) — анализ **кода** целиком: связи без FK (Eloquent `belongsTo/hasMany`, Doctrine-ассоциации, сырые JOIN), карта «колонка → код», ключевые поля и бизнес-сегменты. Пакет готовит вход и инструкции, агент возвращает JSON, который пакет поглощает.

> Если LLM не настроен, анализ мягко деградирует на regex-эвристики — пакет остаётся работоспособным. См. также [Быстрый запуск](#%D0%B1%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9-%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA-llm--opencode).

### Настройка LLM (интерактивно)

[](#настройка-llm-интерактивно)

**При первом запуске `prepare-config`** (если настройки LLM ещё не заданы и сессия интерактивна) пакет сам предложит настроить LLM — спросит `API URL`, `Модель` и `Token` (token можно оставить пустым), сохранит ответы в `database/dbdump_llm.json` и применит их немедленно в этом же запуске. Отказ тоже запоминается, чтобы не спрашивать снова. Авто-запрос подавляется флагом `--no-ai` и в неинтерактивном режиме (`--no-interaction`, CI).

Настроить или изменить LLM в любой момент можно явной командой — она дополнительно умеет проверить соединение:

```
php artisan dbdump:configure-llm                 # Laravel
php bin/console app:dbdump:configure-llm         # Symfony
```

После настройки `--ai`/`--deep` и `prepare-analysis` подхватывают параметры автоматически. Приоритет источников: переменные окружения `DBDUMP_LLM_*` (если задан URL) перекрывают сохранённый файл. Файл может содержать token — добавьте `database/dbdump_llm.json` в `.gitignore`.

### LLM-детекция ПД и профилирование

[](#llm-детекция-пд-и-профилирование)

```
# Symfony
php bin/console app:dbdump:prepare-config all --deep
php bin/console app:dbdump:prepare-config all --ai          # только LLM-PII
php bin/console app:dbdump:prepare-config all --criteria    # только авто sample.criteria

# Laravel
php artisan dbdump:prepare-config all --deep
```

- `--ai` использует LLM для классификации ПД (regex-результаты подаются как hints; принимаются типы с уверенностью выше порога, маппятся на `fio/email/phone/...`). При недоступном LLM — тихий fallback на regex + предупреждение.
- `--criteria` профилирует категориальные колонки и предлагает `sample.criteria` (по корзине на топ-значение).
- `--deep` включает всё перечисленное + пишет отчёт `database/analysis/REPORT.md` (+ машинный `analysis_result.json`): режим экспорта, предложенные критерии с SQL и обоснованием, ПД (regex vs LLM), профиль колонок.

Переменные окружения LLM:

ПеременнаяНазначениеПо умолчанию`DBDUMP_LLM_URL`Базовый URL OpenAI-совместимого API (например `https://llm.example.com/v1`). Пусто → AI-функции выключены—`DBDUMP_LLM_MODEL`Имя модели`openai/gpt-oss-120b``DBDUMP_LLM_TOKEN`Bearer-токен (опционально)—`DBDUMP_LLM_TIMEOUT`Таймаут запроса, сек`120``DBDUMP_LLM_ENABLED``true`/`false`; по умолчанию авто (включено при заданном URL)автоHTTP-запросы выполняются через `ext-curl` (без guzzle). Данные PII в промптах ограничены примерами значений колонок.

### Анализ кода через OPENCODE

[](#анализ-кода-через-opencode)

**Самый простой путь — одной командой** (нужен `opencode` в PATH):

```
php artisan dbdump:prepare-analysis --run            # Laravel
php bin/console app:dbdump:prepare-analysis --run    # Symfony
```

С `--run` модуль сам провижинит пакет, прогонит OPENCODE по чанку на каждую схему и применит результат к `dump_config.yaml`. Если opencode не найден — команда напечатает готовые к вставке строки запуска и не упадёт.

**Ручной путь (3 шага)** — если хотите контролировать прогон агента:

```
# 1. Подготовить пакет (агент + инвентарь + контракт + RUN.md)
php bin/console app:dbdump:prepare-analysis        # Symfony
php artisan dbdump:prepare-analysis                # Laravel

# 2. Запустить агента по чанку на схему (точные строки печатает команда из шага 1, см. также RUN.md)
opencode run --agent dbdump-mapper \
  -f database/analysis/schema_inventory.public.json \
  "Обработай схему public по инструкции; результат запиши в database/analysis/out/public.json"

# 3. Применить результат к dump_config.yaml
php bin/console app:dbdump:apply-analysis          # Symfony
php artisan dbdump:apply-analysis                  # Laravel
```

Что провижинит `prepare-analysis` в хост-проект:

- `.opencode/agents/dbdump-mapper.md` — готовый агент (read-only по коду; пишет только в `database/analysis/out/`);
- `.opencode/commands/dbdump-map.md` — слэш-команда для TUI (опционально);
- `database/analysis/schema_inventory.json` — полный инвентарь + `schema_inventory..json` по каждой схеме (для прогона по чанку без переполнения контекста 128k), **без значений данных** (PII в OPENCODE не выгружается);
- `database/analysis/output_schema.json` — JSON-контракт ответа;
- `database/analysis/RUN.md` — точные команды запуска и применения.

`apply-analysis` читает `database/analysis/out/*.json`, валидирует против контракта, объединяет чанки и обогащает `dump_config.yaml`: `cascade_from` из кода (с пометкой `source: code` в отчёте) и `sample.criteria` из бизнес-сегментов. Пользовательские правки в приоритете — добавляется только отсутствующее; провенанс/уверенность фиксируются в `database/analysis/REPORT.md`.

Провайдер и модель LLM предполагаются уже настроенными в opencode пользователя (`~/.config/opencode/opencode.json`); агент не задаёт модель явно и наследует дефолтную — отдельной настройки не требуется. Для больших схем дробите прогон по чанку на схему (см. RUN.md).

Настройка Symfony
-----------------

[](#настройка-symfony)

### Регистрация бандла

[](#регистрация-бандла)

Бандл регистрируется автоматически через Symfony Flex. Если нет — добавьте в `config/bundles.php`:

```
return [
    // ...
    Timbrs\DatabaseDumps\Bridge\Symfony\DatabaseDumpsBundle::class => ['all' => true],
];
```

Укажите платформу в `services.yaml`:

```
parameters:
    database_dumps.platform: 'postgresql'  # или 'mysql', 'oracle'
```

### Структура каталогов (Symfony)

[](#структура-каталогов-symfony)

```
your-symfony-project/
├── config/
│   └── dump_config.yaml          # настройки экспорта
├── database/
│   ├── before_exec/              # скрипты до импорта
│   │   └── 01_prepare.sql
│   ├── dumps/                    # SQL-дампы
│   │   ├── public/
│   │   │   ├── users.sql
│   │   │   └── roles.sql
│   │   └── analytics/            # именованное подключение
│   │       └── analytics/
│   │           └── events.sql
│   └── after_exec/               # скрипты после импорта
│       └── 01_finalize.sql

```

### Команды Symfony

[](#команды-symfony)

```
# Экспорт всех таблиц
php bin/console app:dbdump:export all

# Экспорт одной таблицы
php bin/console app:dbdump:export public.users

# Экспорт только из одной схемы
php bin/console app:dbdump:export all --schema=public

# Экспорт из конкретного подключения
php bin/console app:dbdump:export all --connection=analytics
php bin/console app:dbdump:export all --connection=all

# Импорт всех дампов
php bin/console app:dbdump:import

# Импорт с опциями
php bin/console app:dbdump:import --skip-before --skip-after
php bin/console app:dbdump:import --schema=public
php bin/console app:dbdump:import --connection=all

# Экспорт без каскадной фильтрации и без замены ПД
php bin/console app:dbdump:export all --no-cascade --no-faker

# Предпросмотр плана экспорта (без реального выполнения)
php bin/console app:dbdump:export all --dry-run

# Импорт с игнорированием расхождений схемы
php bin/console app:dbdump:import --ignore-schema-mismatch

# Сгенерировать конфигурацию по структуре БД
php bin/console app:dbdump:prepare-config all
php bin/console app:dbdump:prepare-config all --threshold=1000 --force
php bin/console app:dbdump:prepare-config schema=billing
php bin/console app:dbdump:prepare-config table=public.users
php bin/console app:dbdump:prepare-config new --no-cascade --no-faker

# Углублённый анализ
php bin/console app:dbdump:prepare-config all --deep
php bin/console app:dbdump:prepare-analysis --run    # всё одной командой (нужен opencode в PATH)
# или вручную: prepare-analysis → opencode run → apply-analysis
```

Настройка Laravel
-----------------

[](#настройка-laravel)

### Регистрация провайдера

[](#регистрация-провайдера)

Сервис-провайдер подключается автоматически. Если нет — зарегистрируйте в `config/app.php`:

```
'providers' => [
    // ...
    Timbrs\DatabaseDumps\Bridge\Laravel\DatabaseDumpsServiceProvider::class,
],
```

### Публикация конфигурации

[](#публикация-конфигурации)

Чтобы изменить пути, опубликуйте PHP-конфигурацию:

```
php artisan vendor:publish --tag=database-dumps-config
```

Появится файл `config/database-dumps.php`:

```
return [
    'config_path' => base_path('database/dump_config.yaml'),
    'project_dir' => base_path(),
];
```

### Команды Laravel

[](#команды-laravel)

```
# Экспорт всех таблиц
php artisan dbdump:export all

# Экспорт одной таблицы
php artisan dbdump:export public.users

# Экспорт только из одной схемы
php artisan dbdump:export all --schema=public

# Экспорт из конкретного подключения
php artisan dbdump:export all --connection=analytics
php artisan dbdump:export all --connection=all

# Импорт всех дампов
php artisan dbdump:import

# Импорт с опциями
php artisan dbdump:import --skip-before --skip-after
php artisan dbdump:import --schema=public
php artisan dbdump:import --connection=all

# Экспорт без каскадной фильтрации и без замены ПД
php artisan dbdump:export all --no-cascade --no-faker

# Предпросмотр плана экспорта (без реального выполнения)
php artisan dbdump:export all --dry-run

# Импорт с игнорированием расхождений схемы
php artisan dbdump:import --ignore-schema-mismatch

# Сгенерировать конфигурацию по структуре БД
php artisan dbdump:prepare-config all
php artisan dbdump:prepare-config all --threshold=1000 --force
php artisan dbdump:prepare-config schema=billing
php artisan dbdump:prepare-config table=public.users
php artisan dbdump:prepare-config new --no-cascade --no-faker

# Углублённый анализ
php artisan dbdump:prepare-config all --deep
php artisan dbdump:prepare-analysis --run            # всё одной командой (нужен opencode в PATH)
# или вручную: prepare-analysis → opencode run → apply-analysis
```

Скрипты before/after
--------------------

[](#скрипты-beforeafter)

Можно выполнять свои SQL-скрипты до и после импорта.

КаталогКогда выполняется`database/before_exec/`**до** импорта дампов`database/after_exec/`**после** импорта дамповСкрипты выполняются в **алфавитном порядке**. Используйте числовые префиксы для управления очерёдностью:

```
database/before_exec/
├── 01_disable_triggers.sql
├── 02_prepare_temp.sql
database/after_exec/
├── 01_enable_triggers.sql
├── 02_refresh_views.sql

```

Чтобы пропустить скрипты, используйте `--skip-before` и `--skip-after`:

```
php artisan dbdump:import --skip-before
php artisan dbdump:import --skip-after
php artisan dbdump:import --skip-before --skip-after
```

Поддержка IDE (JSON Schema)
---------------------------

[](#поддержка-ide-json-schema)

В пакете есть JSON Schema для `dump_config.yaml` — файл `resources/dump_config.schema.json`. Он даёт автодополнение и валидацию в PHPStorm и других IDE.

### Вариант 1: YAML-комментарий (рекомендуется)

[](#вариант-1-yaml-комментарий-рекомендуется)

Добавьте в начало `dump_config.yaml`:

```
# yaml-language-server: $schema=../vendor/timbrs/database-dumps/resources/dump_config.schema.json
```

> Путь указывается относительно файла: для Symfony — относительно `config/`, для Laravel — относительно `database/`.

### Вариант 2: Настройка PHPStorm вручную

[](#вариант-2-настройка-phpstorm-вручную)

1. Откройте **Settings &gt; Languages &amp; Frameworks &gt; Schemas and DTDs &gt; JSON Schema Mappings**
2. Добавьте маппинг:
    - **Schema file**: `vendor/timbrs/database-dumps/resources/dump_config.schema.json`
    - **File path pattern**: `dump_config.yaml`

Архитектура
-----------

[](#архитектура)

### Как работает экспорт

[](#как-работает-экспорт)

```
Команда → TableConfigResolver → DatabaseDumper → [FK-сортировка + Cycle Breaking] → DataFetcher → [Cascade WHERE] → [Faker] → SqlGenerator → .sql файлы

```

1. **TableConfigResolver** — читает YAML и собирает список таблиц для экспорта
2. **DatabaseDumper** — управляет процессом экспорта
3. **TableDependencyResolver** — топологическая сортировка таблиц по FK (родители экспортируются первыми). При обнаружении циклов — автоматический разрыв через nullable-рёбра
4. **DataFetcher** — получает данные из БД через `ConnectionRegistry`
5. **CascadeWhereResolver** — генерирует WHERE-подзапросы из `cascade_from` для связности данных
6. **RussianFaker** — заменяет персональные данные (ФИО, email, телефон, пол) на сгенерированные
7. **SqlGenerator** — генерирует SQL: TRUNCATE + INSERT (с NULL для разорванных FK) + сброс счётчиков + UPDATE (восстановление FK)
8. Результат сохраняется в `database/dumps/{schema}/{table}.sql`

### Как работает импорт

[](#как-работает-импорт)

```
Команда → DatabaseImporter → ProductionGuard → TransactionManager → [FK-сортировка + Cycle Breaking] → [SchemaValidator] → ScriptExecutor → SqlParser → выполнение

```

1. **ProductionGuard** — проверяет, что мы не на продакшене
2. **TransactionManager** — оборачивает всё в транзакцию
3. **TableDependencyResolver** — топологическая сортировка файлов по FK (родители импортируются первыми), с автоматическим разрывом циклов
4. **SchemaValidator** — сравнивает столбцы дампа со столбцами в БД, предупреждает о расхождениях
5. **ScriptExecutor** — выполняет скрипты из `before_exec/`
6. **SqlParser** / **StatementSplitter** — разбирает .sql файлы на отдельные выражения
7. Выражения выполняются в БД
8. **ScriptExecutor** — выполняет скрипты из `after_exec/`

### Различия платформ

[](#различия-платформ)

Пакет сам генерирует правильный SQL в зависимости от СУБД:

PostgreSQLMySQLOracle (12c+)Имена таблиц`"table"` (двойные кавычки)``table`` (обратные кавычки)`"TABLE"` (двойные кавычки, UPPERCASE)TRUNCATE`TRUNCATE ... CASCADE``SET FOREIGN_KEY_CHECKS=0``DELETE FROM` (FK-safe)Счётчики`setval()` / `pg_get_serial_sequence()``ALTER TABLE ... AUTO_INCREMENT`Комментарий-заглушка (используйте `after_exec/`)LIMIT`LIMIT N``LIMIT N``FETCH FIRST N ROWS ONLY`INSERTБатч 1000 строкБатч 1000 строкПо одной строке (нет multi-row INSERT)Случайное число`RANDOM()``RAND()``DBMS_RANDOM.VALUE`Платформа определяется автоматически по подключению к БД.

> **Oracle:** используется `DELETE FROM` вместо `TRUNCATE TABLE`, т.к. Oracle TRUNCATE не поддерживает CASCADE и блокируется FK constraints. Сброс sequences требует PL/SQL — используйте скрипты в `database/after_exec/`.

### Структура исходного кода

[](#структура-исходного-кода)

```
src/
├── Adapter/                          # Адаптеры подключений к БД
│   ├── DoctrineDbalAdapter.php       #   Doctrine DBAL
│   ├── LaravelDatabaseAdapter.php    #   Laravel DB
│   └── PdoAdapter.php               #   Универсальный PDO (Oracle и др.)
├── Bridge/                           # Интеграции с фреймворками
│   ├── Laravel/
│   │   ├── Command/                  #   Artisan-команды
│   │   ├── DatabaseDumpsServiceProvider.php
│   │   └── LaravelLogger.php
│   └── Symfony/
│       ├── Command/                  #   Console-команды
│       ├── DependencyInjection/
│       ├── ConnectionRegistryFactory.php
│       ├── ConsoleLogger.php
│       └── DatabaseDumpsBundle.php
├── Config/                           # Классы конфигурации
│   ├── DumpConfig.php                #   Общие настройки дампов
│   ├── EnvironmentConfig.php         #   Определение окружения
│   ├── FakerConfig.php               #   Настройки замены ПД
│   └── TableConfig.php              #   Настройки экспорта таблицы
├── Contract/                         # Интерфейсы
├── Exception/                        # Исключения
├── Platform/                         # Поддержка SQL-диалектов
│   ├── MySqlPlatform.php
│   ├── OraclePlatform.php
│   ├── PostgresPlatform.php
│   └── PlatformFactory.php
├── Service/
│   ├── ConfigGenerator/              # Автогенерация конфигурации
│   │   ├── ConfigGenerator.php       #   Генератор dump_config.yaml
│   │   ├── ConfigSplitter.php        #   Разделение на per-schema файлы
│   │   └── ForeignKeyInspector.php   #   Инспекция FK из information_schema
│   ├── ConnectionRegistry.php        # Реестр подключений
│   ├── Dumper/                       # Экспорт дампов
│   │   ├── CascadeWhereResolver.php  #   Рекурсивная резолюция cascade WHERE
│   │   ├── DatabaseDumper.php        #   Основной экспортёр
│   │   └── DataFetcher.php           #   Загрузка данных из таблицы
│   ├── Faker/                        # Замена персональных данных
│   │   ├── PatternDetector.php       #   Автодетекция паттернов ПД
│   │   └── RussianFaker.php          #   Генератор русских ФИО/email/телефонов
│   ├── Generator/                    # Генерация SQL
│   │   ├── DeferredUpdateGenerator.php # UPDATE для восстановления разорванных FK
│   │   └── ...
│   ├── Graph/                        # Граф FK-зависимостей
│   │   ├── SortResult.php            #   DTO результата сортировки с deferred-рёбрами
│   │   ├── TableDependencyResolver.php #  FK-граф + топологическая сортировка
│   │   └── TopologicalSorter.php     #   Kahn (BFS) + Tarjan (SCC) + Cycle Breaking
│   ├── Importer/                     # Импорт дампов
│   │   ├── SchemaValidator.php       #   Валидация столбцов дампа vs БД
│   │   ├── ValidationResult.php      #   DTO результата валидации
│   │   └── ...
│   ├── Parser/                       # Разбор SQL
│   └── Security/                     # Защита от продакшена
└── Util/
    ├── FileSystemHelper.php
    └── YamlConfigLoader.php

```

Безопасность
------------

[](#безопасность)

Пакет не позволяет случайно импортировать дампы на продакшен. Импорт заблокирован, когда переменная окружения `APP_ENV` равна `prod` или `predprod`.

Тестирование
------------

[](#тестирование)

```
# Все тесты
composer test

# Тесты с покрытием кода
composer test-coverage

# Статический анализ (PHPStan level 8)
composer phpstan

# Исправление стиля кода
composer cs-fix
```

Локальная разработка
--------------------

[](#локальная-разработка)

Чтобы подключить пакет из локальной папки (без Packagist), добавьте в `composer.json` вашего проекта:

```
{
    "repositories": [
        {
            "type": "path",
            "url": "../database-dumps"
        }
    ],
    "require": {
        "timbrs/database-dumps": "*"
    }
}
```

Затем выполните `composer update timbrs/database-dumps` — Composer создаст симлинк на локальный пакет.

Требования
----------

[](#требования)

**Обязательные:**

- PHP ^7.2 | ^8.0
- `symfony/yaml` ^4.4 | ^5.4 | ^6.0 | ^7.0
- `symfony/finder` ^4.4 | ^5.4 | ^6.0 | ^7.0

**Опциональные (зависят от фреймворка):**

ЗависимостьДля чего нужна`doctrine/dbal` ^2.13 | ^3.0 | ^4.0Адаптер Doctrine DBAL (Symfony)`symfony/console` ^4.4 | ^5.4 | ^6.0 | ^7.0Консольные команды Symfony`symfony/http-kernel` ^5.4 | ^6.0 | ^7.0Регистрация бандла Symfony`illuminate/support` ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0Сервис-провайдер Laravel`illuminate/console` ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0Artisan-команды Laravel`illuminate/database` ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0Адаптер БД LaravelЛицензия
--------

[](#лицензия)

MIT License. Подробнее в файле [LICENSE](LICENSE).

---

English
=======

[](#english)

PHP package for exporting and importing database dumps as SQL. Supports PostgreSQL, MySQL, and Oracle (12c+). Works with Symfony, Laravel, and any PHP project.

Table of Contents
-----------------

[](#table-of-contents)

- [Description](#description)
- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
    - [Symfony](#quick-start-symfony)
    - [Laravel](#quick-start-laravel)
- [Configuration](#configuration)
    - [Full Export](#full-export)
    - [Partial Export](#partial-export)
    - [Cascade Dependencies (cascade\_from)](#cascade-dependencies-cascade_from)
    - [Personal Data Masking (faker)](#personal-data-masking-faker)
    - [Config Splitting by Schema (includes)](#config-splitting-by-schema-includes)
    - [Multiple Connections](#multiple-connections)
    - [Settings](#settings)
    - [Auto-generate Configuration](#auto-generate-configuration)
- [Symfony Setup](#symfony-setup)
    - [Bundle Registration](#bundle-registration)
    - [Directory Structure (Symfony)](#directory-structure-symfony)
    - [Symfony Commands](#symfony-commands)
- [Laravel Setup](#laravel-setup)
    - [Provider Registration](#provider-registration)
    - [Publishing Configuration](#publishing-configuration)
    - [Laravel Commands](#laravel-commands)
- [Before/After Scripts](#beforeafter-scripts)
- [IDE Support (JSON Schema)](#ide-support-json-schema)
- [Architecture](#architecture)
    - [How Export Works](#how-export-works)
    - [How Import Works](#how-import-works)
    - [Platform Differences](#platform-differences)
    - [Source Directory Structure](#source-directory-structure)
- [Security](#security)
- [Testing](#testing)
- [Local Development](#local-development)
- [Requirements](#requirements)
- [License](#license)

---

Description
-----------

[](#description)

**Database Dumps** is a PHP package that helps developers create and deploy database dumps for local and test environments.

**What problem does it solve?** On a project with a large production database, developers need up-to-date test data — but copying the entire database is slow, and using real customer data in dev environments is not acceptable. This package lets you configure export rules once — which tables to grab in full, which partially — and forget about manual dump preparation.

**How does it work?** You describe export rules in a YAML file. The package then:

- generates SQL dumps from production (or staging) database, respecting FK dependencies between tables
- replaces personal data (Russian names, emails, phone numbers) with generated values, making dumps safe to use
- deploys dumps into the target database with a single command, with built-in protection against accidental runs on production

**Where is it useful?** In any PHP project using Symfony or Laravel (or standalone), where you need to:

- quickly set up a test database for developers
- share dumps across teams without leaking personal data
- keep seed data in the repository and update it from a real database
- work with multiple database connections simultaneously

Features
--------

[](#features)

- **No framework lock-in** — works with Symfony, Laravel, and any PHP project
- **PostgreSQL, MySQL &amp; Oracle** — automatically generates the right SQL for each database
- **Multiple connections** — export/import from several databases at once
- **Batched INSERTs** — automatically groups rows (1000 per statement)
- **Rollback on errors** — import runs inside a transaction
- **Production guard** — import is blocked when `APP_ENV=prod`
- **Before/After scripts** — run custom SQL before and after import
- **Flexible config** — YAML file with full and partial export rules
- **Sequence reset** — automatic sequence / auto-increment reset after import
- **Auto-generate config** — `prepare-config` command creates YAML from DB structure
- **FK-aware ordering** — automatic topological sorting of tables during export and import (parents first)
- **Cascade dependencies** — `cascade_from` generates WHERE subqueries to keep data consistent across FK relations
- **Personal data masking (faker)** — automatic detection and replacement of PII (Russian names, email, phone, gender) during export
- **Config splitting** — automatic splitting of configuration into per-schema files
- **Smart Cycle Breaking** — automatic resolution of circular FK dependencies (two-phase INSERT NULL → UPDATE) instead of falling back to alphabetical order
- **Self-referential FK** — support for self-referencing tables (category trees, org structures, threaded comments)
- **Schema validation on import** — warnings when dump columns don't match the DB, `--ignore-schema-mismatch` option
- **Config settings** — `settings:` section for batch\_size, sample\_size, max\_cascade\_depth
- **Dry-run export** — `--dry-run` option to preview the export plan without executing

Installation
------------

[](#installation)

```
composer require --dev timbrs/database-dumps
```

Quick Start
-----------

[](#quick-start)

### Symfony

[](#symfony-1)

1. The bundle registers automatically via Symfony Flex.
2. Create `config/dump_config.yaml`:

```
full_export:
  public:
    - users
    - roles

partial_export:
  public:
    clients:
      limit: 1000
      order_by: created_at DESC
```

3. Export dumps:

```
php bin/console app:dbdump:export all
```

4. Import dumps:

```
php bin/console app:dbdump:import
```

### Laravel

[](#laravel-1)

1. The service provider is discovered automatically. The file `database/dump_config.yaml` is created on first run.
2. Edit `database/dump_config.yaml` (same format as Symfony).
3. Export dumps:

```
php artisan dbdump:export all
```

4. Import dumps:

```
php artisan dbdump:import
```

Configuration
-------------

[](#configuration)

Export is configured via a YAML file with two sections: `full_export` (all rows) and `partial_export` (with limits).

#### Full Export

[](#full-export)

Exports **all rows** from listed tables:

```
full_export:
  public:          # schema name
    - users        # tables — all rows
    - roles
  system:
    - settings
```

#### Partial Export

[](#partial-export)

Exports a **limited number of rows** with filtering:

```
partial_export:
  public:
    clients:
      limit: 1000                    # max rows
      order_by: created_at DESC      # sorting
      where: "is_active = true"      # WHERE condition
    orders:
      limit: 5000
      order_by: id DESC
```

**Available options:**

OptionDescription`limit`Max rows`order_by`Sorting (must end with `ASC` or `DESC`)`where`WHERE condition`cascade_from`Cascade filtering by FK parent (see below)### Cascade Dependencies (cascade\_from)

[](#cascade-dependencies-cascade_from)

When partially exporting related tables, data can become inconsistent: a child table may reference rows that didn't make it into the parent's dump. The `cascade_from` option solves this by automatically generating a WHERE subquery that limits the selection to only those rows whose FK parent is present in the dump.

```
partial_export:
  public:
    users:
      limit: 500
      order_by: id DESC
    orders:
      limit: 1000
      order_by: created_at DESC
      cascade_from:
        - parent: public.users
          fk_column: user_id
          parent_column: id
    order_items:
      limit: 5000
      order_by: id DESC
      cascade_from:
        - parent: public.orders
          fk_column: order_id
          parent_column: id
```

In this example:

- `orders` exports only orders whose `user_id` exists among exported `users`
- `order_items` exports only items belonging to exported `orders`
- Subqueries are nested: `order_items` -&gt; `orders` -&gt; `users` (up to 10 levels deep)

The `prepare-config` command automatically detects FK dependencies and generates `cascade_from`. To disable: `--no-cascade`.

### Personal Data Masking (faker)

[](#personal-data-masking-faker)

The package can automatically detect and replace personal data during export. This allows safe use of dumps in dev/staging environments.

**Supported patterns:**

PatternDescriptionOriginal exampleReplacement example`fio`Full Russian nameИванов Иван ИвановичПетров Александр Сергеевич`fio_short`Short Russian nameИванов И.И.Козлов А.В.`name`First and last nameИванов ИванПетров Александр`firstname`First name (cross-correlated with composite column)ИванАлександр`lastname`Last name (cross-correlated with composite column)ИвановПетров`patronymic`Patronymic (cross-correlated with composite column)ИвановичСергеевич`email`Email address`phone`Phone number+79161234567+79234567890`gender`Gender (12 formats: male/female, m/f, м/ж, etc.)МужскойЖенский**The `faker` section in configuration:**

```
faker:
  public:
    users:
      full_name: fio
      display_name: name
      first_name: firstname
      last_name: lastname
      middle_name: patronymic
      email: email
      phone: phone
      sex: gender
    employees:
      fio: fio
      short_fio: fio_short
      contact_email: email
```

The `firstname`, `lastname`, and `patronymic` patterns are detected via cross-correlation: if a composite column (fio, fio\_short, name) is already found in the table and there's an adjacent column with individual first names/last names/patronymics — it will be detected automatically.

The `gender` pattern is detected by matching both the column name (`gender`, `sex`, `пол`) **and** its contents (valid values: `male`/`female`, `m`/`f`, `м`/`ж`, `мужской`/`женский`, `муж`/`жен`, `мужчина`/`женщина`). The original value's case and format are preserved during replacement.

The `prepare-config` command automatically analyzes table contents and generates the `faker` section when PII patterns are detected in columns (threshold: 80% match from 200 random rows). To disable: `--no-faker`.

Replacement is deterministic — the seed is based on the hash of the FIO value (column with `fio` pattern), if such a column exists in the table's faker config. If there is no `fio` column, the seed is computed from the hash of all faker column values in the row. This ensures the same person always gets the same replacement regardless of the table or run.

### Config Splitting by Schema (includes)

[](#config-splitting-by-schema-includes)

When dealing with many tables, the configuration can become unwieldy. The `prepare-config` command splits config into per-schema files by default:

```
config/
├── dump_config.yaml          # main file with includes
├── public.yaml               # public schema config
├── system.yaml               # system schema config
└── analytics/                # named connection
    └── analytics.yaml

```

**Main file (`dump_config.yaml`):**

```
includes:
  public: public.yaml
  system: system.yaml

connections:
  analytics:
    includes:
      analytics: analytics/analytics.yaml
```

**Schema file (`public.yaml`):**

```
full_export:
  - users
  - roles
partial_export:
  clients:
    limit: 1000
    order_by: created_at DESC
faker:
  users:
    full_name: fio
    email: email
```

To generate a single file without splitting: `--no-split`.

### Multiple Connections

[](#multiple-connections)

To work with several databases, add a `connections` section:

```
# Main connection
full_export:
  public:
    - users
    - roles

partial_export:
  public:
    posts:
      limit: 100

# Additional connections
connections:
  analytics:                 # connection name (as in framework config)
    full_export:
      analytics:
        - events
        - metrics
    partial_export:
      analytics:
        logs:
          limit: 50
          order_by: id DESC
```

**Where dumps are saved:**

- Main connection: `database/dumps/{schema}/{table}.sql`
- Named connection: `database/dumps/{connection}/{schema}/{table}.sql`

**The `--connection` option:**

```
# Main connection only (default)
php artisan dbdump:export all

# Specific connection only
php artisan dbdump:export all --connection=analytics

# All connections at once
php artisan dbdump:export all --connection=all
```

### Settings

[](#settings)

The `settings` section allows you to customize internal package parameters:

```
settings:
  batch_size: 1000        # rows per INSERT statement (default: 1000)
  sample_size: 200        # rows for PII analysis in PatternDetector (default: 200)
  max_cascade_depth: 10   # max depth for cascade_from subqueries (default: 10)
```

### Auto-generate Configuration

[](#auto-generate-configuration)

The `prepare-config` command looks at your DB structure and creates or updates `dump_config.yaml`. The required `mode` argument defines the scope:

```
# Symfony
php bin/console app:dbdump:prepare-config all                    # Full regeneration
php bin/console app:dbdump:prepare-config schema=billing         # Regenerate one schema
php bin/console app:dbdump:prepare-config table=public.users     # Regenerate one table
php bin/console app:dbdump:prepare-config new                    # Add only new tables

# Laravel
php artisan dbdump:prepare-config all
php artisan dbdump:prepare-config schema=billing
php artisan dbdump:prepare-config table=public.users
php artisan dbdump:prepare-config new
```

**Modes:**

ModeDescription`all`Full config regeneration (overwrites file)`schema=`Regenerate one schema, merge into existing config`table=`Regenerate one table, merge into existing config`new`Detect and append new tables only (doesn't touch existing entries)**Options:**

OptionDescriptionDefault`--threshold`, `-t`Row threshold: tables with rows &lt;= threshold go to full\_export, more — to partial\_export500`--force`, `-f`Overwrite file without asking (only for `all` mode)—`--no-cascade`Skip FK detection and `cascade_from` generation—`--no-faker`Skip personal data detection—`--no-split`Generate a single YAML without splitting by schema—**How tables are sorted:**

- Rows &lt;= threshold — `full_export`
- Rows &gt; threshold — `partial_export` (with limit, auto-detected sorting and `where: "1=1"` template for easy customization)
- Empty tables — skipped
- Service tables (migrations, sessions, cache\_*, telescope\_*, oauth\_*, audit\_*) — skipped

Symfony Setup
-------------

[](#symfony-setup)

### Bundle Registration

[](#bundle-registration)

The bundle registers automatically via Symfony Flex. If not, add to `config/bundles.php`:

```
return [
    // ...
    Timbrs\DatabaseDumps\Bridge\Symfony\DatabaseDumpsBundle::class => ['all' => true],
];
```

Set the platform in `services.yaml`:

```
parameters:
    database_dumps.platform: 'postgresql'  # or 'mysql', 'oracle'
```

### Directory Structure (Symfony)

[](#directory-structure-symfony)

```
your-symfony-project/
├── config/
│   └── dump_config.yaml          # export settings
├── database/
│   ├── before_exec/              # pre-import scripts
│   │   └── 01_prepare.sql
│   ├── dumps/                    # SQL dumps
│   │   ├── public/
│   │   │   ├── users.sql
│   │   │   └── roles.sql
│   │   └── analytics/            # named connection
│   │       └── analytics/
│   │           └── events.sql
│   └── after_exec/               # post-import scripts
│       └── 01_finalize.sql

```

### Symfony Commands

[](#symfony-commands)

```
# Export all tables
php bin/console app:dbdump:export all

# Export one table
php bin/console app:dbdump:export public.users

# Export from one schema only
php bin/console app:dbdump:export all --schema=public

# Export from a specific connection
php bin/console app:dbdump:export all --connection=analytics
php bin/console app:dbdump:export all --connection=all

# Import all dumps
php bin/console app:dbdump:import

# Import with options
php bin/console app:dbdump:import --skip-before --skip-after
php bin/console app:dbdump:import --schema=public
php bin/console app:dbdump:import --connection=all

# Export without cascade filtering and without PII replacement
php bin/console app:dbdump:export all --no-cascade --no-faker

# Preview export plan (no actual export)
php bin/console app:dbdump:export all --dry-run

# Import ignoring schema mismatches
php bin/console app:dbdump:import --ignore-schema-mismatch

# Generate config from DB structure
php bin/console app:dbdump:prepare-config all
php bin/console app:dbdump:prepare-config all --threshold=1000 --force
php bin/console app:dbdump:prepare-config schema=billing
php bin/console app:dbdump:prepare-config table=public.users
php bin/console app:dbdump:prepare-config new --no-cascade --no-faker
```

Laravel Setup
-------------

[](#laravel-setup)

### Provider Registration

[](#provider-registration)

The service provider is discovered automatically. If not, register it in `config/app.php`:

```
'providers' => [
    // ...
    Timbrs\DatabaseDumps\Bridge\Laravel\DatabaseDumpsServiceProvider::class,
],
```

### Publishing Configuration

[](#publishing-configuration)

To customize paths, publish the PHP config:

```
php artisan vendor:publish --tag=database-dumps-config
```

This creates `config/database-dumps.php`:

```
return [
    'config_path' => base_path('database/dump_config.yaml'),
    'project_dir' => base_path(),
];
```

### Laravel Commands

[](#laravel-commands)

```
# Export all tables
php artisan dbdump:export all

# Export one table
php artisan dbdump:export public.users

# Export from one schema only
php artisan dbdump:export all --schema=public

# Export from a specific connection
php artisan dbdump:export all --connection=analytics
php artisan dbdump:export all --connection=all

# Import all dumps
php artisan dbdump:import

# Import with options
php artisan dbdump:import --skip-before --skip-after
php artisan dbdump:import --schema=public
php artisan dbdump:import --connection=all

# Export without cascade filtering and without PII replacement
php artisan dbdump:export all --no-cascade --no-faker

# Preview export plan (no actual export)
php artisan dbdump:export all --dry-run

# Import ignoring schema mismatches
php artisan dbdump:import --ignore-schema-mismatch

# Generate config from DB structure
php artisan dbdump:prepare-config all
php artisan dbdump:prepare-config all --threshold=1000 --force
php artisan dbdump:prepare-config schema=billing
php artisan dbdump:prepare-config table=public.users
php artisan dbdump:prepare-config new --no-cascade --no-faker
```

Before/After Scripts
--------------------

[](#beforeafter-scripts)

You can run custom SQL scripts before and after import.

DirectoryWhen it runs`database/before_exec/`**before** importing dumps`database/after_exec/`**after** importing dumpsScripts run in **alphabetical order**. Use numeric prefixes to control the order:

```
database/before_exec/
├── 01_disable_triggers.sql
├── 02_prepare_temp.sql
database/after_exec/
├── 01_enable_triggers.sql
├── 02_refresh_views.sql

```

To skip scripts, use `--skip-before` and `--skip-after`:

```
php artisan dbdump:import --skip-before
php artisan dbdump:import --skip-after
php artisan dbdump:import --skip-before --skip-after
```

IDE Support (JSON Schema)
-------------------------

[](#ide-support-json-schema)

The package includes a JSON Schema for `dump_config.yaml` at `resources/dump_config.schema.json`. It provides autocompletion and validation in PHPStorm and other IDEs.

### Option 1: YAML comment (recommended)

[](#option-1-yaml-comment-recommended)

Add to the top of your `dump_config.yaml`:

```
# yaml-language-server: $schema=../vendor/timbrs/database-dumps/resources/dump_config.schema.json
```

> The path is relative to the file: for Symfony — relative to `config/`, for Laravel — relative to `database/`.

### Option 2: PHPStorm manual setup

[](#option-2-phpstorm-manual-setup)

1. Open **Settings &gt; Languages &amp; Frameworks &gt; Schemas and DTDs &gt; JSON Schema Mappings**
2. Add a mapping:
    - **Schema file**: `vendor/timbrs/database-dumps/resources/dump_config.schema.json`
    - **File path pattern**: `dump_config.yaml`

Architecture
------------

[](#architecture)

### How Export Works

[](#how-export-works)

```
Command → TableConfigResolver → DatabaseDumper → [FK sorting + Cycle Breaking] → DataFetcher → [Cascade WHERE] → [Faker] → SqlGenerator → .sql files

```

1. **TableConfigResolver** — reads YAML and builds a list of tables to export
2. **DatabaseDumper** — manages the export process
3. **TableDependencyResolver** — topological sorting of tables by FK (parents are exported first). Circular dependencies are automatically broken via nullable edges
4. **DataFetcher** — fetches data from the DB via `ConnectionRegistry`
5. **CascadeWhereResolver** — generates WHERE subqueries from `cascade_from` for data consistency
6. **RussianFaker** — replaces personal data (names, email, phone, gender) with generated values
7. **SqlGenerator** — generates SQL: TRUNCATE + INSERT (with NULL for broken FKs) + counter reset + UPDATE (FK restoration)
8. Result is saved to `database/dumps/{schema}/{table}.sql`

### How Import Works

[](#how-import-works)

```
Command → DatabaseImporter → ProductionGuard → TransactionManager → [FK sorting + Cycle Breaking] → [SchemaValidator] → ScriptExecutor → SqlParser → execution

```

1. **ProductionGuard** — checks we're not on production
2. **TransactionManager** — wraps everything in a transaction
3. **TableDependencyResolver** — topological sorting of files by FK (parents are imported first), with automatic cycle breaking
4. **SchemaValidator** — compares dump columns against DB columns, warns about mismatches
5. **ScriptExecutor** — runs scripts from `before_exec/`
6. **SqlParser** / **StatementSplitter** — splits .sql files into individual statements
7. Statements are executed against the DB
8. **ScriptExecutor** — runs scripts from `after_exec/`

### Platform Differences

[](#platform-differences)

The package generates the right SQL depending on the database:

PostgreSQLMySQLOracle (12c+)Table names`"table"` (double quotes)``table`` (backticks)`"TABLE"` (double quotes, UPPERCASE)TRUNCATE`TRUNCATE ... CASCADE``SET FOREIGN_KEY_CHECKS=0``DELETE FROM` (FK-safe)Counters`setval()` / `pg_get_serial_sequence()``ALTER TABLE ... AUTO_INCREMENT`Stub comment (use `after_exec/`)LIMIT`LIMIT N``LIMIT N``FETCH FIRST N ROWS ONLY`INSERTBatch 1000 rowsBatch 1000 rowsOne row per INSERT (no multi-row INSERT)Random function`RANDOM()``RAND()``DBMS_RANDOM.VALUE`The platform is detected automatically from the DB connection.

> **Oracle:** `DELETE FROM` is used instead of `TRUNCATE TABLE` because Oracle TRUNCATE doesn't support CASCADE and is blocked by FK constraints. Sequence reset requires PL/SQL — use scripts in `database/after_exec/`.

### Source Directory Structure

[](#source-directory-structure)

```
src/
├── Adapter/                          # DB connection adapters
│   ├── DoctrineDbalAdapter.php       #   Doctrine DBAL
│   ├── LaravelDatabaseAdapter.php    #   Laravel DB
│   └── PdoAdapter.php               #   Universal PDO (Oracle, etc.)
├── Bridge/                           # Framework integrations
│   ├── Laravel/
│   │   ├── Command/                  #   Artisan commands
│   │   ├── DatabaseDumpsServiceProvider.php
│   │   └── LaravelLogger.php
│   └── Symfony/
│       ├── Command/                  #   Console commands
│       ├── DependencyInjection/
│       ├── ConnectionRegistryFactory.php
│       ├── ConsoleLogger.php
│       └── DatabaseDumpsBundle.php
├── Config/                           # Configuration classes
│   ├── DumpConfig.php                #   Overall dump settings
│   ├── EnvironmentConfig.php         #   Environment detection
│   ├── FakerConfig.php               #   PII masking settings
│   └── TableConfig.php              #   Per-table export settings
├── Contract/                         # Interfaces
├── Exception/                        # Exceptions
├── Platform/                         # SQL dialect support
│   ├── MySqlPlatform.php
│   ├── OraclePlatform.php
│   ├── PostgresPlatform.php
│   └── PlatformFactory.php
├── Service/
│   ├── ConfigGenerator/              # Config auto-generation
│   │   ├── ConfigGenerator.php       #   dump_config.yaml generator
│   │   ├── ConfigSplitter.php        #   Splitting into per-schema files
│   │   └── ForeignKeyInspector.php   #   FK inspection from information_schema
│   ├── ConnectionRegistry.php        # Connection registry
│   ├── Dumper/                       # Dump export
│   │   ├── CascadeWhereResolver.php  #   Recursive cascade WHERE resolution
│   │   ├── DatabaseDumper.php        #   Main exporter
│   │   └── DataFetcher.php           #   Table data loading
│   ├── Faker/                        # Personal data masking
│   │   ├── PatternDetector.php       #   Automatic PII pattern detection
│   │   └── RussianFaker.php          #   Russian names/email/phone generator
│   ├── Generator/                    # SQL generation
│   │   ├── DeferredUpdateGenerator.php # UPDATE for restoring broken FK edges
│   │   └── ...
│   ├── Graph/                        # FK dependency graph
│   │   ├── SortResult.php            #   DTO for sort result with deferred edges
│   │   ├── TableDependencyResolver.php #  FK graph + topological sorting
│   │   └── TopologicalSorter.php     #   Kahn (BFS) + Tarjan (SCC) + Cycle Breaking
│   ├── Importer/                     # Dump import
│   │   ├── SchemaValidator.php       #   Dump columns vs DB schema validation
│   │   ├── ValidationResult.php      #   Validation result DTO
│   │   └── ...
│   ├── Parser/                       # SQL parsing
│   └── Security/                     # Production guard
└── Util/
    ├── FileSystemHelper.php
    └── YamlConfigLoader.php

```

Security
--------

[](#security)

The package prevents accidental imports on production. Import is blocked when the `APP_ENV` environment variable is `prod` or `predprod`.

Testing
-------

[](#testing)

```
# All tests
composer test

# Tests with code coverage
composer test-coverage

# Static analysis (PHPStan level 8)
composer phpstan

# Code style fix
composer cs-fix
```

Local Development
-----------------

[](#local-development)

To use the package from a local folder (without Packagist), add to your project's `composer.json`:

```
{
    "repositories": [
        {
            "type": "path",
            "url": "../database-dumps"
        }
    ],
    "require": {
        "timbrs/database-dumps": "*"
    }
}
```

Then run `composer update timbrs/database-dumps` — Composer will create a symlink to the local package.

Requirements
------------

[](#requirements)

**Required:**

- PHP ^7.2 | ^8.0
- `symfony/yaml` ^4.4 | ^5.4 | ^6.0 | ^7.0
- `symfony/finder` ^4.4 | ^5.4 | ^6.0 | ^7.0

**Optional (depends on framework):**

DependencyWhat it's for`doctrine/dbal` ^2.13 | ^3.0 | ^4.0Doctrine DBAL adapter (Symfony)`symfony/console` ^4.4 | ^5.4 | ^6.0 | ^7.0Symfony console commands`symfony/http-kernel` ^5.4 | ^6.0 | ^7.0Symfony bundle registration`illuminate/support` ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0Laravel service provider`illuminate/console` ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0Laravel artisan commands`illuminate/database` ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0Laravel DB adapterLicense
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

---

Developed by Timur Bayan (Timbrs).

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance92

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~31 days

Total

2

Last Release

71d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/16aff05839660d944ce55a02979b42b68c88abd4c2225b82b08fd27130357f89?d=identicon)[backbista](/maintainers/backbista)

---

Top Contributors

[![timbrs](https://avatars.githubusercontent.com/u/264475107?v=4)](https://github.com/timbrs "timbrs (5 commits)")

---

Tags

symfonylaraveldatabaseexportdumpmysqlpostgresqlsqlimport

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/timbrs-database-dumps/health.svg)

```
[![Health](https://phpackages.com/badges/timbrs-database-dumps/health.svg)](https://phpackages.com/packages/timbrs-database-dumps)
```

###  Alternatives

[rah/danpu

Zero-dependency MySQL dump library for easily exporting and importing databases

62410.3k11](/packages/rah-danpu)[friendsoftypo3/content-blocks

TYPO3 CMS Content Blocks - Content Types API | Define reusable components via YAML

101466.4k45](/packages/friendsoftypo3-content-blocks)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1155.2k](/packages/rcsofttech-audit-trail-bundle)[perplorm/perpl

Perpl is an improved and still maintained fork of Propel2, an open-source Object-Relational Mapping (ORM) for PHP.

239.4k](/packages/perplorm-perpl)[ramadan/easy-model

A Laravel package for enjoyably managing database queries.

111.6k](/packages/ramadan-easy-model)[moharrum/laravel-adminer

Adminer database management tool for your Laravel application.

451.0k](/packages/moharrum-laravel-adminer)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
