Перейти до вмісту

Довідник PHP API

Повний довідник усіх публічних класів і методів у merql.

Merql (фасад)

Merql\Merql — статична точка входу для типових операцій. Вона обгортає класи нижчого рівня та автоматично керує збереженням знімків.

PHP
use Merql\Connection;
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;
use Merql\Merql;

$connection = Connection::sqlite(':memory:');
Merql::init($connection, identityRules: new IdentityRuleSet([
    'options' => IdentityRule::natural(['option_name']),
]));

init(DatabaseConnection $connection, ?Driver $driver = null, ?IdentityRuleSet $identityRules = null): void

Ініціалізуйте фасад, передавши підключення до бази даних. Це потрібно зробити перед викликом snapshot(), apply() або applyGuarded(). Щоб перемкнути базу даних, викличте метод ще раз — наприклад, щоб створити знімки ours і theirs із двох різних копій. Без $driver метод викликає DriverFactory::create(), який завершується помилкою для рушіїв, відмінних від MySQL і SQLite, якщо не зареєстровано драйвер. Передайте драйвер, щоб перевизначити автоматичне виявлення, або набір правил ідентичності, щоб перевизначити ідентичність рядків у кожній таблиці під час знімання даних.

snapshot(string $name, array $tables = []): Snapshot

Зніміть поточний стан бази даних і збережіть його на диску. Передайте масив назв таблиць, щоб створити знімок лише для вказаних таблиць, або не передавайте його, щоб охопити всі таблиці.

PHP
$snapshot = Merql::snapshot('baseline');
$snapshot = Merql::snapshot('baseline', ['posts', 'users']);

diff(string $base, string $current): Changeset

Завантажте два іменовані знімки та обчисліть набір змін між ними. Для цього не потрібен init(), оскільки операція виконується на основі збережених знімків.

PHP
$changeset = Merql::diff('before', 'after');

merge(string $base, string $ours, string $theirs): MergeResult

Тристороннє злиття трьох іменованих знімків. Повертає результат, що містить операції без конфліктів і всі конфлікти. Злиття виконується на рівні стовпців: фасад формує ThreeWayMerge без CellMergeConfig, тому злиття на рівні комірок не застосовується. Для цього безпосередньо використовуйте ThreeWayMerge.

PHP
$result = Merql::merge('base', 'ours', 'theirs');

patch(string $base, string $changes): MergeResult

Двостороннє злиття: застосувати зміни до базового стану. Еквівалент merge($base, $base, $changes). Завжди дає результат без конфліктів, оскільки паралельних змін немає. Лише на рівні стовпців, як і merge().

PHP
$result = Merql::patch('base', 'changes');

apply(MergeResult $result): ApplyResult

Виконайте результат злиття без конфліктів у базі даних, переданій до init(). Потрібен init(). Викидає ConflictException, якщо залишаються невирішені конфлікти.

Виконуються всі операції результату, тому повний результат merge() можна успішно застосувати лише до бази даних, у якій досі зберігається базовий стан. Якщо база даних уже містить один із боків, застосуйте вибрані операції, яких їй бракує; див. Захищене застосування.

PHP
$applied = Merql::apply($result);
echo $applied->rowsAffected();

plan(string $id, string $base, string $ours, string $theirs, array $metadata = []): MergePlan

Створіть план злиття, готовий для UI, на основі трьох іменованих знімків. План містить стабільні ідентифікатори операцій, ідентифікатори груп змін, контекст операцій, конфлікти, невідповідності схем, зведення, метадані та хеш плану. Злиття виконується на рівні стовпців, як у merge(); передайте результат злиття комірок до MergePlanBuilder::build() для злиття на рівні комірок.

PHP
$plan = Merql::plan('plan-1', 'base', 'ours', 'theirs', [
    'source' => 'review-ui',
]);

applyGuarded(MergeResult $result, Snapshot $expectedLive): ApplyResult

Застосуйте результат злиття без конфліктів з оптимістичними передумовами для активних рядків. Для оновлення та видалення потрібна відповідність поточних активних рядків $expectedLive; для вставлення цільова сутність не має вже існувати. $expectedLive — це знімок цільової бази даних (сторона theirs, коли ours переноситься до бази даних, з якої було зроблено знімок theirs). Якщо будь-який оператор змінює нуль рядків, транзакцію буде скасовано.

PHP
use Merql\Snapshot\SnapshotStore;

$applied = Merql::applyGuarded($selectedResult, SnapshotStore::load('theirs'));

reset(): void

Очистіть внутрішні екземпляри з'єднання та Snapshotter. Використовується переважно в тестах для скидання стану між запусками.


З'єднання

Merql\Connection створює адаптери з'єднання з оптимальними типовими параметрами. З'єднання PDO використовують винятки у разі помилки, режим отримання асоціативних масивів, справжню підготовку запитів і перетворення отриманих значень на рядки. Адаптер mysqli нормалізує отримані значення до такого самого формату: рядок або null.

mysql(string $host, string $database, string $username, string $password = '', int $port = 3306, string $charset = 'utf8mb4'): PdoDatabaseConnection

PHP
use Merql\Connection;

$connection = Connection::mysql('127.0.0.1', 'my_app', 'root', 'secret');

mysqli(string $host, string $database, string $username, string $password = '', int $port = 3306, string $charset = 'utf8mb4'): MysqliDatabaseConnection

PHP
$connection = Connection::mysqli('127.0.0.1', 'my_app', 'root', 'secret');

sqlite(string $path = ':memory:'): PdoDatabaseConnection

Створює з'єднання SQLite. Автоматично вмикає зовнішні ключі за допомогою PRAGMA foreign_keys = ON.

PHP
$connection = Connection::sqlite('/var/data/app.sqlite');
$connection = Connection::sqlite(':memory:');

fromDsn(string $dsn, string $username = '', string $password = ''): PdoDatabaseConnection

Підключайтеся за допомогою будь-якого рядка DSN PDO. merql постачається лише з драйверами для mysql та sqlite; з іншими DSN з'єднання встановлюється, але Merql::init(), Snapshotter та засоби застосування викидають Unsupported database driver, якщо драйвер не зареєстровано через DriverFactory::register().

PHP
$connection = Connection::fromDsn('mysql:host=localhost;dbname=app', 'root', 'pass');

fromPdo(PDO $pdo): PdoDatabaseConnection

Обгортає наявний екземпляр PDO.

fromMysqli(mysqli $mysqli, string $charset = 'utf8mb4'): MysqliDatabaseConnection

Обгортає наявний екземпляр mysqli.

Контракт адаптера

Усі адаптери реалізують Merql\Database\DatabaseConnection:

PHP
interface DatabaseConnection
{
    public function driverName(): string;
    public function execute(string $sql, array $params = []): int;
    public function query(string $sql, array $params = []): array;
    public function scalar(string $sql, array $params = []): ?string;
    public function beginTransaction(): void;
    public function commit(): void;
    public function rollBack(): void;
    public function lastInsertId(): string;
}

execute(), query() та scalar() приймають позиційні параметри list<scalar|null> для заповнювачів ?. query() повертає list<array<string, scalar|null>>; значення нормалізуються до однакового формату «рядок або null» в адаптерах PDO та mysqli.


Створення знімків

Merql\Snapshot\Snapshotter фіксує стан бази даних. На відміну від фасаду, він дає повний контроль над фільтрами та не зберігає дані автоматично.

__construct(DatabaseConnection $connection, ?Driver $driver = null, ?IdentityRuleSet $identityRules = null)

Якщо драйвер не вказано, він визначається автоматично за ідентифікатором з'єднання. Передайте IdentityRuleSet, якщо ідентифікатори рядків для конкретних таблиць мають перевизначати типові параметри схеми.

capture(string $name, array $tables = [], array $filters = []): Snapshot

Зафіксуйте поточний стан. Передайте назви таблиць, щоб обмежити область дії. Передайте об'єкти фільтрів, щоб виключити таблиці, стовпці або рядки.

PHP
use Merql\Snapshot\Snapshotter;
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Filter\RowFilter;
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;

$snapshotter = new Snapshotter(
    $connection,
    identityRules: new IdentityRuleSet([
        'wp_options' => IdentityRule::natural(['option_name']),
    ]),
);

// All tables.
$snapshot = $snapshotter->capture('full');

// Specific tables with filters.
$snapshot = $snapshotter->capture('filtered', ['posts', 'users'], [
    TableFilter::exclude(['cache_*', 'sessions']),
    ColumnFilter::ignore(['updated_at', 'created_at']),
    RowFilter::create(fn(string $table, array $row) => $row['status'] !== 'trash'),
]);

captureAliased(string $name, array $physicalToCanonicalTableMap, array $filters = []): Snapshot

Зафіксуйте фізичні таблиці під канонічними назвами. Використовуйте цей варіант, коли та сама логічна таблиця має різні фізичні назви в різних середовищах.

PHP
$snapshot = $snapshotter->captureAliased('sandbox', [
    'wp_onumia_abcd_posts' => 'wp_posts',
    'wp_onumia_abcd_postmeta' => 'wp_postmeta',
]);

Отриманий знімок зберігає канонічні назви таблиць, водночас зберігаючи фізичну схему таблиці, налаштовані стовпці ідентифікації, ключі рядків і фільтри.

fromData(string $name, array $tableData): Snapshot (статичний метод)

Створює знімок із необроблених даних без підключення до бази даних. Зручно для тестування або імпорту даних з іншого джерела.

PHP
use Merql\Snapshot\Snapshotter;
use Merql\Snapshot\TableSnapshotData;
use Merql\Schema\TableSchema;

$schema = new TableSchema('posts', ['id' => 'int', 'title' => 'varchar'], ['id']);

$snapshot = Snapshotter::fromData('test', [
    'posts' => new TableSnapshotData($schema, [
        ['id' => '1', 'title' => 'Hello'],
        ['id' => '2', 'title' => 'World'],
    ], ['id']),
]);

Знімок

Merql\Snapshot\Snapshot — це об'єкт-значення лише для читання, що представляє повний стан бази даних.

PHP
$snapshot->name;                    // string: snapshot identifier
$snapshot->tables;                  // array<string, TableSnapshot>
$snapshot->tableNames();            // list<string>
$snapshot->hasTable('posts');       // bool
$snapshot->getTable('posts');       // ?TableSnapshot

TableSnapshot

Merql\Snapshot\TableSnapshot містить рядки, відбитки та схему однієї таблиці.

PHP
$table = $snapshot->getTable('posts');

$table->schema;                    // TableSchema
$table->identityColumns;           // list<string>: columns used for row identity
$table->fingerprints;              // array<string, string>: row key to hash
$table->rows;                      // array<string, array<string, mixed>>

$table->rowKeys();                 // list<string>
$table->rowCount();                // int
$table->hasRow('42');              // bool
$table->getRow('42');              // ?array<string, mixed>
$table->getFingerprint('42');      // ?string

TableSnapshotData

Merql\Snapshot\TableSnapshotData — це вхідні дані для Snapshotter::fromData().

PHP
use Merql\Snapshot\TableSnapshotData;
use Merql\Schema\TableSchema;

$data = new TableSnapshotData(
    schema: new TableSchema('posts', ['id' => 'int', 'title' => 'varchar'], ['id']),
    rows: [
        ['id' => '1', 'title' => 'First Post'],
    ],
    identityColumns: ['id'],
);

IdentityRule

Merql\Identity\IdentityRule визначає стовпці, які використовуються для формування ключів рядків.

PHP
use Merql\Identity\IdentityRule;

$primary = IdentityRule::primary(['id']);
$natural = IdentityRule::natural(['option_name']);
$composite = IdentityRule::composite(['object_id', 'term_taxonomy_id']);
$content = IdentityRule::content(['name', 'value']);

$key = $natural->key(['option_name' => 'siteurl']);
// "siteurl"

forSchema(TableSchema $schema): IdentityRule (статичний метод)

Визначає типове правило ідентифікації за схемою: первинний ключ, перший унікальний ключ, потім запасний варіант на основі вмісту.

toArray(): array

Серіалізує правило як ['type' => string, 'columns' => list<string>].

fromArray(array $data): IdentityRule (статичний метод)

Відновлює правило із серіалізованих даних.


IdentityRuleSet

Merql\Identity\IdentityRuleSet зберігає перевизначення ідентифікації для окремих таблиць.

PHP
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;

$rules = new IdentityRuleSet([
    'wp_options' => IdentityRule::natural(['option_name']),
]);

$rule = $rules->ruleFor($schema);

with(string $table, IdentityRule $rule): IdentityRuleSet

Повертає новий набір правил з доданим перевизначенням для однієї таблиці.

conflictsFor(string $table, IdentityRule $rule, array $rows): array

Повертає записи IdentityConflict, якщо для правила кілька рядків утворюють однаковий ключ.

toArray(): array

Серіалізує правила таблиць у вигляді масиву, сумісного з JSON.

fromArray(array $data): IdentityRuleSet (статичний метод)

Відновлює набір правил із серіалізованих даних.


SnapshotStore

Merql\Snapshot\SnapshotStore зберігає знімки у файлах JSON та завантажує їх.

setDirectory(string $directory): void

Вказує каталог зберігання. Типове значення — .merql/snapshots.

save(Snapshot $snapshot): void

Записує знімок на диск.

load(string $name): Snapshot

Завантажує знімок за назвою. Викидає SnapshotException, якщо його не знайдено.

exists(string $name): bool

Перевіряє, чи існує файл знімка.

delete(string $name): void

Видаляє файл знімка.


Порівнювач

Merql\Diff\Differ порівнює два знімки та створює набір змін.

diff(Snapshot $base, Snapshot $current): Changeset

PHP
use Merql\Diff\Differ;

$differ = new Differ();
$changeset = $differ->diff($baseSnapshot, $currentSnapshot);

valuesEqual(mixed $a, mixed $b): bool (статичний метод)

Порівнює два значення, приводячи їх до рядків. NULL вважається окремим значенням: NULL === NULL — true, NULL === '' — false.


Набір змін

Merql\Diff\Changeset — це колекція операцій на рівні рядків, доступна лише для читання.

PHP
$changeset->inserts();             // list<RowInsert>
$changeset->updates();             // list<RowUpdate>
$changeset->deletes();             // list<RowDelete>
$changeset->isEmpty();             // bool
$changeset->count();               // int: total operations
$changeset->forTable('posts');     // Changeset: filtered to one table

RowInsert, RowUpdate, RowDelete

Об'єкти-значення лише для читання, що представляють окремі зміни рядків.

RowInsert

PHP
$insert->table;                    // string
$insert->rowKey;                   // string
$insert->values;                   // array<string, mixed>

RowUpdate

PHP
$update->table;                    // string
$update->rowKey;                   // string
$update->columnDiffs;              // list<ColumnDiff>
$update->fullRow;                  // array<string, mixed>: complete current row
$update->columnDiffMap();          // array<string, ColumnDiff>: keyed by column name

RowDelete

PHP
$delete->table;                    // string
$delete->rowKey;                   // string
$delete->oldValues;                // array<string, mixed>: values before deletion

ColumnDiff

Merql\Diff\ColumnDiff представляє одну зміну стовпця під час оновлення рядка.

PHP
$diff->column;                     // string
$diff->oldValue;                   // mixed
$diff->newValue;                   // mixed

ThreeWayMerge

Merql\Merge\ThreeWayMerge — основний алгоритм злиття.

__construct(?CellMergeConfig $cellMergeConfig = null)

Передайте CellMergeConfig, щоб увімкнути злиття на рівні комірок для стовпців TEXT і JSON.

PHP
use Merql\Merge\ThreeWayMerge;
use Merql\CellMerge\CellMergeConfig;

// Default: column-level merge only.
$merge = new ThreeWayMerge();

// With cell-level merge for TEXT and JSON columns.
$merge = new ThreeWayMerge(CellMergeConfig::auto());

merge(Snapshot $base, Snapshot $ours, Snapshot $theirs): MergeResult

Виконує тристороннє злиття. Внутрішньо обчислює набори змін (від базового стану до ours, від базового стану до theirs) та об'єднує їх.

PHP
$result = $merge->merge($baseSnapshot, $oursSnapshot, $theirsSnapshot);

patch(Snapshot $base, Snapshot $changes): MergeResult

Скорочений варіант двостороннього злиття. Еквівалент merge($base, $base, $changes).

schemaMismatches(): array

Повертає SchemaException[] для всіх розбіжностей схем, виявлених під час останнього злиття (стовпці додані або видалені між знімками).


MergeResult

Merql\Merge\MergeResult — це об'єкт-значення лише для читання, що містить результат злиття.

PHP
$result->isClean();                // bool: no conflicts
$result->operations();             // list<MergeOperation>
$result->conflicts();              // list<Conflict>
$result->operationCount();         // int
$result->conflictCount();          // int
$result->baseSnapshot();           // ?Snapshot
$result->schemaMismatches();       // list<SchemaException>
$result->hasSchemaMismatches();    // bool

MergePlan

Merql\Plan\MergePlan — це серіалізована модель злиття для перевірки.

PHP
$plan->id;                        // string
$plan->baseSnapshot;              // string
$plan->oursSnapshot;              // string
$plan->theirsSnapshot;            // string
$plan->summary;                   // MergePlanSummary
$plan->changeGroups;              // list<MergePlanChangeGroup>
$plan->operations;                // list<MergePlanOperation>
$plan->conflicts;                 // list<MergePlanConflict>
$plan->schemaMismatches;          // list<string>
$plan->hash;                      // string
$plan->metadata;                  // array<string, mixed>

Використовуйте MergePlanSerializer::toJson() і ::fromJson() для стабільних циклічних перетворень JSON.

Вибірки

ChangeGroupSelection зберігає ідентифікатори підготовлених груп змін. Під час створення результатів злиття для вибраних елементів або планів відкату перетворіть його на OperationSelection.

PHP
use Merql\Plan\ChangeGroupSelection;
use Merql\Plan\SelectedMergeResultFactory;

$selection = ChangeGroupSelection::fromIds([$groupId]);
$operationSelection = $selection->toOperationSelection($plan);

$selected = (new SelectedMergeResultFactory())
    ->fromOperationSelection($plan, $operationSelection);

RollbackPlan

Merql\Rollback\RollbackPlan зберігає зворотні операції та очікування щодо відхилень для вибіркового застосування.

PHP
use Merql\Rollback\RollbackPlanBuilder;
use Merql\Rollback\RollbackPlanSerializer;

$rollback = (new RollbackPlanBuilder())->build(
    'rollback-1',
    $plan,
    $operationSelection,
    $liveBeforeRows,
);

$json = RollbackPlanSerializer::toJson($rollback);

Використовуйте RollbackDrift перед застосуванням відкату, а потім RollbackPlanApplier для виконання зворотних операцій.


MergeOperation

Merql\Merge\MergeOperation — це одна визначена операція з результату злиття.

PHP
$op->type;                         // string: 'insert' | 'update' | 'delete'
$op->table;                        // string
$op->rowKey;                       // string
$op->values;                       // array<string, mixed>
$op->source;                       // string: 'ours' | 'theirs' | 'merged'

Константи типів:

PHP
MergeOperation::TYPE_INSERT;       // 'insert'
MergeOperation::TYPE_UPDATE;       // 'update'
MergeOperation::TYPE_DELETE;       // 'delete'

Конфлікт

Merql\Merge\Conflict представляє невирішений конфлікт злиття.

PHP
$conflict->table();                // string
$conflict->rowKey();               // string
$conflict->type();                 // string: 'update_update' | 'update_delete' | 'delete_update' | 'insert_insert'
$conflict->column();               // ?string (null for structural conflicts)
$conflict->oursValue();            // mixed
$conflict->theirsValue();          // mixed
$conflict->baseValue();            // mixed
$conflict->primaryKey(['id']);     // array<string, string>: decoded from rowKey

Типи конфліктів

Тип Значення
update_update Обидві сторони змінили той самий стовпець на різні значення
update_delete Сторона ours оновила рядок, який сторона theirs видалила
delete_update Сторона ours видалила рядок, який сторона theirs оновила
insert_insert Обидві сторони вставили рядок з однаковим первинним ключем

ConflictResolver

Merql\Merge\ConflictResolver застосовує політику вирішення до всіх конфліктів у результаті злиття.

resolve(MergeResult $result, ConflictPolicy $policy): MergeResult (статичний метод)

Повертає новий MergeResult із конфліктами, вирішеними відповідно до політики.

PHP
use Merql\Merge\ConflictResolver;
use Merql\Merge\ConflictPolicy;

// Accept all "theirs" values when conflicts arise.
$resolved = ConflictResolver::resolve($result, ConflictPolicy::TheirsWins);

// Accept all "ours" values.
$resolved = ConflictResolver::resolve($result, ConflictPolicy::OursWins);

// Return unchanged (for manual inspection).
$resolved = ConflictResolver::resolve($result, ConflictPolicy::Manual);

ConflictPolicy

Merql\Merge\ConflictPolicy — це enum із трьома варіантами.

PHP
use Merql\Merge\ConflictPolicy;

ConflictPolicy::OursWins;          // Resolve all conflicts in favor of "ours"
ConflictPolicy::TheirsWins;        // Resolve all conflicts in favor of "theirs"
ConflictPolicy::Manual;            // Leave conflicts unresolved for manual handling

ColumnMerge

Merql\Merge\ColumnMerge виконує логіку злиття окремих стовпців одного рядка. Внутрішньо використовується ThreeWayMerge.

merge(string $table, string $rowKey, array $base, array $ours, array $theirs, ?CellMergeConfig $cellMergeConfig = null, array $columnTypes = []): array (статичний метод)

Повертає ['values' => array, 'conflicts' => list<Conflict>].

PHP
use Merql\Merge\ColumnMerge;

$result = ColumnMerge::merge(
    'posts',
    '42',
    ['title' => 'Hello', 'status' => 'draft'],     // base
    ['title' => 'Hello', 'status' => 'published'],  // ours
    ['title' => 'New Title', 'status' => 'draft'],   // theirs
);

// $result['values'] = ['title' => 'New Title', 'status' => 'published']
// $result['conflicts'] = [] (clean merge)

Застосовувач

Merql\Apply\Applier застосовує результат злиття до бази даних.

__construct(DatabaseConnection $connection, ?Driver $driver = null)

apply(MergeResult $result, ?Snapshot $base = null): ApplyResult

Виконує всі операції в одній транзакції. У разі помилки відкочує транзакцію та повідомляє про неї в ApplyResult::errors(), а не викидає виняток. Викидає ConflictException, якщо результат містить невирішені конфлікти.

PHP
use Merql\Apply\Applier;

$applier = new Applier($connection);
$applied = $applier->apply($result);

echo "Rows affected: {$applied->rowsAffected()}\n";
if ($applied->hasErrors()) {
    print_r($applied->errors());
}

Порядок зовнішніх ключів обробляється автоматично: вставлення сортуються за залежностями, а видалення — у зворотному порядку залежностей.


ApplyResult

Merql\Apply\ApplyResult — це об'єкт-значення лише для читання, який повертає засіб застосування.

PHP
$applied->rowsAffected();         // int
$applied->errors();               // list<string>
$applied->hasErrors();            // bool

Після скасованого застосування rowsAffected() усе ще враховує оператори, виконані до помилки (#4). Перш ніж покладатися на це число, перевірте hasErrors().


DryRun

Merql\Apply\DryRun формує зрозумілі людині оператори SQL, не виконуючи жодних дій.

generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (статичний метод)

Повертає список рядків SQL зі вбудованими значеннями (лише для відображення).

PHP
use Merql\Apply\DryRun;

$statements = DryRun::generate($result);

foreach ($statements as $sql) {
    echo "{$sql};\n";
}

// Output:
// INSERT INTO `posts` (`id`, `title`) VALUES ('10', 'New Post');
// UPDATE `posts` SET `title` = 'Updated' WHERE `id` = '5';
// DELETE FROM `comments` WHERE `id` = '3';

SqlGenerator

Merql\Apply\SqlGenerator формує параметризовані оператори SQL. Внутрішньо використовується і Applier, і DryRun.

generate(MergeResult $result, ?Snapshot $base = null, array $fkDependencies = [], ?Driver $driver = null): array (статичний метод)

Повертає list<array{sql: string, params: list<scalar|null>}>.

PHP
use Merql\Apply\SqlGenerator;

$statements = SqlGenerator::generate($result);

foreach ($statements as $stmt) {
    $connection->execute($stmt['sql'], $stmt['params']);
}

CellMergeConfig

Merql\CellMerge\CellMergeConfig налаштовує стратегії злиття на рівні комірок для окремих стовпців або типів стовпців.

auto(): self (статичний метод)

Фабричний метод для зручного призначення TextCellMerger стовпцям TEXT/LONGTEXT і JsonCellMerger стовпцям JSON.

PHP
use Merql\CellMerge\CellMergeConfig;

$config = CellMergeConfig::auto();

forColumn(string $column, CellMerger $merger): self

Призначає об'єднувач конкретному стовпцю. Використовуйте table.column для повних назв або лише column для всіх таблиць.

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\TextCellMerger;

$config = (new CellMergeConfig())
    ->forColumn('posts.content', new TextCellMerger())
    ->forColumn('description', new TextCellMerger());

forType(string $typePattern, CellMerger $merger): self

Призначає об'єднувач усім стовпцям, що відповідають шаблону типу (регістронезалежний пошук підрядка).

PHP
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;

$config = (new CellMergeConfig())
    ->forType('json', new JsonCellMerger());

getMerger(string $table, string $column, string $columnType = ''): CellMerger

Шукає об'єднувач для заданих таблиці, стовпця й типу. Пріоритет: повна назва стовпця, коротка назва стовпця, шаблон типу, типовий варіант (opaque).


CellMerger (інтерфейс)

Merql\CellMerge\CellMerger — це інтерфейс стратегій злиття на рівні комірок.

PHP
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;

interface CellMerger
{
    public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult;
}

Надаються три вбудовані реалізації.

TextCellMerger

Merql\CellMerge\TextCellMerger об'єднує багаторядковий текст за допомогою тристороннього порівняння рядок за рядком (той самий алгоритм, який git використовує для вмісту файлів). Якщо обидві сторони редагують різні рядки, конфлікту немає. Якщо обидві сторони по-різному редагують той самий рядок, повідомляється про конфлікт.

PHP
use Merql\CellMerge\TextCellMerger;

$merger = new TextCellMerger();
$result = $merger->merge(
    "line 1\nline 2\nline 3",
    "line 1\nline 2 modified\nline 3",
    "line 1\nline 2\nline 3 modified",
);
// $result->clean === true
// $result->value === "line 1\nline 2 modified\nline 3 modified"

JsonCellMerger

Merql\CellMerge\JsonCellMerger об'єднує значення JSON, порівнюючи ключі верхнього рівня незалежно один від одного. Кожен ключ об'єднується за тристоронньою логікою. Вкладені об'єкти порівнюються як непрозорі рядки JSON (рекурсивне злиття не виконується).

PHP
use Merql\CellMerge\JsonCellMerger;

$merger = new JsonCellMerger();
$result = $merger->merge(
    '{"a": 1, "b": 2}',
    '{"a": 10, "b": 2}',        // changed "a"
    '{"a": 1, "b": 20}',         // changed "b"
);
// $result->clean === true
// $result->value === '{"a":10,"b":20}'

OpaqueCellMerger

Merql\CellMerge\OpaqueCellMerger — типовий варіант. Він сприймає значення як непрозорі рядки та завжди повідомляє про конфлікт, якщо вони відрізняються.


CellMergeResult

Merql\CellMerge\CellMergeResult — це тип повернення всіх засобів злиття комірок.

PHP
$result->clean;                    // bool: true if merge succeeded
$result->value;                    // mixed: merged value (or ours on conflict)
$result->conflicts;                // int: number of conflicts

// Factory methods.
CellMergeResult::resolved($value);           // clean merge
CellMergeResult::conflict($oursValue, $n);   // conflict with count

TableSchema

Merql\Schema\TableSchema — це доступне лише для читання представлення структури таблиці.

PHP
use Merql\Schema\TableSchema;

$schema = new TableSchema(
    name: 'posts',
    columns: ['id' => 'int', 'title' => 'varchar(255)', 'content' => 'text'],
    primaryKey: ['id'],
    uniqueKeys: [['slug']],
);

$schema->name;                     // string
$schema->columns;                  // array<string, string>: name to type
$schema->primaryKey;               // list<string>
$schema->uniqueKeys;               // list<list<string>>
$schema->hasPrimaryKey();          // bool
$schema->hasUniqueKeys();          // bool
$schema->columnNames();            // list<string>

Система драйверів

merql використовує систему драйверів із можливістю підключення, щоб абстрагувати операції, специфічні для баз даних. Драйвери автоматично визначаються за ідентифікатором драйвера з'єднання.

Driver (інтерфейс)

Merql\Driver\Driver визначає контракт, якого дотримуються всі драйвери баз даних.

PHP
interface Driver
{
    public function quoteIdentifier(string $name): string;
    public function listTables(DatabaseConnection $connection): array;
    public function readSchema(DatabaseConnection $connection, string $table): TableSchema;
    public function readForeignKeys(DatabaseConnection $connection): array;
    public function selectAll(string $table): string;
}

Вбудовані реалізації: MysqlDriver і SqliteDriver.

DriverFactory

Merql\Driver\DriverFactory автоматично визначає драйвер за з'єднанням.

PHP
use Merql\Driver\DriverFactory;

$driver = DriverFactory::create($connection);

Зареєструйте власний драйвер для інших баз даних:

PHP
DriverFactory::register('pgsql', MyPostgresDriver::class);

Фільтри

TableFilter

Merql\Filter\TableFilter включає або виключає таблиці за шаблонами glob.

PHP
use Merql\Filter\TableFilter;

$filter = TableFilter::exclude(['cache_*', 'sessions', 'temp_*']);
$filter = TableFilter::include(['posts', 'users', 'comments']);

ColumnFilter

Merql\Filter\ColumnFilter вилучає окремі стовпці зі знімків.

PHP
use Merql\Filter\ColumnFilter;

$filter = ColumnFilter::ignore(['updated_at', 'created_at', 'modified_date']);

RowFilter

Merql\Filter\RowFilter фільтрує рядки за допомогою функції-предиката.

PHP
use Merql\Filter\RowFilter;

$filter = RowFilter::create(function (string $table, array $row): bool {
    // Exclude trashed posts.
    if ($table === 'posts' && ($row['status'] ?? '') === 'trash') {
        return false;
    }
    return true;
});

Винятки

SnapshotException

Merql\Exceptions\SnapshotException викидається, якщо знімок не знайдено або його назва недійсна.

PHP
SnapshotException::notFound('baseline', '/path/to/baseline.json');

MergeException

Merql\Exceptions\MergeException викидається, якщо для злиття бракує обов'язкового знімка.

PHP
MergeException::snapshotRequired('base');

ConflictException

Merql\Exceptions\ConflictException викидається під час спроби застосувати результат злиття з невирішеними конфліктами.

PHP
ConflictException::unresolved(3);
// Message: "Cannot apply merge with 3 unresolved conflict(s)"

SchemaException

Merql\Exceptions\SchemaException викидається (або додається до звіту), якщо схеми знімків відрізняються.

PHP
SchemaException::mismatch('posts', 'column "tags" exists in current but not in base');

Невідповідності схем не зупиняють злиття. Вони збираються та доступні для перевірки через $result->schemaMismatches().