al-rahabi / fancy-crud
Opinionated abstract building blocks (controllers, services, repositories, actions, policies, resources) for well-structured Laravel CRUD projects.
Requires
- php: ^8.3
- guzzlehttp/psr7: ^2.0
- laravel-notification-channels/fcm: ^6.2
- laravel/framework: ^11.0|^12.0|^13.0
- maatwebsite/excel: ^3.1
- spatie/laravel-permission: ^6.0|^7.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Abstract building blocks for well-structured Laravel projects: base controllers, services, repositories, CRUD actions, policies, requests, resources, enums, casts and traits.
Install
composer require al-rahabi/fancy-crud php artisan vendor:publish --tag=fancy-crud-config
Structure
| Namespace | Contents |
|---|---|
FancyCrud\Actions\Crud |
AbstractAction, CreateAction, UpdateAction, DestroyAction |
FancyCrud\Services |
BaseService, BaseCrudService |
FancyCrud\Repositories |
BaseRepository |
FancyCrud\Contracts |
Controller, CrudController, BasePolicy, BaseRequest, BaseResource, BaseEnumTrait, BaseNotification |
FancyCrud\Casts |
MediaCast |
FancyCrud\Traits |
Activable, HasSlug, Sortable, ResponseTrait, PaginationMetaTrait |
FancyCrud\Middleware |
AcceptedLanguagesMiddleware |
BaseNotification needs laravel-notification-channels/fcm.
Testing
composer install && composer test
Testing your CRUD endpoints (Pest)
The package ships a declarative test generator, FancyCrud\Testing\CrudTestBuilder
(helper: crudTest()), that expands into the standard suite for a CrudController.
- Use
InteractsWithCrudon the base test case your CRUD files run on, call$this->setUpCrud()at the end ofsetUp(), and implementcrudUser(?array $permissions)(null= may do everything, array = exactly those permissions, e.g.['index posts']). Token-based apps overridecrudHeaders(),crudUnauthedHeaders(),crudRestrictedHeaders(); apps needing an environment (tenant, transaction) overridecrudSeed(). - Bind the directory in
tests/Pest.php:pest()->extend(CrudTestCase::class)->in('Feature/Crud'); - One file per controller:
crudTest('posts') ->model(Post::class) ->all() // or ->only(['index','store',...]) / ->except([...]) ->createPayload(['title' => 'Hello']) ->invalidPayload(['title' => '']) ->jsonStructure(['id', 'title']) ->assertCreated(['title' => 'Hello']) ->importRows([['Title'], ['First'], ['Second']]) // for the import verb (CSV upload) ->run();
Verbs: index store show update patch destroy export template import, plus always
401 (unauthenticated) and 403 (no permission; ->restrictedPermission(null) to skip).
Defaults: base URL /api (->baseUrl()), records from Model::factory() (or ->record(fn)).
See tests/ for a complete working example (fixture controller, policy, Excel sheet).