api-platform / core

The server component of API Platform: hypermedia and GraphQL APIs in minutes
https://api-platform.com
MIT License
2.45k stars 875 forks source link

Can't use ODM and ORM together #5020

Closed Oskmoz closed 2 years ago

Oskmoz commented 2 years ago

Hi,

I'm facing a problem on my application using both an SQL and a MongoDB database. Using only the SQL databases with ORM and PHP attributes everything works fine. However, as soon as I composer require doctrine/mongodb-odm-bundle (Tried with many versions), the POST resources break and I'm unable to POST anything. I tried with ODM annotations and attributes, this doesn't fix the issue.

Here is the doctrine_mongodb.yaml I am using :

Is there any solution to make attributes and resource work both with Documents and Entities ?

doctrine_mongodb:
    auto_generate_proxy_classes: true
    auto_generate_hydrator_classes: true
    connections:
        default:
            server: '%env(resolve:MONGODB_URL)%'
            options: {}
    default_database: '%env(resolve:MONGODB_DB)%'
    document_managers:
        default:
            # auto_mapping: true
            mappings:
                App:
                    is_bundle: false
                    type: attribute
                    dir: '%kernel.project_dir%/src/Document'
                    prefix: 'App\Document'
                    alias: App

bug

bechir commented 2 years ago

Hello, I have same issue here in after upgrading from 2.6 to 3.0.0:

{
  "@context": "/contexts/Error",
  "@type": "hydra:Error",
  "hydra:title": "An error occurred",
  "hydra:description": "Unable to generate an IRI for the item of type \"App\\Entity\\Ticket\\Ticket\"",
  "trace": [
    {
      "file": "/.../vendor/api-platform/core/src/Symfony/Routing/IriConverter.php",
      "line": 159
    },
    {
      "namespace": "ApiPlatform\\Symfony\\Routing",
      "short_class": "IriConverter",
      "class": "ApiPlatform\\Symfony\\Routing\\IriConverter",
      "type": "->",
      "function": "getIriFromResource",
      "file": "/.../vendor/api-platform/core/src/Hydra/Serializer/CollectionNormalizer.php",
      "line": 76,
      "args": [
        [
          "string",
          "App\\Entity\\Ticket\\Ticket"
        ],
        [
          "integer",
          1
        ],
        [
          "object",
          "ApiPlatform\\Metadata\\Get"
        ],
        [
          "array",
          {
            "operation_name": [
              "string",
              "api_tickets_post_collection"
            ],

https://github.com/api-platform/core/blob/14c7cba9d9fbdee086e1c0a3f142ea0cbc1e1674/src/Symfony/Routing/IriConverter.php#L156-L160

On line 159 when I throw $e:

        try {
            return $this->router->generate($operation->getName(), $identifiers, $operation->getUrlGenerationStrategy() ?? $referenceType);
        } catch (RoutingExceptionInterface $e) {
            throw $e;
            throw new InvalidArgumentException(sprintf('Unable to generate an IRI for the item of type "%s"', $resourceClass), $e->getCode(), $e);
        }

I got this error:

{
  "@context": "/contexts/Error",
  "@type": "hydra:Error",
  "hydra:title": "An error occurred",
  "hydra:description": "Some mandatory parameters are missing (\"id\") to generate a URL for route \"api_tickets_get_item\".",
  "trace": [
    {
      "file": "/.../vendor/symfony/routing/Generator/UrlGenerator.php",
      "line": 161
    }

the weird thing is that when I dump the generated route I got the expected result:

$this->router->generate($operation->getName(), $identifiers, $operation->getUrlGenerationStrategy() ?? $referenceType)

Output: /tickets/194 and the entity is persisted on the database: GET /tickets/194:

{
  "id": 194,
  "title": "Lorem ipsum",
  "type": "Bug report",
  "status": "opened",
  "createdAt": "2022-09-29T06:32:50+00:00"
}

My entity Ticket:


#[ORM\Entity(repositoryClass: TicketRepository::class)]
#[ApiResource(
    operations: [
        new GetCollection(),
        new Get(),
        new Post(
            name: 'api_tickets_post_collection',
            denormalizationContext: ['groups' => ['post:Ticket']]
        ),
        new Delete()
    ]
)]
class Ticket
{

php bin/console debug:router api_tickets_post_collection return:

+--------------+---------------------------------------------------------+
| Property     | Value                                                   |
+--------------+---------------------------------------------------------+
| Route Name   | api_tickets_post_collection                             |
| Path         | /tickets.{_format}                                      |
| Path Regex   | {^/tickets(?:\.(?P<_format>[^/]++))?$}sDu               |
| Host         | ANY                                                     |
| Host Regex   |                                                         |
| Scheme       | ANY                                                     |
| Method       | POST                                                    |
| Requirements | NO CUSTOM                                               |
| Class        | Symfony\Component\Routing\Route                         |
| Defaults     | _api_operation_name: api_tickets_post_collection        |
|              | _api_resource_class: App\Entity\Ticket\Ticket           |
|              | _controller: api_platform.action.placeholder()          |
|              | _format: NULL                                           |
|              | _stateless: NULL                                        |
| Options      | compiler_class: Symfony\Component\Routing\RouteCompiler |
|              | utf8: true                                              |
+--------------+---------------------------------------------------------+
Oskmoz commented 2 years ago

Are you using too both doctrine mongodb ODM and an doctrine orm ?

bechir commented 2 years ago

I don't use mongodb.

soyuka commented 2 years ago

we have a bug on this I'm on it

nsetyo commented 2 years ago

I am facing the same issue when I access api with nested collection

given I have 4 resource User, Organization, Address, and AddressType

#[ApiResource(
    denormalizationContext:['groups' => ['User']],
    normalizationContext: ['groups' => ['User', 'Relationship']],
)]
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: 'users')]
#[UniqueEntity(fields: 'username')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[Groups(['User', 'Relationship'])]
    #[ORM\ManyToOne(targetEntity: Organization::class, inversedBy: 'users')]
    #[ORM\JoinColumn(nullable: false)]
    private Organization $org;
}

#[Metadata\ApiResource(
    normalizationContext: [
        'groups' => ['Organization', 'Relationship'],
    ],
)]
#[ORM\Entity(repositoryClass: OrganizationRepository::class)]
class Organization
{
    /** @var Collection<int,Address> */
    #[Groups(['Organization'])]
    #[ORM\OneToMany(
        targetEntity: Address::class,
        mappedBy: 'org'
    )]
    private Collection $addresses;
}

#[ORM\Entity(repositoryClass: AddressRepository::class)]
class Address
{
    #[Groups(['Relationship'])]
    #[ORM\JoinColumn(name: 'address_type_code', referencedColumnName: 'code', nullable: false)]
    #[ORM\ManyToOne(targetEntity: AddressType::class)]
    private AddressType $addressType;
}

When I access org endpoint I don't have any error but when I try to access user endpoint I get

Unable to generate an IRI for the item of type "App\Entity\AddressType"
soyuka commented 2 years ago

This issue is only for using mongodb and doctrine orm together. For your addressType it's probably related to #5017.

nsetyo commented 2 years ago

From

This issue is only for using mongodb and doctrine orm together. For your addressType it's probably related to #5017.

I'm not using ApiResource as Identifier I try to debug the data and I found when api-platform try to get the IRI of AddressType the Operation value still the same Operation value from Organization which itu should be unset

soyuka commented 2 years ago

not the same issue please open a new one

bechir commented 2 years ago

I don't use ODM but I have the issue.