testmonitor/eloquent-revisable
Keep a full revision history for your Eloquent models. This package automatically saves snapshots on create, update, and delete, lets you inspect what changed, and restore or revert models to any previous version through a simple, familiar API.
This is the initial v1.0.0 release, so treat the source as the documentation until a README/site exists. The release notes only state "Initial version," which tells you nothing about API surface — verify everything below against the actual package before adopting it.
composer require <vendor>/<package>:^1.0
Open the package's composer.json and confirm the php and illuminate/* (or laravel/framework) constraints match your app. A brand-new package often pins tighter than you expect (e.g. ^11.0 only), and that is the single most common reason an install "works" in isolation but fails in a real project.src/ for:
*ServiceProvider (bindings, config merge, publish paths)*Facade (if it exposes one)config/*.php (defaults you'll override)database/migrations/ and routes/ (anything publishable)extra.laravel.providers and extra.laravel.aliases keys. If they're present, you don't register anything manually; if absent, add the provider to bootstrap/providers.php (Laravel 11+) or config/app.php.php artisan vendor:publish --provider="Vendor\Package\PackageServiceProvider"
php artisan vendor:publish --provider="Vendor\Package\PackageServiceProvider" --tag=config
php artisan vendor:publish --provider="Vendor\Package\PackageServiceProvider" --tag=migrations
Run the bare command first (no tag) to see the available tags — guessing tags wastes time.php artisan tinker and exercise the smallest public method. Doing this before wiring it into a controller isolates "package misconfigured" from "my integration is wrong."vendor/bin/phpunit inside the package or composer test if defined). For a 1.0.0, passing tests are the only real signal of intended behavior.Prefer constructor injection over facades. Even if the package ships a facade, type-hint the underlying contract/class so the dependency is explicit and swappable in tests:
public function __construct(private \Vendor\Package\Client $client) {}
Reserve the facade for one-off calls in Blade, Artisan commands, or quick scripts.
Bind interfaces, not concretes. If the service provider registers a contract (e.g. Vendor\Package\Contracts\Client → Vendor\Package\Client), resolve the contract. That gives you a seam for $this->app->bind(...) in a test or a local fake, and it survives a minor-version refactor better than referencing the concrete class.
Keep configuration in config/. After publishing, move any environment-specific values to .env and reference them from the config file — never call env() from application code, especially once config:cache is in play. A typical pattern:
// config/package.php (published)
'api_key' => env('PACKAGE_API_KEY'),
'timeout' => env('PACKAGE_TIMEOUT', 10),
Wrap it in your own thin adapter. For a 1.0.0 with no BC track record, put the package behind a small app-level service or interface. When a breaking change lands in 1.1 or 2.0, you edit one class instead of grepping the codebase:
final class PackageGateway
{
public function __construct(private \Vendor\Package\Client $client) {}
public function lookup(string $id): array
{
return $this->client->get($id)->toArray();
}
}
Migrations and data. If the package publishes migrations, let them own their tables and don't add columns by editing the published file — add your own follow-up migration instead. This keeps vendor:publish --force from silently reverting your schema changes.
Queue/cache integration. If the package provides jobs, listeners, or cache keys, check whether it registers its own queue connection or cache prefix. In multi-tenant or multi-app setups you'll want those namespaced so two apps sharing Redis don't collide.
Testing patterns.
setUp(): $this->app->instance(Client::class, new FakeClient());Package::fake(), use it — check the source for a testing helper before hand-rolling one.use RefreshDatabase and run the package migrations in the test suite.Http::fake() if the package builds on the Laravel HTTP client; otherwise check for Guzzle middleware hooks.Events and extension points. Grep for event(, dispatch(, and fire( in src/. A well-built Laravel package dispatches events at the boundaries of its work; subscribing to them is usually a cleaner integration than subclassing internals.
src/ before you trust any assumed method signature, and pin the version in composer.json ("^1.0" at minimum) so a surprise 1.1.0 doesn't ship to production while you sleep.composer dump-autoload && php artisan package:discover — then php artisan about to confirm it registered.php artisan config:clear. Same for route:clear if the package publishes routes, and view:clear if it ships views.bootstrap/cache/ if a facade alias resolves to nothing after an upgrade. Facade aliases are registered at boot; a cached packages.php from a previous version can point at a removed class.--tag=config outputs "No publishable resources," re-run without the tag and read the printed list.env(). A fresh package almost always calls env() in its config file. That's fine there, but if you copy those calls into your own code the values become null under config:cache. Always go through config() in app code.report() it). For network-backed packages, a bad key looks identical to a network error at first glance — log the response body once during bring-up.Macroable trait on the main class. If none exist, prefer the adapter pattern over subclassing — subclassing an undocumented internal is exactly what breaks in 2.0.How can I help you explore Laravel packages today?