Skip to content

Commit 34c6f00

Browse files
authored
fix(doctrine): put-create under a slug parent link (#8688)
* test(doctrine): put-create under a slug parent link * fix(doctrine): put-create under a slug parent link * test(doctrine): add the ODM CompanyBadge fixture
1 parent 996c37a commit 34c6f00

5 files changed

Lines changed: 129 additions & 3 deletions

File tree

‎src/Doctrine/Common/State/PersistProcessor.php‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,15 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
102102
$referenceIdentifier = $this->getIdentifierValue($identifiers);
103103
}
104104

105-
$reflectionProperties[$toProperty]->setValue($newData, $parentManager->getReference($fromClass, $referenceIdentifier));
105+
$doctrineIdentifiers = $parentManager->getClassMetadata($fromClass)->getIdentifierFieldNames();
106+
if (!array_diff($identifierProperties, $doctrineIdentifiers) && !array_diff($doctrineIdentifiers, $identifierProperties)) {
107+
$parent = $parentManager->getReference($fromClass, $referenceIdentifier);
108+
} else {
109+
$criteria = $hasCompositeIdentifiers ? $referenceIdentifier : [$identifierProperties[0] => $referenceIdentifier];
110+
$parent = $parentManager->getRepository($fromClass)->findOneBy($criteria);
111+
}
112+
113+
$reflectionProperties[$toProperty]->setValue($newData, $parent);
106114

107115
continue;
108116
}

‎src/Doctrine/Common/Tests/State/PersistProcessorTest.php‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,11 @@ public function testPersistPutCreateResolvesParentLinkViaToProperty(): void
220220
$deviceManagerProphecy->flush()->shouldBeCalled();
221221
$deviceManagerProphecy->refresh($device)->shouldBeCalled();
222222

223+
$userClassMetadata = new ORMClassMetadata(PersistProcessorTestUserStub::class);
224+
$userClassMetadata->identifier = ['id'];
225+
223226
$userManagerProphecy = $this->prophesize(EntityManagerInterface::class);
227+
$userManagerProphecy->getClassMetadata(PersistProcessorTestUserStub::class)->willReturn($userClassMetadata);
224228
$userManagerProphecy->getReference(PersistProcessorTestUserStub::class, 'user-uuid')
225229
->willReturn($userReference)
226230
->shouldBeCalledTimes(1);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\Document;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\Link;
19+
use ApiPlatform\Metadata\Put;
20+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
21+
22+
#[ApiResource]
23+
#[Get(uriTemplate: '/company_badges/{code}')]
24+
#[Put(
25+
uriTemplate: '/companies-by-name/{name}/badges/{code}',
26+
allowCreate: true,
27+
uriVariables: [
28+
'name' => new Link(identifiers: ['name'], fromClass: Company::class, toProperty: 'company'),
29+
'code' => new Link(fromClass: self::class),
30+
],
31+
)]
32+
#[ODM\Document]
33+
class CompanyBadge
34+
{
35+
#[ODM\Id(type: 'string', strategy: 'NONE')]
36+
public string $code;
37+
38+
#[ODM\ReferenceOne(targetDocument: Company::class, storeAs: 'id')]
39+
public ?Company $company = null;
40+
41+
#[ODM\Field]
42+
public string $label;
43+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\Link;
19+
use ApiPlatform\Metadata\Put;
20+
use Doctrine\ORM\Mapping as ORM;
21+
22+
#[ApiResource]
23+
#[Get(uriTemplate: '/company_badges/{code}')]
24+
#[Put(
25+
uriTemplate: '/companies-by-name/{name}/badges/{code}',
26+
allowCreate: true,
27+
uriVariables: [
28+
'name' => new Link(identifiers: ['name'], fromClass: Company::class, toProperty: 'company'),
29+
'code' => new Link(fromClass: self::class),
30+
],
31+
)]
32+
#[ORM\Entity]
33+
class CompanyBadge
34+
{
35+
#[ORM\Id]
36+
#[ORM\Column]
37+
public string $code;
38+
39+
#[ORM\ManyToOne(targetEntity: Company::class)]
40+
public ?Company $company = null;
41+
42+
#[ORM\Column]
43+
public string $label;
44+
}

‎tests/Functional/Parameters/LinkProviderParameterTest.php‎

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue7939FooResource;
2121
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\LinkParameterProviderResource;
2222
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\WithParameter;
23+
use ApiPlatform\Tests\Fixtures\TestBundle\Document\Company as DocumentCompany;
24+
use ApiPlatform\Tests\Fixtures\TestBundle\Document\CompanyBadge as DocumentCompanyBadge;
2325
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Company;
26+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\CompanyBadge;
2427
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy;
2528
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Employee;
2629
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7469Dummy;
@@ -43,15 +46,15 @@ final class LinkProviderParameterTest extends ApiTestCase
4346
*/
4447
public static function getResources(): array
4548
{
46-
return [WithParameter::class, Dummy::class, Employee::class, Company::class, LinkParameterProviderResource::class, Issue7469TestResource::class, Issue7469Dummy::class, Pairing::class, Plan::class, Issue7939FooResource::class, Issue7939BarResource::class, Issue7939BazResource::class];
49+
return [WithParameter::class, Dummy::class, Employee::class, Company::class, CompanyBadge::class, LinkParameterProviderResource::class, Issue7469TestResource::class, Issue7469Dummy::class, Pairing::class, Plan::class, Issue7939FooResource::class, Issue7939BarResource::class, Issue7939BazResource::class];
4750
}
4851

4952
/**
5053
* @throws \Throwable
5154
*/
5255
protected function setUp(): void
5356
{
54-
$this->recreateSchema([Dummy::class, RelatedOwnedDummy::class, RelatedDummy::class, Employee::class, Company::class, Issue7469Dummy::class, Plan::class, Pairing::class]);
57+
$this->recreateSchema([Dummy::class, RelatedOwnedDummy::class, RelatedDummy::class, Employee::class, Company::class, CompanyBadge::class, Issue7469Dummy::class, Plan::class, Pairing::class]);
5558
}
5659

5760
public function testReadDummyProviderFromQueryParameter(): void
@@ -147,6 +150,30 @@ public function testLinkSecurityWithSlug(): void
147150
self::assertResponseStatusCodeSame(200);
148151
}
149152

153+
public function testPutCreateUnderSlugParentLink(): void
154+
{
155+
$companyClass = $this->isMongoDB() ? DocumentCompany::class : Company::class;
156+
$badgeClass = $this->isMongoDB() ? DocumentCompanyBadge::class : CompanyBadge::class;
157+
158+
$manager = $this->getManager();
159+
$company = new $companyClass();
160+
$company->setName('Test');
161+
$manager->persist($company);
162+
$manager->flush();
163+
$companyId = $company->getId();
164+
165+
self::createClient()->request('PUT', '/companies-by-name/Test/badges/gold', [
166+
'headers' => ['Content-Type' => 'application/ld+json'],
167+
'json' => ['label' => 'Gold'],
168+
]);
169+
self::assertResponseStatusCodeSame(201);
170+
171+
$manager->clear();
172+
$badge = $manager->getRepository($badgeClass)->find('gold');
173+
self::assertNotNull($badge);
174+
self::assertSame($companyId, $badge->company->getId());
175+
}
176+
150177
/**
151178
* See https://github.com/api-platform/core/issues/7061.
152179
*/

0 commit comments

Comments
 (0)