| 1: | <?php |
| 2: | |
| 3: | declare(strict_types=1); |
| 4: | |
| 5: | namespace LaravelUi5\OData\Service\Contracts; |
| 6: | |
| 7: | use Illuminate\Http\Request; |
| 8: | use LaravelUi5\OData\Service\ReadContext; |
| 9: | |
| 10: | /** |
| 11: | * The read-authorization forward-exit. |
| 12: | * |
| 13: | * OData is security-agnostic: it ships this seam and a no-op default |
| 14: | * ({@see \LaravelUi5\OData\Service\AllowAllReadAuthorizer}). A host that knows about actors |
| 15: | * and permissions binds its own implementation — via the `odata.read_authorizer` config key |
| 16: | * or by rebinding this interface — and records verdicts into the {@see ReadContext}: |
| 17: | * |
| 18: | * - `denyHard()` on a primary / root target → the controller answers a 403; |
| 19: | * - `denyDrop()` on an `$expand` target → the engine prunes it and emits a `sap-messages` |
| 20: | * warning (the honest-partial model); |
| 21: | * - no verdict / `allow()` → the read proceeds. |
| 22: | * |
| 23: | * The `$plan` is typed as the marker {@see QueryPlanInterface} to respect the |
| 24: | * Service → Protocol ring boundary; an enforcer downcasts to the concrete plan |
| 25: | * (`EntitySetQueryPlan`, `EntityQueryPlan`, …) to read its target set. It must not throw for |
| 26: | * an authorization decision — it records into the collector, and the caller enforces. |
| 27: | */ |
| 28: | interface ReadAuthorizerInterface |
| 29: | { |
| 30: | public function authorize(QueryPlanInterface $plan, Request $request, ReadContext $read): void; |
| 31: | } |
| 32: |