Parse and validate AT Protocol Lexicons with DTO generation for Laravel
at dev 2.6 kB view raw
1<?php 2 3namespace SocialDept\AtpSchema\Validation\Rules; 4 5use Closure; 6use Illuminate\Contracts\Validation\ValidationRule; 7 8class AtUri implements ValidationRule 9{ 10 /** 11 * Run the validation rule. 12 */ 13 public function validate(string $attribute, mixed $value, Closure $fail): void 14 { 15 if (! is_string($value)) { 16 $fail("The {$attribute} must be a string."); 17 18 return; 19 } 20 21 if (! $this->isValidAtUri($value)) { 22 $fail("The {$attribute} is not a valid AT URI."); 23 } 24 } 25 26 /** 27 * Validate AT URI format. 28 * 29 * Format: at://did:plc:xyz/collection/rkey 30 * or: at://handle.domain/collection/rkey 31 */ 32 protected function isValidAtUri(string $value): bool 33 { 34 // Must start with at:// 35 if (! str_starts_with($value, 'at://')) { 36 return false; 37 } 38 39 // Remove at:// prefix 40 $remainder = substr($value, 5); 41 42 // Must have at least authority part 43 if (empty($remainder)) { 44 return false; 45 } 46 47 // Split into authority and path 48 $parts = explode('/', $remainder, 2); 49 $authority = $parts[0]; 50 51 // Validate authority (DID or handle) 52 $didRule = new Did(); 53 $handleRule = new Handle(); 54 55 $isValidDid = true; 56 $isValidHandle = true; 57 58 $didRule->validate('authority', $authority, function () use (&$isValidDid) { 59 $isValidDid = false; 60 }); 61 62 $handleRule->validate('authority', $authority, function () use (&$isValidHandle) { 63 $isValidHandle = false; 64 }); 65 66 if (! $isValidDid && ! $isValidHandle) { 67 return false; 68 } 69 70 // If there's a path, validate it 71 if (isset($parts[1]) && ! empty($parts[1])) { 72 // Path should be collection/rkey format 73 $pathParts = explode('/', $parts[1]); 74 75 if (count($pathParts) < 1) { 76 return false; 77 } 78 79 // Each path segment should be valid 80 foreach ($pathParts as $segment) { 81 if (empty($segment) || ! $this->isValidPathSegment($segment)) { 82 return false; 83 } 84 } 85 } 86 87 return true; 88 } 89 90 /** 91 * Check if path segment is valid. 92 */ 93 protected function isValidPathSegment(string $segment): bool 94 { 95 // Path segments should be alphanumeric with dots, hyphens, underscores 96 return (bool) preg_match('/^[a-zA-Z0-9._-]+$/', $segment); 97 } 98}