Skip to content

Commit

Permalink
fix(metadata): notexposed no urivariables inheritance (#5765)
Browse files Browse the repository at this point in the history
* fix(metadata): notexposed no urivariables inheritance

* use named arguments

Co-authored-by: Vincent <407859+vincentchalamon@users.noreply.github.com>

* fix tests

---------

Co-authored-by: Vincent <407859+vincentchalamon@users.noreply.github.com>
  • Loading branch information
soyuka and vincentchalamon committed Aug 22, 2023
1 parent e2e59b0 commit 07c9989
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 5 deletions.
8 changes: 8 additions & 0 deletions features/doctrine/issue5722/subresource_without_get.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Feature: Get a subresource from inverse side that has no item operation

@!mongodb
@createSchema
Scenario: Get a subresource from inverse side that has no item operation
Given there are logs on an event
When I send a "GET" request to "/events/03af3507-271e-4cca-8eee-6244fb06e95b/logs"
Then the response status code should be 200
9 changes: 5 additions & 4 deletions src/Api/IdentifiersExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ private function getIdentifiersFromOperation(object $item, Operation $operation,
}

$identifiers = [];
foreach ($links ?? [] as $link) {
if (1 < (is_countable($link->getIdentifiers()) ? \count($link->getIdentifiers()) : 0)) {
foreach ($links ?? [] as $k => $link) {
$linkIdentifiers = $link->getIdentifiers() ?? [$k];
if (1 < \count($linkIdentifiers)) {
$compositeIdentifiers = [];
foreach ($link->getIdentifiers() as $identifier) {
foreach ($linkIdentifiers as $identifier) {
$compositeIdentifiers[$identifier] = $this->getIdentifierValue($item, $link->getFromClass() ?? $operation->getClass(), $identifier, $link->getParameterName());
}

Expand All @@ -84,7 +85,7 @@ private function getIdentifiersFromOperation(object $item, Operation $operation,
}

$parameterName = $link->getParameterName();
$identifiers[$parameterName] = $this->getIdentifierValue($item, $link->getFromClass() ?? $operation->getClass(), $link->getIdentifiers()[0], $parameterName, $link->getToProperty());
$identifiers[$parameterName] = $this->getIdentifierValue($item, $link->getFromClass() ?? $operation->getClass(), $linkIdentifiers[0], $parameterName, $link->getToProperty());
}

return $identifiers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function create(string $resourceClass): ResourceMetadataCollection
// No item operation has been found on all resources for resource class: generate one on the last resource
// Helpful to generate an IRI for a resource without declaring the Get operation
/** @var HttpOperation $operation */
[$key, $operation] = $this->getOperationWithDefaults($resource, new NotExposed(), true, ['uriTemplate']); // @phpstan-ignore-line $resource is defined if count > 0
[$key, $operation] = $this->getOperationWithDefaults(resource: $resource, operation: new NotExposed(), generated: true, ignoredOptions: ['uriTemplate', 'uriVariables']); // @phpstan-ignore-line $resource is defined if count > 0

if (!$this->linkFactory->createLinksFromIdentifiers($operation)) {
$operation = $operation->withUriTemplate(self::$skolemUriTemplate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ class: AttributeResource::class
shortName: 'AttributeResource',
types: ['https://schema.org/Book'],
uriTemplate: '/custom_api_resources', // uriTemplate should not be inherited on NotExposed operation
uriVariables: ['slug'], // same as it is used to generate the uriTemplate of our NotExposed operation
operations: [
'_api_AttributeResource_get_collection' => new GetCollection(controller: 'api_platform.action.placeholder', shortName: 'AttributeResource', class: AttributeResource::class),
],
Expand All @@ -227,6 +228,7 @@ class: AttributeResource::class
new ApiResource(
shortName: 'AttributeResource',
uriTemplate: '/custom_api_resources',
uriVariables: ['slug'],
types: ['https://schema.org/Book'],
operations: [
'_api_AttributeResource_get_collection' => new GetCollection(controller: 'api_platform.action.placeholder', shortName: 'AttributeResource', class: AttributeResource::class),
Expand Down
19 changes: 19 additions & 0 deletions tests/Behat/DoctrineContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\InitializeInput;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\InternalUser;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\IriOnlyDummy;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5722\Event;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5722\ItemLog;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\MaxDepthDummy;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\MultiRelationsDummy;
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\MultiRelationsRelatedDummy;
Expand Down Expand Up @@ -2147,6 +2149,23 @@ public function thereIsAResourceUsingEntityClassAndDateTime(): void
$this->manager->flush();
}

/**
* @Given there are logs on an event
*/
public function thereAreLogsOnAnEvent(): void
{
$entity = new Event();
$entity->logs = new ArrayCollection([new ItemLog(), new ItemLog()]);
$entity->uuid = Uuid::fromString('03af3507-271e-4cca-8eee-6244fb06e95b');
$this->manager->persist($entity);
foreach ($entity->logs as $log) {
$log->item = $entity;
$this->manager->persist($log);
}

$this->manager->flush();
}

private function isOrm(): bool
{
return null !== $this->schemaTool;
Expand Down
53 changes: 53 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Issue5722/Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5722;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;

#[ApiResource(
shortName: 'EventIssue5722',
operations: [
new GetCollection(),
new Get(),
],
)]
#[ORM\Entity]
class Event
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ApiProperty(readable: false, writable: false, identifier: false)]
public $id;

#[ApiProperty(writable: false, identifier: true)]
#[ORM\Column(type: 'uuid', unique: true)]
public $uuid;

#[ORM\OneToMany(targetEntity: ItemLog::class, cascade: ['persist'], orphanRemoval: false, mappedBy: 'item')]
public Collection $logs;

public function __construct()
{
$this->logs = new ArrayCollection();
$this->uuid = Uuid::uuid4();
}
}
70 changes: 70 additions & 0 deletions tests/Fixtures/TestBundle/Entity/Issue5722/ItemLog.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5722;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;

#[ApiResource(
shortName: 'ItemLogIssue5722',
operations: [
new GetCollection(),
],
)]
#[ApiResource(
uriTemplate: '/events/{uuid}/logs{._format}',
operations: [
new GetCollection(),
],
uriVariables: [
'uuid' => new Link(fromProperty: 'logs', fromClass: Event::class),
],
)]
#[ORM\Entity]
class ItemLog
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
#[ApiProperty(readable: false, writable: false, identifier: false)] // identifier was false before 3.1.14, changing this to true fixed some errors
private ?int $id = null;

#[ApiProperty(writable: false, identifier: true)]
#[ORM\Column(type: 'uuid', unique: true)]
public $uuid;

#[ORM\ManyToOne(targetEntity: Event::class, inversedBy: 'logs')]
public ?Event $item = null;

#[ApiProperty(required: true)]
#[ORM\Column]
public string $action = 'insert';

private \DateTimeInterface $createdAt;

public function __construct()
{
$this->createdAt = new \DateTime();
$this->uuid = Uuid::uuid4();
}

public function getId(): ?int
{
return $this->id;
}
}

0 comments on commit 07c9989

Please sign in to comment.