gblix / laravel-controller-repository-traits
Traits para Controllers de Laravel facilitando uso da lib `prettus/l5-repository`
Package info
github.com/GBLIX/laravel-controller-repository-traits
pkg:composer/gblix/laravel-controller-repository-traits
Requires
- php: ^8.3
- ext-json: *
- itsgoingd/clockwork: ^5.2
- lorisleiva/laravel-actions: ^2.8
- prettus/l5-repository: ^2.10 || ^4.0
- spatie/laravel-fractal: ^6.3
Requires (Dev)
- orchestra/testbench: ^10.0 || ^11.0
- spatie/laravel-package-tools: ^1.92
- squizlabs/php_codesniffer: ^3.12
This package is auto-updated.
Last update: 2026-06-11 10:31:03 UTC
README
Controller traits for Laravel that streamline building REST APIs on top of
prettus/l5-repository. The package wires
controllers, repositories, Fractal presenters and validators together so each CRUD endpoint
becomes a one-liner with well-defined customization hooks.
Version compatibility
| Package version | Laravel | PHP | prettus/l5-repository |
|---|---|---|---|
| 1.8.x | 12, 13 | ≥ 8.3 | ^2.10 || ^4.0 |
| 1.7.x (beta) | 12 | ≥ 8.3 | ^2.10 |
| 1.6.x | 11 | ≥ 8.3 | ^2.9.1 |
Laravel 13 requires prettus/l5-repository 4.x (2.x/3.x cap at
illuminate/* ^12). On Laravel 12 either prettus major works, which lets you upgrade this package first and migrate to prettus 4.x at your own pace.
Upgrading with prettus 4.x installed
prettus/l5-repository 4.0 bundles the Prettus\Validator\* classes inside the package itself.
Do not require prettus/laravel-validation alongside l5-repository 4.x — both define the
same Prettus\Validator namespace and composer will report ambiguous class resolution. Remove
prettus/laravel-validation from your app's composer.json when moving to prettus 4.x; no code
changes are needed (Prettus\Validator\LaravelValidator and friends keep the same API).
Installation
composer require gblix/laravel-controller-repository-traits
Register the macro service provider (not auto-discovered) to enable the
paginateNoLimit/paginateAll Eloquent builder macros:
// config/app.php (or bootstrap/providers.php on Laravel 11+) Gblix\ServiceProviders\EloquentMacroServiceProvider::class,
Usage
Controller traits
Six traits under Gblix\Controllers\ApiTraits implement the default REST actions. They expect
the controller to expose a $repository property implementing
Gblix\Repository\Contracts\RepositoryInterface:
use Gblix\Controllers\ApiTraits; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Symfony\Component\HttpFoundation\Response; class UsersController extends Controller { use ApiTraits\Retrieve; // index() use ApiTraits\Read; // getCurrentEntryId() + shared read hooks use ApiTraits\Show; // show() use ApiTraits\Create; // runStore() — you implement store() use ApiTraits\Update; // runUpdate() — you implement update() use ApiTraits\Delete; // destroy() protected UserRepository $repository; public function __construct(UserRepository $repository) { $this->repository = $repository; } public function store(Request $request): Response { return $this->runStore($request, CreateUserAction::class); } public function update(Request $request): Response { return $this->runUpdate($request, UpdateUserAction::class); } }
Create/Update/Delete dispatch a "job" object: Laravel Actions v2 (asController()),
Laravel Actions v1 (actingAs()->run()) and plain classes with run()/handle(array $data)
are all supported.
Index behavior (Retrieve)
index() paginates by default and honors the limit query parameter:
limit |
Result |
|---|---|
| absent | paginate() with the default page size (repository.pagination.limit) |
0 |
paginateNoLimit() — pagination metadata only, empty data |
-1 |
paginateAll() — every record plus pagination metadata |
| any other int | paginate(limit) |
If the repository's model defines scopeFilter, the request input is forwarded to it through
EntityFilterCriteria (a JSON filter query parameter is decoded automatically).
Customization hooks
| Hook | Trait | Purpose |
|---|---|---|
pushIndexCriteria($repository, $request) |
Retrieve | Extra criteria for index |
pushEntityRelations($repository, $request) |
Retrieve | Eager-load relations |
filterRequestToEntityFilter($request, $data) |
Retrieve | Mutate filter data |
willIndexPaginate() |
Retrieve | Return false to disable pagination |
getRetrievePresenter() / getShowPresenter() / getStorePresenter() / getUpdatePresenter() |
each | Per-action presenter override |
pushReadCriteria($repository) |
Read | Criteria shared by show/update/delete |
pushShowCriteria($repository) / pushDestroyCriteria($repository) |
Show / Delete | Per-action criteria |
$routeKey / $resource properties |
Read | Customize how the entry id is read from the route |
Repository
Extend Gblix\Repository\BaseRepository (which extends
Prettus\Repository\Eloquent\BaseRepository):
use Gblix\Repository\BaseRepository; class UserRepository extends BaseRepository { public function model() { return User::class; } public function presenter() { return UserPresenter::class; } public function validator() { return UserValidator::class; } }
Extras on top of prettus: exists($id), cursor(), paginateNoLimit(), paginateAll() and
collectionPresenter() (an optional presenter class used for collections).
Presenter
Extend Gblix\Presenters\FractalPresenter and return a
league/fractal transformer:
use Gblix\Presenters\FractalPresenter; use League\Fractal\TransformerAbstract; class UserPresenter extends FractalPresenter { public function getTransformer(): TransformerAbstract { return new UserTransformer(); } }
Validator
Extend Gblix\Validators\BaseValidator (a Prettus\Validator\LaravelValidator).
passesOrFail() throws Laravel's own Illuminate\Validation\ValidationException, so failures
render as standard 422 responses:
use Gblix\Validators\BaseValidator; use Prettus\Validator\Contracts\ValidatorInterface; class UserValidator extends BaseValidator { protected $rules = [ ValidatorInterface::RULE_CREATE => ['name' => 'required'], ValidatorInterface::RULE_UPDATE => ['name' => 'sometimes|required'], ]; }
Entity filter criteria
Gblix\Repositories\Criteria\EntityFilterCriteria forwards an array to the model's
scopeFilter:
public function scopeFilter(Builder $query, ?array $data): Builder { if (isset($data['name'])) { $query->where('name', 'like', "%{$data['name']}%"); } return $query; }
Testing
All tests run inside Docker — nothing is executed on the host machine. One command runs every supported combination (CI uses the same script):
./scripts/test-all.sh
| Matrix | PHP | Laravel | prettus/l5-repository |
|---|---|---|---|
test-l13 |
8.4 | 13 | 4.x |
test-l12 |
8.3 | 12 | 4.x |
test-l12-prettus2 |
8.3 | 12 | 2.x |
Individual matrices can be run with docker compose run --rm <matrix>. The non-canonical
matrices use isolated composer-<matrix>.json/.lock/vendor-<matrix>/ artifacts
(gitignored) so they never clobber the committed lock file.
Releasing
- Merge to
mastervia pull request (CI runs both matrices). - Tag the release (
git tag 1.8.0 && git push origin 1.8.0). - The
Releaseworkflow re-runs the matrices and creates the GitHub Release; Packagist syncs automatically.