我正在使用Symfony 4,ApiPlatform 1和VichUploaderBundle 1。
按照说明in docs进行了所有操作,但出现错误:Cannot validate values of type \"NULL\" automatically. Please provide a constraint.
我什至不知道如何调试它-错误和回溯非常无用。从哪里开始搜索?请帮助。
我的图片实体:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity(repositoryClass="App\Repository\ImageRepository")
* @ApiResource(iri="http://schema.org/MediaObject")
* @Vich\Uploadable
*/
class Image
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @Groups({"user"})
*/
private $id;
/**
* @var File|null
* @Assert\NotNull()
* @Vich\UploadableField(mapping="image", fileNameProperty="contentUrl")
*/
public $file;
/**
* @var string|null
* @ORM\Column(nullable=true)
* @ApiProperty(iri="http://schema.org/contentUrl")
* @Groups({"user"})
*/
private $contentUrl;
public function getId(): ?int { return $this->id; }
public function getContentUrl(): ?string { return $this->contentUrl; }
public function setContentUrl(string $contentUrl): void { $this->contentUrl = $contentUrl; }
}
路由Yaml配置:
app_image_upload:
methods : ['POST']
path : '/images'
defaults:
_controller : App\Controller\CreateImageAction
_api_resource_class: App\Entity\Image
_api_receive : false
为其自定义操作:
<?php
namespace App\Controller;
use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
use App\Entity\Image;
use App\Form\ImageType;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
final class CreateImageAction
{
private $validator;
private $doctrine;
private $factory;
private $uploader;
public function __construct(
RegistryInterface $doctrine,
FormFactoryInterface $factory,
ValidatorInterface $validator,
UploaderHelper $uploader
) {
$this->validator = $validator;
$this->doctrine = $doctrine;
$this->factory = $factory;
$this->uploader = $uploader;
}
public function __invoke(Request $request): Image
{
$image = new Image();
$form = $this->factory->create(ImageType::class, $image);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->doctrine->getManager();
$em->persist($image);
$em->flush();
$image->setContentUrl($this->uploader->asset($image, 'file'));
$em->merge($image);
$em->flush();
// Prevent the serialization of the file property
$image->file = null;
return $image;
}
// This will be handled by API Platform and returns a validation error.
throw new ValidationException($this->validator->validate($image));
}
}
和形式:
<?php
namespace App\Form;
use App\Entity\Image;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class ImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('file', FileType::class, [
'label' => 'label.file',
'required' => false,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Image::class,
'csrf_protection' => false,
]);
}
public function getBlockPrefix(): string
{
return '';
}
}
我的请求如下:
$ http -v --form 'api.example.com/api/images' @image.png
POST /api/images HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Authorization: Bearer [API_TOKEN]
Connection: keep-alive
Content-Length: 48888
Content-Type: multipart/form-data; boundary=aedf69840efb693f8ef3f566bc1be656
Host: api.example.com
User-Agent: HTTPie/1.0.2
+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+
然后回应:
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache, private
Connection: keep-alive
Content-Type: application/ld+json; charset=utf-8
Date: Sat, 29 Dec 2018 04:10:27 GMT
Link: <http://api.example.com/api/docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: deny
{
"@context": "/api/contexts/Error",
"@type": "hydra:Error",
"hydra:description": "Cannot validate values of type \"NULL\" automatically. Please provide a constraint.",
"hydra:title": "An error occurred",
"trace": [
{
"args": [],
"class": "",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/validator/Validator/RecursiveContextualValidator.php",
"function": "",
"line": 166,
"namespace": "",
"short_class": "",
"type": ""
},
{
"args": [
[
"null",
null
],
[
"null",
null
],
[
"array",
[
[
"string",
"Default"
]
]
]
],
"class": "Symfony\\Component\\Validator\\Validator\\RecursiveContextualValidator",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/validator/Validator/RecursiveValidator.php",
"function": "validate",
"line": 100,
"namespace": "Symfony\\Component\\Validator\\Validator",
"short_class": "RecursiveContextualValidator",
"type": "->"
},
{
"args": [
[
"null",
null
],
[
"null",
null
],
[
"null",
null
]
],
"class": "Symfony\\Component\\Validator\\Validator\\RecursiveValidator",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/validator/Validator/TraceableValidator.php",
"function": "validate",
"line": 66,
"namespace": "Symfony\\Component\\Validator\\Validator",
"short_class": "RecursiveValidator",
"type": "->"
},
{
"args": [
[
"null",
null
],
[
"null",
null
],
[
"null",
null
]
],
"class": "Symfony\\Component\\Validator\\Validator\\TraceableValidator",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/api-platform/core/src/Bridge/Symfony/Validator/Validator.php",
"function": "validate",
"line": 61,
"namespace": "Symfony\\Component\\Validator\\Validator",
"short_class": "TraceableValidator",
"type": "->"
},
{
"args": [
[
"null",
null
],
[
"array",
{
"groups": [
"null",
null
]
}
]
],
"class": "ApiPlatform\\Core\\Bridge\\Symfony\\Validator\\Validator",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/api-platform/core/src/Validator/EventListener/ValidateListener.php",
"function": "validate",
"line": 59,
"namespace": "ApiPlatform\\Core\\Bridge\\Symfony\\Validator",
"short_class": "Validator",
"type": "->"
},
{
"args": [
[
"object",
"Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"
],
[
"string",
"kernel.view"
],
[
"object",
"Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"
]
],
"class": "ApiPlatform\\Core\\Validator\\EventListener\\ValidateListener",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/event-dispatcher/Debug/WrappedListener.php",
"function": "onKernelView",
"line": 111,
"namespace": "ApiPlatform\\Core\\Validator\\EventListener",
"short_class": "ValidateListener",
"type": "->"
},
{
"args": [
[
"object",
"Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"
],
[
"string",
"kernel.view"
],
[
"object",
"Symfony\\Component\\EventDispatcher\\EventDispatcher"
]
],
"class": "Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/event-dispatcher/EventDispatcher.php",
"function": "__invoke",
"line": 212,
"namespace": "Symfony\\Component\\EventDispatcher\\Debug",
"short_class": "WrappedListener",
"type": "->"
},
{
"args": [
[
"array",
[
[
"object",
"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
],
[
"object",
"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
],
[
"object",
"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
],
[
"object",
"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
],
[
"object",
"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
],
[
"object",
"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
],
[
"object",
"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"
]
]
],
[
"string",
"kernel.view"
],
[
"object",
"Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"
]
],
"class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/event-dispatcher/EventDispatcher.php",
"function": "doDispatch",
"line": 44,
"namespace": "Symfony\\Component\\EventDispatcher",
"short_class": "EventDispatcher",
"type": "->"
},
{
"args": [
[
"string",
"kernel.view"
],
[
"object",
"Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"
]
],
"class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php",
"function": "dispatch",
"line": 142,
"namespace": "Symfony\\Component\\EventDispatcher",
"short_class": "EventDispatcher",
"type": "->"
},
{
"args": [
[
"string",
"kernel.view"
],
[
"object",
"Symfony\\Component\\HttpKernel\\Event\\GetResponseForControllerResultEvent"
]
],
"class": "Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/http-kernel/HttpKernel.php",
"function": "dispatch",
"line": 155,
"namespace": "Symfony\\Component\\EventDispatcher\\Debug",
"short_class": "TraceableEventDispatcher",
"type": "->"
},
{
"args": [
[
"object",
"Symfony\\Component\\HttpFoundation\\Request"
],
[
"integer",
1
]
],
"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/http-kernel/HttpKernel.php",
"function": "handleRaw",
"line": 67,
"namespace": "Symfony\\Component\\HttpKernel",
"short_class": "HttpKernel",
"type": "->"
},
{
"args": [
[
"object",
"Symfony\\Component\\HttpFoundation\\Request"
],
[
"integer",
1
],
[
"boolean",
true
]
],
"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/vendor/symfony/http-kernel/Kernel.php",
"function": "handle",
"line": 198,
"namespace": "Symfony\\Component\\HttpKernel",
"short_class": "HttpKernel",
"type": "->"
},
{
"args": [
[
"object",
"Symfony\\Component\\HttpFoundation\\Request"
]
],
"class": "Symfony\\Component\\HttpKernel\\Kernel",
"file": "/Users/SOMEUSER/Projects/MYPROJECT/www/public/index.php",
"function": "handle",
"line": 37,
"namespace": "Symfony\\Component\\HttpKernel",
"short_class": "Kernel",
"type": "->"
}
]
}
UPD:MWE on GitHub
答案 0 :(得分:1)
通过更精确地遵循文档,一切正常:您只是忘记了正确的new Subject<boolean>().next(true)
批注和@ApiResource
中的use语句
Image.php