gsferro/powermodel
PowerModel supercharges Laravel's Eloquent models with reusable helpers for querying, caching, and CRUD operations. It cuts boilerplate and speeds development, helping you build cleaner, more maintainable applications with less code.
Install and pin.
composer require gsferro/powermodel
Because adoption is low (5 stars, 0 dependents), pin an exact version in composer.json ("gsferro/powermodel": "1.0.x") rather than a caret range so a surprise release can't silently change base-model behavior across your app.
Read in this order before writing code. The package is small enough to audit in one sitting:
README.md — the intended API surface and any published config.src/ — the service provider and the model/trait that carries the "power" behavior. This is the single most important step; with no ecosystem around it, the source is the documentation.config/powermodel.php (if present) — feature flags and defaults.Publish config if offered.
php artisan vendor:publish --tag=powermodel-config
Check the tag name against the provider's publishes() call; small packages often use non-obvious tags.
First use case. Don't retrofit every model. Pick one read-heavy CRUD resource (an admin index page) and either extend the package's base model or apply its trait to a single existing model. Then wire up the package's query helpers for filtering/sorting/searching on that resource and confirm generated SQL with ->toSql() before trusting it.
Verify Laravel compatibility. Confirm the illuminate/* constraints in the package's composer.json match your Laravel version; a package last released Jan 2025 may not have been tested against the newest minor.
app/Models/PowerModel.php that extends the package base, then have your domain models extend it. This centralizes helpers but couples every model to the package — keep a app/Models/BaseModel.php shim of your own that extends the package class, so a future swap is a one-file change.User::query()
->filter($request->only(['status', 'role']))
->sort($request->query('sort', '-created_at'))
->paginate();
Keep the raw Request out of the model layer — pass validated arrays from a form request or a dedicated query object so the helpers stay testable."users:index:{$filtersHash}"), not the package's implicit keys, so you control invalidation on writes.newEloquentBuilder, newQuery, scope* methods, or getAttribute. If you also use SoftDeletes, HasFactory, or custom casts, test for collisions — two traits defining the same method cause a fatal error, and one silently winning in a parent/child hierarchy is worse.exists() checks. Check getGlobalScopes() in php artisan tinker and use withoutGlobalScope() where needed.DB::listen(fn ($q) => logger($q->sql, $q->bindings));
or ->ddRawSql() / ->toSql() on the builder. Bindings are the usual source of "the filter isn't working" — helper names rarely match column names exactly.php artisan config:cache can mask a missing key; clear it (config:clear) when behavior doesn't match config/powermodel.php.abstract, subclass it rather than editing vendor code. If helpers are protected, override them in your shim model. If the package has no extension points at all, that's a signal to limit adoption to non-critical models.composer.lock commit is non-negotiable. Also watch composer outdated gsferro/powermodel during Laravel upgrades and read the diff before bumping.gsferro/powermodel for filter/sort helpers; removal plan is to inline into app/Models/BaseModel.php." Future you (or a new hire) will thank you.How can I help you explore Laravel packages today?