Zum Inhalt springen

Filter

Filter steuern, welche Daten in einen Snapshot aufgenommen werden. Schließe Cache-Tabellen aus, ignoriere veränderliche Zeitstempelspalten oder überspringe temporäre Zeilen. Die Filter werden während der Snapshot-Erfassung angewendet und wirken sich auf alle nachgelagerten Vorgänge aus (Diff, Merge, Apply).

PHP
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Snapshot\Snapshotter;

$snapshotter = new Snapshotter($connection);

$snapshot = $snapshotter->capture('baseline', filters: [
    TableFilter::exclude(['sessions', 'cache_*']),
    ColumnFilter::ignore(['updated_at', 'modified_date']),
]);

TableFilter

Legt fest, welche Tabellen in einen Snapshot aufgenommen werden. Unterstützt Glob-Muster über PHPs fnmatch().

Tabellen ausschließen

PHP
use Merql\Filter\TableFilter;

$filter = TableFilter::exclude(['sessions', 'cache_*', 'wp_*_log']);

Tabellen, die einem Ausschlussmuster entsprechen, werden aus dem Snapshot ausgelassen. Der Platzhalter * steht für eine beliebige Zeichenfolge.

Tabellen einschließen

PHP
$filter = TableFilter::include(['posts', 'comments', 'users']);

Nur Tabellen, die einem Einschlussmuster entsprechen, werden erfasst. Alle anderen werden ausgeschlossen.

Funktionsweise

Die Methode apply() des Filters nimmt eine Liste von Tabellennamen entgegen und gibt die gefilterte Teilmenge zurück:

PHP
$allTables = ['posts', 'comments', 'sessions', 'cache_pages', 'users'];

$filter = TableFilter::exclude(['sessions', 'cache_*']);
$filtered = $filter->apply($allTables);
// ['posts', 'comments', 'users']

$filter = TableFilter::include(['posts', 'users']);
$filtered = $filter->apply($allTables);
// ['posts', 'users']

Wenn Einschluss- und Ausschlussmuster vorhanden sind (über separate Filterinstanzen), wird der Ausschluss zuerst ausgewertet. Eine Tabelle bleibt erhalten, wenn sie keinem Ausschlussmuster und mindestens einem Einschlussmuster entspricht.

ColumnFilter

Entfernt bei der Erfassung bestimmte Spalten aus den Zeilendaten. Nützlich für veränderliche Spalten, die sich bei jedem Schreibvorgang ändern und falsche Diffs verursachen würden.

PHP
use Merql\Filter\ColumnFilter;

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

Häufige Anwendungsfälle

  • updated_at / modified_at-Zeitstempel, die sich bei jedem Speichern ändern.
  • revision-Zähler, die automatisch hochgezählt werden.
  • session_token oder andere temporäre Felder.

Funktionsweise

Der Filter entfernt benannte Spalten aus jeder Zeile, nachdem der Zeilenschlüssel berechnet wurde:

PHP
$filter = ColumnFilter::ignore(['updated_at']);

$row = ['id' => 1, 'title' => 'Hello', 'updated_at' => '2026-01-15 10:30:00'];
$filtered = $filter->applyToRow($row);
// ['id' => 1, 'title' => 'Hello']

Der Zeilenschlüssel (Identität) wird anhand der ungefilterten Zeile berechnet. Daher sind Identitätsspalten vom Spaltenfilter nicht betroffen. Gefiltert werden nur die Daten, die für Fingerprinting und Diff-Berechnungen verwendet werden.

RowFilter

Filtert einzelne Zeilen mithilfe einer Prädikat-Closure. Die Closure erhält den Tabellennamen und die vollständigen Zeilendaten und gibt true zurück, um die Zeile einzuschließen, oder false, um sie auszuschließen.

PHP
use Merql\Filter\RowFilter;

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

// Exclude rows with NULL email.
$filter = RowFilter::create(function (string $table, array $row): bool {
    if ($table === 'users') {
        return $row['email'] !== null;
    }
    return true;
});

Funktionsweise

Die Methode shouldInclude() wird während der Erfassung für jede Zeile aufgerufen:

PHP
$include = $filter->shouldInclude('posts', ['id' => 1, 'status' => 'draft']);
// false

Ausgeschlossene Zeilen werden nicht mit einem Fingerprint versehen, nicht im Snapshot gespeichert und erscheinen weder in Diffs noch in Merges.

Filter kombinieren

Übergib mehrere Filter an capture(). Es wird höchstens ein Filter jedes Typs verwendet:

PHP
$snapshot = $snapshotter->capture('baseline', filters: [
    TableFilter::exclude(['cache_*']),
    ColumnFilter::ignore(['updated_at']),
    RowFilter::create(fn($table, $row) => ($row['active'] ?? '1') === '1'),
]);

Verarbeitungsreihenfolge:

  1. TableFilter wird zuerst ausgeführt und bestimmt, welche Tabellen erfasst werden.
  2. Für jede Tabelle werden die Zeilen aus der Datenbank gelesen.
  3. RowFilter wird auf jede Zeile angewendet und schließt nicht passende Zeilen aus.
  4. Der Zeilenschlüssel wird anhand der ungefilterten Zeile berechnet (Identitätsspalten bleiben erhalten).
  5. ColumnFilter entfernt ignorierte Spalten aus den Zeilendaten.
  6. Der Fingerprint wird anhand der gefilterten Zeilendaten berechnet.

Diese Reihenfolge stellt sicher, dass Identitätsspalten für die Berechnung des Schlüssels verfügbar bleiben, auch wenn der Spaltenfilter sie später entfernt.

Filter und Konsistenz

Für alle drei Snapshots eines Merge-Vorgangs (Basis, ours, theirs) sollten dieselben Filter verwendet werden. Bei unterschiedlichen Filtern können Zeilen oder Spalten als hinzugefügt oder entfernt erscheinen, obwohl sie lediglich unterschiedlich gefiltert wurden.

PHP
// Use the same filter set for all snapshots.
$filters = [
    TableFilter::exclude(['sessions']),
    ColumnFilter::ignore(['updated_at']),
];

$base   = $snapshotter->capture('base', filters: $filters);
$ours   = $snapshotter->capture('ours', filters: $filters);
$theirs = $snapshotter->capture('theirs', filters: $filters);