-
Notifications
You must be signed in to change notification settings - Fork 0
feat(Http): CRUD scaffolding via Resource handlers (theme 1.6, core primitive) #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
8f2f225
feat(Http): CRUD scaffolding via Resource handlers (theme 1.6, core p…
davidwyly e97b5d4
fix(Http\Resource): five review concerns on the CRUD primitive
davidwyly 889a424
fix(Http\Resource): three review concerns on the CRUD primitive
davidwyly 34baeee
feat(ResourceRegistrar): normalize path + validate DTO classes at reg…
Copilot 8794e83
fix(ResourceRegistrar): validate $create/$update unconditionally, not…
Copilot e4938a7
docs: correct Binder binding semantics and test count in docs/comments
Copilot f1e8a45
fix(Resource): search binds from query params only, not body
Copilot 80329ab
fix(Http\Resource): two more review concerns + lock the contract with…
davidwyly File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| <?php declare(strict_types=1); | ||
|
|
||
| namespace Rxn\Framework\Http\Resource; | ||
|
|
||
| use Rxn\Framework\Http\Binding\RequestDto; | ||
|
|
||
| /** | ||
| * Handler shape that `ResourceRegistrar::register()` wires to a | ||
| * five-route URL family. Implement once; get | ||
| * | ||
| * POST /path → create($dto) | ||
| * GET /path → search($filter) | ||
| * GET /path/{id:type} → read($id) | ||
| * PATCH /path/{id:type} → update($id, $dto) | ||
| * DELETE /path/{id:type} → delete($id) | ||
| * | ||
| * for free, with DTO binding + validation + RFC 7807 failure | ||
| * shapes already wired by the registrar. | ||
| * | ||
| * The interface is storage-agnostic. Implementations can use | ||
| * `davidwyly/rxn-orm` (the natural fit — `RxnOrmCrudHandler` | ||
| * abstract class lives there and reduces boilerplate to the | ||
| * point of "extend a class, set TABLE constant, done"), Doctrine, | ||
| * raw PDO, in-memory arrays for tests, or even a remote API | ||
| * gateway. The framework's job is the HTTP layer; storage is the | ||
| * caller's choice. | ||
| * | ||
| * Return-shape contract (so the registrar's wrapping is uniform): | ||
| * | ||
| * - `create()` always returns the created row's representation | ||
| * as an `array<string, mixed>`. The registrar wraps it as | ||
| * 201 + `{data: ..., meta: {status: 201}}`. | ||
| * - `read()` / `update()` return the row's representation, or | ||
| * `null` when no row matches the id. Null becomes 404 | ||
| * Problem Details. | ||
| * - `delete()` returns `true` (the row was deleted, 204 with | ||
| * empty body) or `false` (no such row, 404 Problem Details). | ||
| * - `search()` always returns a list (possibly empty). The | ||
| * registrar wraps it as 200 + `{data: [...]}` — there is no | ||
| * top-level `meta` slot. Pagination metadata (total count, | ||
| * next-page link) is the `Http\Middleware\Pagination` | ||
| * middleware's concern: stack it on the resource's GET | ||
| * route via `$routes->search->middleware(new Pagination(...))` | ||
| * and it adds `X-Total-Count` + RFC 8288 `Link` headers | ||
| * without changing the response body shape. | ||
| * | ||
| * IDs are typed `int|string` — the registrar coerces the URL | ||
| * placeholder according to the `idType` argument it received | ||
| * (`'int'` casts to int; everything else stays string for UUID | ||
| * / slug / opaque-token shapes). | ||
| */ | ||
| interface CrudHandler | ||
| { | ||
| /** | ||
| * Create a new resource from a hydrated + validated DTO. | ||
| * | ||
| * @return array<string, mixed> | ||
| */ | ||
| public function create(RequestDto $dto): array; | ||
|
|
||
| /** | ||
| * Read the resource by id, or `null` when no such resource | ||
| * exists. The registrar turns null into a 404 Problem | ||
| * Details response. | ||
| * | ||
| * @return array<string, mixed>|null | ||
| */ | ||
| public function read(int|string $id): ?array; | ||
|
|
||
| /** | ||
| * Apply a partial update to the resource. Returns the | ||
| * updated row, or `null` when no such id exists. | ||
| * | ||
| * @return array<string, mixed>|null | ||
| */ | ||
| public function update(int|string $id, RequestDto $dto): ?array; | ||
|
|
||
| /** | ||
| * Delete the resource. `true` on success (registrar emits | ||
| * 204), `false` when no such id exists (registrar emits | ||
| * 404). | ||
| */ | ||
| public function delete(int|string $id): bool; | ||
|
|
||
| /** | ||
| * List / filter / search resources. `$filter` is null when | ||
| * no search DTO was registered for this resource — apps | ||
| * that want unfiltered listing can ignore it; apps that | ||
| * registered a filter receive a hydrated + validated DTO. | ||
| * | ||
| * @return list<array<string, mixed>> | ||
| */ | ||
| public function search(?RequestDto $filter): array; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.