|
| 1 | +# AI Input Class Generator Prompt |
| 2 | + |
| 3 | +## Universal Prompt for Generating Ray.InputQuery Input Classes |
| 4 | + |
| 5 | +Use this prompt with AI assistants to automatically generate appropriate Input classes from various structured formats (HTML forms, JSON schemas, ALPS profiles, etc.). |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## The Prompt |
| 10 | + |
| 11 | +``` |
| 12 | +You are an expert PHP developer specializing in Ray.InputQuery. Generate Input classes from the provided structured data format. |
| 13 | +
|
| 14 | +## Input Class Design Rules |
| 15 | +
|
| 16 | +1. **Use #[Input] attribute on parameters that come from external data** |
| 17 | +2. **Create separate classes for logical groupings of fields** |
| 18 | +3. **Use readonly properties for immutability** |
| 19 | +4. **Apply proper PHP typing (string, int, bool, array, nullable types)** |
| 20 | +5. **Convert field names to camelCase for property names** |
| 21 | +6. **Group related fields into nested Input objects** |
| 22 | +7. **Use appropriate default values for optional fields** |
| 23 | +8. **Include @psalm-type annotations for complex arrays** |
| 24 | +9. **Add @param documentation for all constructor parameters** |
| 25 | +10. **Use Psalm domain types for precise type constraints** |
| 26 | +
|
| 27 | +## Naming Conventions |
| 28 | +
|
| 29 | +- Class names: PascalCase ending with "Input" (e.g., `UserInput`, `PaymentMethodInput`) |
| 30 | +- Property names: camelCase (e.g., `firstName`, `emailAddress`) |
| 31 | +- Convert snake_case, kebab-case to camelCase |
| 32 | +- Keep semantic meaning clear and concise |
| 33 | +
|
| 34 | +## Structure Guidelines |
| 35 | +
|
| 36 | +- **Flat fields** → Direct properties with #[Input] |
| 37 | +- **Grouped fields** (same prefix/logical group) → Nested Input class |
| 38 | +- **Arrays** → Use `array` type with @psalm-type for typed arrays |
| 39 | +- **Optional fields** → Use nullable types or default values |
| 40 | +- **Validation logic** → Include in constructor if business-rule related |
| 41 | +
|
| 42 | +## Documentation Standards |
| 43 | +
|
| 44 | +- Add comprehensive @param documentation |
| 45 | +- Use @psalm-type for complex array structures |
| 46 | +- Use Psalm domain types for precise constraints (e.g., `positive-int`, `non-empty-string`, `int-range<1,12>`) |
| 47 | +- Include class-level PHPDoc explaining the Input's purpose |
| 48 | +- Document validation rules and constraints |
| 49 | +
|
| 50 | +## Required Information |
| 51 | +
|
| 52 | +**You MUST provide:** |
| 53 | +- **Title**: A clear, descriptive title for what these Input classes represent (e.g., "User Registration Form", "E-commerce Checkout Process", "Blog Post Creation") |
| 54 | +
|
| 55 | +**You MAY provide (if helpful):** |
| 56 | +- **Description**: Additional context about the purpose, business rules, or special requirements for these Input classes |
| 57 | +
|
| 58 | +## Psalm Domain Types Examples |
| 59 | +
|
| 60 | +Use precise Psalm types for better documentation and type safety: |
| 61 | +
|
| 62 | +### Numeric Constraints |
| 63 | +```php |
| 64 | +/** |
| 65 | + * @param positive-int $quantity Product quantity (must be > 0) |
| 66 | + * @param int-range<1,12> $month Month (1-12) |
| 67 | + * @param int-range<1900,2100> $year Year range |
| 68 | + * @param float-range<0.0,100.0> $discountRate Discount percentage (0-100%) |
| 69 | + * @param int-range<0,150> $age Person age |
| 70 | + * @param positive-int $port Network port number |
| 71 | + */ |
| 72 | +``` |
| 73 | + |
| 74 | +### String Constraints |
| 75 | +```php |
| 76 | +/** |
| 77 | + * @param non-empty-string $title Article title (cannot be empty) |
| 78 | + * @param non-empty-string $email Email address |
| 79 | + * @param non-empty-string $password Password (min length handled in constructor) |
| 80 | + * @param lowercase-string $username Username (normalized to lowercase) |
| 81 | + * @param numeric-string $phoneNumber Phone number (digits only) |
| 82 | + */ |
| 83 | +``` |
| 84 | + |
| 85 | +### Array Constraints |
| 86 | +```php |
| 87 | +/** |
| 88 | + * @param non-empty-array<string> $tags At least one tag required |
| 89 | + * @param array<positive-int> $productIds Product IDs (all positive) |
| 90 | + * @param list<non-empty-string> $categories Ordered list of category names |
| 91 | + */ |
| 92 | +``` |
| 93 | + |
| 94 | +### URL and Format Constraints |
| 95 | +```php |
| 96 | +/** |
| 97 | + * @psalm-type EmailAddress = non-empty-string |
| 98 | + * @psalm-type Url = non-empty-string |
| 99 | + * @psalm-type PhoneNumber = numeric-string |
| 100 | + * @psalm-type CountryCode = non-empty-string // Could be more specific: 'US'|'CA'|'JP' |
| 101 | + * @psalm-type CurrencyCode = 'USD'|'EUR'|'JPY'|'GBP' |
| 102 | + * @psalm-type Priority = 'low'|'medium'|'high'|'urgent' |
| 103 | + */ |
| 104 | +``` |
| 105 | + |
| 106 | +## Two-Phase Approach |
| 107 | + |
| 108 | +**Phase 1: Generate a comprehensive flat Input class with all fields** |
| 109 | +**Phase 2: Propose hierarchical refactoring with nested Input classes** |
| 110 | + |
| 111 | +This allows you to see both the complete picture and the organized structure. |
| 112 | + |
| 113 | +## Example Output Format with Psalm Domain Types |
| 114 | + |
| 115 | +```php |
| 116 | +<?php |
| 117 | + |
| 118 | +declare(strict_types=1); |
| 119 | + |
| 120 | +use Ray\InputQuery\Attribute\Input; |
| 121 | + |
| 122 | +/** |
| 123 | + * E-commerce product input data |
| 124 | + * |
| 125 | + * @psalm-type ProductCategory = 'electronics'|'clothing'|'books'|'home' |
| 126 | + * @psalm-type CurrencyCode = 'USD'|'EUR'|'JPY'|'GBP' |
| 127 | + * @psalm-type ProductStatus = 'draft'|'active'|'discontinued' |
| 128 | + */ |
| 129 | +final class ProductInput |
| 130 | +{ |
| 131 | + /** |
| 132 | + * @param non-empty-string $name Product name (required, cannot be empty) |
| 133 | + * @param non-empty-string $sku Product SKU (unique identifier) |
| 134 | + * @param positive-int $quantity Available quantity (must be > 0) |
| 135 | + * @param float $price Product price (positive number) |
| 136 | + * @param CurrencyCode $currency Currency code |
| 137 | + * @param ProductCategory $category Product category |
| 138 | + * @param ProductStatus $status Product status |
| 139 | + * @param int-range<0,100> $discountPercent Discount percentage (0-100%) |
| 140 | + * @param positive-int $weight Weight in grams |
| 141 | + * @param non-empty-array<non-empty-string> $tags Product tags (at least one required) |
| 142 | + */ |
| 143 | + public function __construct( |
| 144 | + #[Input] public readonly string $name, |
| 145 | + #[Input] public readonly string $sku, |
| 146 | + #[Input] public readonly int $quantity, |
| 147 | + #[Input] public readonly float $price, |
| 148 | + #[Input] public readonly string $currency = 'USD', |
| 149 | + #[Input] public readonly string $category = 'electronics', |
| 150 | + #[Input] public readonly string $status = 'draft', |
| 151 | + #[Input] public readonly int $discountPercent = 0, |
| 152 | + #[Input] public readonly int $weight = 1, |
| 153 | + #[Input] public readonly array $tags = ['general'] |
| 154 | + ) { |
| 155 | + if ($this->price <= 0) { |
| 156 | + throw new \InvalidArgumentException('Price must be positive'); |
| 157 | + } |
| 158 | + |
| 159 | + if ($this->quantity <= 0) { |
| 160 | + throw new \InvalidArgumentException('Quantity must be positive'); |
| 161 | + } |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +/** |
| 166 | + * User registration input with precise constraints |
| 167 | + * |
| 168 | + * @psalm-type UserRole = 'user'|'admin'|'moderator' |
| 169 | + * @psalm-type CountryCode = 'US'|'CA'|'JP'|'UK'|'DE'|'FR' |
| 170 | + */ |
| 171 | +final class UserRegistrationInput |
| 172 | +{ |
| 173 | + /** |
| 174 | + * @param non-empty-string $email User's email address |
| 175 | + * @param non-empty-string $password User's password (will be hashed) |
| 176 | + * @param non-empty-string $firstName User's first name |
| 177 | + * @param non-empty-string $lastName User's last name |
| 178 | + * @param int-range<13,120> $age User's age (13-120 years) |
| 179 | + * @param CountryCode $country User's country |
| 180 | + * @param UserRole $role User's role in system |
| 181 | + * @param numeric-string|null $phoneNumber Phone number (digits only, optional) |
| 182 | + */ |
| 183 | + public function __construct( |
| 184 | + #[Input] public readonly string $email, |
| 185 | + #[Input] public readonly string $password, |
| 186 | + #[Input] public readonly string $firstName, |
| 187 | + #[Input] public readonly string $lastName, |
| 188 | + #[Input] public readonly int $age, |
| 189 | + #[Input] public readonly string $country, |
| 190 | + #[Input] public readonly string $role = 'user', |
| 191 | + #[Input] public readonly ?string $phoneNumber = null |
| 192 | + ) { |
| 193 | + if (strlen($this->password) < 8) { |
| 194 | + throw new \InvalidArgumentException('Password must be at least 8 characters'); |
| 195 | + } |
| 196 | + |
| 197 | + if (!filter_var($this->email, FILTER_VALIDATE_EMAIL)) { |
| 198 | + throw new \InvalidArgumentException('Invalid email format'); |
| 199 | + } |
| 200 | + } |
| 201 | +} |
| 202 | +``` |
| 203 | + |
| 204 | +## Real-World Domain Type Examples |
| 205 | + |
| 206 | +### Payment Processing |
| 207 | +```php |
| 208 | +/** |
| 209 | + * @psalm-type CardType = 'visa'|'mastercard'|'amex'|'discover' |
| 210 | + * @psalm-type CurrencyAmount = positive-int // Amount in cents |
| 211 | + * |
| 212 | + * @param non-empty-string $cardNumber Credit card number |
| 213 | + * @param int-range<1,12> $expiryMonth Expiry month (1-12) |
| 214 | + * @param int-range<2024,2040> $expiryYear Expiry year |
| 215 | + * @param int-range<100,9999> $cvv Card verification value |
| 216 | + * @param CurrencyAmount $amount Payment amount in cents |
| 217 | + * @param CardType $cardType Detected card type |
| 218 | + */ |
| 219 | +``` |
| 220 | + |
| 221 | +### Content Management |
| 222 | +```php |
| 223 | +/** |
| 224 | + * @psalm-type ContentStatus = 'draft'|'review'|'published'|'archived' |
| 225 | + * @psalm-type Priority = 'low'|'normal'|'high'|'urgent' |
| 226 | + * |
| 227 | + * @param non-empty-string $title Content title |
| 228 | + * @param non-empty-string $slug URL slug (lowercase, hyphenated) |
| 229 | + * @param ContentStatus $status Publication status |
| 230 | + * @param Priority $priority Content priority |
| 231 | + * @param positive-int $authorId Author's user ID |
| 232 | + * @param non-empty-array<non-empty-string> $tags Content tags |
| 233 | + */ |
| 234 | +``` |
| 235 | + |
| 236 | +### Customer Feedback Form Example |
| 237 | +```php |
| 238 | +/** |
| 239 | + * @psalm-type SatisfactionRating = int-range<1,5> |
| 240 | + * |
| 241 | + * @param non-empty-string|null $customerName 任意の顧客名 |
| 242 | + * @param SatisfactionRating $satisfactionRating 満足度(1〜5) |
| 243 | + * @param non-empty-string $feedbackComment フィードバック内容 |
| 244 | + * @param bool $anonymous 匿名投稿かどうか |
| 245 | + */ |
| 246 | +``` |
| 247 | + |
| 248 | +### API Rate Limiting |
| 249 | +```php |
| 250 | +/** |
| 251 | + * @psalm-type HttpMethod = 'GET'|'POST'|'PUT'|'DELETE'|'PATCH' |
| 252 | + * @psalm-type RateLimit = int-range<1,10000> // Requests per hour |
| 253 | + * |
| 254 | + * @param non-empty-string $apiKey API key |
| 255 | + * @param HttpMethod $method HTTP method |
| 256 | + * @param RateLimit $requestsPerHour Rate limit |
| 257 | + * @param positive-int $retryAfterSeconds Retry delay |
| 258 | + */ |
| 259 | +``` |
| 260 | + |
| 261 | +### Geographic Data |
| 262 | +```php |
| 263 | +/** |
| 264 | + * @psalm-type Latitude = float-range<-90.0,90.0> |
| 265 | + * @psalm-type Longitude = float-range<-180.0,180.0> |
| 266 | + * @psalm-type ZipCode = numeric-string // US ZIP codes |
| 267 | + * |
| 268 | + * @param Latitude $latitude Geographic latitude |
| 269 | + * @param Longitude $longitude Geographic longitude |
| 270 | + * @param ZipCode $zipCode Postal code |
| 271 | + * @param int-range<1,50> $radius Search radius in miles |
| 272 | + */ |
| 273 | +``` |
0 commit comments