I am facing an issue from days by trying to upgrade my code from PHP 7.4 to PHP8.x.
I am working with Symfony 5.4 and API Platform 2.7.16.
My problem concern an ApiSubresource link.
Indeed, I have a class attribute on my entity which refers to another class which is not an Entity as SubResource.
When I am dealing with PHP 7 annotation, everything is fine, but when I switch to PHP8 Attributes, it does not work anymore.
I have to say, I made changes in doctrine config file for working with attributes and not annotations obviously.
Here is the Annotations form entity
<?php
namespace App\AwesomeDirectory\Entity;
/**
* @ApiResource(
* forceEager=false,
* order={"sortableName"="ASC"},
* attributes={
* "pagination_enabled"=true,
* "pagination_client_enabled"=false,
* "pagination_items_per_page"=15,
* "pagination_maximum_items_per_page"=30
* },
* normalizationContext={"groups"={"group:read"}},
* denormalizationContext={"groups"={"group:write"}},
* collectionOperations={...},
* itemOperations={...},
* subresourceOperations={...}
* )
* @ORM\Entity(repositoryClass=FooRepository::class)
* @Gedmo\SoftDeleteable(fieldName="deletedAt", hardDelete=false)
* @Gedmo\Loggable
* @ORM\HasLifecycleCallbacks()
*/
class Foo extends BaseEntity
{
// ... Class variables ...
/**
* @ApiSubresource
* @var Bar[]
* @ApiProperty(security="is_granted('AWESOME_ROLE')")
*/
private $bars;
// ...
}
The Bar class, still with Annotations' style
<?php
namespace App\AwesomeDirectory\Model;
/**
* @ApiResource(
* normalizationContext={"groups"={...}},
* itemOperations={
* "get"={
* "controller"=NotFoundAction::class
* }
* },
* collectionOperations={},
* subresourceOperations={
* "api_foos_bars_get_subresource"={
* "security"="is_granted('read_foo_simple_subresource', request.attributes.get('id'))"
* }
* }
* )
*/
class Bar
{
/**
* @Groups({"foo_bar:read"})
* @ApiProperty(readableLink=false)
*/
private ?Foo $foo;
/**
* @Groups({"foo_indicator:read"})
* @ApiProperty(
* attributes={
* "openapi_context"={
* "array"={
* "Fubar"="baz"
* }
* }
* }
* )
*/
private ?string $name;
/**
* @Groups({"foo_bar:read"})
*/
private ?float $value;
/**
* @ApiProperty(identifier=true)
*/
public function getId(): string
{
// ...
}
public function getFoo(): ?Foo
{
return $this->foo;
}
public function setFoo(?Foo $foo): self
{
$this->foo = $foo;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getValue(): ?float
{
return $this->value;
}
public function setValue(?float $value): self
{
$this->value = $value;
return $this;
}
}
And now the PHP8's attributes' style :
<?php
declare(strict_types=1);
namespace App\AwesomeDirectory\Entity;
#[ApiResource(
collectionOperations: [...],
itemOperations: [...],
subresourceOperations: [...],
attributes: [
'pagination_enabled' => true,
'pagination_client_enabled' => false,
'pagination_items_per_page' => 15,
'pagination_maximum_items_per_page' => 30,
],
denormalizationContext: ['groups' => ['group:write']],
forceEager: false,
normalizationContext: ['groups' => ['group:read']],
order: ['sortableName' => 'ASC'],
)]
#[ORM\Entity(repositoryClass: FooRepository::class)]
#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', hardDelete: false)]
#[Gedmo\Loggable]
#[ORM\HasLifecycleCallbacks]
class Foo extends BaseEntity
{
// ... class attributes ...
#[ApiSubresource]
#[ApiProperty(security: "is_granted('AWESOME_ROLE')")]
private array $bars;
// ...
}
The Bar class, Attributes' style
<?php
declare(strict_types=1);
namespace App\AwesomeDirectory\Model;
#[ApiResource(
collectionOperations: [],
itemOperations: ['get' => ['controller' => NotFoundAction::class]],
subresourceOperations: [
'api_foos_bars_get_subresource' => [
'security' => "is_granted('read_foo_simple_subresource', request.attributes.get('id'))"
]
],
normalizationContext: ['groups' => ['foo_bar:read']]
)]
final class Bar
{
#[Groups(['foo_bar:read'])]
#[ApiProperty(readableLink: false)]
private ?Foo $foo;
#[Groups(['foo_bar:read'])]
#[ApiProperty(attributes: ['openapi_context' => ['array' => ['Fubar' => 'baz']]])]
private ?string $name;
#[Groups(['foo_bar:read'])]
private ?float $value;
#[ApiProperty(identifier: true)]
public function getId(): string
{
// ...
}
public function getFoo(): ?Foo
{
return $this->foo;
}
public function setFoo(?Foo $foo): self
{
$this->foo = $foo;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): self
{
$this->name = $name;
return $this;
}
public function getValue(): ?float
{
return $this->value;
}
public function setValue(?float $value): self
{
$this->value = $value;
return $this;
}
}
In the Annotations' style, everything works well, but in Attributes' style, I have this issue :
SELECT o FROM App\AwesomeDirectory\Entity\Foo o WHERE o IN(SELECT WHERE id_a1.id = :id_p1)
[Syntax Error] line 0, col 67: Error: Unexpected 'WHERE'
The Data Provider Context is :
Context
[▼
"property" => "bars"
"identifiers" => [▼
"id" => [▼
"App\AwesomeDirectory\Entity\Foo"
"id"
true
]
]
"collection" => false
"operationId" => "api_foos_bars_get_subresource"
"groups" => [▼
"group:read"
"common:read"
]
"operation_type" => "subresource"
"subresource_operation_name" => "api_foos_bars_get_subresource"
"iri_only" => false
"input" => null
"output" => null
"resource_class" => "App\AwesomeDirectory\Entity\Patient"
"request_uri" => "/api/foos/e3d27cbd-696a-4994-b7d5-cfb3195a3c80/bars"
"uri" => "https://localhost:8000/api/foos/e3d27cbd-696a-4994-b7d5-cfb3195a3c80/bars"
"subresource_identifiers" => [▼
"id" => "e3d27cbd-696a-4994-b7d5-cfb3195a3c80"
]
"subresource_resources" => [▼
"App\AwesomeDirectory\Entity\Foo" => [▼
"id" => "e3d27cbd-696a-4994-b7d5-cfb3195a3c80"
]
]
"disable_type_enforcement" => true
"skip_null_values" => false
"enable_max_depth" => true
"has_identifier_converter" => true
]
Could you point me out where is the issue and/or help me to solve it please ? I am pacing around with this issue and drives me crazy :)
Thanks !