Building Monica: we bouwden de databasebrowser die we voor Laravel wilden
Tijdens het herbouwen van Monica maakten we een kleine, alleen-lezen databasebrowser voor Laravel, en we besloten die als losstaand pakket uit te brengen.
Dit is een volgend artikel in de reeks Building Monica, waarin ik schrijf over het proces van Monica helemaal opnieuw opbouwen. De meeste artikelen in deze reeks zullen waarschijnlijk over het product zelf gaan: relaties, herinneringen, aanpasbaarheid, activiteiten, privacy, en alle vragen die opduiken wanneer je het leven van mensen in software probeert weer te geven. Maar het herbouwen van een grote applicatie levert onderweg ook kleinere dingen op. LaraDB is er daar een van.
Terwijl ik aan Monica v3 werkte, merkte ik dat ik veel tijd besteedde aan het rechtstreeks bekijken van de database. Dat is niet bijzonder ongewoon bij het bouwen van een Laravel-applicatie. Je maakt een contact aan en controleert wat er weggeschreven is. Je maakt een relatie aan en bekijkt de bijbehorende rijen. Je wijzigt een herinnering en controleert de datums. Je voert een actie uit, ververst de gegevens, volgt een foreign key, en herhaalt dat vele keren per dag.
Er bestaan al veel goede manieren om dit te doen. Tinker is nuttig, maar niet eenvoudig en snel in gebruik. Applicaties als TablePlus, DBeaver, phpMyAdmin of Adminer kunnen erg handig zijn, maar niet om even snel iets op te zoeken. Ik gebruik TablePlus regelmatig, vooral wanneer ik queries moet schrijven, gegevens moet bewerken of het schema in detail wil bekijken. Maar het grootste deel van de tijd had ik tijdens het ontwikkelen van Monica geen databasebeheertool nodig. Ik wilde alleen snel kunnen zien wat er in de database stond, zonder de applicatie te verlaten waarin ik toch al aan het werk was.
Dat was het oorspronkelijke idee achter LaraDB. Een ontwikkelafhankelijkheid installeren, naar /db gaan en de database zien.
composer require --dev monicahq/laradb
Wat je krijgt is heel eenvoudig. Links staan de tabellen, rechts de rijen, en de pagina draait binnen de Laravel-applicatie zelf. LaraDB ondersteunt SQLite, MySQL en MariaDB, en PostgreSQL.

Een browser in plaats van een databasebeheerder
De belangrijkste beslissing die we namen, was LaraDB alleen-lezen houden. Het heeft geen bewerkknop, geen verwijderknop, geen invoerformulier en geen SQL-console. Beide routes die het pakket blootstelt zijn GET-routes, en het pakket voert uitsluitend SELECT-statements uit.
Dat is deels een veiligheidsbeslissing, maar het gaat vooral over reikwijdte. Er bestaan al volwassen tools om databases te beheren, en een deel van hun functies binnen Laravel nabouwen zou LaraDB niet nuttiger maken voor het probleem dat we probeerden op te lossen.
Het pakket vermijdt ook het accepteren van willekeurige identifiers of queries vanuit de browser. Een opgevraagde tabel moet eerst bestaan in het schema dat de driver heeft gevonden. Identifiers worden gequote volgens de database-engine. Waarden die gebruikt worden bij het volgen van foreign keys worden als parameters gebonden. Er is geen interface om willekeurige SQL in te dienen, omdat willekeurige SQL niet tot het doel van het pakket behoort.
Een klein hulpmiddel blijft begrijpelijk als het een heel nauwkeurige taak heeft. LaraDB is bedoeld om te beantwoorden wat er op dit moment in de database staat en hoe die rijen zich tot elkaar verhouden. Het is niet bedoeld om een vervanging te worden voor een volwaardige databaseclient.
Wat we uiteindelijk nodig hadden
De interface weerspiegelt die beperkte reikwijdte. LaraDB somt de tabellen in het huidige schema op en toont hun rijen in een dichte tabel. Kolomtypes worden getoond, primaire en foreign keys worden aangeduid, NULL-waarden zijn visueel te onderscheiden van lege strings, en lange waarden worden afgekapt zodat grote tekst- of JSON-kolommen de pagina niet onbruikbaar maken.
Foreign keys bleken een van de nuttigere functies voor Monica. Als een kolom naar een andere tabel verwijst, kun je de waarde ervan direct volgen. Erop klikken opent de verwezen tabel, gefilterd op de bijbehorende rij. Dat is vooral handig in Monica v3, omdat een groeiend aantal domeinen wordt weergegeven via expliciete relaties tussen meerdere tabellen in plaats van via grote, op zichzelf staande records.
De pagina toont ook wat context over de huidige database en query. Afhankelijk van wat de database-engine beschikbaar stelt, kan LaraDB de engine en versie, de databasenaam, de omvang, het aantal indexen en andere engine-specifieke metadata weergeven. Voor de huidige pagina toont het bovendien het SQL-statement dat het resultaat opleverde en hoe lang de query duurde.
Er is ook een JSON-weergave van een tabel. Die was goedkoop toe te voegen zodra de databaselaag gescheiden was van het renderen van de HTML, en is nuttig gebleken om gegevens buiten de pagina zelf te bekijken.
De frontend is bewust op zichzelf staand. Het pakket levert zijn eigen CSS en JavaScript mee en leunt niet op de asset-pipeline van de host-applicatie. LaraDB installeren zou niet mogen betekenen dat je een Tailwind-configuratie, een Alpine-afhankelijkheid of nog een buildstap aan een bestaand project moet toevoegen.
De database-abstractie werd het echte werk
Rijen in een browser tonen is rechttoe rechtaan. SQLite, MySQL en PostgreSQL consistent ondersteunen, daar belandde het meeste interessante werk.
De engines verschillen aanzienlijk in de manier waarop ze schema- en databasemetadata blootstellen. Tabellen opsommen, kolommen beschrijven, primaire keys vinden, foreign keys oplossen, rijen tellen en informatie op databaseniveau ophalen vragen allemaal andere queries, afhankelijk van de engine. Zelfs details als het quoten van identifiers moeten correct worden afgehandeld in plaats van als een generieke SQL-operatie.
LaraDB verbergt die verschillen achter een kleine driver-interface. De Laravel-laag vraagt om tabellen, kolommen, rijen en metadata zonder te hoeven weten of de onderliggende verbinding SQLite, MySQL of PostgreSQL is.
Een vereenvoudigd deel van het contract ziet er zo uit:
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;
Elke databasedriver implementeert die operaties anders, terwijl de rest van LaraDB werkt met de gemeenschappelijke resultaatobjecten die de interface teruggeeft.
Een interessant gevolg van dit ontwerp is dat de kern van de databaselezende code helemaal niet van Laravel afhangt. Die werkt rechtstreeks met PDO. Laravel zorgt voor package discovery, configuratie, routing en rendering, maar de eigenlijke database-inspectie kun je los gebruiken.
use LaraDb\DriverFactory;
$pdo = new PDO('sqlite:database.sqlite');
$driver = DriverFactory::fromPdo($pdo);
foreach ($driver->listTables() as $table) {
echo $table->name;
}
Alleen-lezen is niet hetzelfde als ongevaarlijk
Dat het pakket alleen leest, voorkomt dat het de database beschadigt, maar het maakt het blootstellen van de database niet ongevaarlijk. Een databasebrowser kan elke rij in elke tabel tonen aan iedereen die erbij kan, wat voor een applicatie als Monica uiteraard een ernstig probleem is.
Daarom is LaraDB bedoeld om als ontwikkelafhankelijkheid geïnstalleerd te worden.
composer require --dev monicahq/laradb
Een normale productie-deploy met composer install --no-dev bevat het pakket niet. LaraDB is bovendien standaard uitgeschakeld buiten de local-omgeving, en de routes gebruiken standaard de web- en auth-middleware wanneer ze wel aanstaan.
Kleine dingen die uit een grote herbouw voortkomen
Toen ik met de reeks Building Monica begon, verwachtte ik dat het meeste schrijfwerk over de grote architectuur- en productbeslissingen achter Monica v3 zou gaan. Dat blijft ook zo. Maar ik wil ook een aantal van de kleinere hulpmiddelen en ideeën vastleggen die uit de herbouw voortkomen, want ook die horen bij het werk.
LaraDB is geen belangrijk onderdeel van Monica v3, en het probeert op zichzelf geen groot product te worden. Het is gewoon een klein ontwikkelhulpmiddel dat een terugkerende ergernis voor ons wegnam. Het pakket is nuttig juist omdat de reikwijdte beperkt is, en dat zou ik graag zo houden.
Als je aan Laravel-applicaties werkt en vaak een databaseclient opent alleen om te bekijken wat je code net heeft weggeschreven, is LaraDB misschien ook voor jou nuttig.
composer require --dev monicahq/laradb
Ga daarna naar /db.
De broncode is beschikbaar op github.com/monicahq/laradb.