| 1: | <?php |
| 2: | |
| 3: | namespace LaravelUi5\Core\Attributes; |
| 4: | |
| 5: | use Attribute; |
| 6: | use LaravelUi5\Core\Enums\ParameterSource; |
| 7: | use LaravelUi5\Core\Enums\ValueType; |
| 8: | |
| 9: | /** |
| 10: | * Declarative runtime parameter definition for Parameterizable classes. |
| 11: | * |
| 12: | * Apply this attribute multiple times on a class (Ui5Action, Resource/Data provider, |
| 13: | * Report provider) to describe each expected request parameter. A central |
| 14: | * ParameterResolver will: |
| 15: | * - read all #[Parameter(...)] attributes, |
| 16: | * - extract raw values from the request (path/query/body), |
| 17: | * - cast them according to ParameterType, |
| 18: | * - resolve Eloquent models when type=Model, |
| 19: | * - enforce required/nullable/default semantics, |
| 20: | * - and return an immutable, normalized argument bag. |
| 21: | * |
| 22: | * **Key distinction**: `name` vs. `uriKey` |
| 23: | * - `name` = *logical backend name* |
| 24: | * Used as array key in the resolved argument bag and as identifier in the |
| 25: | * application code (controller, handler, service). |
| 26: | * |
| 27: | * - `uriKey` = *external transport key* |
| 28: | * The concrete identifier used on the communication layer (path segment or |
| 29: | * query string key). This is what the client sends, and what is reflected |
| 30: | * into the manifest. |
| 31: | * |
| 32: | * This separation allows: |
| 33: | * - Stable API contracts even if backend internals are refactored. |
| 34: | * - Aliasing: `uriKey` may differ from `name` (e.g. legacy URL key mapped to |
| 35: | * a cleaner internal parameter name). |
| 36: | * - Explicit, enterprise-grade clarity in manifests and generated clients. |
| 37: | * |
| 38: | * **Path resolution** |
| 39: | * - If you use a catch-all {uri} route, `uriKey` specifies the segment name. |
| 40: | * - The order of #[Parameter(...)] attributes in the source code defines the |
| 41: | * positional order of path parameters. |
| 42: | * |
| 43: | * **Example** |
| 44: | * <code> |
| 45: | * #[Parameter( |
| 46: | * name: 'projectModel', |
| 47: | * uriKey: 'project', |
| 48: | * type: ValueType::Model, |
| 49: | * source: ParameterSource::Path, |
| 50: | * model: Project::class |
| 51: | * ), |
| 52: | * Parameter( |
| 53: | * name: 'withPositions', |
| 54: | * uriKey: 'withPositions', |
| 55: | * type: ValueType::Bool, |
| 56: | * source: ParameterSource::Query, |
| 57: | * required: false, |
| 58: | * default: false |
| 59: | * ) |
| 60: | * ] |
| 61: | * </code> |
| 62: | */ |
| 63: | #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] |
| 64: | class Parameter |
| 65: | { |
| 66: | /** |
| 67: | * @param string $name Logical parameter name (used as array key in the resolved args) |
| 68: | * @param string $uriKey External transport key (path segment or query key, as seen by the client) |
| 69: | * @param ValueType $type Declared runtime type (drives casting/model binding) |
| 70: | * @param ParameterSource $source Where to read from: Path, Query, Body |
| 71: | * @param bool $required If true and no value is provided (after source lookup), the resolver fails (400) |
| 72: | * @param bool $nullable Allow explicit null (distinct from “missing”); if true and null provided, no cast is applied |
| 73: | * @param mixed $default Default used when value is missing and not required |
| 74: | * @param class-string|null $model Eloquent model FQCN; required when $type = ValueType::Model |
| 75: | */ |
| 76: | public function __construct( |
| 77: | public string $name, |
| 78: | public string $uriKey, |
| 79: | public ValueType $type, |
| 80: | public ParameterSource $source = ParameterSource::Path, |
| 81: | public bool $required = true, |
| 82: | public bool $nullable = false, |
| 83: | public mixed $default = null, |
| 84: | public ?string $model = null, |
| 85: | ) {} |
| 86: | } |
| 87: |