Skip to content

Merge 4.3.x up into 5.0.x #6648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ all drivers and middleware.

# Upgrade to 4.3

## Deprecated using invalid database object names

Using the following objects with an empty name is deprecated: `Column`, `View`, `Sequence`, `Identifier`.

Using the following objects with a qualified name is deprecated: `Column`, `ForeignKeyConstraint`, `Index`, `Schema`,
`UniqueConstraint`. If the object name contains a dot, the name should be quoted.

Using the following objects with a name that has more than one qualifier is deprecated: `Sequence`, `Table`, `View`.
The name should be unqualified or contain one qualifier.

The `AbstractAsset` class has been marked as internal.

## Deprecated configuration-related `Table` methods

The `Table::setSchemaConfig()` method and `$_schemaConfig` property have been deprecated. Pass a `TableConfiguration`
Expand Down
6 changes: 4 additions & 2 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
<!-- see https://github.com/squizlabs/PHP_CodeSniffer/issues/2099 -->
<rule ref="Squiz.Commenting.FunctionComment.InvalidNoReturn">
<exclude-pattern>src/Platforms/AbstractPlatform.php</exclude-pattern>
<exclude-pattern>src/Schema/AbstractAsset.php</exclude-pattern>
<exclude-pattern>src/Schema/AbstractSchemaManager.php</exclude-pattern>
<exclude-pattern>tests/Platforms/AbstractPlatformTestCase.php</exclude-pattern>
</rule>
Expand Down Expand Up @@ -128,13 +129,14 @@
<exclude-pattern>src/Driver/SQLSrv/Statement.php</exclude-pattern>
</rule>

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

<!-- This issue is likely fixed in Slevomat Coding Standard 8.0.0 -->
Expand Down
30 changes: 30 additions & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@

<!-- TODO for PHPUnit 11 -->
<referencedMethod name="PHPUnit\Framework\TestCase::iniSet"/>

<!--
https://github.com/doctrine/dbal/pull/6646
TODO: remove in 5.0.0
-->
<referencedMethod name="Doctrine\DBAL\Schema\AbstractAsset::getNameParser" />
<referencedMethod name="Doctrine\DBAL\Schema\AbstractAsset::setName" />
</errorLevel>
</DeprecatedMethod>
<DocblockTypeContradiction>
Expand Down Expand Up @@ -131,6 +138,14 @@
<file name="tests/Driver/PDO/*/DriverTest.php"/>
<file name="tests/Functional/Driver/Mysqli/ConnectionTest.php"/>
<file name="tests/Platforms/AbstractPlatformTestCase.php"/>

<!--
https://github.com/doctrine/dbal/pull/6646
TODO: remove in 5.0.0

This looks like a Psalm bug.
-->
<referencedFunction name="Doctrine\DBAL\Schema\AbstractAsset::setName"/>
</errorLevel>
</InvalidArgument>
<InvalidArrayOffset>
Expand Down Expand Up @@ -237,6 +252,21 @@
</PossiblyFalseReference>
<PropertyNotSetInConstructor>
<errorLevel type="suppress">
<!--
https://github.com/doctrine/dbal/pull/6646
TODO: remove in 5.0.0
-->
<referencedProperty name="Doctrine\DBAL\Schema\AbstractAsset::$name"/>

<!--
https://github.com/doctrine/dbal/pull/6646
TODO: remove in 5.0.0

For some reason, referencing the property name doesn't work. Furthermore,
the class doesn't reference the property.
-->
<file name="src/Schema/Table.php"/>

<!-- See https://github.com/psalm/psalm-plugin-phpunit/issues/107 -->
<!-- See https://github.com/sebastianbergmann/phpunit/pull/4610 -->
<directory name="tests"/>
Expand Down
80 changes: 70 additions & 10 deletions src/Schema/AbstractAsset.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Schema\Exception\InvalidObjectName;
use Doctrine\DBAL\Schema\Exception\InvalidName;
use Doctrine\DBAL\Schema\Exception\NotImplemented;
use Doctrine\DBAL\Schema\Name\GenericName;
use Doctrine\DBAL\Schema\Name\Identifier;
use Doctrine\DBAL\Schema\Name\OptionallyQualifiedName;
use Doctrine\DBAL\Schema\Name\Parser;
use Doctrine\DBAL\Schema\Name\Parser\Identifier;
use Doctrine\DBAL\Schema\Name\UnqualifiedName;

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

/**
* Indicates whether the object name has been initialized.
*/
protected bool $isNameInitialized = false;

/**
* Namespace of the asset. If none isset the default namespace is assumed.
*/
Expand All @@ -43,16 +56,37 @@

public function __construct(string $name)
{
if ($name === '') {
return;
if ($name !== '') {
try {
$parsedName = $this->getNameParser()->parse($name);
} catch (Parser\Exception $e) {
throw InvalidName::fromParserException($name, $e);
}
} else {
$parsedName = null;
}

$parser = new Parser();
$this->setName($parsedName);

try {
$identifiers = $parser->parse($name);
} catch (Parser\Exception $e) {
throw InvalidObjectName::fromParserException($name, $e);
$this->isNameInitialized = true;

if ($parsedName === null) {
return;
}

if ($parsedName instanceof UnqualifiedName) {
$identifiers = [$parsedName->getIdentifier()];
} elseif ($parsedName instanceof OptionallyQualifiedName) {
$unqualifiedName = $parsedName->getUnqualifiedName();
$qualifier = $parsedName->getQualifier();

$identifiers = $qualifier !== null
? [$qualifier, $unqualifiedName]
: [$unqualifiedName];
} elseif ($parsedName instanceof GenericName) {
$identifiers = $parsedName->getIdentifiers();
} else {
return;

Check warning on line 89 in src/Schema/AbstractAsset.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/AbstractAsset.php#L89

Added line #L89 was not covered by tests
}

$count = count($identifiers);
Expand All @@ -70,7 +104,9 @@
break;

default:
throw InvalidObjectName::tooManyQualifiers($name, $count - 1);
$namespace = null;
$name = $identifiers[$count - 1];
break;
}

$this->_name = $name->getValue();
Expand All @@ -79,6 +115,30 @@
$this->identifiers = $identifiers;
}

/**
* Returns a parser for parsing the object name.
*
* @deprecated Parse the name in the constructor instead.
*
* @return Parser<N>
*/
protected function getNameParser(): Parser

Check warning on line 125 in src/Schema/AbstractAsset.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/AbstractAsset.php#L125

Added line #L125 was not covered by tests
{
throw NotImplemented::fromMethod(static::class, __FUNCTION__);

Check warning on line 127 in src/Schema/AbstractAsset.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/AbstractAsset.php#L127

Added line #L127 was not covered by tests
}

/**
* Sets the object name.
*
* @deprecated Set the name in the constructor instead.
*
* @param ?N $name
*/
protected function setName(?Name $name): void

Check warning on line 137 in src/Schema/AbstractAsset.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/AbstractAsset.php#L137

Added line #L137 was not covered by tests
{
throw NotImplemented::fromMethod(static::class, __FUNCTION__);

Check warning on line 139 in src/Schema/AbstractAsset.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/AbstractAsset.php#L139

Added line #L139 was not covered by tests
}

/**
* Is this asset in the default namespace?
*/
Expand Down
58 changes: 58 additions & 0 deletions src/Schema/AbstractNamedObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Schema\Exception\InvalidName;
use Doctrine\DBAL\Schema\Exception\NameIsNotInitialized;

/**
* An abstract {@see NamedObject}.
*
* @template N of Name
* @extends AbstractAsset<N>
* @implements NamedObject<N>
*/
abstract class AbstractNamedObject extends AbstractAsset implements NamedObject
{
/**
* The name of the database object.
*
* Until the validity of the name is enforced, this property isn't guaranteed to be always initialized. The property
* can be accessed only if {@see $isNameInitialized} is set to true.
*
* @var N
*/
protected Name $name;

public function __construct(string $name)
{
parent::__construct($name);
}

/**
* Returns the object name.
*
* @return N
*
* @throws NameIsNotInitialized
*/
public function getObjectName(): Name
{
if (! $this->isNameInitialized) {
throw NameIsNotInitialized::new();

Check warning on line 44 in src/Schema/AbstractNamedObject.php

View check run for this annotation

Codecov / codecov/patch

src/Schema/AbstractNamedObject.php#L44

Added line #L44 was not covered by tests
}

return $this->name;
}

protected function setName(?Name $name): void
{
if ($name === null) {
throw InvalidName::fromEmpty();
}

$this->name = $name;
}
}
46 changes: 46 additions & 0 deletions src/Schema/AbstractOptionallyNamedObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Schema\Exception\NameIsNotInitialized;

/**
* An abstract {@see OptionallyNamedObject}.
*
* @template N of Name
* @extends AbstractAsset<N>
* @implements OptionallyNamedObject<N>
*/
abstract class AbstractOptionallyNamedObject extends AbstractAsset implements OptionallyNamedObject
{
/**
* The name of the database object.
*
* Until the validity of the name is enforced, this property isn't guaranteed to be always initialized. The property
* can be accessed only if {@see $isNameInitialized} is set to true.
*
* @var ?N
*/
protected ?Name $name;

public function __construct(?string $name)
{
parent::__construct($name ?? '');
}

public function getObjectName(): ?Name
{
if (! $this->isNameInitialized) {
throw NameIsNotInitialized::new();
}

return $this->name;
}

protected function setName(?Name $name): void
{
$this->name = $name;
}
}
12 changes: 11 additions & 1 deletion src/Schema/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Schema\Exception\UnknownColumnOption;
use Doctrine\DBAL\Schema\Name\Parser\UnqualifiedNameParser;
use Doctrine\DBAL\Schema\Name\Parsers;
use Doctrine\DBAL\Schema\Name\UnqualifiedName;
use Doctrine\DBAL\Types\Type;

use function array_merge;
use function method_exists;

/**
* Object representation of a database column.
*
* @extends AbstractNamedObject<UnqualifiedName>
*/
class Column extends AbstractAsset
class Column extends AbstractNamedObject
{
protected Type $_type;

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

protected function getNameParser(): UnqualifiedNameParser
{
return Parsers::getUnqualifiedNameParser();
}

/** @param array<string, mixed> $options */
public function setOptions(array $options): self
{
Expand Down
2 changes: 1 addition & 1 deletion src/Schema/Exception/IndexNameInvalid.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use function sprintf;

/** @psalm-immutable */
final class IndexNameInvalid extends InvalidObjectName
final class IndexNameInvalid extends InvalidName
{
public static function new(string $indexName): self
{
Expand Down
17 changes: 17 additions & 0 deletions src/Schema/Exception/InvalidIdentifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Schema\Exception;

use Doctrine\DBAL\Schema\SchemaException;
use InvalidArgumentException;

/** @psalm-immutable */
final class InvalidIdentifier extends InvalidArgumentException implements SchemaException
{
public static function fromEmpty(): self
{
return new self('Identifier cannot be empty.');
}
}
Loading