Skip to content

Commit 4b062a4

Browse files
committed
Merge branch '2.11.x' into 3.0.x
* 2.11.x: Bump PHPStan & Psalm (doctrine#9303) Removing list "Lifecycle Events" (doctrine#9243) Drop unneeded backslashes Fix Hidden fields triggering error when using getSingleScalarResult() (doctrine#8340) Findby joined lookup (doctrine#8285)
2 parents d781779 + 133cc95 commit 4b062a4

File tree

9 files changed

+353
-204
lines changed

9 files changed

+353
-204
lines changed

composer.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@
4141
"doctrine/annotations": "^1.13",
4242
"doctrine/coding-standard": "^9.0",
4343
"phpbench/phpbench": "^1.0",
44-
"phpstan/phpstan": "1.2.0",
44+
"phpstan/phpstan": "1.3.0",
4545
"phpunit/phpunit": "^9.5",
4646
"squizlabs/php_codesniffer": "3.6.2",
4747
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
48-
"vimeo/psalm": "4.15.0"
48+
"vimeo/psalm": "4.16.1"
4949
},
5050
"conflict": {
5151
"doctrine/annotations": "<1.13 || >= 2.0"

docs/en/reference/dql-doctrine-query-language.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ clauses:
730730
- ``SQRT(q)`` - Return the square-root of q.
731731
- ``SUBSTRING(str, start [, length])`` - Return substring of given
732732
string.
733-
- ``TRIM([LEADING \| TRAILING \| BOTH] ['trchar' FROM] str)`` - Trim
733+
- ``TRIM([LEADING | TRAILING | BOTH] ['trchar' FROM] str)`` - Trim
734734
the string by the given trim char, defaults to whitespaces.
735735
- ``UPPER(str)`` - Return the upper-case of the given string.
736736
- ``DATE_ADD(date, value, unit)`` - Add the given time to a given date.

docs/en/reference/events.rst

+86-127
Large diffs are not rendered by default.

docs/en/reference/working-with-associations.rst

+2
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,8 @@ For each cascade operation that gets activated, Doctrine also
521521
applies that operation to the association, be it single or
522522
collection valued.
523523

524+
.. _persistence-by-reachability:
525+
524526
Persistence by Reachability: Cascade Persist
525527
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
526528

lib/Doctrine/ORM/Internal/Hydration/SingleScalarHydrator.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ protected function hydrateAllData()
3232
throw new NonUniqueResultException('The query returned multiple rows. Change the query or use a different result function like getScalarResult().');
3333
}
3434

35-
if (count($data[key($data)]) > 1) {
35+
$result = $this->gatherScalarRowData($data[key($data)]);
36+
37+
if (count($result) > 1) {
3638
throw new NonUniqueResultException('The query returned a row containing multiple columns. Change the query or use a different result function like getScalarResult().');
3739
}
3840

39-
$result = $this->gatherScalarRowData($data[key($data)]);
40-
4141
return array_shift($result);
4242
}
4343
}

lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php

+24-19
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
use function array_values;
4040
use function assert;
4141
use function count;
42-
use function get_class;
4342
use function implode;
4443
use function is_array;
4544
use function is_object;
@@ -1932,36 +1931,42 @@ private function getValues($value): array
19321931
return [$newValue];
19331932
}
19341933

1935-
if (is_object($value) && $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
1936-
$class = $this->em->getClassMetadata(get_class($value));
1937-
if ($class->isIdentifierComposite) {
1938-
$newValue = [];
1939-
1940-
foreach ($class->getIdentifierValues($value) as $innerValue) {
1941-
$newValue = array_merge($newValue, $this->getValues($innerValue));
1942-
}
1943-
1944-
return $newValue;
1945-
}
1946-
}
1947-
1948-
return [$this->getIndividualValue($value)];
1934+
return $this->getIndividualValue($value);
19491935
}
19501936

19511937
/**
19521938
* Retrieves an individual parameter value.
19531939
*
19541940
* @param mixed $value
19551941
*
1956-
* @return mixed
1942+
* @return array<mixed>
1943+
* @psalm-return list<mixed>
19571944
*/
19581945
private function getIndividualValue($value)
19591946
{
1960-
if (! is_object($value) || ! $this->em->getMetadataFactory()->hasMetadataFor(ClassUtils::getClass($value))) {
1961-
return $value;
1947+
if (! is_object($value)) {
1948+
return [$value];
1949+
}
1950+
1951+
$valueClass = ClassUtils::getClass($value);
1952+
1953+
if ($this->em->getMetadataFactory()->isTransient($valueClass)) {
1954+
return [$value];
1955+
}
1956+
1957+
$class = $this->em->getClassMetadata($valueClass);
1958+
1959+
if ($class->isIdentifierComposite) {
1960+
$newValue = [];
1961+
1962+
foreach ($class->getIdentifierValues($value) as $innerValue) {
1963+
$newValue = array_merge($newValue, $this->getValues($innerValue));
1964+
}
1965+
1966+
return $newValue;
19621967
}
19631968

1964-
return $this->em->getUnitOfWork()->getSingleIdentifierValue($value);
1969+
return [$this->em->getUnitOfWork()->getSingleIdentifierValue($value)];
19651970
}
19661971

19671972
/**

psalm-baseline.xml

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="v4.15.0@a1b5e489e6fcebe40cb804793d964e99fc347820">
2+
<files psalm-version="4.16.1@aa7e400908833b10c0333861f86cd48c510b60eb">
33
<file src="lib/Doctrine/ORM/AbstractQuery.php">
44
<DeprecatedMethod occurrences="3">
55
<code>getResultCacheDriver</code>
@@ -3073,17 +3073,12 @@
30733073
<RedundantConditionGivenDocblockType occurrences="1"/>
30743074
</file>
30753075
<file src="lib/Doctrine/ORM/Tools/SchemaTool.php">
3076-
<DocblockTypeContradiction occurrences="2">
3077-
<code>! $definingClass</code>
3078-
<code>$definingClass</code>
3079-
</DocblockTypeContradiction>
30803076
<MissingClosureParamType occurrences="1">
30813077
<code>$asset</code>
30823078
</MissingClosureParamType>
3083-
<PossiblyNullArrayAccess occurrences="2">
3084-
<code>$definingClass</code>
3079+
<PossiblyNullArgument occurrences="1">
30853080
<code>$referencedFieldName</code>
3086-
</PossiblyNullArrayAccess>
3081+
</PossiblyNullArgument>
30873082
<PossiblyNullReference occurrences="1">
30883083
<code>getColumns</code>
30893084
</PossiblyNullReference>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\ORM\Functional\Ticket;
6+
7+
use Doctrine\Common\Collections\Collection;
8+
use Doctrine\ORM\Mapping\Column;
9+
use Doctrine\ORM\Mapping\DiscriminatorMap;
10+
use Doctrine\ORM\Mapping\Entity;
11+
use Doctrine\ORM\Mapping\GeneratedValue;
12+
use Doctrine\ORM\Mapping\Id;
13+
use Doctrine\ORM\Mapping\InheritanceType;
14+
use Doctrine\ORM\Mapping\ManyToOne;
15+
use Doctrine\ORM\Mapping\OneToMany;
16+
use Doctrine\Tests\OrmFunctionalTestCase;
17+
18+
class GH7512Test extends OrmFunctionalTestCase
19+
{
20+
protected function setUp(): void
21+
{
22+
parent::setUp();
23+
24+
$this->setUpEntitySchema([
25+
GH7512EntityA::class,
26+
GH7512EntityB::class,
27+
GH7512EntityC::class,
28+
]);
29+
30+
$this->_em->persist(new GH7512EntityA());
31+
$this->_em->persist(new GH7512EntityC());
32+
$this->_em->flush();
33+
$this->_em->clear();
34+
}
35+
36+
public function testFindEntityByAssociationPropertyJoinedChildWithClearMetadata(): void
37+
{
38+
// unset metadata for entity B as though it hasn't been touched yet in application lifecycle.
39+
$this->_em->getMetadataFactory()->setMetadataFor(GH7512EntityB::class, null);
40+
$result = $this->_em->getRepository(GH7512EntityC::class)->findBy([
41+
'entityA' => new GH7512EntityB(),
42+
]);
43+
$this->assertEmpty($result);
44+
}
45+
}
46+
47+
/**
48+
* @Entity()
49+
* @InheritanceType("JOINED")
50+
* @DiscriminatorMap({
51+
* "entitya"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA::class,
52+
* "entityB"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityB::class
53+
* })
54+
*/
55+
class GH7512EntityA
56+
{
57+
/**
58+
* @Column(type="integer")
59+
* @Id()
60+
* @GeneratedValue(strategy="AUTO")
61+
* @var int
62+
*/
63+
public $id;
64+
65+
/**
66+
* @OneToMany(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityC", mappedBy="entityA")
67+
* @var Collection<int, GH7512EntityC>
68+
*/
69+
public $entityCs;
70+
}
71+
72+
/**
73+
* @Entity()
74+
*/
75+
class GH7512EntityB extends GH7512EntityA
76+
{
77+
}
78+
79+
/**
80+
* @Entity()
81+
*/
82+
class GH7512EntityC
83+
{
84+
/**
85+
* @Column(type="integer")
86+
* @Id()
87+
* @GeneratedValue(strategy="AUTO")
88+
* @var int
89+
*/
90+
public $id;
91+
92+
/**
93+
* @ManyToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA", inversedBy="entityCs")
94+
* @var GH7512EntityA
95+
*/
96+
public $entityA;
97+
}

0 commit comments

Comments
 (0)