我目前正在开发一个PHP v5.5.9项目,其中我正在使用一些独立组件(我不使用全栈框架),目前如下:
psr/log 1.0.0 Common interface for logging libraries
sonata-project/intl-bundle 2.2.1 Symfony SonataIntlBundle
symfony/debug v2.4.2 Symfony Debug Component
symfony/dependency-injection v2.4.2 Symfony DependencyInjection Component
symfony/event-dispatcher v2.4.2 Symfony EventDispatcher Component
symfony/form v2.4.2 Symfony Form Component
symfony/http-foundation v2.4.2 Symfony HttpFoundation Component
symfony/http-kernel v2.4.2 Symfony HttpKernel Component
symfony/icu v1.2.0 Contains an excerpt of the ICU data and classes to load it.
symfony/intl v2.4.2 A PHP replacement layer for the C intl extension that includes additional data from the ICU library.
symfony/locale v2.4.2 Symfony Locale Component
symfony/options-resolver v2.4.2 Symfony OptionsResolver Component
symfony/property-access v2.4.2 Symfony PropertyAccess Component
symfony/security-core v2.4.2 Symfony Security Component - Core Library
symfony/security-csrf v2.4.2 Symfony Security Component - CSRF Library
symfony/templating v2.4.2 Symfony Templating Component
symfony/translation v2.4.2 Symfony Translation Component
symfony/twig-bridge v2.4.2 Symfony Twig Bridge
symfony/validator v2.4.2 Symfony Validator Component
twig/extensions v1.0.1 Common additional features for Twig that do not directly belong in core
twig/twig v1.15.1 Twig, the flexible, fast, and secure template language for PHP
我有一个实体类,一个 FormType 类和一个 Controller ,我能够持久保存实体通过“Twig”模板查看。所以完整堆栈工作正常。
然后我在 Entity 中添加了File
属性,以便按照官方文档1中的说明添加图像文件。我还使用以下代码扩展了我的 FormType :
$builder->add('pictureFile', 'file', array('label' => 'Image File'));
运行更新后的代码(选择了图像文件)后,会显示以下错误:
Catchable fatal error: Argument 1 passed to MyEntity::setPictureFile() must be an instance of Symfony\Component\HttpFoundation\File\File, array given, called in [.]\vendor\symfony\property-access\Symfony\Component\PropertyAccess\PropertyAccessor.php on line [.] and defined in MyEntity.php on line [.]
因此,Symfony 不会自动从表单中创建UploadedFile
,但会将$_FILE
数据绑定到array
。我注意到,其他人也有这个问题:
目前我在 Controller 中使用以下代码,但我想使用自动绑定功能(因为目前我无法在中验证上传的文件实体)。
$formType = new MyType;
$entity = new MyEntity;
$form = $this->formFactory->create($formType, $entity);
$form->handleRequest();
if (true === $form->isSubmitted()) {
if (true === $form->isValid()) {
// TODO Replace ugly workaround to partially solve the problem of the file upload.
$request = Request::createFromGlobals();
$file = $request->files->get('myentity')['pictureFile'];
// Persist entity, upload file to server and redirect.
}
}
// Load View template.
编辑(2014-03-03):以下是实体的相关代码:
<?php
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Mapping\ClassMetadata;
class MyEntity
{
private $id;
private $name;
private $picture;
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getPictureFile()
{
return $this->pictureFile;
}
public function setPictureFile(File $pictureFile = null)
{
$this->pictureFile = $pictureFile;
}
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
$metadata->addPropertyConstraint(
'name',
new Assert\NotBlank
);
$metadata->addPropertyConstraint(
'name',
new Assert\Type('string'));
$metadata->addPropertyConstraint(
'pictureFile',
new Assert\Image(
array(
'maxSize' => '2048k',
'minWidth' => 640,
'maxWidth' => 4096,
'minHeight' => 480,
'maxHeight' => 4096
)
)
);
}
}
FormType 的源代码:
<?php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text')
->add(
'pictureFile',
'file',
array('label' => 'Image File')
)
->add('submit', 'submit', array('label' => 'Save'));
}
public function getName()
{
return 'myentity';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => __NAMESPACE__ . '\MyEntity'));
}
}
有关如何使这项工作的任何建议吗?
编辑(2014-03-07):简化的源代码,为我的回答做准备。
答案 0 :(得分:1)
我找到了问题中描述的问题的解决方案。由于这似乎是许多人的问题,我在这个答案中描述了我的解决方案。
在我的研究过程中,我遇到了issue on GitHub,其中包含一个虚拟 DataTransformer 。
在阅读该页面的内容后,我提出了使用自定义 DataTransformer 进行尝试的想法,该文件将array
转换为UploadedFile
的实例。< / p>
以下是逐步解决方案:
使用以下源代码创建名为UploadedFileTransformer
的{{3}}:
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class UploadedFileTransformer implements DataTransformerInterface
{
/**
* {@inheritdoc}
*
* @param array $data The array to transform to an uploaded file.
*
* @return \Symfony\Component\HttpFoundation\File\UploadedFile|null The
* uploaded file or `null` if no file has been uploaded.
*/
public function reverseTransform($data)
{
if (!$data) {
return null;
}
$path = $data['tmp_name'];
$pathinfo = pathinfo($path);
$basename = $pathinfo['basename'];
try {
$uploadedFile = new UploadedFile(
$path,
$basename,
$data['type'],
$data['size'],
$data['error']
);
} catch (FileNotFoundException $ex) {
throw new TransformationFailedException($ex->getMessage());
}
return $uploadedFile;
}
/**
* {@inheritdoc}
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile|null $file The
* uploaded file to transform to an `array`.
*
* @return \Symfony\Component\HttpFoundation\File\UploadedFile|null The
* argument `$file`.
*/
public function transform($file)
{
return $file;
}
}
更新 FormType 以使用UploadedFileTransformer
作为file
类型输入字段(与问题中的代码进行比较):
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text')
->add(
$builder->create(
'pictureFile',
'file',
array('label' => 'Image File')
)->addModelTransformer(new \UploadedFileTransformer)
)
->add('submit', 'submit', array('label' => 'Save'));
}
public function getName()
{
return 'myentity';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array('data_class' => __NAMESPACE__ . '\MyEntity'));
}
}
从 Controller 中删除垃圾,在我的示例中,访问Request
对象以获取上传的文件(与问题中的代码进行比较)。
$formType = new MyType;
$entity = new MyEntity;
$form = $this->formFactory->create($formType, $entity);
$form->handleRequest();
if (true === $form->isSubmitted()) {
if (true === $form->isValid()) {
$file = $entity->getPictureFile();
// Persist entity, upload file to server and redirect.
}
}
// Load View template.
就是这样。没有摆弄 FormType 中的属性以及 Entity 中的验证也可以。
我真的不知道,为什么这不是Symfony组件的默认行为?也许我错过了在我的启动代码中注册的东西?
答案 1 :(得分:0)
只需将多部分添加到表单中即可使用
<form action="#" method="post" enctype="multipart/form-data">
</form>