ArrayOf.php
2 months ago
ConnectionOf.php
2 months ago
Deprecated.php
2 months ago
Description.php
2 months ago
Experimental.php
4 weeks ago
HiddenFromMetadataQuery.php
4 weeks ago
Ignore.php
2 months ago
Internal.php
4 weeks ago
Metadata.php
4 weeks ago
Name.php
2 months ago
Parameter.php
2 months ago
ParameterDescription.php
2 months ago
PublicAccess.php
4 weeks ago
RequiredCapability.php
4 weeks ago
ReturnType.php
2 months ago
ScalarType.php
2 months ago
Unroll.php
2 months ago
Metadata.php
108 lines
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Automattic\WooCommerce\Api\Attributes; |
| 6 | |
| 7 | use Attribute; |
| 8 | |
| 9 | /** |
| 10 | * Attaches a name/value metadata entry to a code-API element. |
| 11 | * (class, class property, method parameter, method parameter, or enum case). |
| 12 | * |
| 13 | * Metadata entries are harvested by ApiBuilder and emitted into the generated |
| 14 | * schema, where they can be queried at runtime through the top-level |
| 15 | * `_apiMetadata` GraphQL field. The mechanism is intentionally open: subclass |
| 16 | * this attribute to ship a category of metadata (e.g. {@see Internal} for |
| 17 | * marking elements as for WooCommerce internal use). Tooling discovers metadata |
| 18 | * by name; the value is scalar-only so it can flow through GraphQL without |
| 19 | * additional encoding. |
| 20 | * |
| 21 | * Two metadata entries with the same name on the same element produce a |
| 22 | * build-time error, see ApiBuilder for the duplicate-name detection. Multiple |
| 23 | * distinct names on one element are allowed. |
| 24 | */ |
| 25 | #[Attribute( Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY | Attribute::TARGET_PARAMETER | Attribute::TARGET_CLASS_CONSTANT | Attribute::IS_REPEATABLE )] |
| 26 | class Metadata { |
| 27 | /** |
| 28 | * Constructor. |
| 29 | * |
| 30 | * @param string $name Identifier for this entry. Must be unique per element across all Metadata subclasses applied to it. |
| 31 | * @param bool|int|float|string|null $value Scalar payload exposed to clients via `_apiMetadata`. |
| 32 | */ |
| 33 | public function __construct( |
| 34 | private string $name, |
| 35 | private bool|int|float|string|null $value, |
| 36 | ) { |
| 37 | } |
| 38 | |
| 39 | /** |
| 40 | * The entry's name (e.g. `internal`, `beta`, `owner`). |
| 41 | */ |
| 42 | public function get_name(): string { |
| 43 | return $this->name; |
| 44 | } |
| 45 | |
| 46 | /** |
| 47 | * The entry's scalar value. |
| 48 | */ |
| 49 | public function get_value(): bool|int|float|string|null { |
| 50 | return $this->value; |
| 51 | } |
| 52 | |
| 53 | /** |
| 54 | * Whether the element carrying this attribute should appear in the |
| 55 | * `_apiMetadata` discovery query. |
| 56 | * |
| 57 | * Returning `false` removes the element's row entirely from |
| 58 | * `_apiMetadata` — neither this metadata entry nor any other |
| 59 | * descriptor on the same target surfaces. The runtime gates and any |
| 60 | * description transforms are unaffected. Useful for plugins that |
| 61 | * attach internal routing or feature hints they prefer not to |
| 62 | * broadcast through the discovery channel. |
| 63 | * |
| 64 | * Despite the colloquial naming around it, this has nothing to do |
| 65 | * with native GraphQL introspection (`__schema` / `__type`); those |
| 66 | * queries continue to expose the schema's shape as usual. |
| 67 | * |
| 68 | * Because this is an instance method, subclasses can decide |
| 69 | * conditionally based on their own constructor arguments. |
| 70 | */ |
| 71 | public function shows_in_metadata_query(): bool { |
| 72 | return true; |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Transform the GraphQL `description` of the element this attribute is |
| 77 | * applied to. |
| 78 | * |
| 79 | * The base implementation is a no-op; the general `#[Metadata]` mechanism |
| 80 | * does not modify descriptions. Subclasses opt into the description-mirror |
| 81 | * convention by overriding this method — typically to prefix the input |
| 82 | * with a marker (`[Internal] `, `[Experimental] `, …) and supply a default |
| 83 | * body when the element has no `#[Description]` of its own. |
| 84 | * |
| 85 | * Conventions for overrides: |
| 86 | * - An empty `$description` means the element has no `#[Description]`. |
| 87 | * If the subclass wants the marker to still reach stock introspection, |
| 88 | * it should supply a sensible default text and prefix it as usual. |
| 89 | * - A non-empty `$description` may be either the developer's own text or |
| 90 | * the output of a previous attribute's transform; the subclass should |
| 91 | * not try to distinguish. Wrap-only (prefix the input, don't replace). |
| 92 | * |
| 93 | * When more than one transforming attribute is applied to the same |
| 94 | * element, ApiBuilder calls `transform_description()` once per attribute |
| 95 | * in PHP reflection (source) order, threading each return value into the |
| 96 | * next call. Because each subclass prefixes the input, the last attribute |
| 97 | * in source ends up as the outermost prefix in the final string. Order |
| 98 | * the attributes accordingly when the reading order matters. |
| 99 | * |
| 100 | * @internal Called by ApiBuilder; not part of any caller-visible contract. |
| 101 | * |
| 102 | * @param string $description The current description text (`''` when the element has no `#[Description]`, or the previous transform's output when chained). |
| 103 | */ |
| 104 | public function transform_description( string $description ): string { |
| 105 | return $description; |
| 106 | } |
| 107 | } |
| 108 |