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

Update History Laravel Package

wikimedia/update-history

A small PHP library from Wikimedia for recording and querying update history. It stores change entries and lets you retrieve recent updates, useful for audit trails, changelogs, and tracking modifications in your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require wikimedia/update-history

Required context first: This library is not a standalone migration tool — it is the persistence layer for MediaWiki's updates.php history, extracted out of MediaWiki core. It expects a MediaWiki-style database handle (Wikimedia\Rdbms\IDatabase / DBConnRef), not an Illuminate\Database\Connection or a raw PDO. If you are in a Laravel app, budget time for an adapter or for a small reimplementation of the logic against the query builder — the package is under ~300 lines of PHP and is more of a reference implementation than a batteries-included dependency.

Where to look first

  1. src/UpdateHistory.php — the entire public surface lives here.
  2. tests/phpunit/UpdateHistoryTest.php — shows the exact calling contract and the shape of the stored payload.
  3. composer.json — confirms the required wikimedia/rdbms version and PHP floor.

First use case (the realistic one for a Laravel dev)

Use it as a schema-update ledger for a legacy data import: store an ordered, keyed list of "updates have run" rows in a single table (historically updatelog with ul_key = 'updatelist' and ul_value holding the serialized list). This lets you answer, per tenant/site, "which numbered update scripts have been applied and in what order" — the same question Laravel's migrations table answers, but scoped per wiki and keyed by name + numeric id rather than by filename.

Minimal flow:

$history = new UpdateHistory( $dbw, $updates ); // $updates = name => id map
$history->load();                               // hydrate state from updatelog
if ( $history->getUpdatesRan() !== $updates ) {
    $history->addUpdate( 'SomeUpdate.php', 12345 );
}

You must create the updatelog table yourself — the library reads and writes it but does not migrate it.

Implementation Patterns

1. Bind as a singleton behind a Laravel service provider

$this->app->singleton(UpdateHistory::class, fn ($app) =>
    new UpdateHistory(
        new MediaWikiDbAdapter($app['db']->connection()),
        config('updates.list')
    )
);

Wrapping the class behind a PendingUpdates contract makes it swappable if you later drop the MediaWiki DB dependency.

2. Treat the updates array as your source of truth

The constructor takes the full ordered map of name => id. Every check, insert, and comparison is relative to that map, not to what's on disk. Pattern: generate that map at build time from a directory of UpdateNNN.php files, commit the lock file, and diff it in CI to catch drift — otherwise a renumbered update silently becomes "not applied."

3. Multi-tenant pattern

MediaWiki uses one updatelog per database (one wiki = one DB). To mirror that in Laravel, either:

  • one history table per tenant connection (preferred — matches the library's assumptions), or
  • a tenant_id column added to updatelog and a repository that scopes every call.

The second option requires forking the class; the constructor signature has no tenant hook.

4. Read-only reporting command

php artisan updates:status

Load the history, diff against the shipped map, print pending names. This is the highest-value day-to-day integration — it turns an opaque ledger into migrate:status for your legacy updater.

5. Hybrid with native Laravel migrations

For a migration-in-progress project, run legacy updates through this ledger first (in artisan db:seed-style bootstrap or a custom command), then hand off to normal php artisan migrate. Keep the two systems' tables distinct (updatelog vs migrations) so a rollback of one never touches the other.

6. Idempotent wrapper

The underlying insert is not INSERT OR IGNORE on all DB engines. Wrap the addUpdate() call:

if (! $history->getUpdatesRan()[$name] ?? null === $id) {
    $history->addUpdate($name, $id);
}

so re-running a partial batch is safe.

Gotchas and Tips

The DB abstraction is the real cost. Wikimedia\Rdbms\IDatabase is a substantial interface (query builder, replica/primary routing, insert(), select(), getDBname(), etc.). Pulling wikimedia/rdbms into Laravel drags in wikimedia/at-ease, wikimedia/assert, and friends, and duplicates a lot of what Eloquent already does. For anything smaller than a faithful MediaWiki port, reimplement the ~50 lines of load()/addUpdate() against your existing connection and keep the library as a spec.

The stored payload is not JSON. ul_value historically holds a PHP-serialized array (older versions used comma-joined lists). Do not json_decode it, and do not assume you can read it with a different language or a DB GUI. There is no schema-version marker on the blob — if you upgrade across a format change you must migrate old rows manually.

Table creation is your job. There is no CREATE TABLE shipped as a migration. The canonical MediaWiki definition is ul_key VARCHAR/TEXT (primary key) and ul_value BLOB/TEXT. Get ul_value size wrong and the insert silently truncates on MySQL in non-strict mode.

Version pinning is fragile. Because this is a Gerrit-hosted mirror, the GitHub repo (mediawiki-libs-UpdateHistory) receives release tags but issues/PRs live on Phabricator. composer.json constraints like ^1.0 may map to MediaWiki core versions; check extension.json/skin.json consumers in core to see which tag is actually paired with your MediaWiki or rdbms version. Mismatches typically surface as a fatal type error on the constructor's IDatabase parameter.

Debugging tip: the fastest path is almost always to inspect updatelog directly. SELECT ul_key, SUBSTRING(ul_value FROM 1 FOR 200) FROM updatelog; — the 'updatelist' row is the one you care about. If getUpdatesRan() returns empty when you expect entries, the row is missing or the key differs (MediaWiki historically used updatelist).

No extension points. The class is final-ish and has no events, hooks, or middleware. Customization means composition: wrap it, decorate it, or fork it. Do not subclass.

Low bus factor / low signal. 1 star, 0 dependents, and the actual development is on Gerrit. Treat this as a read-only reference for a MediaWiki-conformant update ledger, not as a library you will get support on. If a bug bites you, the fix belongs in a Laravel-side wrapper or a fork; upstreaming to Gerrit is possible but not a realistic maintenance plan for a single Laravel app.

When NOT to use it: any greenfield project, any project without a MediaWiki DB layer, any project where you can use php artisan migrate. The only defensible reasons to adopt it are (a) interoperability with an existing MediaWiki updatelog, or (b) you specifically want the MediaWiki update-history data model and are willing to pay the wikimedia/rdbms tax.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console