Skip to content

[Docs] Constructor arguments conflict with class fields #7260

Open
@rvanlaak

Description

@rvanlaak

API Platform version(s) affected: x.y.z
4.1.17

Description

When a constructor argument gets defined that has the same name as the class's field, in which the constructor argument gets used to instantiate values in the constructor, the OpenAPI docs then type the field as array<string> items while they actually should be typed as the classes that just were instantiated.

How to reproduce

The collection is fairly straight forward

class Foo {
   # ...

  #[ORM\OneToMany(targetEntity: Bar::class, mappedBy: 'foo', fetch: 'EXTRA_LAZY')]
  #[ORM\OrderBy(['level' => 'ASC'])]
  public Collection $bars;

  public __construct(array $bars) 
  {
     $this->bars = new ArrayCollection(array_map( ... , $bars));   
  }

And when the constructor argument is named differently, the bar field on foo is correctly documented as object with it's related fields again:

class Foo
{

    /**
     * @var Bar[]
     */
    #[ORM\OneToMany(targetEntity: PackagingLayer::class, mappedBy: 'packagingHierarchy', fetch: 'EXTRA_LAZY')]
    public Collection $bars;

    public function __construct(
-        array $bars,
+        array $inputBars,
    ) {
-     $this->bars = new ArrayCollection(array_map( ... , $bars));   
+     $this->bars = new ArrayCollection(array_map( ... , $inputBars));   
    }
}

Possible Solution

The typing of the class field should take precedence over the typing of the constructor parameter. Especially as the constructor parameter won't be available after construction, which is how it will be read by APIP. That makes this classify as bug.

Renaming the constructor argument is a workaround for this, as the argument then doesn't relate to the class field anymore.

Additional Context

Probably this is related to an earlier change for promoted properties. That check should be enhanced, by adding a check whether that constructor argument actually does have a class field with the same name. The class field should then be used over the constructor parameter.

[...] is Bar also a resource?

see #6173

I've tested this by either attributing both classes or none of the classes as ApiResource, but that does not change the behavior. The Foo class is a field on another entity (let's call it Baz), which is an ApiResource, so on normalization these three layers should result in a json graph like Baz -> Foo -> Bar[]

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions