Looking to hire Laravel developers? Try LaraJobs

laravel-bitemporal maintained by vusys

Description
Effective-dated and bitemporal models for Laravel 11+.
Last update
2026/08/31 07:31 (dev-master)
License
Downloads
40

Comments
comments powered by Disqus

Laravel Bitemporal Models

Tests Docs codecov Mutation testing OpenSSF Scorecard PHP Laravel PHPStan Rector Code Style: Pint License

Safe effective-dated and bitemporal relations for Laravel.

vusys/laravel-bitemporal provides first-class support for effective-dated and bitemporal Eloquent data — modelling facts that change over time, where the application needs to answer:

  • What was true on this business date?
  • What did the system believe was true on this business date at the time?
  • When did this value become effective, and when was a correction recorded?

The value is not a handful of query scopes. It is a custom temporal relation with safe write operations, range splitting, correction handling, point-in-time eager loading, and overlap prevention — so you can correct the past without destroying the previous state of knowledge or creating overlapping historical facts.

$product->prices()->correct(attributes: ['amount' => 12.00], validFrom: '2026-02-01');

Installation

composer require vusys/laravel-bitemporal

PHP 8.4+, Laravel 11 / 12 / 13, and PostgreSQL, MySQL/MariaDB, or SQLite. The service provider is auto-discovered. See Installation for the optional config publish.

Quick example

A product has many price versions. The entity model exposes the timeline; the temporal model carries the period columns.

use Vusys\Bitemporal\Concerns\HasBitemporalRelations;
use Vusys\Bitemporal\Relations\BitemporalMany;

class Product extends Model
{
    use HasBitemporalRelations;

    public function prices(): BitemporalMany
    {
        return $this->bitemporalMany(ProductPrice::class);
    }
}

use Vusys\Bitemporal\Bitemporal;

class ProductPrice extends Model
{
    use Bitemporal;

    protected string $temporalEntity = Product::class;
}

Period-column casts are applied automatically — you don't declare them. The migration uses the package's Blueprint macros:

Schema::create('product_prices', function (Blueprint $table) {
    $table->id();
    $table->bitemporalForeignFor(Product::class);
    $table->decimal('amount', 10, 2);
    $table->bitemporalPeriods();
    $table->timestamps();
    $table->preventBitemporalOverlaps(['product_id']);
});

Read at a point in time:

$price = $product->prices()
    ->validAt($invoice->issued_at)     // true on this business date
    ->knownAt($invoice->created_at)    // as we believed it then
    ->sole();

Write safely:

$product->prices()->changeEffectiveFrom(['amount' => 12.00], validFrom: '2026-06-01');
$product->prices()->correct(['amount' => 12.00], validFrom: '2026-02-01', validTo: '2026-03-01');
$product->prices()->retract(validFrom: '2026-02-01', validTo: '2026-03-01');

Documentation

📚 Full documentation: vusys.github.io/laravel-bitemporal

Also readable directly in docs/:

Requirements

  • PHP 8.4+
  • Laravel 11 / 12 / 13
  • PostgreSQL, MySQL/MariaDB, or SQLite

Status

The package is built from a detailed internal specification and its feature set is complete and green across SQLite, MySQL 8.4, MariaDB, and PostgreSQL 16. The read side, the core write side (change / correct / retract / end / supersede / hard-delete), dimensions, the as-of lens, polymorphic entities, backfill, optimistic concurrency, lock strategies, and the migration macros are implemented — along with temporal pivots (BitemporalBelongsToMany), idempotency keys, the first-party audit-log subscriber, diff and timeline helpers, the testing helpers and factories, boot guards and advisory lints, and the full generator/command set (make:bitemporal-*, bitemporal:audit-*, bitemporal:diff-timelines, bitemporal:warm-guards, bitemporal:prune-idempotency-keys).

Enhancements and further hardening are tracked in the issue tracker under the roadmap label.

Development

composer install
composer ci          # phpstan (L9, no baseline) + pint + rector + phpunit
composer test
composer infection   # mutation testing

License

MIT. See LICENSE.