Skip to content

Commit 4a99f86

Browse files
committed
Merge branch '4.3.x' into 5.0.x
2 parents 1cc0f29 + 3b9bc11 commit 4a99f86

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1315
-146
lines changed

UPGRADE.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ all drivers and middleware.
6464

6565
# Upgrade to 4.3
6666

67+
## Deprecated using invalid database object names
68+
69+
Using the following objects with an empty name is deprecated: `Column`, `View`, `Sequence`, `Identifier`.
70+
71+
Using the following objects with a qualified name is deprecated: `Column`, `ForeignKeyConstraint`, `Index`, `Schema`,
72+
`UniqueConstraint`. If the object name contains a dot, the name should be quoted.
73+
74+
Using the following objects with a name that has more than one qualifier is deprecated: `Sequence`, `Table`, `View`.
75+
The name should be unqualified or contain one qualifier.
76+
77+
The `AbstractAsset` class has been marked as internal.
78+
6779
## Deprecated configuration-related `Table` methods
6880

6981
The `Table::setSchemaConfig()` method and `$_schemaConfig` property have been deprecated. Pass a `TableConfiguration`

phpcs.xml.dist

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<!-- see https://github.com/squizlabs/PHP_CodeSniffer/issues/2099 -->
7777
<rule ref="Squiz.Commenting.FunctionComment.InvalidNoReturn">
7878
<exclude-pattern>src/Platforms/AbstractPlatform.php</exclude-pattern>
79+
<exclude-pattern>src/Schema/AbstractAsset.php</exclude-pattern>
7980
<exclude-pattern>src/Schema/AbstractSchemaManager.php</exclude-pattern>
8081
<exclude-pattern>tests/Platforms/AbstractPlatformTestCase.php</exclude-pattern>
8182
</rule>
@@ -128,13 +129,14 @@
128129
<exclude-pattern>src/Driver/SQLSrv/Statement.php</exclude-pattern>
129130
</rule>
130131

131-
<!-- This could be considered a bug in the sniff or the shortcoming of the Platform API design
132+
<!-- False positives caused by the limitation of PHP_CodeSniffer
132133
see https://github.com/squizlabs/PHP_CodeSniffer/issues/3035 -->
133134
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod.Found">
134-
<exclude-pattern>src/Platforms/SQLitePlatform.php</exclude-pattern>
135135
<exclude-pattern>src/Platforms/*/Comparator.php</exclude-pattern>
136136
<exclude-pattern>src/Driver/PDO/SQLSrv/Connection.php</exclude-pattern>
137137
<exclude-pattern>src/Driver/PDO/SQLSrv/Statement.php</exclude-pattern>
138+
<exclude-pattern>src/Schema/AbstractNamedObject.php</exclude-pattern>
139+
<exclude-pattern>src/Schema/Name/UnqualifiedName.php</exclude-pattern>
138140
</rule>
139141

140142
<!-- This issue is likely fixed in Slevomat Coding Standard 8.0.0 -->

psalm.xml.dist

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@
5555

5656
<!-- TODO for PHPUnit 11 -->
5757
<referencedMethod name="PHPUnit\Framework\TestCase::iniSet"/>
58+
59+
<!--
60+
https://github.com/doctrine/dbal/pull/6646
61+
TODO: remove in 5.0.0
62+
-->
63+
<referencedMethod name="Doctrine\DBAL\Schema\AbstractAsset::getNameParser" />
64+
<referencedMethod name="Doctrine\DBAL\Schema\AbstractAsset::setName" />
5865
</errorLevel>
5966
</DeprecatedMethod>
6067
<DocblockTypeContradiction>
@@ -131,6 +138,14 @@
131138
<file name="tests/Driver/PDO/*/DriverTest.php"/>
132139
<file name="tests/Functional/Driver/Mysqli/ConnectionTest.php"/>
133140
<file name="tests/Platforms/AbstractPlatformTestCase.php"/>
141+
142+
<!--
143+
https://github.com/doctrine/dbal/pull/6646
144+
TODO: remove in 5.0.0
145+
146+
This looks like a Psalm bug.
147+
-->
148+
<referencedFunction name="Doctrine\DBAL\Schema\AbstractAsset::setName"/>
134149
</errorLevel>
135150
</InvalidArgument>
136151
<InvalidArrayOffset>
@@ -237,6 +252,21 @@
237252
</PossiblyFalseReference>
238253
<PropertyNotSetInConstructor>
239254
<errorLevel type="suppress">
255+
<!--
256+
https://github.com/doctrine/dbal/pull/6646
257+
TODO: remove in 5.0.0
258+
-->
259+
<referencedProperty name="Doctrine\DBAL\Schema\AbstractAsset::$name"/>
260+
261+
<!--
262+
https://github.com/doctrine/dbal/pull/6646
263+
TODO: remove in 5.0.0
264+
265+
For some reason, referencing the property name doesn't work. Furthermore,
266+
the class doesn't reference the property.
267+
-->
268+
<file name="src/Schema/Table.php"/>
269+
240270
<!-- See https://github.com/psalm/psalm-plugin-phpunit/issues/107 -->
241271
<!-- See https://github.com/sebastianbergmann/phpunit/pull/4610 -->
242272
<directory name="tests"/>

src/Schema/AbstractAsset.php

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
namespace Doctrine\DBAL\Schema;
66

77
use Doctrine\DBAL\Platforms\AbstractPlatform;
8-
use Doctrine\DBAL\Schema\Exception\InvalidObjectName;
8+
use Doctrine\DBAL\Schema\Exception\InvalidName;
9+
use Doctrine\DBAL\Schema\Exception\NotImplemented;
10+
use Doctrine\DBAL\Schema\Name\GenericName;
11+
use Doctrine\DBAL\Schema\Name\Identifier;
12+
use Doctrine\DBAL\Schema\Name\OptionallyQualifiedName;
913
use Doctrine\DBAL\Schema\Name\Parser;
10-
use Doctrine\DBAL\Schema\Name\Parser\Identifier;
14+
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
1115

1216
use function array_map;
1317
use function assert;
@@ -26,11 +30,20 @@
2630
* This encapsulation hack is necessary to keep a consistent state of the database schema. Say we have a list of tables
2731
* array($tableName => Table($tableName)); if you want to rename the table, you have to make sure this does not get
2832
* recreated during schema migration.
33+
*
34+
* @internal This class should be extended only by DBAL itself.
35+
*
36+
* @template N of Name
2937
*/
3038
abstract class AbstractAsset
3139
{
3240
protected string $_name = '';
3341

42+
/**
43+
* Indicates whether the object name has been initialized.
44+
*/
45+
protected bool $isNameInitialized = false;
46+
3447
/**
3548
* Namespace of the asset. If none isset the default namespace is assumed.
3649
*/
@@ -43,16 +56,37 @@ abstract class AbstractAsset
4356

4457
public function __construct(string $name)
4558
{
46-
if ($name === '') {
47-
return;
59+
if ($name !== '') {
60+
try {
61+
$parsedName = $this->getNameParser()->parse($name);
62+
} catch (Parser\Exception $e) {
63+
throw InvalidName::fromParserException($name, $e);
64+
}
65+
} else {
66+
$parsedName = null;
4867
}
4968

50-
$parser = new Parser();
69+
$this->setName($parsedName);
5170

52-
try {
53-
$identifiers = $parser->parse($name);
54-
} catch (Parser\Exception $e) {
55-
throw InvalidObjectName::fromParserException($name, $e);
71+
$this->isNameInitialized = true;
72+
73+
if ($parsedName === null) {
74+
return;
75+
}
76+
77+
if ($parsedName instanceof UnqualifiedName) {
78+
$identifiers = [$parsedName->getIdentifier()];
79+
} elseif ($parsedName instanceof OptionallyQualifiedName) {
80+
$unqualifiedName = $parsedName->getUnqualifiedName();
81+
$qualifier = $parsedName->getQualifier();
82+
83+
$identifiers = $qualifier !== null
84+
? [$qualifier, $unqualifiedName]
85+
: [$unqualifiedName];
86+
} elseif ($parsedName instanceof GenericName) {
87+
$identifiers = $parsedName->getIdentifiers();
88+
} else {
89+
return;
5690
}
5791

5892
$count = count($identifiers);
@@ -70,7 +104,9 @@ public function __construct(string $name)
70104
break;
71105

72106
default:
73-
throw InvalidObjectName::tooManyQualifiers($name, $count - 1);
107+
$namespace = null;
108+
$name = $identifiers[$count - 1];
109+
break;
74110
}
75111

76112
$this->_name = $name->getValue();
@@ -79,6 +115,30 @@ public function __construct(string $name)
79115
$this->identifiers = $identifiers;
80116
}
81117

118+
/**
119+
* Returns a parser for parsing the object name.
120+
*
121+
* @deprecated Parse the name in the constructor instead.
122+
*
123+
* @return Parser<N>
124+
*/
125+
protected function getNameParser(): Parser
126+
{
127+
throw NotImplemented::fromMethod(static::class, __FUNCTION__);
128+
}
129+
130+
/**
131+
* Sets the object name.
132+
*
133+
* @deprecated Set the name in the constructor instead.
134+
*
135+
* @param ?N $name
136+
*/
137+
protected function setName(?Name $name): void
138+
{
139+
throw NotImplemented::fromMethod(static::class, __FUNCTION__);
140+
}
141+
82142
/**
83143
* Is this asset in the default namespace?
84144
*/

src/Schema/AbstractNamedObject.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema;
6+
7+
use Doctrine\DBAL\Schema\Exception\InvalidName;
8+
use Doctrine\DBAL\Schema\Exception\NameIsNotInitialized;
9+
10+
/**
11+
* An abstract {@see NamedObject}.
12+
*
13+
* @template N of Name
14+
* @extends AbstractAsset<N>
15+
* @implements NamedObject<N>
16+
*/
17+
abstract class AbstractNamedObject extends AbstractAsset implements NamedObject
18+
{
19+
/**
20+
* The name of the database object.
21+
*
22+
* Until the validity of the name is enforced, this property isn't guaranteed to be always initialized. The property
23+
* can be accessed only if {@see $isNameInitialized} is set to true.
24+
*
25+
* @var N
26+
*/
27+
protected Name $name;
28+
29+
public function __construct(string $name)
30+
{
31+
parent::__construct($name);
32+
}
33+
34+
/**
35+
* Returns the object name.
36+
*
37+
* @return N
38+
*
39+
* @throws NameIsNotInitialized
40+
*/
41+
public function getObjectName(): Name
42+
{
43+
if (! $this->isNameInitialized) {
44+
throw NameIsNotInitialized::new();
45+
}
46+
47+
return $this->name;
48+
}
49+
50+
protected function setName(?Name $name): void
51+
{
52+
if ($name === null) {
53+
throw InvalidName::fromEmpty();
54+
}
55+
56+
$this->name = $name;
57+
}
58+
}
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;
6+
7+
use Doctrine\DBAL\Schema\Exception\NameIsNotInitialized;
8+
9+
/**
10+
* An abstract {@see OptionallyNamedObject}.
11+
*
12+
* @template N of Name
13+
* @extends AbstractAsset<N>
14+
* @implements OptionallyNamedObject<N>
15+
*/
16+
abstract class AbstractOptionallyNamedObject extends AbstractAsset implements OptionallyNamedObject
17+
{
18+
/**
19+
* The name of the database object.
20+
*
21+
* Until the validity of the name is enforced, this property isn't guaranteed to be always initialized. The property
22+
* can be accessed only if {@see $isNameInitialized} is set to true.
23+
*
24+
* @var ?N
25+
*/
26+
protected ?Name $name;
27+
28+
public function __construct(?string $name)
29+
{
30+
parent::__construct($name ?? '');
31+
}
32+
33+
public function getObjectName(): ?Name
34+
{
35+
if (! $this->isNameInitialized) {
36+
throw NameIsNotInitialized::new();
37+
}
38+
39+
return $this->name;
40+
}
41+
42+
protected function setName(?Name $name): void
43+
{
44+
$this->name = $name;
45+
}
46+
}

src/Schema/Column.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@
55
namespace Doctrine\DBAL\Schema;
66

77
use Doctrine\DBAL\Schema\Exception\UnknownColumnOption;
8+
use Doctrine\DBAL\Schema\Name\Parser\UnqualifiedNameParser;
9+
use Doctrine\DBAL\Schema\Name\Parsers;
10+
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
811
use Doctrine\DBAL\Types\Type;
912

1013
use function array_merge;
1114
use function method_exists;
1215

1316
/**
1417
* Object representation of a database column.
18+
*
19+
* @extends AbstractNamedObject<UnqualifiedName>
1520
*/
16-
class Column extends AbstractAsset
21+
class Column extends AbstractNamedObject
1722
{
1823
protected Type $_type;
1924

@@ -56,6 +61,11 @@ public function __construct(string $name, Type $type, array $options = [])
5661
$this->setOptions($options);
5762
}
5863

64+
protected function getNameParser(): UnqualifiedNameParser
65+
{
66+
return Parsers::getUnqualifiedNameParser();
67+
}
68+
5969
/** @param array<string, mixed> $options */
6070
public function setOptions(array $options): self
6171
{

src/Schema/Exception/IndexNameInvalid.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use function sprintf;
88

99
/** @psalm-immutable */
10-
final class IndexNameInvalid extends InvalidObjectName
10+
final class IndexNameInvalid extends InvalidName
1111
{
1212
public static function new(string $indexName): self
1313
{
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Schema\Exception;
6+
7+
use Doctrine\DBAL\Schema\SchemaException;
8+
use InvalidArgumentException;
9+
10+
/** @psalm-immutable */
11+
final class InvalidIdentifier extends InvalidArgumentException implements SchemaException
12+
{
13+
public static function fromEmpty(): self
14+
{
15+
return new self('Identifier cannot be empty.');
16+
}
17+
}

0 commit comments

Comments
 (0)