Skip to content

Centralize driver registries with known-drivers.php pattern #89

@markshust

Description

@markshust

Problem

Each interface package with drivers currently maintains three independently-hardcoded lists of its drivers:

  1. NoDriverException::DRIVER_PACKAGES const — read at runtime when no driver is bound
  2. Each driver's composer.json conflict block — read by Composer at install time
  3. marko/skeleton's suggest block — read by Composer during create-project

Adopting a new driver requires editing all three locations across multiple files (e.g., adding marko/view-blade needs ~5 file edits). This is error-prone, and existing lists already drift from each other.

Solution

Introduce a curated known-drivers.php file per interface package as the single source of truth:

// packages/database/known-drivers.php
<?php

declare(strict_types=1);

return [
    'marko/database-pgsql' => 'PostgreSQL driver (recommended for new projects — strong JSON, FTS, pgvector support)',
    'marko/database-mysql' => 'MySQL/MariaDB driver',
];

NoDriverException reads from this file at runtime. CI tests mechanically enforce sync between this file, each driver's composer.json conflict block, and skeleton's suggest block. Adopting a new driver becomes ~3 edits with a CI test catching any missed step.

Scope

All-or-nothing rollout to every interface package with ≥1 driver:

  • Multi-driver: cache, errors, filesystem, inertia, mail, media, pubsub, queue, session, view
  • Single-driver: authentication, encryption, http, log, notification, translation, page-cache
  • Pilot in marko/database to prove the pattern; roll out to the rest in parallel.

Additional improvements

  • NoDriverException output includes derived docs URLs (https://marko.build/docs/packages/{basename}/) for each driver, opening in a new tab when rendered via marko/errors-advanced
  • marko/errors-advanced gains URL auto-linkification (currently strips URLs to plain text)
  • marko/errors-advanced starts rendering context and suggestion fields (currently only renders message)
  • marko/view test suite cleaned up to have zero dependency on marko/view-latte (move IntegrationTest to view-latte where it belongs)
  • marko/page-cache's outlier noBinding() factory renamed to noDriverInstalled() for consistency
  • Skeleton's suggest block expanded to comprehensively list all drivers + optional add-ons (database-readwrite, page-cache-entity) with recommended-first ordering per interface
  • Sensible recommended defaults: Twig (view), pgsql (database), file (cache/session/log), simple (errors prod), gd (media), sync (queue dev), redis (pubsub), smtp (mail prod), react (inertia)

Mechanical rule

A package is a driver iff its module.php bindings array contains the interface's defining contract. Add-ons like marko/database-readwrite (empty bindings, conditional boot-callback override) and marko/page-cache-entity (observer-only bridge) are NOT enrolled in known-drivers.php — they appear in skeleton suggest only.

For v1, known-drivers.php is the curated source. Future enhancement (deferred): marker interfaces or extra.marko.driver_for declarations for mechanical enforcement.

Out of scope (separate concerns)

  • Wiring NoDriverException to actually be thrown when no driver is bound (pre-existing gap across all 18 packages — exceptions are defined but unused)
  • admin/NoDriverException cleanup (admin sub-modules aren't drivers; that exception is vestigial)
  • Marker interfaces for mechanical driver enforcement

Implementation

Plan written and ready: .claude/plans/known-drivers-registry/ on branch feature/known-drivers-registry. 25 tasks, ~5 parallel batches. Devil's-advocate review applied.

This is WIP — depends on PR #88 (view-twig) being merged first so task 017 can be expanded to cover both view drivers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions