Parse and validate AT Protocol Lexicons with DTO generation for Laravel
at main 5.2 kB view raw
1<?php 2 3namespace SocialDept\AtpSchema\Generator; 4 5class ConstructorGenerator 6{ 7 /** 8 * Property generator instance. 9 */ 10 protected PropertyGenerator $propertyGenerator; 11 12 /** 13 * Stub renderer instance. 14 */ 15 protected StubRenderer $renderer; 16 17 /** 18 * Create a new ConstructorGenerator. 19 */ 20 public function __construct( 21 ?PropertyGenerator $propertyGenerator = null, 22 ?StubRenderer $renderer = null 23 ) { 24 $this->propertyGenerator = $propertyGenerator ?? new PropertyGenerator(); 25 $this->renderer = $renderer ?? new StubRenderer(); 26 } 27 28 /** 29 * Generate constructor with promoted properties. 30 * 31 * @param array<string, array<string, mixed>> $properties 32 * @param array<string> $required 33 */ 34 public function generate(array $properties, array $required = []): string 35 { 36 if (empty($properties)) { 37 return $this->generateEmpty(); 38 } 39 40 $parameters = $this->generateParameters($properties, $required); 41 $body = $this->generateBody($properties, $required); 42 43 return $this->renderer->render('constructor', [ 44 'docBlock' => $this->generateDocBlock($properties, $required), 45 'parameters' => $parameters, 46 'body' => $body, 47 ]); 48 } 49 50 /** 51 * Generate empty constructor. 52 */ 53 protected function generateEmpty(): string 54 { 55 return ''; 56 } 57 58 /** 59 * Generate constructor parameters. 60 * 61 * @param array<string, array<string, mixed>> $properties 62 * @param array<string> $required 63 */ 64 protected function generateParameters(array $properties, array $required = []): string 65 { 66 $params = []; 67 68 foreach ($properties as $name => $definition) { 69 $promoted = $this->propertyGenerator->generatePromoted($name, $definition, $required); 70 $params[] = ' '.$promoted.','; 71 } 72 73 // Remove trailing comma from last parameter 74 if (! empty($params)) { 75 $params[count($params) - 1] = rtrim($params[count($params) - 1], ','); 76 } 77 78 return implode("\n", $params); 79 } 80 81 /** 82 * Generate constructor body. 83 * 84 * @param array<string, array<string, mixed>> $properties 85 * @param array<string> $required 86 */ 87 protected function generateBody(array $properties, array $required = []): string 88 { 89 // For promoted properties, constructor body is usually empty 90 // But we can add validation or initialization logic here if needed 91 return ''; 92 } 93 94 /** 95 * Generate constructor documentation block. 96 * 97 * @param array<string, array<string, mixed>> $properties 98 * @param array<string> $required 99 */ 100 protected function generateDocBlock(array $properties, array $required = []): string 101 { 102 if (empty($properties)) { 103 return ''; 104 } 105 106 $lines = [' /**']; 107 $lines[] = ' * Create a new instance.'; 108 109 // Add @param tags for each parameter 110 foreach ($properties as $name => $definition) { 111 $docType = $this->propertyGenerator->getDocType( 112 $definition, 113 ! in_array($name, $required) 114 ); 115 $description = $definition['description'] ?? null; 116 117 if ($description) { 118 $lines[] = ' * @param '.$docType.' $'.$name.' '.$description; 119 } else { 120 $lines[] = ' * @param '.$docType.' $'.$name; 121 } 122 } 123 124 $lines[] = ' */'; 125 126 return implode("\n", $lines); 127 } 128 129 /** 130 * Generate constructor with assignments (non-promoted). 131 * 132 * @param array<string, array<string, mixed>> $properties 133 * @param array<string> $required 134 */ 135 public function generateWithAssignments(array $properties, array $required = []): string 136 { 137 if (empty($properties)) { 138 return $this->generateEmpty(); 139 } 140 141 $parameters = []; 142 $assignments = []; 143 144 foreach ($properties as $name => $definition) { 145 $signature = $this->propertyGenerator->generateSignature($name, $definition, $required); 146 $parameters[] = ' '.$signature.','; 147 $assignments[] = ' $this->'.$name.' = $'.$name.';'; 148 } 149 150 // Remove trailing comma from last parameter 151 if (! empty($parameters)) { 152 $parameters[count($parameters) - 1] = rtrim($parameters[count($parameters) - 1], ','); 153 } 154 155 $params = implode("\n", $parameters); 156 $body = implode("\n", $assignments); 157 158 return " /**\n". 159 " * Create a new instance.\n". 160 " */\n". 161 " public function __construct(\n". 162 $params."\n". 163 " ) {\n". 164 $body."\n". 165 ' }'; 166 } 167 168 /** 169 * Check if constructor should be generated. 170 * 171 * @param array<string, array<string, mixed>> $properties 172 */ 173 public function shouldGenerate(array $properties): bool 174 { 175 return ! empty($properties); 176 } 177}