Parse and validate AT Protocol Lexicons with DTO generation for Laravel
at dev 4.4 kB view raw
1<?php 2 3namespace SocialDept\AtpSchema\Services; 4 5use Illuminate\Support\Traits\Macroable; 6use SocialDept\AtpSchema\Contracts\Transformer; 7use SocialDept\AtpSchema\Exceptions\SchemaException; 8 9class ModelMapper 10{ 11 use Macroable; 12 13 /** 14 * Registered transformers. 15 * 16 * @var array<string, Transformer> 17 */ 18 protected array $transformers = []; 19 20 /** 21 * Register a transformer for a specific type. 22 */ 23 public function register(string $type, Transformer $transformer): self 24 { 25 $this->transformers[$type] = $transformer; 26 27 return $this; 28 } 29 30 /** 31 * Register multiple transformers at once. 32 * 33 * @param array<string, Transformer> $transformers 34 */ 35 public function registerMany(array $transformers): self 36 { 37 foreach ($transformers as $type => $transformer) { 38 $this->register($type, $transformer); 39 } 40 41 return $this; 42 } 43 44 /** 45 * Transform raw data to model. 46 */ 47 public function fromArray(string $type, array $data): mixed 48 { 49 $transformer = $this->getTransformer($type); 50 51 if ($transformer === null) { 52 throw SchemaException::withContext( 53 "No transformer registered for type '{$type}'", 54 ['type' => $type] 55 ); 56 } 57 58 return $transformer->fromArray($data); 59 } 60 61 /** 62 * Transform model to raw data. 63 */ 64 public function toArray(string $type, mixed $model): array 65 { 66 $transformer = $this->getTransformer($type); 67 68 if ($transformer === null) { 69 throw SchemaException::withContext( 70 "No transformer registered for type '{$type}'", 71 ['type' => $type] 72 ); 73 } 74 75 return $transformer->toArray($model); 76 } 77 78 /** 79 * Transform multiple items from arrays. 80 * 81 * @param array<array> $items 82 * @return array<mixed> 83 */ 84 public function fromArrayMany(string $type, array $items): array 85 { 86 return array_map( 87 fn (array $item) => $this->fromArray($type, $item), 88 $items 89 ); 90 } 91 92 /** 93 * Transform multiple items to arrays. 94 * 95 * @param array<mixed> $items 96 * @return array<array> 97 */ 98 public function toArrayMany(string $type, array $items): array 99 { 100 return array_map( 101 fn (mixed $item) => $this->toArray($type, $item), 102 $items 103 ); 104 } 105 106 /** 107 * Get transformer for a specific type. 108 */ 109 public function getTransformer(string $type): ?Transformer 110 { 111 // Check exact match first 112 if (isset($this->transformers[$type])) { 113 return $this->transformers[$type]; 114 } 115 116 // Check if any transformer supports this type 117 foreach ($this->transformers as $transformer) { 118 if ($transformer->supports($type)) { 119 return $transformer; 120 } 121 } 122 123 return null; 124 } 125 126 /** 127 * Check if a transformer is registered for a type. 128 */ 129 public function has(string $type): bool 130 { 131 return $this->getTransformer($type) !== null; 132 } 133 134 /** 135 * Unregister a transformer. 136 */ 137 public function unregister(string $type): self 138 { 139 unset($this->transformers[$type]); 140 141 return $this; 142 } 143 144 /** 145 * Get all registered transformers. 146 * 147 * @return array<string, Transformer> 148 */ 149 public function all(): array 150 { 151 return $this->transformers; 152 } 153 154 /** 155 * Clear all registered transformers. 156 */ 157 public function clear(): self 158 { 159 $this->transformers = []; 160 161 return $this; 162 } 163 164 /** 165 * Try to transform from array, return null if transformer not found. 166 */ 167 public function tryFromArray(string $type, array $data): mixed 168 { 169 if (! $this->has($type)) { 170 return null; 171 } 172 173 return $this->fromArray($type, $data); 174 } 175 176 /** 177 * Try to transform to array, return null if transformer not found. 178 */ 179 public function tryToArray(string $type, mixed $model): ?array 180 { 181 if (! $this->has($type)) { 182 return null; 183 } 184 185 return $this->toArray($type, $model); 186 } 187 188 /** 189 * Get count of registered transformers. 190 */ 191 public function count(): int 192 { 193 return count($this->transformers); 194 } 195}