Skip to content

Commit c87d1d6

Browse files
authored
Merge pull request #7165 from morozov/collections-in-tables
Use object collections in Table
2 parents 09ee3b1 + 9a8b783 commit c87d1d6

15 files changed

+445
-187
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Collections\Exception;
6+
7+
use Doctrine\DBAL\Schema\Collections\Exception;
8+
use Doctrine\DBAL\Schema\Name;
9+
use LogicException;
10+
11+
use function sprintf;
12+
13+
/** @internal */
14+
final class SetAlreadyContainsName extends LogicException implements Exception
15+
{
16+
public static function new(Name $name): self
17+
{
18+
return new self(sprintf('Set already contains name %s.', $name->toString()));
19+
}
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Collections\Exception;
6+
7+
use Doctrine\DBAL\Schema\Collections\Exception;
8+
use Doctrine\DBAL\Schema\Name;
9+
use LogicException;
10+
11+
use function sprintf;
12+
13+
/** @internal */
14+
final class SetDoesNotContainName extends LogicException implements Exception
15+
{
16+
public static function new(Name $name): self
17+
{
18+
return new self(sprintf('Set does not contain name %s.', $name->toString()));
19+
}
20+
}

src/Schema/Collections/NameSet.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Collections;
6+
7+
use Doctrine\DBAL\Schema\Collections\Exception\SetAlreadyContainsName;
8+
use Doctrine\DBAL\Schema\Collections\Exception\SetDoesNotContainName;
9+
use Doctrine\DBAL\Schema\Name;
10+
use IteratorAggregate;
11+
12+
/**
13+
* A set of unique {@see Name}s.
14+
*
15+
* @internal
16+
*
17+
* @template N of Name
18+
* @template-extends IteratorAggregate<int, N>
19+
*/
20+
interface NameSet extends IteratorAggregate
21+
{
22+
/**
23+
* Returns whether the set contains the given name.
24+
*
25+
* @phpstan-param N $name
26+
*/
27+
public function contains(Name $name): bool;
28+
29+
/**
30+
* Adds the given name to the set.
31+
*
32+
* @phpstan-param N $name
33+
*
34+
* @throws SetAlreadyContainsName If the set already contains the name.
35+
*/
36+
public function add(Name $name): void;
37+
38+
/**
39+
* Removes the given name from the set.
40+
*
41+
* @phpstan-param N $name
42+
*
43+
* @throws SetDoesNotContainName If the set does not contain the name.
44+
*/
45+
public function remove(Name $name): void;
46+
}

src/Schema/Collections/OptionallyUnqualifiedNamedObjectSet.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,39 @@ public function modify(UnqualifiedName $elementName, callable $modification): vo
100100
$this->replace($key, $position, $modification($this->elements[$position]));
101101
}
102102

103+
public function modifyByPosition(int $position, callable $modification): void
104+
{
105+
if (! isset($this->elements[$position])) {
106+
return;
107+
}
108+
109+
$current = $this->elements[$position];
110+
$currentName = $current->getObjectName();
111+
112+
$element = $modification($current);
113+
114+
if ($currentName !== null) {
115+
$oldKey = $this->getKey($currentName);
116+
$this->replace($oldKey, $position, $element);
117+
118+
return;
119+
}
120+
121+
$newName = $element->getObjectName();
122+
if ($newName !== null) {
123+
$newKey = $this->getKey($newName);
124+
125+
if (isset($this->elementPositionsByKey[$newKey])) {
126+
throw ObjectAlreadyExists::new($newName);
127+
}
128+
129+
$this->elementPositionsByKey[$newKey] = $position;
130+
}
131+
132+
// @phpstan-ignore assign.propertyType
133+
$this->elements[$position] = $element;
134+
}
135+
103136
public function clear(): void
104137
{
105138
$this->elements = $this->elementPositionsByKey = [];
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Collections;
6+
7+
use Doctrine\DBAL\Schema\Collections\Exception\SetAlreadyContainsName;
8+
use Doctrine\DBAL\Schema\Collections\Exception\SetDoesNotContainName;
9+
use Doctrine\DBAL\Schema\Name;
10+
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
11+
use Traversable;
12+
13+
use function strtolower;
14+
15+
/**
16+
* A set of unique {@see UnqualifiedName}s
17+
*
18+
* @internal
19+
*
20+
* @template-implements NameSet<UnqualifiedName>
21+
*/
22+
final class UnqualifiedNameSet implements NameSet
23+
{
24+
/** @var array<string, UnqualifiedName> */
25+
private array $elements = [];
26+
27+
public function contains(Name $name): bool
28+
{
29+
$key = $this->getKey($name);
30+
31+
return isset($this->elements[$key]);
32+
}
33+
34+
public function add(Name $name): void
35+
{
36+
$key = $this->getKey($name);
37+
38+
if (isset($this->elements[$key])) {
39+
throw SetAlreadyContainsName::new($name);
40+
}
41+
42+
$this->elements[$key] = $name;
43+
}
44+
45+
public function remove(Name $name): void
46+
{
47+
$key = $this->getKey($name);
48+
49+
if (! isset($this->elements[$key])) {
50+
throw SetDoesNotContainName::new($name);
51+
}
52+
53+
unset($this->elements[$key]);
54+
}
55+
56+
/** @return Traversable<int, UnqualifiedName> */
57+
public function getIterator(): Traversable
58+
{
59+
foreach ($this->elements as $element) {
60+
yield $element;
61+
}
62+
}
63+
64+
/** @param UnqualifiedName $name */
65+
private function getKey(Name $name): string
66+
{
67+
return strtolower($name->getIdentifier()->getValue());
68+
}
69+
}

src/Schema/Collections/UnqualifiedNamedObjectSet.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use function array_combine;
1414
use function array_keys;
15+
use function array_map;
1516
use function array_search;
1617
use function array_values;
1718
use function assert;
@@ -106,6 +107,18 @@ public function getIterator(): Traversable
106107
}
107108
}
108109

110+
/**
111+
* As long as there are mutable implementations of <code>NamedObject<UnqualifiedName></code>, cloning the set will
112+
* require cloning its elements as well.
113+
*/
114+
public function __clone()
115+
{
116+
$this->elements = array_map(
117+
static fn (NamedObject $element): NamedObject => clone $element,
118+
$this->elements,
119+
);
120+
}
121+
109122
/**
110123
* Replaces the element corresponding to the old key with the provided element. The position of the element in the
111124
* set is preserved.

src/Schema/Exception/ForeignKeyAlreadyExists.php

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)