Search code examples
symfonyswagger

NelmioApiDocBundle (Symfony) - How to specified the Items for array with objects


I am using Symfony 5.4 with PHP 7.4. I use MongoDB too. I want to use the Nelmio Api Doc Bundle to document the routes. Partly it works, but I have a problem when I have an array in my entity.

I have an entity "Order" which looks like this:

<?php

namespace App\Entity;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;

/**
 * @MongoDB\Document
 */
class Order
{
    /**
     * @MongoDB\Id
     */
    protected $id;

    /**
     * @MongoDB\Field(type="string")
     */
    protected $orderNumber;

    /**
     * @MongoDB\Field(type="string")
     */
    protected $firstname;

    /**
     * @MongoDB\Field(type="string")
     */
    protected $lastname;

    /**
     * @MongoDB\Field(type="collection")
     *
     */
    protected $address;



    /**
     * @MongoDB\Field(type="string")
     */
    protected $orderFile;

    /**
     * Get the value of id.
     */
    public function getId(): string
    {
        return $this->id;
    }

    /**
     * Get the value of firstname.
     */
    public function getFirstname(): string
    {
        return $this->firstname;
    }

    /**
     * Set the value of firstname.
     */
    public function setFirstname(string $firstname): void
    {
        $this->firstname = $firstname;
    }

    /**
     * Get the value of lastname.
     */
    public function getLastname(): string
    {
        return $this->lastname;
    }

    /**
     * Set the value of lastname.
     */
    public function setLastname(string $lastname): void
    {
        $this->lastname = $lastname;
    }

    /**
     * Get the value of address.
     */
    public function getAddress(): array
    {
        return $this->address;
    }

    /**
     * Set the value of address.
     */
    public function setAddress(array $address): void
    {
        $this->address = $address;
    }
}

I have a controller with my route and annotations for the bundle or doc. It looks like this:

Now as an error message I get the following:

<?php

namespace App\Controller\Api;

use App\Entity\Order;
use Doctrine\ODM\MongoDB\DocumentManager;
use Nelmio\ApiDocBundle\Annotation\Model;
use OpenApi\Annotations as OA;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

/**
 * @Route("/api/orders")
 */
class OrderApiController extends AbstractController
{

    /**
     * Creates a new order.
     *
     * @Route("", methods={"POST"})
     *
     * @OA\Response(
     *    response=200,
     *    description="Creates a new order",
     *
     *    @Model(type=Order::class)
     * )
     *
     * @OA\RequestBody(
     *  required=true,
     *
     *  @OA\MediaType(
     *      mediaType="application/json",
     *
     *      @OA\Schema(
     *          type="object",
     *          required={"address"},
     *
     *              @OA\Property(
     *          property="address",
     *          type="array",
     *
     *          @OA\Items(type="object")
     *          ),
     *      )
     * )
     * )
     *
     * @OA\Tag(name="Order")
     */
    public function create(DocumentManager $dm, Request $request): JsonResponse
    {
           // ... some code here
    }

Now as an error message I get the following:

Property "App\Entity\Order::address" is an array, but its items type isn't specified. You can specify that by using the type string[] for instance or @OA\Property(type="array", @OA\Items(type="string")).

Does anyone have any idea why I absolutely need to specify the type of the items and how to specify it correctly? Also as info.... the address array always contains two objects. It looks something like this:

[
    {
        "addresstype" : "delivery",
        "company" : "Test",
        "firstname" : "",
        "lastname" : "",
        "address1" : "",
        "address2" : "",
        "zip" : "",
        "city" : "Musterstadt",
        "country" : "DE"
    },
    {
        "addresstype" : "invoice",
        "company" : "Test",
        "firstname" : "",
        "lastname" : "",
        "address1" : "",
        "address2" : "",
        "zip" : "",
        "city" : "Musterstadt",
        "country" : "DE"
    }
]

I have tried different ways to define the items. For the most part, I have followed this documentation:

https://symfony.com/bundles/NelmioApiDocBundle/current/index.html#use-models

I also searched with Google and asked Chat GPT. I can't find a workable solution.

If I use as a test an entity only with fields that expect a string, the bundle runs as well. Only this special case I don't understand.


Solution

  • First, thank you @Đuro Mandinić! I will try your solution in the future too. But for now I was able to "fix" my problem like this.

    In my order class I added an annotation for the items of address.

        /**
     * @MongoDB\Field(type="collection")
     *
     * @OA\Property(property="address", type="array", @OA\Items(type="object"))
     */
    protected $address;
    

    Hope this helps others too!

    Have a nice day!