marceauka/laravel-crudable
Laravel CRUDable provides a reusable controller trait for adding create, read, update, and delete actions to Laravel models with minimal boilerplate. Configure the model and fields, and it handles the repetitive CRUD logic so your controllers stay clean and consistent.
Read the archived notice before anything else. This package is archived and last saw meaningful activity in the Laravel 5.x era. Before writing a line of code, open composer.json in the repo and check the illuminate/* constraints and the php requirement. If you are on Laravel 8+, assume the package will not install cleanly and budget for either a fork or a rewrite.
Minimal steps for an existing codebase that already depends on it:
composer require marceauka/laravel-crudable — pin the exact version in composer.json ("marceauka/laravel-crudable": "1.x" style) so a future composer update cannot pull a surprise.config/app.php. Grep vendor/marceauka/laravel-crudable/src for ServiceProvider to see what it binds.php artisan vendor:publish and inspect what tags appear — config and/or Blade views. If nothing is published, the package is likely config-free and view-free, which tells you it is a thin routing/controller abstraction.php artisan route:list before and after wiring up your first resource. This is the fastest way to learn what the package actually generates, and it is more reliable than the README if the README has drifted.First use case: wire up exactly one resource end-to-end — a trivial model like Post with title and body. Get index/create/store/edit/update/destroy working against a throwaway table, then read the generated routes and controller flow. Do not attempt to convert your whole app; the value proposition here is boilerplate reduction for simple resources, and you need to see the shape of that boilerplate before deciding whether it fits your conventions.
Where to look first: the README's first code block (canonical entry point), then src/ for the base controller or trait it asks you to extend. The entire package is small enough to read in ten minutes — do that instead of trusting docs.
Extend, don't wrap. Packages of this genre typically give you a base controller (or a trait) that implements the seven resource actions and expects you to override hooks: validation rules, the query used for index, the model class, the view namespace, and redirect targets. Keep your per-resource controllers as thin as possible — overriding store() wholesale defeats the point and makes future Laravel upgrades harder. Override the narrow hooks (rules, scopes, eager loads) and leave the action methods alone.
Co-locate validation with the model. Put $rules (and separate $updateRules if the package supports it) on the Eloquent model or in a rules() method, and have the controller hook read from there. This keeps the rules reusable if you later call the same validation from an API controller or a console command, and it makes the eventual migration off the package mostly a controller swap.
Layer authorization outside the package. Do not rely on the package for access control. Register a Policy per model and call $this->authorize(...) from a single overridden hook or from middleware on the generated routes. Archived packages rarely receive security fixes, so nothing security-relevant should live inside its action methods.
Use route groups for cross-cutting concerns. Since the package owns route generation, wrap its route registrations in a Route::middleware([...])->prefix(...)->group(...) block rather than editing each generated route. This is also where you bolt on auth, throttling, and can: middleware.
Scope index queries explicitly. A generic index almost always does Model::all() or Model::paginate(). In a multi-tenant or soft-deleted app that is a data leak waiting to happen. Override the query hook to apply tenant scoping, with() eager loads, and default ordering — and write a feature test asserting a user from tenant A cannot see tenant B's rows through the generated index route.
Testing pattern. Since the routes are generated, test at the HTTP layer, not the controller layer. A ResourceCrudTest trait that takes a model factory and asserts the six routes behave (200 on index, 302 on store, 403 for unauthorized) gives you coverage across every resource with one class. This is the single highest-leverage thing you can build around the package.
Migration insurance. If you expect to leave the package, keep a thin App\Http\Controllers\ResourceController base of your own that the package-backed controllers extend. When you drop the dependency, you change one file's extends target instead of every controller.
illuminate/support constraint first. If it caps below your Laravel version, Composer will either refuse to install or (worse, with --ignore-platform-reqs) install something that fatals at runtime. Fork it, bump the constraints, and run the test suite before trusting it.store/update typically call create($request->all()). If a field isn't in $fillable, it vanishes with no error. When a form "saves" but a column stays null, check $fillable before you debug the request.{model} route parameters and soft-deleted records behave differently than you expect. Confirm with route:list --columns=uri,action and a dd() in the overridden hook.protected function store(Request $request) or lack type hints. Adding a return type or changing visibility in your override causes a fatal error that reads like a mystery. Match the parent signature exactly, or you'll spend an hour on it.route:list, the provider isn't registered, the macro is registered after your routes file loads, or the config cache is stale — run php artisan route:clear && php artisan config:clear before anything else.php artisan config:cache && php artisan route:cache still produces the same route:list output; a package that does config() lookups at request time or uses closures in routes will break route:cache entirely.Route::resource and buys you full framework support.php artisan make:controller --resource --model=Post plus a FormRequest gets you 80% of the same benefit with zero dependency risk. Reserve this package for maintaining an app that already uses it, and use the maintenance window to plan the extraction.How can I help you explore Laravel packages today?