Skip to content

Commit 6ba1ab2

Browse files
committed
TypeRegistry accepts instances directly
1 parent 8613bad commit 6ba1ab2

File tree

4 files changed

+138
-61
lines changed

4 files changed

+138
-61
lines changed

lib/Doctrine/DBAL/DBALException.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use function is_resource;
1919
use function is_string;
2020
use function json_encode;
21-
use function spl_object_id;
21+
use function spl_object_hash;
2222
use function sprintf;
2323
use function str_split;
2424

@@ -287,6 +287,13 @@ public static function typeNotFound($name)
287287

288288
public static function typeNotRegistered(Type $type) : self
289289
{
290-
return new self(sprintf('Type of the class %s@%d is not registered.', get_class($type), spl_object_id($type)));
290+
return new self(sprintf('Type of the class %s@%s is not registered.', get_class($type), spl_object_hash($type)));
291+
}
292+
293+
public static function typeAlreadyRegistered(Type $type) : self
294+
{
295+
return new self(
296+
sprintf('Type of the class %s@%s is already registered.', get_class($type), spl_object_hash($type))
297+
);
291298
}
292299
}

lib/Doctrine/DBAL/Types/Type.php

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
use Doctrine\DBAL\DBALException;
66
use Doctrine\DBAL\ParameterType;
77
use Doctrine\DBAL\Platforms\AbstractPlatform;
8+
use function array_map;
89
use function end;
910
use function explode;
11+
use function get_class;
1012
use function str_replace;
1113

1214
/**
@@ -77,7 +79,7 @@ abstract class Type
7779
private static $typeRegistry;
7880

7981
/**
80-
* @internal Do not instantiate directly - use the factory method instead.
82+
* @internal Do not instantiate directly - use {@see Type::addType()} method instead.
8183
*/
8284
final public function __construct()
8385
{
@@ -156,7 +158,7 @@ private static function createTypeRegistry() : TypeRegistry
156158
$registry = new TypeRegistry();
157159

158160
foreach (self::BUILTIN_TYPES_MAP as $name => $class) {
159-
$registry->register($name, $class);
161+
$registry->register($name, new $class());
160162
}
161163

162164
return $registry;
@@ -189,7 +191,7 @@ public static function getType($name)
189191
*/
190192
public static function addType($name, $className)
191193
{
192-
self::getTypeRegistry()->register($name, $className);
194+
self::getTypeRegistry()->register($name, new $className());
193195
}
194196

195197
/**
@@ -216,7 +218,7 @@ public static function hasType($name)
216218
*/
217219
public static function overrideType($name, $className)
218220
{
219-
self::getTypeRegistry()->override($name, $className);
221+
self::getTypeRegistry()->override($name, new $className());
220222
}
221223

222224
/**
@@ -240,7 +242,12 @@ public function getBindingType()
240242
*/
241243
public static function getTypesMap()
242244
{
243-
return self::getTypeRegistry()->getTypeClasses();
245+
return array_map(
246+
static function (Type $type) : string {
247+
return get_class($type);
248+
},
249+
self::getTypeRegistry()->all()
250+
);
244251
}
245252

246253
/**

lib/Doctrine/DBAL/Types/TypeRegistry.php

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@
66

77
use Doctrine\DBAL\DBALException;
88
use function array_search;
9+
use function in_array;
910

1011
/**
1112
* @internal
1213
*/
1314
final class TypeRegistry
1415
{
15-
/** @var Type[] Map of already instantiated type objects. One instance per type (flyweight). */
16-
private $typeInstances = [];
17-
18-
/** @var string[] Map of defined types and their classes. */
19-
private $typeClasses = [];
16+
/** @var Type[] Map of already instantiated type objects. */
17+
private $instances = [];
2018

2119
/**
2220
* Factory method to create type instances.
@@ -26,15 +24,11 @@ final class TypeRegistry
2624
*/
2725
public function get(string $name) : Type
2826
{
29-
if (isset($this->typeInstances[$name])) {
30-
return $this->typeInstances[$name];
31-
}
32-
33-
if (isset($this->typeClasses[$name])) {
34-
return $this->typeInstances[$name] = new $this->typeClasses[$name]();
27+
if (! isset($this->instances[$name])) {
28+
throw DBALException::unknownColumnType($name);
3529
}
3630

37-
throw DBALException::unknownColumnType($name);
31+
return $this->instances[$name];
3832
}
3933

4034
/**
@@ -44,9 +38,9 @@ public function get(string $name) : Type
4438
*/
4539
public function lookupName(Type $type) : string
4640
{
47-
$name = array_search($type, $this->typeInstances, true);
41+
$name = $this->findTypeName($type);
4842

49-
if ($name === false) {
43+
if ($name === null) {
5044
throw DBALException::typeNotRegistered($type);
5145
}
5246

@@ -58,50 +52,63 @@ public function lookupName(Type $type) : string
5852
*/
5953
public function has(string $name) : bool
6054
{
61-
return isset($this->typeClasses[$name]);
55+
return isset($this->instances[$name]);
6256
}
6357

6458
/**
6559
* Adds a custom type to the type map.
6660
*
67-
* @param string $name The name of the type. This should correspond to what getName() returns.
68-
* @param string $class The class name of the custom type.
69-
*
7061
* @throws DBALException
7162
*/
72-
public function register(string $name, string $class) : void
63+
public function register(string $name, Type $type) : void
7364
{
74-
if (isset($this->typeClasses[$name])) {
65+
if (isset($this->instances[$name])) {
7566
throw DBALException::typeExists($name);
7667
}
7768

78-
$this->typeClasses[$name] = $class;
69+
if ($this->findTypeName($type) !== null) {
70+
throw DBALException::typeAlreadyRegistered($type);
71+
}
72+
73+
$this->instances[$name] = $type;
7974
}
8075

8176
/**
8277
* Overrides an already defined type to use a different implementation.
8378
*
8479
* @throws DBALException
8580
*/
86-
public function override(string $name, string $class) : void
81+
public function override(string $name, Type $type) : void
8782
{
88-
if (! isset($this->typeClasses[$name])) {
83+
if (! isset($this->instances[$name])) {
8984
throw DBALException::typeNotFound($name);
9085
}
9186

92-
unset($this->typeInstances[$name]);
87+
if (! in_array($this->findTypeName($type), [$name, null], true)) {
88+
throw DBALException::typeAlreadyRegistered($type);
89+
}
9390

94-
$this->typeClasses[$name] = $class;
91+
$this->instances[$name] = $type;
9592
}
9693

9794
/**
98-
* Gets the types array map which holds all registered types and the corresponding
99-
* type class
95+
* Gets the map of all registered types and their corresponding type instances.
10096
*
101-
* @return string[]
97+
* @return Type[]
10298
*/
103-
public function getTypeClasses() : array
99+
public function all() : array
104100
{
105-
return $this->typeClasses;
101+
return $this->instances;
102+
}
103+
104+
private function findTypeName(Type $type) : ?string
105+
{
106+
$name = array_search($type, $this->instances, true);
107+
108+
if ($name === false) {
109+
return null;
110+
}
111+
112+
return $name;
106113
}
107114
}

tests/Doctrine/Tests/DBAL/Types/TypeRegistryTest.php

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,32 @@
1414

1515
class TypeRegistryTest extends TestCase
1616
{
17-
private const TEST_TYPE_NAME = 'test';
18-
private const TEST_TYPE_CLASS = BlobType::class;
19-
private const OTHER_TYPE_NAME = 'other';
20-
private const OTHER_TYPE_CLASS = BinaryType::class;
17+
private const TEST_TYPE_NAME = 'test';
18+
private const OTHER_TEST_TYPE_NAME = 'other';
2119

2220
/** @var TypeRegistry */
2321
private $registry;
2422

23+
/** @var BlobType */
24+
private $testType;
25+
26+
/** @var BinaryType */
27+
private $otherTestType;
28+
2529
protected function setUp() : void
2630
{
31+
$this->testType = new BlobType();
32+
$this->otherTestType = new BinaryType();
33+
2734
$this->registry = new TypeRegistry();
28-
$this->registry->register(self::OTHER_TYPE_NAME, self::OTHER_TYPE_CLASS);
29-
$this->registry->register(self::TEST_TYPE_NAME, self::TEST_TYPE_CLASS);
35+
$this->registry->register(self::TEST_TYPE_NAME, $this->testType);
36+
$this->registry->register(self::OTHER_TEST_TYPE_NAME, $this->otherTestType);
3037
}
3138

3239
public function testGet() : void
3340
{
34-
self::assertInstanceOf(self::TEST_TYPE_CLASS, $this->registry->get(self::TEST_TYPE_NAME));
41+
self::assertSame($this->testType, $this->registry->get(self::TEST_TYPE_NAME));
42+
self::assertSame($this->otherTestType, $this->registry->get(self::OTHER_TEST_TYPE_NAME));
3543

3644
$this->expectException(DBALException::class);
3745
$this->registry->get('unknown');
@@ -49,7 +57,11 @@ public function testLookupName() : void
4957
{
5058
self::assertSame(
5159
self::TEST_TYPE_NAME,
52-
$this->registry->lookupName($this->registry->get(self::TEST_TYPE_NAME))
60+
$this->registry->lookupName($this->testType)
61+
);
62+
self::assertSame(
63+
self::OTHER_TEST_TYPE_NAME,
64+
$this->registry->lookupName($this->otherTestType)
5365
);
5466

5567
$this->expectException(DBALException::class);
@@ -59,40 +71,84 @@ public function testLookupName() : void
5971
public function testHas() : void
6072
{
6173
self::assertTrue($this->registry->has(self::TEST_TYPE_NAME));
74+
self::assertTrue($this->registry->has(self::OTHER_TEST_TYPE_NAME));
6275
self::assertFalse($this->registry->has('unknown'));
6376
}
6477

6578
public function testRegister() : void
6679
{
67-
$this->registry->register('some', TextType::class);
80+
$newType = new TextType();
81+
82+
$this->registry->register('some', $newType);
6883

6984
self::assertTrue($this->registry->has('some'));
70-
self::assertInstanceOf(TextType::class, $this->registry->get('some'));
85+
self::assertSame($newType, $this->registry->get('some'));
86+
}
87+
88+
public function testRegisterWithAlradyRegisteredName() : void
89+
{
90+
$this->registry->register('some', new TextType());
7191

7292
$this->expectException(DBALException::class);
73-
$this->registry->register('some', TextType::class);
93+
$this->registry->register('some', new TextType());
94+
}
95+
96+
public function testRegisterWithAlreadyRegisteredInstance() : void
97+
{
98+
$newType = new TextType();
99+
100+
$this->registry->register('some', $newType);
101+
102+
$this->expectException(DBALException::class);
103+
$this->registry->register('some', $newType);
74104
}
75105

76106
public function testOverride() : void
77107
{
78-
$this->registry->register('some', TextType::class);
79-
$this->registry->override('some', StringType::class);
108+
$baseType = new TextType();
109+
$overrideType = new StringType();
80110

81-
self::assertTrue($this->registry->has('some'));
82-
self::assertInstanceOf(StringType::class, $this->registry->get('some'));
111+
$this->registry->register('some', $baseType);
112+
$this->registry->override('some', $overrideType);
113+
114+
self::assertSame($overrideType, $this->registry->get('some'));
115+
}
116+
117+
public function testOverrideAllowsExistingInstance() : void
118+
{
119+
$type = new TextType();
120+
121+
$this->registry->register('some', $type);
122+
$this->registry->override('some', $type);
123+
124+
self::assertSame($type, $this->registry->get('some'));
125+
}
126+
127+
public function testOverrideWithAlreadyRegisteredInstance() : void
128+
{
129+
$newType = new TextType();
130+
131+
$this->registry->register('first', $newType);
132+
$this->registry->register('second', new StringType());
83133

84134
$this->expectException(DBALException::class);
85-
$this->registry->override('unknown', StringType::class);
135+
$this->registry->override('second', $newType);
86136
}
87137

88-
public function testGetTypeClasses() : void
138+
public function testOverrideWithUnknownType() : void
89139
{
90-
self::assertSame(
91-
[
92-
self::OTHER_TYPE_NAME => self::OTHER_TYPE_CLASS,
93-
self::TEST_TYPE_NAME => self::TEST_TYPE_CLASS,
94-
],
95-
$this->registry->getTypeClasses()
96-
);
140+
$this->expectException(DBALException::class);
141+
$this->registry->override('unknown', new TextType());
142+
}
143+
144+
public function testAll() : void
145+
{
146+
$registeredTypes = $this->registry->all();
147+
148+
self::assertCount(2, $registeredTypes);
149+
self::assertArrayHasKey(self::TEST_TYPE_NAME, $registeredTypes);
150+
self::assertArrayHasKey(self::OTHER_TEST_TYPE_NAME, $registeredTypes);
151+
self::assertSame($this->testType, $registeredTypes[self::TEST_TYPE_NAME]);
152+
self::assertSame($this->otherTestType, $registeredTypes[self::OTHER_TEST_TYPE_NAME]);
97153
}
98154
}

0 commit comments

Comments
 (0)