Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/2.17.x' into 2.17.x-merge-up-int…
Browse files Browse the repository at this point in the history
…o-2.18.x_5AQ0zJbx
  • Loading branch information
greg0ire committed Jan 28, 2024
2 parents 020d31e + 82533af commit a9c45a3
Show file tree
Hide file tree
Showing 15 changed files with 176 additions and 132 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
| [3.0.x][3.0] | [2.16.x][2.16] | [2.15.x][2.15] |
| [3.0.x][3.0] | [2.18.x][2.18] | [2.17.x][2.17] |
|:----------------:|:----------------:|:----------:|
| [![Build status][3.0 image]][3.0] | [![Build status][2.16 image]][2.16] | [![Build status][2.15 image]][2.15] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.16 coverage image]][2.16 coverage] | [![Coverage Status][2.15 coverage image]][2.15 coverage] |
| [![Build status][3.0 image]][3.0] | [![Build status][2.18 image]][2.18] | [![Build status][2.17 image]][2.17] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.18 coverage image]][2.18 coverage] | [![Coverage Status][2.17 coverage image]][2.17 coverage] |

[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)

Expand All @@ -22,11 +22,11 @@ without requiring unnecessary code duplication.
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
[2.16 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.16.x
[2.16]: https://github.com/doctrine/orm/tree/2.16.x
[2.16 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.16.x/graph/badge.svg
[2.16 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.16.x
[2.15 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.15.x
[2.15]: https://github.com/doctrine/orm/tree/2.15.x
[2.15 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.15.x/graph/badge.svg
[2.15 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.15.x
[2.18 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.18.x
[2.18]: https://github.com/doctrine/orm/tree/2.18.x
[2.18 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.18.x/graph/badge.svg
[2.18 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.18.x
[2.17 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.17.x
[2.17]: https://github.com/doctrine/orm/tree/2.17.x
[2.17 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.17.x/graph/badge.svg
[2.17 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.17.x
5 changes: 2 additions & 3 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ understand the assumptions we make.
- [DBAL Security Page](https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/security.html)
- [ORM Security Page](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/reference/security.html)

If you find a Security bug in Doctrine, please report it on Jira and change the
Security Level to "Security Issues". It will be visible to Doctrine Core
developers and you only.
If you find a Security bug in Doctrine, please follow our
[Security reporting guidelines](https://www.doctrine-project.org/policies/security.html#reporting).
127 changes: 50 additions & 77 deletions docs/en/cookbook/aggregate-fields.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,71 +36,50 @@ Our entities look like:
namespace Bank\Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
#[ORM\Entity]
class Account
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id;
/**
* @ORM\Column(type="string", unique=true)
*/
private string $no;
/**
* @ORM\OneToMany(targetEntity="Entry", mappedBy="account", cascade={"persist"})
*/
private array $entries;
/**
* @ORM\Column(type="integer")
*/
private int $maxCredit = 0;
public function __construct(string $no, int $maxCredit = 0)
{
$this->no = $no;
$this->maxCredit = $maxCredit;
$this->entries = new \Doctrine\Common\Collections\ArrayCollection();
#[ORM\OneToMany(targetEntity: Entry::class, mappedBy: 'account', cascade: ['persist'])]
private Collection $entries;
public function __construct(
#[ORM\Column(type: 'string', unique: true)]
private string $no,
#[ORM\Column(type: 'integer')]
private int $maxCredit = 0,
) {
$this->entries = new ArrayCollection();
}
}
/**
* @ORM\Entity
*/
#[ORM\Entity]
class Entry
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private ?int $id;
/**
* @ORM\ManyToOne(targetEntity="Account", inversedBy="entries")
*/
private Account $account;
/**
* @ORM\Column(type="integer")
*/
private int $amount;
public function __construct(Account $account, int $amount)
{
$this->account = $account;
$this->amount = $amount;
public function __construct(
#[ORM\ManyToOne(targetEntity: Account::class, inversedBy: 'entries')]
private Account $account,
#[ORM\Column(type: 'integer')]
private int $amount,
) {
// more stuff here, from/to whom, stated reason, execution date and such
}
public function getAmount(): Amount
{
return $this->amount;
Expand Down Expand Up @@ -193,9 +172,8 @@ relation with this method:
public function addEntry(int $amount): void
{
$this->assertAcceptEntryAllowed($amount);
$e = new Entry($this, $amount);
$this->entries[] = $e;
$this->entries[] = new Entry($this, $amount);
}
}
Expand All @@ -213,18 +191,18 @@ Now look at the following test-code for our entities:
{
$account = new Account("123456", maxCredit: 200);
$this->assertEquals(0, $account->getBalance());
$account->addEntry(500);
$this->assertEquals(500, $account->getBalance());
$account->addEntry(-700);
$this->assertEquals(-200, $account->getBalance());
}
public function testExceedMaxLimit()
{
$account = new Account("123456", maxCredit: 200);
$this->expectException(Exception::class);
$account->addEntry(-1000);
}
Expand Down Expand Up @@ -285,22 +263,19 @@ entries collection) we want to add an aggregate field called
<?php
class Account
{
/**
* @ORM\Column(type="integer")
*/
#[ORM\Column(type: 'integer')]
private int $balance = 0;
public function getBalance(): int
{
return $this->balance;
}
public function addEntry(int $amount): void
{
$this->assertAcceptEntryAllowed($amount);
$e = new Entry($this, $amount);
$this->entries[] = $e;
$this->entries[] = new Entry($this, $amount);
$this->balance += $amount;
}
}
Expand Down Expand Up @@ -331,13 +306,13 @@ potentially lead to inconsistent state. See this example:
// The Account $accId has a balance of 0 and a max credit limit of 200:
// request 1 account
$account1 = $em->find(Account::class, $accId);
// request 2 account
$account2 = $em->find(Account::class, $accId);
$account1->addEntry(-200);
$account2->addEntry(-200);
// now request 1 and 2 both flush the changes.
The aggregate field ``Account::$balance`` is now -200, however the
Expand All @@ -357,10 +332,8 @@ Optimistic locking is as easy as adding a version column:
class Account
{
/**
* @ORM\Column(type="integer")
* @ORM\Version
*/
#[ORM\Column(type: 'integer')]
#[ORM\Version]
private int $version;
}
Expand Down
21 changes: 6 additions & 15 deletions docs/en/cookbook/resolve-target-entity-listener.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,8 @@ A Customer entity
use Acme\CustomerModule\Entity\Customer as BaseCustomer;
use Acme\InvoiceModule\Model\InvoiceSubjectInterface;
/**
* @ORM\Entity
* @ORM\Table(name="customer")
*/
#[ORM\Entity]
#[ORM\Table(name: 'customer')]
class Customer extends BaseCustomer implements InvoiceSubjectInterface
{
// In our example, any methods defined in the InvoiceSubjectInterface
Expand All @@ -69,19 +67,12 @@ An Invoice entity
use Doctrine\ORM\Mapping AS ORM;
use Acme\InvoiceModule\Model\InvoiceSubjectInterface;
/**
* Represents an Invoice.
*
* @ORM\Entity
* @ORM\Table(name="invoice")
*/
#[ORM\Entity]
#[ORM\Table(name: 'invoice')]
class Invoice
{
/**
* @ORM\ManyToOne(targetEntity="Acme\InvoiceModule\Model\InvoiceSubjectInterface")
* @var InvoiceSubjectInterface
*/
protected $subject;
#[ORM\ManyToOne(targetEntity: InvoiceSubjectInterface::class)]
protected InvoiceSubjectInterface $subject;
}
An InvoiceSubjectInterface
Expand Down
5 changes: 2 additions & 3 deletions docs/en/reference/security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ page only handles Security issues in the ORM.

- `DBAL Security Page <https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/security.html>`

If you find a Security bug in Doctrine, please report it on Jira and change the
Security Level to "Security Issues". It will be visible to Doctrine Core
developers and you only.
If you find a Security bug in Doctrine, please follow our
`Security reporting guidelines <https://www.doctrine-project.org/policies/security.html#reporting>`_.

User input and Doctrine ORM
---------------------------
Expand Down
2 changes: 2 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
<referencedMethod name="Doctrine\DBAL\Platforms\AbstractPlatform::supportsForeignKeyConstraints"/>
<!-- Remove on 3.0.x -->
<referencedMethod name="Doctrine\DBAL\Connection::getEventManager"/>
<referencedMethod name="Doctrine\DBAL\Platforms\AbstractPlatform::getReadLockSQL"/>
<referencedMethod name="Doctrine\DBAL\Platforms\AbstractPlatform::getWriteLockSQL"/>
<referencedMethod name="Doctrine\DBAL\Schema\Schema::visit"/>
<referencedMethod name="Doctrine\DBAL\Schema\SchemaDiff::toSaveSql"/>
<referencedMethod name="Doctrine\DBAL\Schema\SchemaDiff::toSql"/>
Expand Down
10 changes: 9 additions & 1 deletion src/Mapping/DefaultTypedFieldMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,15 @@ public function validateAndComplete(array $mapping, ReflectionProperty $field):
$mapping['enumType'] = $type->getName();

$reflection = new ReflectionEnum($type->getName());
$type = $reflection->getBackingType();
if (! $reflection->isBacked()) {
throw MappingException::backedEnumTypeRequired(
$field->class,
$mapping['fieldName'],
$mapping['enumType']
);
}

$type = $reflection->getBackingType();

assert($type instanceof ReflectionNamedType);
}
Expand Down
10 changes: 0 additions & 10 deletions src/Mapping/Driver/XmlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Doctrine\ORM\Mapping\Driver;

use Doctrine\Common\Collections\Criteria;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\Mapping\Builder\EntityListenerBuilder;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\MappingException;
Expand Down Expand Up @@ -56,15 +55,6 @@ public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENS
);
}

if (! $isXsdValidationEnabled) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/6728',
'Using XML mapping driver with XSD validation disabled is deprecated'
. ' and will not be supported in Doctrine ORM 3.0.'
);
}

if ($isXsdValidationEnabled && ! extension_loaded('dom')) {
throw new LogicException(
'XSD validation cannot be enabled because the DOM extension is missing.'
Expand Down
10 changes: 10 additions & 0 deletions src/Mapping/MappingException.php
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,16 @@ public static function enumsRequirePhp81(string $className, string $fieldName):
return new self(sprintf('Enum types require PHP 8.1 in %s::$%s', $className, $fieldName));
}

public static function backedEnumTypeRequired(string $className, string $fieldName, string $enumType): self
{
return new self(sprintf(
'Attempting to map a non-backed enum type %s in entity %s::$%s. Please use backed enums only',
$enumType,
$className,
$fieldName
));
}

public static function nonEnumTypeMapped(string $className, string $fieldName, string $enumType): self
{
return new self(sprintf(
Expand Down
2 changes: 1 addition & 1 deletion src/Tools/Pagination/LimitSubqueryOutputWalker.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public function walkSelectStatementWithoutRowNumber(SelectStatement $AST, $addMi
$innerSql
);

// http://www.doctrine-project.org/jira/browse/DDC-1958
// https://github.com/doctrine/orm/issues/2630
$sql = $this->preserveSqlOrdering($sqlIdentifier, $innerSql, $sql, $orderByClause);

// Apply the limit and offset.
Expand Down
22 changes: 22 additions & 0 deletions tests/Tests/Models/Enums/FaultySwitch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\Enums;

use Doctrine\ORM\Mapping\Column;

class FaultySwitch
{
#[Column(type: 'string')]
public string $value;

/**
* The following line is ignored on psalm and phpstan so that we can test
* that the mapping is throwing an exception when a non-backed enum is used.
*
* @psalm-suppress InvalidArgument
*/
#[Column(enumType: SwitchStatus::class)]
public SwitchStatus $status;
}
11 changes: 11 additions & 0 deletions tests/Tests/Models/Enums/SwitchStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Doctrine\Tests\Models\Enums;

enum SwitchStatus
{
case ON;
case OFF;
}

0 comments on commit a9c45a3

Please sign in to comment.