Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Dbal Timestamp Type Laravel Package

marktopper/doctrine-dbal-timestamp-type

A Doctrine DBAL custom type that maps SQL TIMESTAMP columns to PHP DateTime objects, making timestamp columns work correctly with Laravel's Doctrine integration. Simple to register and use in your entity mappings.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require marktopper/doctrine-dbal-timestamp-type

The package provides a single Doctrine DBAL type (MarkTopper\DoctrineDBALTimestampType\TimestampType) that teaches DBAL the SQL TIMESTAMP column type — something DBAL does not ship out of the box (it has datetime, datetimetz, date, and time). This matters most in Laravel when Doctrine DBAL is used under the hood for operations like ->change() on a timestamp column, or when introspecting an existing schema that contains TIMESTAMP columns.

Look first at the package's src/ directory — it is a small class that extends DBAL's DateTimeType and overrides getName() / getSQLDeclaration(). Read that before anything else; the entire surface area is one class.

Register the type before any schema work happens — typically in AppServiceProvider::boot():

use Doctrine\DBAL\Types\Type;
use MarkTopper\DoctrineDBALTimestampType\TimestampType;

public function boot(): void
{
    if (! Type::hasType('timestamp')) {
        Type::addType('timestamp', TimestampType::class);
    }
}

First use case: modifying a timestamp column in a Laravel migration that previously failed with Unknown column type "timestamp" requested:

Schema::table('users', function (Blueprint $table) {
    $table->timestamp('email_verified_at')->nullable()->change();
});

Implementation Patterns

Guard registration in a service provider. DBAL throws if you call Type::addType() for an already-registered type. Both AppServiceProvider and package auto-discovery can run, so always wrap in Type::hasType().

Mapping platform types to the custom type. For schema introspection to recognize existing MySQL TIMESTAMP columns, register the platform mapping on the connection:

DB::connection()->getDoctrineConnection()
    ->getDatabasePlatform()
    ->registerDoctrineTypeMapping('timestamp', 'timestamp');

Call this once per connection after the type is registered.

Laravel ->change() workflows. Any migration that mutates a timestamp column (nullable, default, precision, unsigned) goes through DBAL and therefore benefits from this type being present. Use it together with a modern doctrine/dbal 3.x install, since DBAL is a hard dependency for ->change().

Doctrine entity usage. With doctrine/dbal or barryvdh/laravel-doctrine, you can declare the column explicitly:

#[Column(type: 'timestamp', nullable: true)]
private ?\DateTimeImmutable $verifiedAt = null;

The type extends DateTimeType, so value coercion to DateTime/DateTimeImmutable behaves as expected — you get the same conversion behavior as datetime, only the SQL declaration differs.

Schema tools / SchemaBuilder. When building tables programmatically through the DBAL schema API:

$table->addColumn('created_at', 'timestamp', ['notnull' => false]);

Testing. Register the type in a base TestCase::setUp() or globally in tests/TestCase.php so schema-introspection tests don't silently pass with datetime behavior and fail in production where the actual column type is TIMESTAMP.

Gotchas and Tips

Do not confuse layers. Laravel's $table->timestamp() builder method and this package are different things — the former creates a TIMESTAMP column already; the latter teaches Doctrine that the returned type name exists. If you never touch DBAL (no ->change(), no schema introspection, no Doctrine entities), you probably don't need this package.

DBAL re-registration errors. Type::addType() throws DBALException when a type name already exists. Guard it, and be mindful that in Octane or in long-running workers the boot method may execute per request/worker — the guard handles this.

MySQL TIMESTAMP semantics leak through. MySQL stores TIMESTAMP in UTC and converts by session timezone, and implicitly supports ON UPDATE CURRENT_TIMESTAMP. This package only handles the PHP/DBAL type mapping; it does not change MySQL's auto-update or TZ behavior. If you rely on the auto-update, declare it in the migration default string rather than expecting the type to emit it.

Range limits. MySQL TIMESTAMP is limited to roughly 1970–2038 (2038 problem) on older versions. For columns that need to store dates outside that window, datetime is the safer choice. Only reach for timestamp when you specifically need UTC-normalized storage.

Cross-platform SQL. The type's SQL declaration is TIMESTAMP, which is valid on MySQL, MariaDB, and PostgreSQL but not on every platform (SQLite treats it as text-like). If you target SQLite for tests and MySQL for production, test the schema diff, not just the value round-trip.

Version compatibility. Last release is 2023; verify against your doctrine/dbal version (3.x is the safe bet). If you upgrade to DBAL 4, check that the class's overridden methods still match — DBAL 4 dropped several deprecated type APIs and moved to stricter signatures.

Extension point. Because it subclasses DateTimeType, overriding convertToDatabaseValue() is the cleanest way to enforce a specific storage format (e.g. 'Y-m-d H:i:s') or to strip microseconds before persisting, rather than trying to configure this at the connection level.

Debugging. If schema introspection still fails, dump what DBAL sees: DB::connection()->getDoctrineSchemaManager()->listTableColumns('users') and inspect the returned type names. A mismatch (timestamp vs datetime) usually means the platform mapping wasn't registered for that connection.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core