Parse and validate AT Protocol Lexicons with DTO generation for Laravel
at main 5.0 kB view raw
1<?php 2 3namespace SocialDept\AtpSchema\Generator; 4 5use SocialDept\AtpSchema\Exceptions\GenerationException; 6 7class TemplateRenderer 8{ 9 /** 10 * Templates directory. 11 */ 12 protected ?string $templatesDirectory = null; 13 14 /** 15 * In-memory templates. 16 * 17 * @var array<string, string> 18 */ 19 protected array $templates = []; 20 21 /** 22 * Create a new TemplateRenderer. 23 */ 24 public function __construct(?string $templatesDirectory = null) 25 { 26 $this->templatesDirectory = $templatesDirectory; 27 $this->registerDefaultTemplates(); 28 } 29 30 /** 31 * Render a template with given data. 32 */ 33 public function render(string $templateName, array $data): string 34 { 35 $template = $this->getTemplate($templateName); 36 37 return $this->renderTemplate($template, $data); 38 } 39 40 /** 41 * Get template content. 42 */ 43 protected function getTemplate(string $templateName): string 44 { 45 // Check in-memory templates first 46 if (isset($this->templates[$templateName])) { 47 return $this->templates[$templateName]; 48 } 49 50 // Check templates directory 51 if ($this->templatesDirectory !== null) { 52 $path = $this->templatesDirectory.'/'.$templateName.'.php.template'; 53 54 if (file_exists($path)) { 55 return file_get_contents($path); 56 } 57 } 58 59 throw GenerationException::templateNotFound($templateName); 60 } 61 62 /** 63 * Render template with data. 64 */ 65 protected function renderTemplate(string $template, array $data): string 66 { 67 // Simple variable replacement 68 foreach ($data as $key => $value) { 69 if (is_scalar($value) || $value === null) { 70 $template = str_replace("{{{$key}}}", (string) $value, $template); 71 } 72 } 73 74 // Handle property lists 75 if (isset($data['properties']) && is_array($data['properties'])) { 76 $template = $this->renderProperties($template, $data['properties']); 77 } 78 79 return $template; 80 } 81 82 /** 83 * Render properties section. 84 */ 85 protected function renderProperties(string $template, array $properties): string 86 { 87 $propertiesCode = []; 88 89 foreach ($properties as $prop) { 90 $typeHint = $prop['phpType']; 91 $nullable = ! ($prop['required'] ?? true); 92 93 if ($nullable && $typeHint !== 'mixed') { 94 $typeHint = '?'.$typeHint; 95 } 96 97 $docComment = ''; 98 if ($prop['description'] ?? null) { 99 $docComment = " /**\n * {$prop['description']}\n */\n"; 100 } 101 102 $propertiesCode[] = sprintf( 103 '%s public readonly %s $%s;', 104 $docComment, 105 $typeHint, 106 $prop['name'] 107 ); 108 } 109 110 $propertiesString = implode("\n\n", $propertiesCode); 111 112 return str_replace('{{properties}}', $propertiesString, $template); 113 } 114 115 /** 116 * Register default templates. 117 */ 118 protected function registerDefaultTemplates(): void 119 { 120 $this->templates['record'] = <<<'PHP' 121<?php 122 123namespace {{namespace}}; 124 125/** 126 * {{description}} 127 * 128 * NSID: {{nsid}} 129 */ 130class {{className}} 131{ 132{{properties}} 133 134 /** 135 * Create a new {{className}}. 136 */ 137 public function __construct( 138 // Constructor parameters will be generated 139 ) { 140 // Property assignments will be generated 141 } 142 143 /** 144 * Create from array data. 145 */ 146 public static function fromArray(array $data): self 147 { 148 return new self( 149 // Assignments will be generated 150 ); 151 } 152 153 /** 154 * Convert to array. 155 */ 156 public function toArray(): array 157 { 158 return [ 159 // Array conversion will be generated 160 ]; 161 } 162} 163 164PHP; 165 166 $this->templates['object'] = <<<'PHP' 167<?php 168 169namespace {{namespace}}; 170 171/** 172 * {{description}} 173 */ 174class {{className}} 175{ 176{{properties}} 177 178 /** 179 * Create a new {{className}}. 180 */ 181 public function __construct( 182 // Constructor parameters will be generated 183 ) { 184 // Property assignments will be generated 185 } 186 187 /** 188 * Create from array data. 189 */ 190 public static function fromArray(array $data): self 191 { 192 return new self( 193 // Assignments will be generated 194 ); 195 } 196 197 /** 198 * Convert to array. 199 */ 200 public function toArray(): array 201 { 202 return [ 203 // Array conversion will be generated 204 ]; 205 } 206} 207 208PHP; 209 } 210 211 /** 212 * Register a custom template. 213 */ 214 public function registerTemplate(string $name, string $template): void 215 { 216 $this->templates[$name] = $template; 217 } 218 219 /** 220 * Set templates directory. 221 */ 222 public function setTemplatesDirectory(string $directory): void 223 { 224 $this->templatesDirectory = $directory; 225 } 226}