Skip to content

Commit b075768

Browse files
authored
Merge pull request #6966 from morozov/more-table-editor-methods
Add more TableEditor methods
2 parents d1fd897 + 907b503 commit b075768

12 files changed

+1990
-36
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Collections;
6+
7+
use Doctrine\DBAL\Schema\SchemaException;
8+
9+
/** @internal */
10+
interface Exception extends SchemaException
11+
{
12+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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\UnqualifiedName;
9+
use LogicException;
10+
11+
use function sprintf;
12+
13+
/** @internal */
14+
final class ObjectAlreadyExists extends LogicException implements Exception
15+
{
16+
public function __construct(string $message, private readonly UnqualifiedName $objectName)
17+
{
18+
parent::__construct($message);
19+
}
20+
21+
public function getObjectName(): UnqualifiedName
22+
{
23+
return $this->objectName;
24+
}
25+
26+
public static function new(UnqualifiedName $objectName): self
27+
{
28+
return new self(sprintf('Object %s already exists.', $objectName->toString()), $objectName);
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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\UnqualifiedName;
9+
use LogicException;
10+
11+
use function sprintf;
12+
13+
/** @internal */
14+
final class ObjectDoesNotExist extends LogicException implements Exception
15+
{
16+
public function __construct(string $message, private readonly UnqualifiedName $objectName)
17+
{
18+
parent::__construct($message);
19+
}
20+
21+
public function getObjectName(): UnqualifiedName
22+
{
23+
return $this->objectName;
24+
}
25+
26+
public static function new(UnqualifiedName $objectName): self
27+
{
28+
return new self(sprintf('Object %s does not exist.', $objectName->toString()), $objectName);
29+
}
30+
}
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\ObjectAlreadyExists;
8+
use Doctrine\DBAL\Schema\Collections\Exception\ObjectDoesNotExist;
9+
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
10+
11+
/**
12+
* A set of objects where each object is uniquely identified by its {@link UnqualifiedName}.
13+
*
14+
* @internal
15+
*
16+
* @template E of object
17+
*/
18+
interface ObjectSet
19+
{
20+
/**
21+
* Checks if the set is empty.
22+
*/
23+
public function isEmpty(): bool;
24+
25+
/**
26+
* Returns the element with the given name. If no such element exists, null is returned.
27+
*
28+
* @phpstan-return E|null
29+
*/
30+
public function get(UnqualifiedName $elementName): ?object;
31+
32+
/**
33+
* Adds the given element to the set.
34+
*
35+
* @phpstan-param E $element
36+
*
37+
* @throws ObjectAlreadyExists If an element with the same name already exists.
38+
*/
39+
public function add(object $element): void;
40+
41+
/**
42+
* Removes the element with the given name from the set.
43+
*
44+
* @throws ObjectDoesNotExist If no element with the given name exists.
45+
*/
46+
public function remove(UnqualifiedName $elementName): void;
47+
48+
/**
49+
* Modifies the element with the given name using the provided callable.
50+
*
51+
* @param callable(E): E $modification
52+
*
53+
* @throws ObjectDoesNotExist If no element with the given name exists.
54+
* @throws ObjectAlreadyExists If an element with the name after modification already exists.
55+
*/
56+
public function modify(UnqualifiedName $elementName, callable $modification): void;
57+
58+
/**
59+
* Clears the set, removing all elements.
60+
*/
61+
public function clear(): void;
62+
63+
/**
64+
* Returns the elements of the set represented as a list.
65+
*
66+
* @phpstan-return list<E>
67+
*/
68+
public function toList(): array;
69+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Collections;
6+
7+
use Doctrine\DBAL\Schema\Collections\Exception\ObjectAlreadyExists;
8+
use Doctrine\DBAL\Schema\Collections\Exception\ObjectDoesNotExist;
9+
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
10+
use Doctrine\DBAL\Schema\OptionallyNamedObject;
11+
12+
use function array_splice;
13+
use function count;
14+
use function strtolower;
15+
16+
/**
17+
* An ordered set of {@link OptionallyNamedObject}s with names being {@link UnqualifiedName}.
18+
*
19+
* New objects are added to the end of the set. The order of elements is preserved during modification.
20+
*
21+
* If an object is unnamed, it can be added to the set but cannot be referenced and, therefore, modified or removed
22+
* from the set. Two unnamed objects are considered as having different names.
23+
*
24+
* @internal
25+
*
26+
* @template E of OptionallyNamedObject<UnqualifiedName>
27+
* @template-implements ObjectSet<E>
28+
*/
29+
final class OptionallyUnqualifiedNamedObjectSet implements ObjectSet
30+
{
31+
/** @var list<E> */
32+
private array $elements = [];
33+
34+
/** @var array<string, int> */
35+
private array $elementPositionsByKey = [];
36+
37+
/** @phpstan-param E ...$elements */
38+
public function __construct(OptionallyNamedObject ...$elements)
39+
{
40+
foreach ($elements as $element) {
41+
$this->add($element);
42+
}
43+
}
44+
45+
public function isEmpty(): bool
46+
{
47+
return count($this->elements) === 0;
48+
}
49+
50+
public function get(UnqualifiedName $elementName): ?OptionallyNamedObject
51+
{
52+
$key = $this->getKey($elementName);
53+
54+
if (isset($this->elementPositionsByKey[$key])) {
55+
return $this->elements[$this->elementPositionsByKey[$key]];
56+
}
57+
58+
return null;
59+
}
60+
61+
public function add(object $element): void
62+
{
63+
$elementName = $element->getObjectName();
64+
65+
if ($elementName !== null) {
66+
$key = $this->getKey($elementName);
67+
68+
if (isset($this->elementPositionsByKey[$key])) {
69+
throw ObjectAlreadyExists::new($elementName);
70+
}
71+
72+
$this->elementPositionsByKey[$key] = count($this->elements);
73+
}
74+
75+
$this->elements[] = $element;
76+
}
77+
78+
public function remove(UnqualifiedName $elementName): void
79+
{
80+
$key = $this->getKey($elementName);
81+
82+
if (! isset($this->elementPositionsByKey[$key])) {
83+
throw ObjectDoesNotExist::new($elementName);
84+
}
85+
86+
$this->removeByKey($key);
87+
}
88+
89+
public function modify(UnqualifiedName $elementName, callable $modification): void
90+
{
91+
$key = $this->getKey($elementName);
92+
93+
if (! isset($this->elementPositionsByKey[$key])) {
94+
throw ObjectDoesNotExist::new($elementName);
95+
}
96+
97+
$position = $this->elementPositionsByKey[$key];
98+
99+
$this->replace($key, $position, $modification($this->elements[$position]));
100+
}
101+
102+
public function clear(): void
103+
{
104+
$this->elements = $this->elementPositionsByKey = [];
105+
}
106+
107+
/** {@inheritDoc} */
108+
public function toList(): array
109+
{
110+
return $this->elements;
111+
}
112+
113+
/**
114+
* Replaces the element corresponding to the old key with the provided element.
115+
*
116+
* @phpstan-param E $element
117+
*
118+
* @throws ObjectAlreadyExists If an element with the same name as the element name already exists.
119+
*/
120+
private function replace(string $oldKey, int $position, OptionallyNamedObject $element): void
121+
{
122+
$elementName = $element->getObjectName();
123+
124+
if ($elementName !== null) {
125+
$newKey = $this->getKey($elementName);
126+
127+
if ($newKey !== $oldKey) {
128+
if (isset($this->elementPositionsByKey[$newKey])) {
129+
throw ObjectAlreadyExists::new($elementName);
130+
}
131+
132+
unset($this->elementPositionsByKey[$oldKey]);
133+
134+
$this->elementPositionsByKey[$newKey] = $position;
135+
}
136+
} else {
137+
unset($this->elementPositionsByKey[$oldKey]);
138+
}
139+
140+
// @phpstan-ignore assign.propertyType
141+
$this->elements[$position] = $element;
142+
}
143+
144+
private function removeByKey(string $key): void
145+
{
146+
$position = $this->elementPositionsByKey[$key];
147+
148+
array_splice($this->elements, $position, 1);
149+
unset($this->elementPositionsByKey[$key]);
150+
151+
foreach ($this->elementPositionsByKey as $elementKey => $elementPosition) {
152+
if ($elementPosition <= $position) {
153+
continue;
154+
}
155+
156+
$this->elementPositionsByKey[$elementKey]--;
157+
}
158+
}
159+
160+
private function getKey(UnqualifiedName $name): string
161+
{
162+
return strtolower($name->getIdentifier()->getValue());
163+
}
164+
}

0 commit comments

Comments
 (0)