Building Monica: Wir haben den Datenbank-Browser gebaut, den wir uns für Laravel gewünscht haben
Beim Neubau von Monica ist ein kleiner, nur lesender Datenbank-Browser für Laravel entstanden, den wir als eigenständiges Paket veröffentlicht haben.
Dies ist ein weiterer Artikel aus der Reihe Building Monica, in der ich über den Neubau von Monica von Grund auf schreibe. Die meisten Artikel dieser Reihe werden sich vermutlich um das Produkt selbst drehen: Beziehungen, Erinnerungen, Anpassbarkeit, Aktivitäten, Privatsphäre und all die Fragen, die auftauchen, wenn man versucht, das Leben von Menschen in Software abzubilden. Aber beim Neubau einer großen Anwendung entstehen unterwegs auch kleinere Dinge. LaraDB ist eines davon.
Während der Arbeit an Monica v3 habe ich gemerkt, dass ich sehr viel Zeit damit verbringe, direkt in die Datenbank zu schauen. Das ist beim Bauen einer Laravel-Anwendung nicht besonders ungewöhnlich. Man legt einen Kontakt an und prüft, was geschrieben wurde. Man legt eine Beziehung an und sieht sich die zugehörigen Zeilen an. Man ändert eine Erinnerung und kontrolliert die Daten. Man löst eine Aktion aus, lädt die Daten neu, folgt einem Fremdschlüssel, und wiederholt das viele Male am Tag.
Dafür gibt es bereits viele gute Wege. Tinker ist nützlich, aber nicht einfach und schnell zu benutzen. Anwendungen wie TablePlus, DBeaver, phpMyAdmin oder Adminer können sehr hilfreich sein, aber nicht für einen kurzen Blick. Ich benutze TablePlus regelmäßig, vor allem wenn ich Abfragen schreiben, Daten bearbeiten oder das Schema im Detail ansehen muss. Aber die meiste Zeit brauchte ich beim Entwickeln von Monica kein Werkzeug zur Datenbankverwaltung. Ich wollte nur schnell sehen, was in der Datenbank steht, ohne die Anwendung zu verlassen, an der ich ohnehin gerade arbeitete.
Das war die ursprüngliche Idee hinter LaraDB. Eine Entwicklungsabhängigkeit installieren, /db aufrufen und die Datenbank sehen.
composer require --dev monicahq/laradb
Was man bekommt, ist sehr einfach. Links werden die Tabellen angezeigt, rechts die Zeilen, und die Seite läuft innerhalb der Laravel-Anwendung selbst. LaraDB unterstützt SQLite, MySQL und MariaDB sowie PostgreSQL.

Ein Browser und keine Datenbankverwaltung
Die wichtigste Entscheidung war, LaraDB nur lesend zu halten. Es gibt keinen Bearbeiten-Knopf, keinen Löschen-Knopf, kein Formular zum Einfügen und keine SQL-Konsole. Beide Routen, die das Paket bereitstellt, sind GET-Routen, und das Paket setzt ausschließlich SELECT-Anweisungen ab.
Das ist zum Teil eine Sicherheitsentscheidung, vor allem aber eine Frage des Umfangs. Es gibt bereits ausgereifte Werkzeuge zur Verwaltung von Datenbanken, und einen Teil ihrer Funktionen innerhalb von Laravel nachzubauen würde LaraDB für das Problem, das wir lösen wollten, nicht nützlicher machen.
Das Paket vermeidet außerdem, beliebige Bezeichner oder Abfragen aus dem Browser entgegenzunehmen. Eine angeforderte Tabelle muss zuerst in dem Schema existieren, das der Treiber ermittelt hat. Bezeichner werden je nach Datenbank-Engine maskiert. Werte, die beim Folgen von Fremdschlüsseln verwendet werden, werden als Parameter gebunden. Es gibt keine Oberfläche, um beliebiges SQL abzuschicken, weil beliebiges SQL nicht zum Zweck des Pakets gehört.
Ein kleines Werkzeug bleibt verständlich, wenn es eine sehr genau umrissene Aufgabe hat. LaraDB soll beantworten, was gerade in der Datenbank steht und wie diese Zeilen zueinander in Beziehung stehen. Es soll kein Ersatz für einen richtigen Datenbank-Client werden.
Was wir am Ende gebraucht haben
Die Oberfläche spiegelt diesen engen Rahmen wider. LaraDB listet die Tabellen des aktuellen Schemas auf und zeigt ihre Zeilen in einer dichten Tabelle. Spaltentypen werden angezeigt, Primär- und Fremdschlüssel sind gekennzeichnet, NULL-Werte unterscheiden sich sichtbar von leeren Zeichenketten, und lange Werte werden gekürzt, damit große Text- oder JSON-Spalten die Seite nicht unbrauchbar machen.
Die Fremdschlüssel haben sich für Monica als eine der nützlicheren Funktionen herausgestellt. Verweist eine Spalte auf eine andere Tabelle, kann man ihrem Wert direkt folgen. Ein Klick öffnet die referenzierte Tabelle, gefiltert auf die entsprechende Zeile. Das ist in Monica v3 besonders praktisch, weil immer mehr Bereiche über ausdrückliche Beziehungen zwischen mehreren Tabellen abgebildet werden statt über große, in sich geschlossene Datensätze.
Die Seite zeigt außerdem etwas Kontext zur aktuellen Datenbank und Abfrage. Je nachdem, was die Datenbank-Engine zur Verfügung stellt, kann LaraDB die Engine und ihre Version, den Namen der Datenbank, ihre Größe, die Anzahl der Indizes und weitere engine-spezifische Metadaten anzeigen. Für die aktuelle Seite zeigt es auch die SQL-Anweisung, die das Ergebnis erzeugt hat, und wie lange die Abfrage gedauert hat.
Es gibt auch eine JSON-Darstellung einer Tabelle. Sie war günstig zu ergänzen, nachdem die Datenbankschicht vom HTML-Rendering getrennt war, und hat sich als nützlich erwiesen, um Daten außerhalb der Seite selbst anzusehen.
Das Frontend ist bewusst eigenständig. Das Paket bringt eigenes CSS und eigenes JavaScript mit und hängt nicht an der Asset-Pipeline der Host-Anwendung. LaraDB zu installieren sollte nicht bedeuten, einem bestehenden Projekt eine Tailwind-Konfiguration, eine Alpine-Abhängigkeit oder einen weiteren Build-Schritt hinzuzufügen.
Die Datenbankabstraktion wurde zur eigentlichen Arbeit
Zeilen in einem Browser anzuzeigen ist unkompliziert. SQLite, MySQL und PostgreSQL einheitlich zu unterstützen, dort ist der Großteil der interessanten Arbeit gelandet.
Die Engines unterscheiden sich deutlich darin, wie sie Schema- und Datenbank-Metadaten offenlegen. Tabellen auflisten, Spalten beschreiben, Primärschlüssel finden, Fremdschlüssel auflösen, Zeilen zählen und Informationen auf Datenbankebene abrufen erfordern je nach Engine unterschiedliche Abfragen. Selbst Details wie das Maskieren von Bezeichnern müssen korrekt behandelt und nicht als allgemeine SQL-Operation betrachtet werden.
LaraDB verbirgt diese Unterschiede hinter einer kleinen Treiber-Schnittstelle. Die Laravel-Schicht fragt nach Tabellen, Spalten, Zeilen und Metadaten, ohne wissen zu müssen, ob die darunterliegende Verbindung SQLite, MySQL oder PostgreSQL ist.
Ein vereinfachter Teil des Vertrags sieht so aus:
public function listTables(): array;
public function getColumns(string $table): array;
public function getRowCount(
string $table,
?RowFilter $filter = null,
): int;
public function getRows(
string $table,
int $page,
int $perPage,
?RowFilter $filter = null,
): TablePage;
public function getForeignKeys(string $table): array;
Jeder Datenbanktreiber setzt diese Operationen anders um, während der Rest von LaraDB mit den gemeinsamen Ergebnisobjekten arbeitet, die die Schnittstelle zurückgibt.
Eine interessante Folge dieses Entwurfs ist, dass der Kern des lesenden Datenbankcodes überhaupt nicht von Laravel abhängt. Er arbeitet direkt mit PDO. Laravel ist für Package Discovery, Konfiguration, Routing und Rendering zuständig, aber die eigentliche Datenbankinspektion lässt sich separat verwenden.
use LaraDb\DriverFactory;
$pdo = new PDO('sqlite:database.sqlite');
$driver = DriverFactory::fromPdo($pdo);
foreach ($driver->listTables() as $table) {
echo $table->name;
}
Nur lesend ist nicht dasselbe wie harmlos
Dass das Paket nur liest, verhindert, dass es die Datenbank beschädigt. Es macht es aber nicht harmlos, die Datenbank offenzulegen. Ein Datenbank-Browser kann jede Zeile jeder Tabelle für jeden sichtbar machen, der ihn erreichen kann, was für eine Anwendung wie Monica offensichtlich ein ernstes Problem wäre.
Aus diesem Grund ist LaraDB dafür gedacht, als Entwicklungsabhängigkeit installiert zu werden.
composer require --dev monicahq/laradb
Ein normales Produktions-Deployment mit composer install --no-dev enthält das Paket nicht. LaraDB ist außerdem außerhalb der Umgebung local standardmäßig deaktiviert, und seine Routen verwenden im aktivierten Zustand standardmäßig die Middleware web und auth.
Kleine Dinge, die aus einem großen Neubau entstehen
Als ich die Reihe Building Monica begonnen habe, ging ich davon aus, dass sich der größte Teil der Texte um die großen Architektur- und Produktentscheidungen hinter Monica v3 drehen würde. Das bleibt auch so. Aber ich möchte auch einige der kleineren Werkzeuge und Ideen festhalten, die bei diesem Neubau entstehen, denn auch sie gehören zur Arbeit dazu.
LaraDB ist kein großer Teil von Monica v3, und es versucht nicht, für sich genommen ein großes Produkt zu werden. Es ist schlicht ein kleines Entwicklungswerkzeug, das uns eine wiederkehrende Störung erspart hat. Das Paket ist gerade deshalb nützlich, weil sein Umfang begrenzt ist, und das soll auch so bleiben.
Wenn Sie an Laravel-Anwendungen arbeiten und oft einen Datenbank-Client öffnen, nur um zu sehen, was Ihr Code gerade geschrieben hat, könnte LaraDB auch für Sie nützlich sein.
composer require --dev monicahq/laradb
Dann rufen Sie /db auf.
Der Quellcode ist unter github.com/monicahq/laradb verfügbar.