Skip to content

Commit

Permalink
Restore reverse lookup determinism (doctrine#6097)
Browse files Browse the repository at this point in the history
In doctrine#5036, it looks like I wrongly assumed I wouldn't be able to allow
having 2 classes of the same type in the type registry without also
allowing having 2 objects of the same type. `array_search` can perfectly
tell the difference between both situations, so let us continue
forbidding that last part, it will allow us to make sure a given type
matches exactly one name.
  • Loading branch information
greg0ire authored Jul 19, 2023
1 parent 6982657 commit 54ae67d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
25 changes: 25 additions & 0 deletions src/Types/Exception/TypeAlreadyRegistered.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Types\Exception;

use Doctrine\DBAL\Types\Type;
use Exception;

use function get_debug_type;
use function spl_object_hash;
use function sprintf;

/** @psalm-immutable */
final class TypeAlreadyRegistered extends Exception implements TypesException
{
public static function new(Type $type): self
{
return new self(sprintf(
'Type of the class %s@%s is already registered.',
get_debug_type($type),
spl_object_hash($type),
));
}
}
10 changes: 10 additions & 0 deletions src/Types/TypeRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
namespace Doctrine\DBAL\Types;

use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Types\Exception\TypeAlreadyRegistered;
use Doctrine\DBAL\Types\Exception\TypeNotFound;
use Doctrine\DBAL\Types\Exception\TypeNotRegistered;
use Doctrine\DBAL\Types\Exception\TypesAlreadyExists;
use Doctrine\DBAL\Types\Exception\UnknownColumnType;

use function array_search;
use function in_array;

/**
* The type registry is responsible for holding a map of all known DBAL types.
Expand Down Expand Up @@ -71,6 +73,10 @@ public function register(string $name, Type $type): void
throw TypesAlreadyExists::new($name);
}

if (array_search($type, $this->instances, true) !== false) {
throw TypeAlreadyRegistered::new($type);
}

$this->instances[$name] = $type;
}

Expand All @@ -85,6 +91,10 @@ public function override(string $name, Type $type): void
throw TypeNotFound::new($name);
}

if (! in_array(array_search($type, $this->instances, true), [$name, false], true)) {
throw TypeAlreadyRegistered::new($type);
}

$this->instances[$name] = $type;
}

Expand Down
22 changes: 22 additions & 0 deletions tests/Types/Exception/TypeAlreadyRegisteredTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Tests\Types\Exception;

use Doctrine\DBAL\Types\Exception\TypeAlreadyRegistered;
use Doctrine\DBAL\Types\Type;
use PHPUnit\Framework\TestCase;

class TypeAlreadyRegisteredTest extends TestCase
{
public function testNew(): void
{
$exception = TypeAlreadyRegistered::new(Type::getType('string'));

self::assertMatchesRegularExpression(
'/Type of the class Doctrine\\\DBAL\\\Types\\\StringType@([0-9a-zA-Z]+) is already registered./',
$exception->getMessage(),
);
}
}
16 changes: 12 additions & 4 deletions tests/Types/TypeRegistryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,8 @@ public function testRegisterWithAlreadyRegisteredInstance(): void
$newType = new TextType();

$this->registry->register('type1', $newType);
$this->expectException(Exception::class);
$this->registry->register('type2', $newType);
self::assertSame(
$this->registry->get('type1'),
$this->registry->get('type2'),
);
}

public function testOverride(): void
Expand Down Expand Up @@ -129,6 +126,17 @@ public function testOverrideWithUnknownType(): void
$this->registry->override('unknown', new TextType());
}

public function testOverrideWithAlreadyRegisteredInstance(): void
{
$newType = new TextType();

$this->registry->register('first', $newType);
$this->registry->register('second', new StringType());

$this->expectException(Exception::class);
$this->registry->override('second', $newType);
}

public function testGetMap(): void
{
$registeredTypes = $this->registry->getMap();
Expand Down

0 comments on commit 54ae67d

Please sign in to comment.