Skip to content

Commit 07875f4

Browse files
committed
Deprecate string default expressions
Right now, the ORM handles the conversion of strings that happen to be default expressions for date, time and datetime columns into the corresponding value objects. Let us allow users to specify these value objects directly, and deprecate relying on the aforementioned conversion.
1 parent 6982c8a commit 07875f4

File tree

11 files changed

+398
-8
lines changed

11 files changed

+398
-8
lines changed

UPGRADE.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,87 @@ and directly start using native lazy objects.
2929

3030
# Upgrade to 3.6
3131

32+
## Deprecate using string expression for default values in mappings
33+
34+
Using a string expression for default values in field mappings is deprecated.
35+
Use `Doctrine\DBAL\Schema\DefaultExpression` instances instead.
36+
37+
Here is how to change your attribute mapping:
38+
39+
```diff
40+
use DateTime;
41+
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentDate;
42+
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentTime;
43+
+use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
44+
use Doctrine\ORM\Mapping as ORM;
45+
46+
#[ORM\Entity]
47+
final class TimeEntity
48+
{
49+
#[ORM\Id]
50+
#[ORM\Column]
51+
public int $id;
52+
53+
- #[ORM\Column(options: ['default' => 'CURRENT_TIMESTAMP'], insertable: false, updatable: false)]
54+
+ #[ORM\Column(options: ['default' => new CurrentTimestamp()], insertable: false, updatable: false)]
55+
public DateTime $createdAt;
56+
57+
- #[ORM\Column(options: ['default' => 'CURRENT_TIME'], insertable: false, updatable: false)]
58+
+ #[ORM\Column(options: ['default' => new CurrentTime()], insertable: false, updatable: false)]
59+
public DateTime $createdTime;
60+
61+
- #[ORM\Column(options: ['default' => 'CURRENT_DATE'], insertable: false, updatable: false)]
62+
+ #[ORM\Column(options: ['default' => new CurrentDate()], insertable: false, updatable: false)]
63+
public DateTime $createdDate;
64+
}
65+
```
66+
67+
If you use XMl for your mappings, do this:
68+
69+
```diff
70+
<?xml version="1.0" encoding="UTF-8"?>
71+
72+
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
73+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
74+
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
75+
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
76+
77+
<entity name="Doctrine\Tests\ORM\Functional\XmlTimeEntity">
78+
<id name="id" type="integer" column="id">
79+
<generator strategy="AUTO"/>
80+
</id>
81+
82+
<field name="createdAt" type="datetime" insertable="false" updatable="false">
83+
<options>
84+
- <option name="default">CURRENT_TIMESTAMP</option>
85+
+ <option name="default">Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp</option>
86+
</options>
87+
</field>
88+
89+
<field name="createdAtImmutable" type="datetime_immutable" insertable="false" updatable="false">
90+
<options>
91+
- <option name="default">CURRENT_TIMESTAMP</option>
92+
+ <option name="default">Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp</option>
93+
</options>
94+
</field>
95+
96+
<field name="createdTime" type="time" insertable="false" updatable="false">
97+
<options>
98+
- <option name="default">CURRENT_TIME</option>
99+
+ <option name="default">Doctrine\DBAL\Schema\DefaultExpression\CurrentTime</option>
100+
</options>
101+
</field>
102+
<field name="createdDate" type="date" insertable="false" updatable="false">
103+
<options>
104+
- <option name="default">CURRENT_DATE</option>
105+
+ <option name="default">Doctrine\DBAL\Schema\DefaultExpression\CurrentDate</option>
106+
</options>
107+
</field>
108+
</entity>
109+
</doctrine-mapping>
110+
```
111+
112+
32113
## Deprecate `FieldMapping::$default`
33114

34115
The `default` property of `Doctrine\ORM\Mapping\FieldMapping` is deprecated and

docs/en/reference/basic-mapping.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ PHP class, Doctrine also allows you to specify default values for
190190
database columns using the ``default`` key in the ``options`` array of
191191
the ``Column`` attribute.
192192

193+
When using XML, values that happen to be the FQCN of a class that
194+
implements ``Doctrine\DBAL\Schema\DefaultExpression`` will be translated
195+
into an instance of that class.
196+
193197
.. configuration-block::
194198
.. literalinclude:: basic-mapping/DefaultValues.php
195199
:language: attribute

docs/en/reference/basic-mapping/DefaultValues.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace App\Entity;
66

7+
use DateTime;
8+
use Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp;
79
use Doctrine\ORM\Mapping\Column;
810
use Doctrine\ORM\Mapping\Entity;
911

@@ -12,4 +14,7 @@ class Message
1214
{
1315
#[Column(options: ['default' => 'Hello World!'])]
1416
private string $text;
17+
18+
#[Column(options: ['default' => new CurrentTimestamp()], insertable: false, updatable: false)]
19+
private DateTime $createdAt;
1520
}

docs/en/reference/basic-mapping/default-values.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
<option name="default">Hello World!</option>
66
</options>
77
</field>
8+
<field name="createdAt">
9+
<options>
10+
<option name="default">Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp</option>
11+
</options>
12+
</field>
813
</entity>
914
</doctrine-mapping>

phpstan-baseline.neon

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,13 @@ parameters:
14471447
path: src/Mapping/Driver/XmlDriver.php
14481448

14491449
-
1450-
message: '#^Parameter \#1 \$columnDef of method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:setDiscriminatorColumn\(\) expects array\{name\: string\|null, fieldName\?\: string\|null, type\?\: string\|null, length\?\: int\|null, columnDefinition\?\: string\|null, enumType\?\: class\-string\<BackedEnum\>\|null, options\?\: array\<string, mixed\>\|null\}\|Doctrine\\ORM\\Mapping\\DiscriminatorColumnMapping\|null, array\{name\: string\|null, type\: string, length\: int, columnDefinition\: string\|null, enumType\: string\|null, options\?\: array\<int\|string, array\<int\|string, mixed\>\|bool\|string\>\} given\.$#'
1450+
message: '#^Method Doctrine\\ORM\\Mapping\\Driver\\XmlDriver\:\:parseOptions\(\) has invalid return type Doctrine\\DBAL\\Schema\\DefaultExpression\.$#'
1451+
identifier: class.notFound
1452+
count: 1
1453+
path: src/Mapping/Driver/XmlDriver.php
1454+
1455+
-
1456+
message: '#^Parameter \#1 \$columnDef of method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:setDiscriminatorColumn\(\) expects array\{name\: string\|null, fieldName\?\: string\|null, type\?\: string\|null, length\?\: int\|null, columnDefinition\?\: string\|null, enumType\?\: class\-string\<BackedEnum\>\|null, options\?\: array\<string, mixed\>\|null\}\|Doctrine\\ORM\\Mapping\\DiscriminatorColumnMapping\|null, array\{name\: string\|null, type\: string, length\: int, columnDefinition\: string\|null, enumType\: string\|null, options\?\: array\<int\|string, array\<int\|string, mixed\>\|bool\|Doctrine\\DBAL\\Schema\\DefaultExpression\|string\>\} given\.$#'
14511457
identifier: argument.type
14521458
count: 1
14531459
path: src/Mapping/Driver/XmlDriver.php
@@ -1464,6 +1470,12 @@ parameters:
14641470
count: 1
14651471
path: src/Mapping/Driver/XmlDriver.php
14661472

1473+
-
1474+
message: '#^Parameter \#1 \$object_or_class of function is_a expects object\|string, array\<int\|string, array\<int\|string, mixed\>\|bool\|Doctrine\\DBAL\\Schema\\DefaultExpression\|string\>\|string given\.$#'
1475+
identifier: argument.type
1476+
count: 1
1477+
path: src/Mapping/Driver/XmlDriver.php
1478+
14671479
-
14681480
message: '#^Parameter \#1 \$repositoryClassName of method Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:setCustomRepositoryClass\(\) expects class\-string\<Doctrine\\ORM\\EntityRepository\>\|null, string given\.$#'
14691481
identifier: argument.type
@@ -1477,7 +1489,7 @@ parameters:
14771489
path: src/Mapping/Driver/XmlDriver.php
14781490

14791491
-
1480-
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:\$table \(array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\?\: array\<string, mixed\>, quoted\?\: bool\}\) does not accept array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\: array\<int\|string, array\<int\|string, mixed\>\|bool\|string\>, quoted\?\: bool\}\.$#'
1492+
message: '#^Property Doctrine\\ORM\\Mapping\\ClassMetadata\<T of object\>\:\:\$table \(array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\?\: array\<string, mixed\>, quoted\?\: bool\}\) does not accept array\{name\: string, schema\?\: string, indexes\?\: array, uniqueConstraints\?\: array, options\: array\<int\|string, array\<int\|string, mixed\>\|bool\|Doctrine\\DBAL\\Schema\\DefaultExpression\|string\>, quoted\?\: bool\}\.$#'
14811493
identifier: assign.propertyType
14821494
count: 1
14831495
path: src/Mapping/Driver/XmlDriver.php

src/Mapping/Driver/XmlDriver.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Doctrine\ORM\Mapping\Driver;
66

7+
use Doctrine\DBAL\Schema\DefaultExpression;
78
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
89
use Doctrine\ORM\Mapping\ClassMetadata;
910
use Doctrine\ORM\Mapping\MappingException;
@@ -23,6 +24,7 @@
2324
use function extension_loaded;
2425
use function file_get_contents;
2526
use function in_array;
27+
use function is_a;
2628
use function libxml_clear_errors;
2729
use function libxml_get_errors;
2830
use function libxml_use_internal_errors;
@@ -656,7 +658,7 @@ public function loadMetadataForClass($className, PersistenceClassMetadata $metad
656658
* Parses (nested) option elements.
657659
*
658660
* @return mixed[] The options array.
659-
* @phpstan-return array<int|string, array<int|string, mixed|string>|bool|string>
661+
* @phpstan-return array<int|string, array<int|string, mixed|string>|bool|string|DefaultExpression>
660662
*/
661663
private function parseOptions(SimpleXMLElement|null $options): array
662664
{
@@ -676,6 +678,11 @@ private function parseOptions(SimpleXMLElement|null $options): array
676678
$array[$nameAttribute] = in_array($nameAttribute, ['unsigned', 'fixed'], true)
677679
? $this->evaluateBoolean($value)
678680
: $value;
681+
682+
/** @phpstan-ignore class.notFound */
683+
if ($nameAttribute === 'default' && is_a($value, DefaultExpression::class, true)) {
684+
$array['default'] = new $value();
685+
}
679686
} else {
680687
$array[] = $value;
681688
}

src/Tools/SchemaTool.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Doctrine\DBAL\Schema\Schema;
2424
use Doctrine\DBAL\Schema\Table;
2525
use Doctrine\DBAL\Types\Types;
26+
use Doctrine\Deprecations\Deprecation;
2627
use Doctrine\ORM\EntityManagerInterface;
2728
use Doctrine\ORM\Mapping\AssociationMapping;
2829
use Doctrine\ORM\Mapping\ClassMetadata;
@@ -507,6 +508,16 @@ private function gatherColumn(
507508
], true)
508509
&& $options['default'] === $this->platform->getCurrentTimestampSQL()
509510
) {
511+
Deprecation::trigger(
512+
'doctrine/orm',
513+
'https://github.com/doctrine/orm/issues/12252',
514+
<<<'DEPRECATION'
515+
Using "%s" as a default value for datetime fields is deprecated and
516+
will not be supported in Doctrine ORM 4.0.
517+
Pass a `Doctrine\DBAL\Schema\DefaultExpression\CurrentTimestamp` instance instead.
518+
DEPRECATION,
519+
$this->platform->getCurrentTimestampSQL(),
520+
);
510521
/** @phpstan-ignore class.notFound (if DefaultExpression exists, CurrentTimestamp exists as well) */
511522
$options['default'] = new CurrentTimestamp();
512523
}
@@ -515,6 +526,16 @@ private function gatherColumn(
515526
in_array($mapping->type, [Types::TIME_MUTABLE, Types::TIME_IMMUTABLE], true)
516527
&& $options['default'] === $this->platform->getCurrentTimeSQL()
517528
) {
529+
Deprecation::trigger(
530+
'doctrine/orm',
531+
'https://github.com/doctrine/orm/issues/12252',
532+
<<<'DEPRECATION'
533+
Using "%s" as a default value for time fields is deprecated and
534+
will not be supported in Doctrine ORM 4.0.
535+
Pass a `Doctrine\DBAL\Schema\DefaultExpression\CurrentTime` instance instead.
536+
DEPRECATION,
537+
$this->platform->getCurrentTimeSQL(),
538+
);
518539
/** @phpstan-ignore class.notFound (if DefaultExpression exists, CurrentTime exists as well) */
519540
$options['default'] = new CurrentTime();
520541
}
@@ -523,6 +544,16 @@ private function gatherColumn(
523544
in_array($mapping->type, [Types::DATE_MUTABLE, Types::DATE_IMMUTABLE], true)
524545
&& $options['default'] === $this->platform->getCurrentDateSQL()
525546
) {
547+
Deprecation::trigger(
548+
'doctrine/orm',
549+
'https://github.com/doctrine/orm/issues/12252',
550+
<<<'DEPRECATION'
551+
Using "%s" as a default value for date fields is deprecated and
552+
will not be supported in Doctrine ORM 4.0.
553+
Pass a `Doctrine\DBAL\Schema\DefaultExpression\CurrentDate` instance instead.
554+
DEPRECATION,
555+
$this->platform->getCurrentDateSQL(),
556+
);
526557
/** @phpstan-ignore class.notFound (if DefaultExpression exists, CurrentDate exists as well) */
527558
$options['default'] = new CurrentDate();
528559
}

0 commit comments

Comments
 (0)