dejwcake / admin-generator
Laravel CRUD generator for dejwcake/craftable
Requires
- php: ^8.5
- illuminate/console: ^13.0
- illuminate/support: ^13.0
Requires (Dev)
- larastan/larastan: ^3.9
- orchestra/testbench: ^11.1
- phpunit/phpunit: ^13.1
- spatie/phpunit-snapshot-assertions: ^5.3
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-31 09:51:04 UTC
README
Admin Generator is a Laravel package that quickly scaffolds full CRUD administration for your existing, migrated database tables. It generates controllers, form requests, models, views, routes, and translations so you can get a production-ready admin interface in minutes instead of wiring everything by hand.
It builds on the admin UI template from our dejwCake/admin-ui package and is shipped as part of the Craftable ecosystem, making it a good fit for new and existing Craftable-based projects.
Example of an administration interface generated with this package:
This package is part of Craftable (dejwCake/craftable), an administration starter kit for Laravel 12, forked from Craftable (brackets/craftable).
Documentation
You can find full documentation at https://docs.getcraftable.com/#/admin-generator
Choosing which actions to generate
By default admin:generate scaffolds every action except export. Use --only or --except with a
comma-separated list to choose the actions for a resource:
php artisan admin:generate posts --only=show,export # a read-only resource with export
php artisan admin:generate posts --except=delete,bulk-delete
| Action | What it generates |
|---|---|
create |
store request, create/store controller methods and routes, create page, form component, the listing's create button |
edit |
update request, edit/update controller methods and routes, edit page, form component, the listing's edit button |
show |
show controller method and route, show page and component, the listing's show button |
delete |
destroy request, controller method and route, the listing's delete button |
bulk-delete |
bulk-destroy request, controller method and route, the listing's bulk-operations bar |
export |
export request, controller method and route, the Export class, the listing's export button |
--onlygenerates exactly the listed actions.--exceptgenerates every action except the listed ones. It starts from all actions, export included, so--except=deleteturns export on, while omitting both options leaves it off.- The two options can't be combined, and each needs at least one action. An unknown action name is an error.
- The form component is generated when the resource has
createoredit.
index is always generated and can't be listed. The listing is the resource's admin page: the
menu link points to it, and it hosts the buttons for every other action. A resource without it would
have nothing to navigate to, so --only=index,… is rejected rather than silently ignored.
What's generated regardless of the selection: the model and factory, the controller with its
index method, the index request, the listing (Blade page and Vue component), routes, translations
and the permissions migration. The routes, translations and listing only contain entries for the
selected actions.
The permissions migration is always complete, with every action's permission. Its rows are
referenced by role_has_permissions, so regenerating a resource with a narrower set would delete
grants roles already have. A permission for an action that isn't generated is harmless.
Soft-deleting models
A table with a deleted_at column gets a trash on top of delete and bulk-delete. Nothing changes
for a table without it.
- Delete and Delete permanently. The listing offers both, single and bulk; the admin chooses.
destroyandbulkDestroydelete row by row (so model events fire) in a transaction. - Show deleted. A toggle in the listing shows only trashed rows (
onlyTrashed()), with a sortabledeleted_atcolumn. Trashed rows offer only Restore and Delete permanently. {Models}TrashController(admin:generate:trash-controller) holdsforceDestroy,bulkForceDestroy,restoreandbulkRestore, with their requests (admin:generate:request:{force-destroy,bulk-force-destroy,restore,bulk-restore}). Its routes are registered before the main ones and resolve trashed rows (withTrashed()). Single actions come withdelete, bulk ones withbulk-delete.- Restorable check. The model gets
isRestorable(): everybelongsToparent must exist and not be trashed (a nullable foreign key may be empty). A row that is not restorable has its Restore button disabled, its restore request fails validation, and bulk restore skips it and reports the count. - Failures are reported, not thrown. An integrity constraint violation (a unique value now taken
by a live row, a row still referenced by another) rolls the operation back and comes back as a
validation error with an
admin-uimessage. - Permissions:
restore,bulk-restore,force-deleteandbulk-force-deleteare added to the permissions migration.
Deprecated flags
--with-export (-e) and --without-bulk (-wb) still work, and are applied on top of
--only/--except. --with-export can only add export, and --without-bulk can only remove
bulk-delete. admin:generate:permissions accepts --without-bulk but ignores it.
admin:generate:user and admin:generate:admin-user accept the same options.
admin:generate:admin-user:profile does not take them.
The generators whose output depends on the selection (admin:generate:controller,
admin:generate:routes, admin:generate:blade-index, admin:generate:vue-listing and
admin:generate:lang) accept the same options, so each one can be run on its own. The others
generate one action's files and are simply not called when that action is left out.
Issues
Where do I report issues? If something is not working as expected, please open an issue in the main repository https://github.com/dejwCake/craftable.
How to develop this project
Composer
Update dependencies:
docker compose run -it --rm test composer update
Composer normalization:
docker compose run -it --rm php-qa composer normalize
Run code analysis tools (php-qa)
PHP compatibility:
docker compose run -it --rm php-qa phpcs --standard=.phpcs.compatibility.xml --cache=.phpcs.cache
Code style:
docker compose run -it --rm php-qa phpcs -s --colors --extensions=php
Fix style issues:
docker compose run -it --rm php-qa phpcbf -s --colors --extensions=php
Static analysis (phpstan):
docker compose run -it --rm php-qa phpstan analyse --configuration=phpstan.neon
Regenerate the phpstan baseline:
docker compose run -it --rm php-qa phpstan analyse --configuration=phpstan.neon --generate-baseline=phpstan-baseline.neon
Mess detector (phpmd):
docker compose run -it --rm php-qa phpmd analyze
Regenerate the phpmd baseline:
docker compose run -it --rm php-qa phpmd analyze --generate-baseline
Run tests
Run tests against mariadb:
docker compose run -it --rm -e DB_CONNECTION=mariadb test ./vendor/bin/phpunit
Run tests against postgresql:
docker compose run -it --rm -e DB_CONNECTION=pgsql test ./vendor/bin/phpunit
Run tests with coverage:
docker compose run -it --rm test ./vendor/bin/phpunit --coverage-text
To regenerate snapshots use:
docker compose run -it --rm -e UPDATE_SNAPSHOTS=true test ./vendor/bin/phpunit
Run the whole PHP suite
Run every PHP check and the test suite against both databases in sequence (stops at the first failure):
docker compose run -it --rm test composer update \ && docker compose run -it --rm php-qa composer normalize \ && docker compose run -it --rm php-qa phpcs --standard=.phpcs.compatibility.xml --cache=.phpcs.cache \ && docker compose run -it --rm php-qa phpcs -s --colors --extensions=php \ && docker compose run -it --rm php-qa phpstan analyse --configuration=phpstan.neon \ && docker compose run -it --rm php-qa phpmd analyze \ && docker compose run -it --rm -e DB_CONNECTION=mariadb test ./vendor/bin/phpunit \ && docker compose run -it --rm -e DB_CONNECTION=pgsql test ./vendor/bin/phpunit