Git Product home page Git Product logo

Comments (7)

DjordyKoert avatar DjordyKoert commented on June 10, 2024 1

Ah I see why this is happening at least. This happens because Member class is used in both the ContactOutput & EventOutput. Both of these "output" classes get different serialization groups applied:
1.SerializationGroup::ContactOutputAll, SerializationGroup::ContactAll & SerializationGroup::MemberAll
2. SerializationGroup::EventOutputAll, SerializationGroup::EventAll & SerializationGroup::MemberAll

These groups also get passed to the child classes (the Member class in this example). Technically speaking the different groups used could result in a different schema for the Member class, which is the reason why you get a Member & Member2 schema. It just so happens that both of these Schema's are the exact same. https://github.com/DjordyKoert/NelmioApiDocBundle/blob/52b297059b2ccf4bf1db3c8e80b5234f672fe4af/Tests/Functional/Fixtures/Issue2218.json#L216

You can see the setup that I used to replicate it in #2221. I am not yet sure what the proper way would be to change this behaviour or if this should stay as it is.

from nelmioapidocbundle.

DjordyKoert avatar DjordyKoert commented on June 10, 2024 1

Maybe creating an optional swagger-php processor which removes duplicate schemas is an option?

from nelmioapidocbundle.

DjordyKoert avatar DjordyKoert commented on June 10, 2024

I cannot seem to reproduce it. I do see a few typo's in your attributes though.

Incorrect Model usage

new Model(Contact::class, groups: [SerializationGroup::ContactAll])

Should be

new Model(type: Contact::class, groups: [SerializationGroup::ContactAll])

Missing new on OA\Items

items: OA\Items(ref: new Model(Contact::class, groups: [SerializationGroup::ContactAll]))

Should be

items: new OA\Items(ref: new Model(type: Contact::class, groups: [SerializationGroup::ContactAll]))

from nelmioapidocbundle.

oriolvinals avatar oriolvinals commented on June 10, 2024

@DjordyKoert sorry for the mistakes, I made them without looking at the code, but this is not the problem I really have.

I'm going to start over, since it's harder to reproduce.

I have 3 entities: Member, Contact i Event

Member

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;

#[ORM\Entity]
class Member 
{
      #[ORM\Id]
      #[ORM\GeneratedValue]
      #[ORM\Column(type: 'integer', options: ['unsigned' => true])]
      #[Serializer\Groups([SerializationGroup::MemberAll])]
      private ?int $id = null;

      // Other variables, constructor, getters and setters...
}

Contact

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;

#[ORM\Entity]
class Contact 
{
      #[ORM\Id]
      #[ORM\GeneratedValue]
      #[ORM\Column(type: 'integer', options: ['unsigned' => true])]
      #[Serializer\Groups([SerializationGroup::ContactAll])]
      private ?int $id = null;

      #[ORM\ManyToOne(targetEntity: Member::class)]
      #[Serializer\Ignore]
      private Member $member;

      // Other variables, constructor, getters and setters...
}

Event

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;

#[ORM\Entity]
class Event 
{
      #[ORM\Id]
      #[ORM\GeneratedValue]
      #[ORM\Column(type: 'integer', options: ['unsigned' => true])]
      #[Serializer\Groups([SerializationGroup::EventAll])]
      private ?int $id = null;

      #[ORM\ManyToOne(targetEntity: Member::class)]
      #[Serializer\Ignore]
      private Member $member;

      // Other variables, constructor, getters and setters...
}

Now i create 2 Outputs called ContactOutput i EventOutput with another serialization groups

ContactOutput

<?php

namespace App\Dto\Output;

use App\Entity\Contact;
use App\Entity\Member;
use App\Serialization\Groups\SerializationGroup;
use Symfony\Component\Serializer\Annotation as Serializer;


class ContactOutput
{
    #[Serializer\Groups([SerializationGroup::ContactOutputAll])]
    private readonly Contact $contact;

    #[Serializer\Groups([SerializationGroup::ContactOutputAll])]
    private readonly Member $member;

    public function __construct(Contact $contact, Member $member)
    {
        $this->contact = $contact;
    }

    public function getContact(): Contact
    {
        return $this->contact;
    }

    public function getMember(): Member
    {
        return $this->member;
    }
}

EventOutput

<?php

namespace App\Dto\Output;

use App\Entity\Event;
use App\Entity\Member;
use App\Serialization\Groups\SerializationGroup;
use Symfony\Component\Serializer\Annotation as Serializer;


class EventOutput
{
    #[Serializer\Groups([SerializationGroup::EventOutputAll])]
    private readonly Event $event;

    #[Serializer\Groups([SerializationGroup::EventOutputAll])]
    private readonly Member $member;

    public function __construct(Event $event, Member $member)
    {
        $this->event = $event;
    }

    public function getEventt(): Event
    {
        return $this->event;
    }

    public function getMember(): Member
    {
        return $this->member;
    }
}

Now I want to use this outputs on the contact and event controllers

<?php

namespace App\Controller;

use OpenApi\Attributes as OA;

class ContactController extends BaseController 
{
   #[OA\Response(
       response: 200, 
       description: 'Success',
       content: new OA\JsonContent(
           type: 'array', 
           items: new OA\Items(ref: new Model(type: ContactOutput::class, groups: [
               SerializationGroup::ContactOutputAll,
               SerializationGroup::ContactAll,
               SerializationGroup::MemberAll
           ]))
       )
    )]
   #[Route(...)]
   public function list(){}

   #[OA\Response(
       response: 200, 
       description: 'Success',
       content: new OA\JsonContent(
           ref: new Model(type: ContactOutput::class, groups: [
               SerializationGroup::ContactOutputAll,
               SerializationGroup::ContactAll,
               SerializationGroup::MemberAll
           ])
       )
    )]
   #[Route(...)]
   public function show(){}

   #[OA\Response(
       response: 201, 
       description: 'Success',
       content: new OA\JsonContent(
           ref: new Model(type: ContactOutput::class, groups: [
               SerializationGroup::ContactOutputAll,
               SerializationGroup::ContactAll,
               SerializationGroup::MemberAll
           ])
       )
    )]
   #[Route(...)]
   public function create(){}

   #[OA\Response(
       response: 200, 
       description: 'Success',
       content: new OA\JsonContent(
           ref: new Model(type: ContactOutput::class, groups: [
               SerializationGroup::ContactOutputAll,
               SerializationGroup::ContactAll,
               SerializationGroup::MemberAll
           ])
       )
    )]
   #[Route(...)]
   public function update(){}
}
<?php

namespace App\Controller;

use OpenApi\Attributes as OA;

class EventController extends BaseController 
{
   #[OA\Response(
       response: 200, 
       description: 'Success',
       content: new OA\JsonContent(
           type: 'array', 
           items: new OA\Items(ref: new Model(type: EventOutput::class, groups: [
               SerializationGroup::EventOutputAll,
               SerializationGroup::EventAll,
               SerializationGroup::MemberAll
           ]))
       )
    )]
   #[Route(...)]
   public function list(){}

   #[OA\Response(
       response: 200, 
       description: 'Success',
       content: new OA\JsonContent(
           ref: new Model(type: EventOutput::class, groups: [
               SerializationGroup::EventOutputAll,
               SerializationGroup::EventAll,
               SerializationGroup::MemberAll
           ])
       )
    )]
   #[Route(...)]
   public function show(){}

   #[OA\Response(
       response: 201, 
       description: 'Success',
       content: new OA\JsonContent(
           ref: new Model(type: EventOutput::class, groups: [
               SerializationGroup::EventOutputAll,
               SerializationGroup::EventAll,
               SerializationGroup::MemberAll
           ])
       )
    )]
   #[Route(...)]
   public function create(){}

   #[OA\Response(
       response: 200, 
       description: 'Success',
       content: new OA\JsonContent(
           ref: new Model(type: EventOutput::class, groups: [
               SerializationGroup::EventOutputAll,
               SerializationGroup::EventAll,
               SerializationGroup::MemberAll
           ])
       )
    )]
   #[Route(...)]
   public function update(){}
}

Now in schemas there's a duplicated schemas
image

from nelmioapidocbundle.

emhovis avatar emhovis commented on June 10, 2024

I have been dealing with the same issue- also using a response object to wraps my entities. I just assumed it was just incorrect usage somewhere else on my end. Coincidentally, this was the root cause for me writing up #2099

image

from nelmioapidocbundle.

mymain avatar mymain commented on June 10, 2024

@DjordyKoert Same issue on my side.

from nelmioapidocbundle.

aprat84 avatar aprat84 commented on June 10, 2024

@DjordyKoert Maybe an approach would be to only consider the groups that actually affect the model for creating the hash, and therefore unique models.

In the example above, even though we are using 3 groups, the Contact submodel is actually only affected by one of them.

Of course we still need to keep track of the root groups for nested models down the serialization tree.

I tried to look at the code, but it won't be an easy task and sadly now I don't have the time :(

from nelmioapidocbundle.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.