1<?php 2 3declare(strict_types=1); 4 5namespace Doctrine\DBAL\Types; 6 7use Doctrine\DBAL\Exception; 8 9use function array_search; 10use function in_array; 11 12/** 13 * The type registry is responsible for holding a map of all known DBAL types. 14 * The types are stored using the flyweight pattern so that one type only exists as exactly one instance. 15 */ 16final class TypeRegistry 17{ 18 /** @var array<string, Type> Map of type names and their corresponding flyweight objects. */ 19 private $instances; 20 21 /** 22 * @param array<string, Type> $instances 23 */ 24 public function __construct(array $instances = []) 25 { 26 $this->instances = $instances; 27 } 28 29 /** 30 * Finds a type by the given name. 31 * 32 * @throws Exception 33 */ 34 public function get(string $name): Type 35 { 36 if (! isset($this->instances[$name])) { 37 throw Exception::unknownColumnType($name); 38 } 39 40 return $this->instances[$name]; 41 } 42 43 /** 44 * Finds a name for the given type. 45 * 46 * @throws Exception 47 */ 48 public function lookupName(Type $type): string 49 { 50 $name = $this->findTypeName($type); 51 52 if ($name === null) { 53 throw Exception::typeNotRegistered($type); 54 } 55 56 return $name; 57 } 58 59 /** 60 * Checks if there is a type of the given name. 61 */ 62 public function has(string $name): bool 63 { 64 return isset($this->instances[$name]); 65 } 66 67 /** 68 * Registers a custom type to the type map. 69 * 70 * @throws Exception 71 */ 72 public function register(string $name, Type $type): void 73 { 74 if (isset($this->instances[$name])) { 75 throw Exception::typeExists($name); 76 } 77 78 if ($this->findTypeName($type) !== null) { 79 throw Exception::typeAlreadyRegistered($type); 80 } 81 82 $this->instances[$name] = $type; 83 } 84 85 /** 86 * Overrides an already defined type to use a different implementation. 87 * 88 * @throws Exception 89 */ 90 public function override(string $name, Type $type): void 91 { 92 if (! isset($this->instances[$name])) { 93 throw Exception::typeNotFound($name); 94 } 95 96 if (! in_array($this->findTypeName($type), [$name, null], true)) { 97 throw Exception::typeAlreadyRegistered($type); 98 } 99 100 $this->instances[$name] = $type; 101 } 102 103 /** 104 * Gets the map of all registered types and their corresponding type instances. 105 * 106 * @internal 107 * 108 * @return array<string, Type> 109 */ 110 public function getMap(): array 111 { 112 return $this->instances; 113 } 114 115 private function findTypeName(Type $type): ?string 116 { 117 $name = array_search($type, $this->instances, true); 118 119 if ($name === false) { 120 return null; 121 } 122 123 return $name; 124 } 125} 126