Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.3] File uploading doesn't work anymore #6342

Closed
Aerendir opened this issue May 1, 2024 · 8 comments
Closed

[3.3] File uploading doesn't work anymore #6342

Aerendir opened this issue May 1, 2024 · 8 comments

Comments

@Aerendir
Copy link
Contributor

Aerendir commented May 1, 2024

API Platform version(s) affected: 3.3.0
Description

The upload of files, as described in the official docs, doesn't work anymore.

How to reproduce

Follow the instructions here: https://api-platform.com/docs/core/file-upload/

Possible Solution

  • Update the docs with the new way of uploading files

OR

  • Make the way currently described in the docs work again

Additional Context

The error is this:

{
    "@id": "\/api\/errors",
    "@type": "hydra:Error",
    "title": "An error occurred",
    "detail": "The controller must return a \u0022Symfony\\Component\\HttpFoundation\\Response\u0022 object but it returned an object of type App\\Common\\Entity\\FileDocVich.",
    "status": 500,
    "type": "\/errors\/500",
    "trace": [
        {
            "line": 178,
            "file": "\/srv\/app\/vendor\/symfony\/http-kernel\/HttpKernel.php"
        },
        {
            "file": "\/srv\/app\/vendor\/symfony\/http-kernel\/HttpKernel.php",
            "line": 76,
            "function": "handleRaw",
            "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor\/symfony\/http-kernel\/Kernel.php",
            "line": 185,
            "function": "handle",
            "class": "Symfony\\Component\\HttpKernel\\HttpKernel",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor\/symfony\/http-kernel\/HttpKernelBrowser.php",
            "line": 61,
            "function": "handle",
            "class": "Symfony\\Component\\HttpKernel\\Kernel",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor\/symfony\/framework-bundle\/KernelBrowser.php",
            "line": 157,
            "function": "doRequest",
            "class": "Symfony\\Component\\HttpKernel\\HttpKernelBrowser",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor\/symfony\/browser-kit\/AbstractBrowser.php",
            "line": 369,
            "function": "doRequest",
            "class": "Symfony\\Bundle\\FrameworkBundle\\KernelBrowser",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor\/api-platform\/core\/src\/Symfony\/Bundle\/Test\/Client.php",
            "line": 116,
            "function": "request",
            "class": "Symfony\\Component\\BrowserKit\\AbstractBrowser",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/tests\/App\/api\/ApiTestCase.php",
            "line": 136,
            "function": "request",
            "class": "ApiPlatform\\Symfony\\Bundle\\Test\\Client",
            "type": "-\u003E"
        },
        ...
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php",
            "line": 1151,
            "function": "runTest",
            "class": "PHPUnit\\Framework\\TestCase",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/Framework\/TestResult.php",
            "line": 726,
            "function": "runBare",
            "class": "PHPUnit\\Framework\\TestCase",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php",
            "line": 903,
            "function": "run",
            "class": "PHPUnit\\Framework\\TestResult",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/Framework\/TestSuite.php",
            "line": 672,
            "function": "run",
            "class": "PHPUnit\\Framework\\TestCase",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/Framework\/TestSuite.php",
            "line": 672,
            "function": "run",
            "class": "PHPUnit\\Framework\\TestSuite",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/TextUI\/TestRunner.php",
            "line": 673,
            "function": "run",
            "class": "PHPUnit\\Framework\\TestSuite",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/TextUI\/Command.php",
            "line": 143,
            "function": "run",
            "class": "PHPUnit\\TextUI\\TestRunner",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/src\/TextUI\/Command.php",
            "line": 96,
            "function": "run",
            "class": "PHPUnit\\TextUI\\Command",
            "type": "-\u003E"
        },
        {
            "file": "\/srv\/app\/vendor-bin\/phpunit\/vendor\/phpunit\/phpunit\/phpunit",
            "line": 98,
            "function": "main",
            "class": "PHPUnit\\TextUI\\Command",
            "type": "::"
        }
    ],
    "hydra:title": "An error occurred",
    "hydra:description": "The controller must return a \u0022Symfony\\Component\\HttpFoundation\\Response\u0022 object but it returned an object of type App\\Common\\Entity\\FileDocVich."
}
@paullallier
Copy link
Contributor

I think this is fixed by adding this to the config file: #6343 (comment)

You might then run into a problem with permitted Content-Types, depending on what you have in your global configuration for input types. You can add multipart to the input format for the affected endpoints using the second option from this comment, if you need it. #6275 (comment)

@soyuka
Copy link
Member

soyuka commented May 1, 2024

#6343 (comment) this should be it sorry for the trouble let me know if setting use_symfony_listeners: true works.

@Aerendir
Copy link
Contributor Author

Aerendir commented May 3, 2024

Hello, first of all, thank you for the hints.

I set use_symfony_listeners: true and the upload now works as expected.

I also added the argument inputFormats to the POST http method.

The missing part is the assertions: I configured two entities, one for docs and one for images.

Each one has its own allowed mime types.

For example, this is the entity to upload a doc (simplified for the purposes of the comment):

#[ORM\Entity]
#[Vich\Uploadable]
#[API\ApiResource(
    normalizationContext: ['groups' => [FileDocVich::GROUP_NOR_READ]],
    types: [self::API_TYPE],
    operations: [
        new API\Get(
            ...
        ),
        new API\Post(
            inputFormats: ['multipart/form-data' => ['multipart/form-data']],
            ...
        ),
    ],
)]
class FileDocVich extends FileAbstractVich
{
    ...
    private const array MIME_TYPES_ALLOWED   = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];

    ...

    #[Vich\UploadableField(mapping: 'file_doc', fileNameProperty: 'name', size: 'size', mimeType: 'mimeType', originalName: 'originalName')]
    #[Assert\NotNull(groups: [self::GROUP_VAL_POST])]
    #[Assert\File(maxSize: '5M', mimeTypes: self::MIME_TYPES_ALLOWED)]
    protected ?File $file = null;

The #[Assert\File(maxSize: '5M', mimeTypes: self::MIME_TYPES_ALLOWED)] is completely ignored and I can upload images using the endpoint dedicated to the docs.

Any idea why the assertions are not working anymore?

@soyuka
Copy link
Member

soyuka commented May 3, 2024

can you run the debug:api-resource command on this class, then select the POST operation and send the output here?

@Aerendir
Copy link
Contributor Author

Aerendir commented May 3, 2024

@soyuka , how is the command supposed to work?

I've tried three alternatives:

bin/console debug:api-resource FileDocVich

bin/console debug:api-resource \Coommercio\App\Common\Entity\FileDocVich

bin/console debug:api-resource Coommercio\\App\\Common\\Entity\\FileDocVich

No one of these works.

In the code, I see the backslashes are removed from the class:

Screenshot_2024-05-03_alle_18_19_44

When calling a route, instead, the namespace is correct.

Which is the correct way of using the command?

@soyuka
Copy link
Member

soyuka commented May 3, 2024

bin/console debug:api-resource 'Coommercio\App\Common\Entity\FileDocVich'

@Aerendir
Copy link
Contributor Author

Aerendir commented May 4, 2024

ApiPlatform\Metadata\ApiResource^ {#725
  #shortName: "FileDocVich"
  #class: "Coommercio\App\Common\Entity\FileDocVich"
  #description: null
  #urlGenerationStrategy: null
  #deprecationReason: null
  #normalizationContext: array:1 [
    "groups" => array:1 [
      0 => "file:read"
    ]
  ]
  #denormalizationContext: null
  #collectDenormalizationErrors: null
  #validationContext: null
  #filters: null
  #elasticsearch: null
  #mercure: null
  #messenger: null
  #input: null
  #output: null
  #order: null
  #fetchPartial: null
  #forceEager: null
  #paginationEnabled: true
  #paginationType: null
  #paginationItemsPerPage: null
  #paginationMaximumItemsPerPage: null
  #paginationPartial: null
  #paginationClientEnabled: null
  #paginationClientItemsPerPage: null
  #paginationClientPartial: null
  #paginationFetchJoinCollection: null
  #paginationUseOutputWalkers: null
  #security: null
  #securityMessage: null
  #securityPostDenormalize: null
  #securityPostDenormalizeMessage: null
  #securityPostValidation: null
  #securityPostValidationMessage: null
  #provider: null
  #processor: null
  #stateOptions: null
  #parameters: null
  #extraProperties: array:2 [
    "standard_put" => true
    "rfc_7807_compliant_errors" => true
  ]
  #operations: ApiPlatform\Metadata\Operations^ {#723
    -operations: array:2 [
      0 => array:2 [
        0 => "_api_/accounts/{account}/files/docs/{file}_get"
        1 => ApiPlatform\Metadata\Get^ {#668
          #shortName: "FileDocVich"
          #class: "Coommercio\App\Common\Entity\FileDocVich"
          #description: null
          #urlGenerationStrategy: null
          #deprecationReason: null
          #normalizationContext: array:1 [
            "groups" => array:1 [
              0 => "file:read"
            ]
          ]
          #denormalizationContext: null
          #collectDenormalizationErrors: null
          #validationContext: null
          #filters: []
          #elasticsearch: null
          #mercure: null
          #messenger: null
          #input: null
          #output: null
          #order: null
          #fetchPartial: null
          #forceEager: null
          #paginationEnabled: true
          #paginationType: null
          #paginationItemsPerPage: null
          #paginationMaximumItemsPerPage: null
          #paginationPartial: null
          #paginationClientEnabled: null
          #paginationClientItemsPerPage: null
          #paginationClientPartial: null
          #paginationFetchJoinCollection: null
          #paginationUseOutputWalkers: null
          #security: null
          #securityMessage: null
          #securityPostDenormalize: null
          #securityPostDenormalizeMessage: null
          #securityPostValidation: null
          #securityPostValidationMessage: null
          #provider: "ApiPlatform\Doctrine\Orm\State\ItemProvider"
          #processor: "api_platform.doctrine.orm.state.persist_processor"
          #stateOptions: ApiPlatform\Doctrine\Orm\State\Options^ {#934
            #handleLinks: "api_platform.doctrine.orm.links_handler"
            #entityClass: null
          }
          #parameters: ApiPlatform\Metadata\Parameters^ {#938
            -parameters: []
          }
          #extraProperties: array:3 [
            "standard_put" => true
            "rfc_7807_compliant_errors" => true
            "user_defined_uri_template" => true
          ]
          #paginationViaCursor: null
          #read: null
          #deserialize: null
          #validate: null
          #write: null
          #serialize: null
          #priority: 0
          #name: "_api_/accounts/{account}/files/docs/{file}_get"
          #method: "GET"
          #uriTemplate: "/accounts/{account}/files/docs/{file}"
          #types: array:1 [
            0 => "FileDoc"
          ]
          #formats: null
          #inputFormats: array:1 [
            "jsonld" => array:1 [
              0 => "application/ld+json"
            ]
          ]
          #outputFormats: array:1 [
            "jsonld" => array:1 [
              0 => "application/ld+json"
            ]
          ]
          #uriVariables: array:2 [
            "account" => ApiPlatform\Metadata\Link^ {#943
              #key: null
              #schema: null
              #openApi: null
              #provider: null
              #filter: null
              #property: null
              #description: null
              #required: null
              #priority: null
              #constraints: null
              #extraProperties: []
              -parameterName: "account"
              -fromProperty: null
              -toProperty: "account"
              -fromClass: "Coommercio\App\Coommercio\Entity\Account"
              -toClass: null
              -identifiers: array:1 [
                0 => "id"
              ]
              -compositeIdentifier: null
              -expandedValue: null
              -security: null
              -securityMessage: null
              -securityObjectName: null
            }
            "file" => ApiPlatform\Metadata\Link^ {#928
              #key: null
              #schema: null
              #openApi: null
              #provider: null
              #filter: null
              #property: null
              #description: null
              #required: null
              #priority: null
              #constraints: null
              #extraProperties: []
              -parameterName: "file"
              -fromProperty: null
              -toProperty: null
              -fromClass: "Coommercio\App\Common\Entity\FileDocVich"
              -toClass: null
              -identifiers: array:1 [
                0 => "id"
              ]
              -compositeIdentifier: null
              -expandedValue: null
              -security: null
              -securityMessage: null
              -securityObjectName: null
            }
          ]
          #routePrefix: null
          #routeName: null
          #defaults: null
          #requirements: null
          #options: null
          #stateless: true
          #sunset: null
          #acceptPatch: null
          #status: null
          #host: null
          #schemes: null
          #condition: null
          #controller: null
          #headers: null
          #cacheHeaders: array:1 [
            "vary" => array:3 [
              0 => "Content-Type"
              1 => "Authorization"
              2 => "Origin"
            ]
          ]
          #hydraContext: null
          #openapiContext: null
          #openapi: ApiPlatform\OpenApi\Model\Operation^ {#929
            -operationId: null
            -tags: array:1 [
              0 => "0. Common > Files"
            ]
            -responses: null
            -summary: null
            -description: null
            -externalDocs: null
            -parameters: null
            -requestBody: null
            -callbacks: null
            -deprecated: null
            -security: null
            -servers: null
            -extensionProperties: []
          }
          #exceptionToStatus: null
          #queryParameterValidationEnabled: null
          #links: null
        }
      ]
      1 => array:2 [
        0 => "_api_/accounts/{account}/files/docs_post"
        1 => ApiPlatform\Metadata\Post^ {#948
          #shortName: "FileDocVich"
          #class: "Coommercio\App\Common\Entity\FileDocVich"
          #description: null
          #urlGenerationStrategy: null
          #deprecationReason: null
          #normalizationContext: array:1 [
            "groups" => array:1 [
              0 => "file:read"
            ]
          ]
          #denormalizationContext: null
          #collectDenormalizationErrors: null
          #validationContext: array:1 [
            "groups" => array:2 [
              0 => "Default"
              1 => "file:post"
            ]
          ]
          #filters: []
          #elasticsearch: null
          #mercure: null
          #messenger: null
          #input: null
          #output: null
          #order: null
          #fetchPartial: null
          #forceEager: null
          #paginationEnabled: true
          #paginationType: null
          #paginationItemsPerPage: null
          #paginationMaximumItemsPerPage: null
          #paginationPartial: null
          #paginationClientEnabled: null
          #paginationClientItemsPerPage: null
          #paginationClientPartial: null
          #paginationFetchJoinCollection: null
          #paginationUseOutputWalkers: null
          #security: null
          #securityMessage: null
          #securityPostDenormalize: null
          #securityPostDenormalizeMessage: null
          #securityPostValidation: null
          #securityPostValidationMessage: null
          #provider: "ApiPlatform\Doctrine\Orm\State\ItemProvider"
          #processor: "Coommercio\App\Coommercio\Api\State\Processor\SetAccountProcessor"
          #stateOptions: ApiPlatform\Doctrine\Orm\State\Options^ {#981
            #handleLinks: "api_platform.doctrine.orm.links_handler"
            #entityClass: null
          }
          #parameters: ApiPlatform\Metadata\Parameters^ {#980
            -parameters: []
          }
          #extraProperties: array:3 [
            "standard_put" => true
            "rfc_7807_compliant_errors" => true
            "user_defined_uri_template" => true
          ]
          #paginationViaCursor: null
          #read: false
          #deserialize: false
          #validate: null
          #write: null
          #serialize: null
          #priority: 1
          #name: "_api_/accounts/{account}/files/docs_post"
          #method: "POST"
          #uriTemplate: "/accounts/{account}/files/docs"
          #types: array:1 [
            0 => "FileDoc"
          ]
          #formats: null
          #inputFormats: array:1 [
            "multipart/form-data" => array:1 [
              0 => "multipart/form-data"
            ]
          ]
          #outputFormats: array:1 [
            "jsonld" => array:1 [
              0 => "application/ld+json"
            ]
          ]
          #uriVariables: array:1 [
            "account" => ApiPlatform\Metadata\Link^ {#979
              #key: null
              #schema: null
              #openApi: null
              #provider: null
              #filter: null
              #property: null
              #description: null
              #required: null
              #priority: null
              #constraints: null
              #extraProperties: []
              -parameterName: "account"
              -fromProperty: null
              -toProperty: "account"
              -fromClass: "Coommercio\App\Coommercio\Entity\Account"
              -toClass: null
              -identifiers: array:1 [
                0 => "id"
              ]
              -compositeIdentifier: null
              -expandedValue: null
              -security: null
              -securityMessage: null
              -securityObjectName: null
            }
          ]
          #routePrefix: null
          #routeName: null
          #defaults: null
          #requirements: null
          #options: null
          #stateless: true
          #sunset: null
          #acceptPatch: null
          #status: null
          #host: null
          #schemes: null
          #condition: null
          #controller: "Coommercio\App\Common\Controller\CreateFileVichAction"
          #headers: null
          #cacheHeaders: array:1 [
            "vary" => array:3 [
              0 => "Content-Type"
              1 => "Authorization"
              2 => "Origin"
            ]
          ]
          #hydraContext: null
          #openapiContext: null
          #openapi: ApiPlatform\OpenApi\Model\Operation^ {#978
            -operationId: null
            -tags: array:1 [
              0 => "0. Common > Files"
            ]
            -responses: null
            -summary: null
            -description: """
              Allowed mime types are:\n
              \n
              - `application/pdf`\n
              - `application/msword`\n
              - `application/vnd.ms-excel`\n
              - `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`\n
              - `application/vnd.openxmlformats-officedocument.wordprocessingml.document`
              """
            -externalDocs: null
            -parameters: null
            -requestBody: ApiPlatform\OpenApi\Model\RequestBody^ {#977
              -description: ""
              -content: ArrayObject {#909
                storage: array:1 [
                  "multipart/form-data" => array:1 [
                    "schema" => array:2 [
                      "type" => "object"
                      "properties" => array:1 [
                        "file" => array:2 [
                          "type" => "string"
                          "format" => "binary"
                        ]
                      ]
                    ]
                  ]
                ]
                flag::STD_PROP_LIST: false
                flag::ARRAY_AS_PROPS: false
                iteratorClass: "ArrayIterator"
              }
              -required: false
              -extensionProperties: []
            }
            -callbacks: null
            -deprecated: null
            -security: null
            -servers: null
            -extensionProperties: []
          }
          #exceptionToStatus: null
          #queryParameterValidationEnabled: null
          #links: null
          -itemUriTemplate: null
        }
      ]
    ]
  }
  #uriTemplate: null
  #types: array:1 [
    0 => "FileDoc"
  ]
  #formats: null
  #inputFormats: null
  #outputFormats: null
  #uriVariables: array:1 [
    "id" => ApiPlatform\Metadata\Link^ {#970
      #key: null
      #schema: null
      #openApi: null
      #provider: null
      #filter: null
      #property: null
      #description: null
      #required: null
      #priority: null
      #constraints: null
      #extraProperties: []
      -parameterName: "id"
      -fromProperty: null
      -toProperty: null
      -fromClass: "Coommercio\App\Common\Entity\FileDocVich"
      -toClass: null
      -identifiers: array:1 [
        0 => "id"
      ]
      -compositeIdentifier: null
      -expandedValue: null
      -security: null
      -securityMessage: null
      -securityObjectName: null
    }
  ]
  #routePrefix: null
  #defaults: null
  #requirements: null
  #options: null
  #stateless: true
  #sunset: null
  #acceptPatch: null
  #status: null
  #host: null
  #schemes: null
  #condition: null
  #controller: null
  #headers: null
  #cacheHeaders: array:1 [
    "vary" => array:3 [
      0 => "Content-Type"
      1 => "Authorization"
      2 => "Origin"
    ]
  ]
  #hydraContext: null
  #openapiContext: null
  #openapi: null
  #paginationViaCursor: null
  #compositeIdentifier: null
  #exceptionToStatus: null
  #queryParameterValidationEnabled: null
  #links: null
  #graphQlOperations: []
} 

@soyuka
Copy link
Member

soyuka commented May 6, 2024

I tried use_symfony_listeners: true it looks to be working I'll edit the docs

@soyuka soyuka closed this as completed May 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants