simba-jirira-source/laravel-schema-contract

Detect inconsistencies between Laravel database schema metadata and Eloquent model casts.

Maintainers

Package info

github.com/simba-jirira-source/laravel-schema-contract

pkg:composer/simba-jirira-source/laravel-schema-contract

Transparency log

Fund package maintenance!

simba-jirira-source

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.2 2026-08-18 12:40 UTC

This package is auto-updated.

Last update: 2026-08-18 12:48:49 UTC


README

Laravel Schema Contract

Detect inconsistencies between Laravel database schema metadata and Eloquent model casts.

Packagist PHP from Packagist Laravel versions GitHub Workflow Status (main) Total Downloads

Purpose

Laravel Schema Contract is developer tooling for Laravel applications. It answers a focused question for v0.1.x:

Do my database columns and Eloquent model casts describe compatible data types?

The package discovers Eloquent models, reads live schema metadata from each model's effective connection and table, normalizes database and cast types, and reports contract violations with CI-friendly exit codes.

v0.1.x scope: Database Schema ↔ Eloquent Model only.

The analyzer is read-only. It never mutates schema, models, or application data.

Requirements

  • PHP 8.3+
  • Laravel 13.x
  • Composer 2+
  • A reachable database connection for the models being analyzed

Installation

Install the package as a development dependency:

composer require simba-jirira-source/laravel-schema-contract --dev

Laravel auto-discovery registers the service provider and Artisan command.

Publish the configuration file when you need custom discovery or ignore rules:

php artisan vendor:publish --tag=schema-contract-config

Quick start

  1. Ensure your application database schema is migrated.
  2. Run the check against all discovered models:
php artisan schema-contract:check
  1. Fix reported ERROR rows before merging. Treat WARNING rows as recommended improvements; they do not fail CI by default.

Analyze one model:

php artisan schema-contract:check User
php artisan schema-contract:check "App\\Models\\User"

Short class names work when they resolve to exactly one discovered model.

Example output

Given a users table with a boolean active column, a decimal credit_limit, and a JSON preferences column, and a model that casts credit_limit to integer while leaving preferences uncast:

App\Models\User
Table: users

PASS    active
        database: boolean
        cast: boolean

ERROR   credit_limit
        database: decimal(10,2)
        cast: integer
        suggested: decimal:2

WARNING preferences
        database: json
        cast: none
        suggested: array

Models inspected: 1
Columns inspected: 5
Errors: 1
Warnings: 1
Passed: 3

Severity meanings:

Severity Meaning Fails CI by default
ERROR High-confidence incompatible contract Yes (exit code 1)
WARNING Suspicious or recommended improvement No
INFO Non-blocking information No

Commands

Command Description
php artisan schema-contract:check Analyze all discovered Eloquent models
php artisan schema-contract:check {model} Analyze one model by FQCN or short name

Exit codes

Code Meaning
0 No blocking contract errors (warnings allowed)
1 One or more contract errors detected
2 Configuration, resolution, or runtime failure

Examples of exit code 2: unresolvable model argument, ambiguous short class name, missing database table for a targeted model.

When no models are discovered, the command exits 0 and prints a warning.

Configuration

Configuration lives in config/schema-contract.php after publishing.

return [
    'model_paths' => [
        app_path('Models'),
    ],

    'ignore_models' => [
        // App\Models\LegacyRecord::class,
    ],

    'ignore_columns' => [
        // 'users' => ['password', 'remember_token'],
    ],
];
Option Purpose
model_paths Directories searched recursively for concrete Eloquent models. Falls back to app_path('Models') when empty.
ignore_models Fully-qualified model classes excluded from bulk discovery and default checks. Targeted analysis by FQCN still works.
ignore_columns Table-specific columns skipped during rule checks. Keys are database table names.

Supported databases and types

Database drivers

Driver Support in v0.1.x CI verification
SQLite First-class Default test suite
MySQL / MariaDB First-class database-compatibility workflow
PostgreSQL First-class database-compatibility workflow

See docs/DATABASE_SUPPORT.md for driver-specific metadata behavior, verified type mappings, and known limitations.

Normalized database types

The package maps raw driver metadata to internal database types:

boolean, integer, big_integer, small_integer, decimal, float, double, string, text, date, datetime, timestamp, json, uuid, enum, binary, unknown

Unknown or incomplete metadata maps to unknown and produces conservative warnings rather than crashing analysis.

Normalized cast types

Built-in and class-based casts normalize to:

boolean, integer, float, double, decimal, string, array, object, collection, date, datetime, timestamp, enum, custom, unknown

Custom cast classes are recognized without being misclassified as enums. Expressions such as decimal:2 retain scale metadata.

Contract rules (v0.1.x)

  • Cast matches column type
  • Decimal scale matches (when precision/scale metadata is available)
  • JSON columns require a compatible cast (missing cast is a warning)
  • Date/time columns require compatible casts (standard Laravel timestamp columns are excluded from noisy warnings)

CI usage

Add the check to your pipeline after migrations are available (or against a migrated test database):

- name: Install dependencies
  run: composer install --no-interaction --prefer-dist

- name: Run schema contract check
  run: php artisan schema-contract:check

The command exits 1 when contract errors exist, so a failing step blocks the pipeline without extra flags.

Warnings alone do not fail the command.

This repository validates the package itself with GitHub Actions:

Workflow Purpose
tests.yml PHP 8.3/8.4/8.5 matrix, Composer validate, PHPStan, Pint, type coverage, Pest
database-compatibility.yml MySQL and PostgreSQL grouped integration tests

Forks and consuming applications can mirror the same quality commands during development:

composer check:composer
composer analyse
composer lint:check
composer test:types
vendor/bin/pest

Limitations

Not implemented in v0.1.x (planned for later releases):

  • Database ↔ Validation (FormRequest validation analysis)
  • API Resource analysis
  • Livewire analysis
  • Baseline generation and suppressions
  • JSON or GitHub annotation output formats
  • Automatic fixes

Current analysis limits:

  • Driver metadata varies; missing precision/scale never produces false-positive decimal errors
  • PostgreSQL native enums and extension types may map to unknown
  • SQLite does not distinguish integer column sizes in schema metadata
  • The package reports structural contract metadata only; it does not dump row data
  • Ignored models are skipped during bulk checks but can still be analyzed when targeted explicitly

Roadmap

Version Focus
v0.1 Database ↔ Eloquent
v0.2 Database ↔ Validation
v0.3 Enums, defaults, nullability
v0.4 Model ↔ FormRequest
v0.5 API Resource contracts
v0.6 Livewire contracts
v0.7 CI / JSON / GitHub reporting
v0.8 Baselines / suppression
v0.9 Public extension API
v1.0 Stable public API

Each release is intended to be independently useful. See the product specification for the full scope and roadmap.

Testing

Package development

Clone the repository and install dependencies:

composer install

Run the full quality suite:

composer test

Individual commands:

composer check:composer   # composer validate --strict
composer analyse          # PHPStan level 8 + Larastan
composer lint:check       # Laravel Pint
composer test:types       # Pest type coverage (100% minimum)
composer test:unit        # Pest parallel (optional smoke)
vendor/bin/pest           # Pest serial

composer test runs the release gate with serial Pest for reliable Testbench bootstrapping.

Driver integration tests

SQLite tests run in the default suite. MySQL and PostgreSQL grouped tests require environment configuration. See docs/DATABASE_SUPPORT.md.

Contributing

Please see CONTRIBUTING.md. For significant changes, open an issue first.

Security

The analyzer may include model names, table names, column names, and type metadata in output. It does not dump application records.

Please review SECURITY.md for vulnerability reporting.

License

Laravel Schema Contract is open-source software licensed under the MIT license.

Changelog

Please see CHANGELOG.md for release notes.