Penggabungan Tingkat Sel
Penggabungan tingkat kolom mendeteksi jika kedua sisi mengubah kolom yang sama. Penggabungan tingkat sel bekerja lebih mendalam dengan menggabungkan isi di dalam kolom tersebut. Dua orang yang mengedit baris berbeda dalam kolom TEXT atau kunci berbeda pada objek JSON dapat menggabungkan perubahan dengan bersih.
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
$config = CellMergeConfig::auto();
$merge = new ThreeWayMerge($config);
$result = $merge->merge($base, $ours, $theirs);
Mengaktifkan penggabungan tingkat sel
Penggabungan tingkat sel bersifat opsional. Penggabungan ini hanya berjalan dalam ThreeWayMerge yang dibuat dengan CellMergeConfig. Tanpanya, setiap kolom yang diubah kedua sisi menjadi nilai berbeda akan menjadi konflik update_update.
Fasade Merql tidak menerima konfigurasi: Merql::merge(), Merql::patch(), dan Merql::plan() membuat new ThreeWayMerge() tanpanya, dan perintah merge milik CLI dijalankan melalui Merql::merge(). Semuanya selalu menggabungkan pada tingkat kolom (#7).
Untuk menggabungkan snapshot yang disimpan oleh fasade atau CLI dengan penggabungan tingkat sel, muat snapshot tersebut dan panggil ThreeWayMerge sendiri. Hasilnya adalah MergeResult biasa, sehingga fasade tetap dapat menerapkannya, dan MergePlanBuilder mengubahnya menjadi rencana penggabungan:
use Merql\CellMerge\CellMergeConfig;
use Merql\Merge\ThreeWayMerge;
use Merql\Merql;
use Merql\Plan\MergePlanBuilder;
use Merql\Snapshot\SnapshotStore;
$base = SnapshotStore::load('base');
$ours = SnapshotStore::load('ours');
$theirs = SnapshotStore::load('theirs');
$result = (new ThreeWayMerge(CellMergeConfig::auto()))->merge($base, $ours, $theirs);
$plan = (new MergePlanBuilder())->build('plan-1', $base, $ours, $theirs, $result);
Penggabung sel hanya berjalan untuk kolom yang diubah kedua sisi. Jika hanya satu sisi yang mengubah kolom, nilainya digunakan apa adanya.
CellMergeConfig
CellMergeConfig memetakan kolom atau jenis kolom ke implementasi penggabung sel. Factory auto() menyediakan nilai default yang sesuai:
use Merql\CellMerge\CellMergeConfig;
use Merql\CellMerge\JsonCellMerger;
use Merql\CellMerge\TextCellMerger;
// Auto: column types containing "text" (TEXT, MEDIUMTEXT, LONGTEXT, ...) use
// TextCellMerger, column types containing "json" use JsonCellMerger.
$config = CellMergeConfig::auto();
// Custom: assign mergers to specific columns.
$config = (new CellMergeConfig())
->forColumn('posts.content', new TextCellMerger())
->forColumn('settings', new JsonCellMerger())
->forType('json', new JsonCellMerger());
Prioritas resolusi penggabung:
- Nama kolom berkualifikasi (
table.column). - Nama kolom tanpa kualifikasi (
column). - Pencocokan pola jenis kolom (
str_containstanpa membedakan huruf besar dan kecil). - Default:
OpaqueCellMerger(selalu melaporkan konflik jika nilainya berbeda).
TextCellMerger
Menggabungkan teks multi-baris menggunakan diff Myers, algoritme yang sama dengan yang digunakan git untuk isi berkas. Setiap baris diperlakukan sebagai satu unit, dan perubahan pada baris yang berbeda dapat digabungkan dengan bersih.
use Merql\CellMerge\TextCellMerger;
$merger = new TextCellMerger();
Contoh: penggabungan teks yang bersih
Base: "line one\nline two\nline three"
Ours: "LINE ONE\nline two\nline three" // changed line 1
Theirs: "line one\nline two\nLINE THREE" // changed line 3
Baris yang berbeda diedit. Penggabungan menghasilkan "LINE ONE\nline two\nLINE THREE" tanpa konflik.
Contoh: konflik teks
Base: "line one\nline two"
Ours: "changed by us\nline two" // changed line 1
Theirs: "changed by them\nline two" // also changed line 1
Kedua sisi mengubah baris yang sama menjadi nilai berbeda. Penggabung mengembalikan hasil konflik. Konten gabungan menyertakan penanda konflik yang mirip dengan git.
Cara kerjanya
TextCellMerger mendelegasikan ke ThreeWayMerge::merge() milik pitmaster, yang menghitung diff Myers antara base dan tiap sisi, lalu menggabungkan kedua skrip edit. Jika edit saling tumpang tindih pada wilayah baris yang sama, konflik akan dilaporkan.
JsonCellMerger
Menggabungkan objek JSON dengan membandingkan kunci tingkat atas secara terpisah. Setiap kunci digabungkan menggunakan aturan tiga arah standar.
use Merql\CellMerge\JsonCellMerger;
$merger = new JsonCellMerger();
Contoh: penggabungan JSON yang bersih
// Base
{"name": "Alice", "role": "editor", "active": true}
// Ours: changed "role"
{"name": "Alice", "role": "admin", "active": true}
// Theirs: changed "name"
{"name": "Bob", "role": "editor", "active": true}
Kunci yang berbeda diubah. Hasil gabungannya adalah:
{"name": "Bob", "role": "admin", "active": true}
Contoh: konflik JSON
// Base
{"color": "red"}
// Ours
{"color": "blue"}
// Theirs
{"color": "green"}
Kedua sisi mengubah kunci color menjadi nilai yang berbeda. Ini adalah konflik. Secara default, penggabung memilih ours dan melaporkan satu konflik.
Aturan tingkat kunci
| Base | Ours | Theirs | Hasil |
|---|---|---|---|
| Kunci tidak berubah | Kunci tidak berubah | Terima base | |
| Kunci tidak berubah | Kunci berubah | Terima theirs | |
| Kunci berubah | Kunci tidak berubah | Terima ours | |
| Kunci berubah (sama) | Kunci berubah (sama) | Terima (sepakat) | |
| Kunci berubah (berbeda) | Kunci berubah (berbeda) | Konflik (default: ours) | |
| Kunci ada | Kunci ada | Kunci dihapus | Terima penghapusan |
| Kunci ada | Kunci dihapus | Kunci ada | Terima penghapusan |
| Kunci tidak ada | Kunci ditambahkan | Kunci tidak ada | Terima penambahan |
| Kunci tidak ada | Kunci tidak ada | Kunci ditambahkan | Terima penambahan |
Objek bersarang dibandingkan sebagai string JSON tanpa struktur rekursif. Jika suatu objek bersarang berbeda, seluruh nilai kunci tersebut akan dibandingkan, bukan subkuncinya.
Persyaratan
Ketiga nilai harus berupa objek atau larik JSON yang valid. Jika ada nilai yang bukan JSON valid, atau berupa skalar JSON (string, angka, boolean), penggabung akan kembali menggunakan konflik.
OpaqueCellMerger
Penggabung default ketika tidak ada strategi tingkat sel yang dikonfigurasi. Penggabung ini memperlakukan nilai kolom sebagai blob buram dan selalu melaporkan konflik ketika kedua sisi berbeda.
use Merql\CellMerge\OpaqueCellMerger;
$merger = new OpaqueCellMerger();
$result = $merger->merge($base, $ours, $theirs);
// $result->clean is always false when $ours !== $theirs
CellMergeResult
Semua penggabung sel mengembalikan CellMergeResult:
$result = $merger->merge($base, $ours, $theirs);
$result->clean; // bool: true if merge resolved cleanly
$result->value; // mixed: the merged value (or ours on conflict)
$result->conflicts; // int: number of conflicts within the cell
Metode factory:
CellMergeResult::resolved($value); // clean merge
CellMergeResult::conflict($oursValue, $n); // n conflicts, defaults to ours
Penggabung sel kustom
Implementasikan antarmuka CellMerger untuk menambahkan strategi penggabungan Anda sendiri:
use Merql\CellMerge\CellMerger;
use Merql\CellMerge\CellMergeResult;
class YamlCellMerger implements CellMerger
{
public function merge(mixed $base, mixed $ours, mixed $theirs): CellMergeResult
{
// Parse YAML, merge keys, return result.
$merged = $this->mergeYaml($base, $ours, $theirs);
if ($merged['clean']) {
return CellMergeResult::resolved($merged['value']);
}
return CellMergeResult::conflict($ours);
}
}
$config = (new CellMergeConfig())
->forColumn('config_data', new YamlCellMerger());