Parse and validate AT Protocol Lexicons with DTO generation for Laravel
at dev 4.7 kB view raw
1<?php 2 3namespace SocialDept\AtpSchema\Generator; 4 5class PropertyGenerator 6{ 7 /** 8 * Type mapper instance. 9 */ 10 protected TypeMapper $typeMapper; 11 12 /** 13 * Stub renderer instance. 14 */ 15 protected StubRenderer $renderer; 16 17 /** 18 * Create a new PropertyGenerator. 19 */ 20 public function __construct(?TypeMapper $typeMapper = null, ?StubRenderer $renderer = null) 21 { 22 $this->typeMapper = $typeMapper ?? new TypeMapper(); 23 $this->renderer = $renderer ?? new StubRenderer(); 24 } 25 26 /** 27 * Generate a single property. 28 * 29 * @param array<string, mixed> $definition 30 * @param array<string> $required 31 */ 32 public function generate(string $name, array $definition, array $required = []): string 33 { 34 $isRequired = in_array($name, $required); 35 $phpType = $this->typeMapper->toPhpType($definition, ! $isRequired); 36 $docType = $this->typeMapper->toPhpDocType($definition, ! $isRequired); 37 $description = $definition['description'] ?? null; 38 $default = $this->getDefaultValue($definition, $isRequired); 39 40 return $this->renderer->render('property', [ 41 'docBlock' => $this->generateDocBlock($description, $docType), 42 'visibility' => 'public ', 43 'static' => '', 44 'readonly' => 'readonly ', 45 'type' => $phpType, 46 'name' => $name, 47 'default' => $default, 48 ]); 49 } 50 51 /** 52 * Generate multiple properties. 53 * 54 * @param array<string, array<string, mixed>> $properties 55 * @param array<string> $required 56 * @return array<string> 57 */ 58 public function generateMultiple(array $properties, array $required = []): array 59 { 60 $result = []; 61 62 foreach ($properties as $name => $definition) { 63 $result[] = $this->generate($name, $definition, $required); 64 } 65 66 return $result; 67 } 68 69 /** 70 * Generate property documentation block. 71 */ 72 protected function generateDocBlock(?string $description, string $type): string 73 { 74 $lines = ['/**']; 75 76 if ($description) { 77 $lines[] = ' * '.$description; 78 $lines[] = ' *'; 79 } 80 81 $lines[] = ' * @var '.$type; 82 $lines[] = ' */'; 83 84 return implode("\n", $lines); 85 } 86 87 /** 88 * Get default value for property. 89 * 90 * @param array<string, mixed> $definition 91 */ 92 protected function getDefaultValue(array $definition, bool $isRequired): string 93 { 94 if ($isRequired) { 95 return ''; 96 } 97 98 $default = $this->typeMapper->getDefaultValue($definition); 99 100 if ($default !== null) { 101 return ' = '.$default; 102 } 103 104 return ''; 105 } 106 107 /** 108 * Generate property signature (for constructor parameters). 109 * 110 * @param array<string, mixed> $definition 111 * @param array<string> $required 112 */ 113 public function generateSignature(string $name, array $definition, array $required = []): string 114 { 115 $isRequired = in_array($name, $required); 116 $phpType = $this->typeMapper->toPhpType($definition, ! $isRequired); 117 $default = $this->getDefaultValue($definition, $isRequired); 118 119 return $phpType.' $'.$name.$default; 120 } 121 122 /** 123 * Generate promoted property signature (for constructor). 124 * 125 * @param array<string, mixed> $definition 126 * @param array<string> $required 127 */ 128 public function generatePromoted(string $name, array $definition, array $required = []): string 129 { 130 $isRequired = in_array($name, $required); 131 $phpType = $this->typeMapper->toPhpType($definition, ! $isRequired); 132 $default = $this->getDefaultValue($definition, $isRequired); 133 134 return 'public readonly '.$phpType.' $'.$name.$default; 135 } 136 137 /** 138 * Check if property should be nullable. 139 * 140 * @param array<string, mixed> $definition 141 * @param array<string> $required 142 */ 143 public function isNullable(string $name, array $definition, array $required = []): bool 144 { 145 return ! in_array($name, $required); 146 } 147 148 /** 149 * Get property type. 150 * 151 * @param array<string, mixed> $definition 152 */ 153 public function getType(array $definition, bool $nullable = false): string 154 { 155 return $this->typeMapper->toPhpType($definition, $nullable); 156 } 157 158 /** 159 * Get property doc type. 160 * 161 * @param array<string, mixed> $definition 162 */ 163 public function getDocType(array $definition, bool $nullable = false): string 164 { 165 return $this->typeMapper->toPhpDocType($definition, $nullable); 166 } 167}