Gå til indhold

Fletning på celleniveau

Fletning på kolonneniveau registrerer, når begge sider har ændret den samme kolonne. Fletning på celleniveau går dybere og fletter indholdet i kolonnen. To personer, der redigerer forskellige linjer i et TEXT-felt eller forskellige nøgler i et JSON-objekt, kan flette uden konflikt.

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

$config = CellMergeConfig::auto();
$merge = new ThreeWayMerge($config);
$result = $merge->merge($base, $ours, $theirs);

Aktivér fletning på celleniveau

Fletning på celleniveau er valgfri. Den kører kun i en ThreeWayMerge, der er konstrueret med en CellMergeConfig. Uden en sådan bliver enhver kolonne, som begge sider har ændret til forskellige værdier, en update_update-konflikt.

Facaden Merql tager ikke imod en konfiguration: Merql::merge(), Merql::patch() og Merql::plan() konstruerer new ThreeWayMerge() uden en, og kommandoen merge i CLI går gennem Merql::merge(). De fletter altid på kolonneniveau (#7).

Hvis du vil flette øjebliksbilleder, der er gemt af facaden eller CLI, med fletning på celleniveau, skal du indlæse dem og selv kalde ThreeWayMerge. Resultatet er en almindelig MergeResult, så facaden stadig kan anvende det, og MergePlanBuilder omdanner det til en fletteplan:

PHP
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);

Celleflettere kører kun for kolonner, som begge sider har ændret. Hvis kun den ene side har ændret en kolonne, bruges dens værdi uændret.

CellMergeConfig

CellMergeConfig knytter kolonner eller kolonnetyper til cellefletterimplementeringer. Fabrikken auto() leverer fornuftige standardindstillinger:

PHP
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());

Prioritet for valg af fletter:

  1. Fuldt kvalificeret kolonnenavn (table.column).
  2. Ukvalificeret kolonnenavn (column).
  3. Mønstermatch af kolonnetype (str_contains uden forskel på store og små bogstaver).
  4. Standard: OpaqueCellMerger (rapporterer altid en konflikt, når værdierne afviger).

TextCellMerger

Fletter tekst med flere linjer ved hjælp af Myers-difference, samme algoritme som git bruger til filindhold. Hver linje behandles som en enhed, og ændringer af forskellige linjer flettes uden konflikt.

PHP
use Merql\CellMerge\TextCellMerger;

$merger = new TextCellMerger();

Eksempel: konfliktfri tekstfletning

Kode
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

Der blev redigeret forskellige linjer. Fletningen giver "LINE ONE\nline two\nLINE THREE" uden konflikt.

Eksempel: tekstkonflikt

Kode
Base:    "line one\nline two"
Ours:    "changed by us\nline two"     // changed line 1
Theirs:  "changed by them\nline two"   // also changed line 1

Begge sider ændrede den samme linje til forskellige værdier. Fletteren returnerer et konfliktresultat. Det flettede indhold indeholder konfliktmarkører, der minder om dem i git.

Sådan fungerer det

TextCellMerger bruger pitmasters ThreeWayMerge::merge(), som beregner en Myers-difference mellem base og hver side og derefter kombinerer de to redigeringsscripts. Hvis redigeringerne overlapper i det samme linjeområde, rapporterer den en konflikt.

JsonCellMerger

Fletter JSON-objekter ved at sammenligne nøgler på øverste niveau uafhængigt af hinanden. Hver nøgle flettes efter de almindelige trevejsregler.

PHP
use Merql\CellMerge\JsonCellMerger;

$merger = new JsonCellMerger();

Eksempel: konfliktfri JSON-fletning

JSON
// 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}

Der blev ændret forskellige nøgler. Det flettede resultat er:

JSON
{"name": "Bob", "role": "admin", "active": true}

Eksempel: JSON-konflikt

JSON
// Base
{"color": "red"}

// Ours
{"color": "blue"}

// Theirs
{"color": "green"}

Begge sider ændrede nøglen color til forskellige værdier. Det er en konflikt. Fletteren vælger som standard vores værdi og rapporterer én konflikt.

Regler for nøgler

Base Vores Deres Resultat
Nøgle uændret Nøgle uændret Brug base
Nøgle uændret Nøgle ændret Brug deres
Nøgle ændret Nøgle uændret Brug vores
Nøgle ændret (ens) Nøgle ændret (ens) Brug værdien (enighed)
Nøgle ændret (forskellig) Nøgle ændret (forskellig) Konflikt (standard: vores)
Nøgle findes Nøgle findes Nøgle fjernet Accepter fjernelse
Nøgle findes Nøgle fjernet Nøgle findes Accepter fjernelse
Nøgle mangler Nøgle tilføjet Nøgle mangler Accepter tilføjelse
Nøgle mangler Nøgle mangler Nøgle tilføjet Accepter tilføjelse

Indlejrede objekter sammenlignes som uigennemsigtige JSON-strenge, ikke rekursivt. Hvis et indlejret objekt afviger, sammenlignes hele værdien af den pågældende nøgle, ikke dens undernøgler.

Krav

Alle tre værdier skal være gyldige JSON-objekter eller -arrays. Hvis en værdi ikke er gyldig JSON eller er en skalar af typen JSON (streng, tal, boolesk værdi), falder fletteren tilbage til en konflikt.

OpaqueCellMerger

Standardfletteren, når der ikke er konfigureret en strategi for fletning på celleniveau. Den behandler kolonneværdien som en uigennemsigtig blok og rapporterer altid en konflikt, når de to sider er forskellige.

PHP
use Merql\CellMerge\OpaqueCellMerger;

$merger = new OpaqueCellMerger();
$result = $merger->merge($base, $ours, $theirs);
// $result->clean is always false when $ours !== $theirs

CellMergeResult

Alle celleflettere returnerer en CellMergeResult:

PHP
$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

Fabrikmetoder:

PHP
CellMergeResult::resolved($value);           // clean merge
CellMergeResult::conflict($oursValue, $n);   // n conflicts, defaults to ours

Brugerdefinerede celleflettere

Implementér grænsefladen CellMerger for at tilføje din egen flette-strategi:

PHP
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());