[Form] Refactored FileField to FormFactory and fixed file upload mechanism

This commit is contained in:
Bernhard Schussek 2011-02-24 20:47:48 +01:00
parent 848ec01f02
commit f2c1976da6
12 changed files with 514 additions and 359 deletions

View File

@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\DataProcessor;
use Symfony\Component\Form\FieldInterface;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\File\TemporaryStorage;
/**
* Moves uploaded files to a temporary location
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class FileUploader implements DataProcessorInterface
{
private $field;
private $storage;
public function __construct(FieldInterface $field, TemporaryStorage $storage)
{
$this->field = $field;
$this->storage = $storage;
}
public function processData($data)
{
// Newly uploaded file
if ($data['file'] instanceof UploadedFile && $data['file']->isValid()) {
$data['token'] = (string)rand(100000, 999999);
$directory = $this->storage->getTempDir($data['token']);
if (!file_exists($directory)) {
// Recursively create directories
mkdir($directory, 0777, true);
}
$data['file']->move($directory);
$data['name'] = $data['file']->getName();
}
// Existing uploaded file
if (!$data['file'] && $data['token'] && $data['name']) {
$path = $this->storage->getTempDir($data['token']) . DIRECTORY_SEPARATOR . $data ['name'];
if (file_exists($path)) {
$data['file'] = new File($path);
}
}
// Clear other fields if we still don't have a file, but keep
// possible existing files of the field
if (!$data['file']) {
$currentData = $this->field->getNormalizedData();
$data['file'] = $currentData['file'];
$data['token'] = '';
$data['name'] = '';
}
return $data;
}
}

View File

@ -1,205 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Form\Exception\FormException;
/**
* A file field to upload files.
*/
class FileField extends Form
{
/**
* Whether the size of the uploaded file exceeds the upload_max_filesize
* directive in php.ini
* @var Boolean
*/
protected $iniSizeExceeded = false;
/**
* Whether the size of the uploaded file exceeds the MAX_FILE_SIZE
* directive specified in the HTML form
* @var Boolean
*/
protected $formSizeExceeded = false;
/**
* Whether the file was completely uploaded
* @var Boolean
*/
protected $uploadComplete = true;
/**
* {@inheritDoc}
*/
protected function configure()
{
$this->addRequiredOption('secret');
$this->addOption('tmp_dir', sys_get_temp_dir());
parent::configure();
$this->add(new Field('file'));
$this->add(new HiddenField('token'));
$this->add(new HiddenField('original_name'));
}
/**
* Moves the file to a temporary location to prevent its deletion when
* the PHP process dies
*
* This way the file can survive if the form does not validate and is
* resubmitted.
*
* @see Symfony\Component\Form\Form::preprocessData()
*/
protected function preprocessData($data)
{
if ($data['file']) {
switch ($data['file']->getError()) {
case UPLOAD_ERR_INI_SIZE:
$this->iniSizeExceeded = true;
break;
case UPLOAD_ERR_FORM_SIZE:
$this->formSizeExceeded = true;
break;
case UPLOAD_ERR_PARTIAL:
$this->uploadComplete = false;
break;
case UPLOAD_ERR_NO_TMP_DIR:
throw new FormException('Could not upload a file because a temporary directory is missing (UPLOAD_ERR_NO_TMP_DIR)');
case UPLOAD_ERR_CANT_WRITE:
throw new FormException('Could not write file to disk (UPLOAD_ERR_CANT_WRITE)');
case UPLOAD_ERR_EXTENSION:
throw new FormException('A PHP extension stopped the file upload (UPLOAD_ERR_EXTENSION)');
case UPLOAD_ERR_OK:
default:
$data['file']->move($this->getTmpDir());
$data['file']->rename($this->getTmpName($data['token']));
$data['original_name'] = $data['file']->getOriginalName();
$data['file'] = '';
break;
}
}
return $data;
}
/**
* Turns a file path into an array of field values
*
* @see Symfony\Component\Form\Field::normalize()
*/
protected function normalize($path)
{
return array(
'file' => '',
'token' => rand(100000, 999999),
'original_name' => '',
);
}
/**
* Turns an array of field values into a file path
*
* @see Symfony\Component\Form\Field::denormalize()
*/
protected function denormalize($data)
{
$path = $this->getTmpPath($data['token']);
return file_exists($path) ? $path : $this->getData();
}
/**
* Returns the absolute temporary path to the uploaded file
*
* @param string $token
*/
protected function getTmpPath($token)
{
return $this->getTmpDir() . DIRECTORY_SEPARATOR . $this->getTmpName($token);
}
/**
* Returns the temporary directory where files are stored
*
* @param string $token
*/
protected function getTmpDir()
{
return realpath($this->getOption('tmp_dir'));
}
/**
* Returns the temporary file name for the given token
*
* @param string $token
*/
protected function getTmpName($token)
{
return md5(session_id() . $this->getOption('secret') . $token);
}
/**
* Returns the original name of the uploaded file
*
* @return string
*/
public function getOriginalName()
{
$data = $this->getNormalizedData();
return $data['original_name'];
}
/**
* {@inheritDoc}
*/
public function isMultipart()
{
return true;
}
/**
* Returns true if the size of the uploaded file exceeds the
* upload_max_filesize directive in php.ini
*
* @return Boolean
*/
public function isIniSizeExceeded()
{
return $this->iniSizeExceeded;
}
/**
* Returns true if the size of the uploaded file exceeds the
* MAX_FILE_SIZE directive specified in the HTML form
*
* @return Boolean
*/
public function isFormSizeExceeded()
{
return $this->formSizeExceeded;
}
/**
* Returns true if the file was completely uploaded
*
* @return Boolean
*/
public function isUploadComplete()
{
return $this->uploadComplete;
}
}

View File

@ -21,6 +21,7 @@ use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Form\DataProcessor\RadioToArrayConverter;
use Symfony\Component\Form\DataProcessor\UrlProtocolFixer;
use Symfony\Component\Form\DataProcessor\CollectionMerger;
use Symfony\Component\Form\DataProcessor\FileUploader;
use Symfony\Component\Form\FieldFactory\FieldFactoryInterface;
use Symfony\Component\Form\Renderer\DefaultRenderer;
use Symfony\Component\Form\Renderer\Theme\ThemeInterface;
@ -51,8 +52,11 @@ use Symfony\Component\Form\ValueTransformer\ValueTransformerChain;
use Symfony\Component\Form\ValueTransformer\ArrayToChoicesTransformer;
use Symfony\Component\Form\ValueTransformer\ArrayToPartsTransformer;
use Symfony\Component\Form\ValueTransformer\ValueToDuplicatesTransformer;
use Symfony\Component\Form\ValueTransformer\FileToArrayTransformer;
use Symfony\Component\Form\ValueTransformer\FileToStringTransformer;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Locale\Locale;
use Symfony\Component\HttpFoundation\File\TemporaryStorage;
class FormFactory
{
@ -64,12 +68,19 @@ class FormFactory
private $fieldFactory;
public function __construct(ThemeInterface $theme, CsrfProviderInterface $csrfProvider, ValidatorInterface $validator, FieldFactoryInterface $fieldFactory)
private $storage;
public function __construct(ThemeInterface $theme,
CsrfProviderInterface $csrfProvider,
ValidatorInterface $validator,
FieldFactoryInterface $fieldFactory,
TemporaryStorage $storage)
{
$this->theme = $theme;
$this->csrfProvider = $csrfProvider;
$this->validator = $validator;
$this->fieldFactory = $fieldFactory;
$this->storage = $storage;
}
protected function getTheme()
@ -866,4 +877,30 @@ class FormFactory
->add($firstChild)
->add($secondChild);
}
public function getFileField($key, array $options = array())
{
$options = array_merge(array(
'template' => 'file',
'type' => 'string',
), $options);
$field = $this->getForm($key, $options);
if ($options['type'] === 'string') {
$field->setNormalizationTransformer(new ValueTransformerChain(array(
new ReversedTransformer(new FileToStringTransformer()),
new FileToArrayTransformer(),
)));
} else {
$field->setNormalizationTransformer(new FileToArrayTransformer());
}
return $field
->setDataPreprocessor(new FileUploader($field, $this->storage))
->setData(null) // FIXME
->add($this->getField('file', array('type' => 'file')))
->add($this->getHiddenField('token'))
->add($this->getHiddenField('name'));
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\ValueTransformer;
use Symfony\Component\Form\ValueTransformer\TransformationFailedException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\HttpFoundation\File\File;
/**
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class FileToArrayTransformer implements ValueTransformerInterface
{
public function transform($file)
{
if (null === $file || '' === $file) {
return array(
'file' => '',
'token' => '',
'name' => '',
);
}
if (!$file instanceof File) {
throw new UnexpectedTypeException($file, 'Symfony\Component\HttpFoundation\File\File');
}
return array(
'file' => $file,
'token' => '',
'name' => '',
);
}
public function reverseTransform($array)
{
if (null === $array || '' === $array || array() === $array) {
return null;
}
if (!is_array($array)) {
throw new UnexpectedTypeException($array, 'array');
}
if (!array_key_exists('file', $array)) {
throw new TransformationFailedException('The key "file" is missing');
}
if (!empty($array['file']) && !$array['file'] instanceof File) {
throw new TransformationFailedException('The key "file" should be empty or instance of File');
}
return $array['file'];
}
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\ValueTransformer;
use Symfony\Component\Form\ValueTransformer\TransformationFailedException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\HttpFoundation\File\File;
/**
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class FileToStringTransformer implements ValueTransformerInterface
{
public function transform($file)
{
if (null === $file || '' === $file) {
return '';
}
if (!$file instanceof File) {
throw new UnexpectedTypeException($file, 'Symfony\Component\HttpFoundation\File\File');
}
return $file->getPath();
}
public function reverseTransform($path)
{
if (null === $path || '' === $path) {
return null;
}
if (!is_string($path)) {
throw new UnexpectedTypeException($path, 'string');
}
return new File($path);
}
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
class UnexpectedTypeException extends FileException
{
public function __construct($value, $expectedType)
{
parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
}
}

View File

@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File\Exception;
/**
* Thrown when an error occurred during file upload
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class UploadException extends FileException
{
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\UnexpectedTypeException;
/**
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class SessionBasedTemporaryStorage extends TemporaryStorage
{
public function __construct(Session $session, $directory, $secret, $nestingLevels = 3)
{
parent::__construct($directory, $secret, $nestingLevels);
$this->session = $session;
}
protected function generateHashInfo($token)
{
$this->session->start();
return $this->session->getId() . parent::generateHashInfo($token);
}
}

View File

@ -0,0 +1,66 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpFoundation\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\UnexpectedTypeException;
/**
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class TemporaryStorage
{
private $directory;
private $secret;
private $nestingLevels;
public function __construct($directory, $secret, $nestingLevels = 3)
{
$this->directory = realpath($directory);
$this->secret = $secret;
$this->nestingLevels = $nestingLevels;
}
protected function generateHashInfo($token)
{
return $this->secret . $token;
}
protected function generateHash($token)
{
return md5($this->generateHashInfo($token));
}
public function getTempDir($token)
{
if (!is_string($token)) {
throw new UnexpectedTypeException($token, 'string');
}
$hash = $this->generateHash($token);
if (strlen($hash) < $this->nestingLevels) {
throw new FileException(sprintf(
'For %s nesting levels the hash must have at least %s characters', $this->nestingLevels, $this->nestingLevels));
}
$directory = $this->directory;
for ($i = 0; $i < ($this->nestingLevels - 1); ++$i) {
$directory .= DIRECTORY_SEPARATOR . $hash{$i};
}
return $directory . DIRECTORY_SEPARATOR . substr($hash, $i);
}
}

View File

@ -2,7 +2,7 @@
/*
* This file is part of the Symfony package.
*
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
@ -12,6 +12,7 @@
namespace Symfony\Component\HttpFoundation\File;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\UploadException;
/**
* A file uploaded through a form.
@ -68,14 +69,24 @@ class UploadedFile extends File
throw new FileException(sprintf('Unable to create UploadedFile because "file_uploads" is disabled in your php.ini file (%s)', get_cfg_var('cfg_file_path')));
}
if (is_file($path)) {
$this->path = realpath($path);
}
if (null === $error) {
$error = UPLOAD_ERR_OK;
}
switch ($error) {
// TESTME
case UPLOAD_ERR_NO_TMP_DIR:
throw new UploadException('Could not upload a file because a temporary directory is missing (UPLOAD_ERR_NO_TMP_DIR)');
case UPLOAD_ERR_CANT_WRITE:
throw new UploadException('Could not write file to disk (UPLOAD_ERR_CANT_WRITE)');
case UPLOAD_ERR_EXTENSION:
throw new UploadException('A PHP extension stopped the file upload (UPLOAD_ERR_EXTENSION)');
}
if (is_file($path)) {
$this->path = realpath($path);
}
if (null === $mimeType) {
$mimeType = 'application/octet-stream';
}
@ -123,6 +134,48 @@ class UploadedFile extends File
return $this->error;
}
/**
* Returns whether the file was uploaded succesfully.
*
* @return Boolean True if no error occurred during uploading
*/
public function isValid()
{
return $this->error === UPLOAD_ERR_OK;
}
/**
* Returns true if the size of the uploaded file exceeds the
* upload_max_filesize directive in php.ini
*
* @return Boolean
*/
protected function isIniSizeExceeded()
{
return $this->error === UPLOAD_ERR_INI_SIZE;
}
/**
* Returns true if the size of the uploaded file exceeds the
* MAX_FILE_SIZE directive specified in the HTML form
*
* @return Boolean
*/
protected function isFormSizeExceeded()
{
return $this->error === UPLOAD_ERR_FORM_SIZE;
}
/**
* Returns true if the file was completely uploaded
*
* @return Boolean
*/
protected function isUploadComplete()
{
return $this->error !== UPLOAD_ERR_PARTIAL;
}
/**
* @inheritDoc
*/

View File

@ -11,10 +11,12 @@
namespace Symfony\Tests\Component\Form;
require_once __DIR__.'/TestCase.php';
use Symfony\Component\Form\FileField;
use Symfony\Component\HttpFoundation\File\File;
class FileFieldTest extends \PHPUnit_Framework_TestCase
class FileFieldTest extends TestCase
{
public static $tmpFiles = array();
@ -24,18 +26,14 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
public static function setUpBeforeClass()
{
self::$tmpDir = sys_get_temp_dir();
// we need a session ID
@session_start();
self::$tmpDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'symfony-test';
}
protected function setUp()
{
$this->field = new FileField('file', array(
'secret' => '$secret$',
'tmp_dir' => self::$tmpDir,
));
parent::setUp();
$this->field = $this->factory->getFileField('file');
}
protected function tearDown()
@ -54,180 +52,119 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
public function testSubmitUploadsNewFiles()
{
$tmpDir = realpath(self::$tmpDir);
$tmpName = md5(session_id() . '$secret$' . '12345');
$tmpPath = $tmpDir . DIRECTORY_SEPARATOR . $tmpName;
$that = $this;
$tmpDir = self::$tmpDir;
$generatedToken = '';
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
$this->storage->expects($this->atLeastOnce())
->method('getTempDir')
->will($this->returnCallback(function ($token) use ($tmpDir, &$generatedToken) {
// A 6-digit token is generated by FileUploader and passed
// to getTempDir()
$generatedToken = $token;
return $tmpDir;
}));
$file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$file->expects($this->once())
->method('move')
->with($this->equalTo($tmpDir));
$file->expects($this->once())
->method('rename')
->with($this->equalTo($tmpName))
->will($this->returnCallback(function ($directory) use ($that, $tmpPath) {
$that->createTmpFile($tmpPath);
}));
$file->expects($this->any())
->method('getOriginalName')
->method('isValid')
->will($this->returnValue(true));
$file->expects($this->any())
->method('getName')
->will($this->returnValue('original_name.jpg'));
$file->expects($this->any())
->method('getPath')
->will($this->returnValue($tmpDir.'/original_name.jpg'));
$this->field->submit(array(
'file' => $file,
'token' => '12345',
'original_name' => '',
'token' => '',
'name' => '',
));
$this->assertTrue(file_exists($tmpPath));
$this->assertRegExp('/^\d{6}$/', $generatedToken);
$this->assertEquals(array(
'file' => '',
'token' => '12345',
'original_name' => 'original_name.jpg',
'file' => $file,
'token' => $generatedToken,
'name' => 'original_name.jpg',
), $this->field->getDisplayedData());
$this->assertEquals($tmpPath, $this->field->getData());
$this->assertFalse($this->field->isIniSizeExceeded());
$this->assertFalse($this->field->isFormSizeExceeded());
$this->assertTrue($this->field->isUploadComplete());
$this->assertEquals($tmpDir.'/original_name.jpg', $this->field->getData());
}
public function testSubmitKeepsUploadedFilesOnErrors()
{
$tmpPath = self::$tmpDir . '/' . md5(session_id() . '$secret$' . '12345');
$tmpDir = self::$tmpDir;
$tmpPath = $tmpDir . DIRECTORY_SEPARATOR . 'original_name.jpg';
$this->createTmpFile($tmpPath);
$this->storage->expects($this->atLeastOnce())
->method('getTempDir')
->with($this->equalTo('123456'))
->will($this->returnValue($tmpDir));
$this->field->submit(array(
'file' => '',
'token' => '12345',
'original_name' => 'original_name.jpg',
'file' => null,
'token' => '123456',
'name' => 'original_name.jpg',
));
$this->assertTrue(file_exists($tmpPath));
$file = new File($tmpPath);
$this->assertEquals(array(
'file' => $file,
'token' => '123456',
'name' => 'original_name.jpg',
), $this->field->getDisplayedData());
$this->assertEquals($tmpPath, $this->field->getData());
}
public function testSubmitEmpty()
{
$this->storage->expects($this->never())
->method('getTempDir');
$this->field->submit(array(
'file' => '',
'token' => '',
'name' => '',
));
$this->assertEquals(array(
'file' => '',
'token' => '12345',
'original_name' => 'original_name.jpg',
'token' => '',
'name' => '',
), $this->field->getDisplayedData());
$this->assertEquals(realpath($tmpPath), realpath($this->field->getData()));
$this->assertEquals(null, $this->field->getData());
}
public function testSubmitKeepsOldFileIfNotOverwritten()
public function testSubmitEmptyKeepsExistingFiles()
{
$oldPath = tempnam(sys_get_temp_dir(), 'FileFieldTest');
$this->createTmpFile($oldPath);
$tmpPath = self::$tmpDir . DIRECTORY_SEPARATOR . 'original_name.jpg';
$this->createTmpFile($tmpPath);
$file = new File($tmpPath);
$this->field->setData($oldPath);
$this->assertEquals($oldPath, $this->field->getData());
$this->storage->expects($this->never())
->method('getTempDir');
$this->field->setData($tmpPath);
$this->field->submit(array(
'file' => '',
'token' => '12345',
'original_name' => '',
'token' => '',
'name' => '',
));
$this->assertTrue(file_exists($oldPath));
$this->assertEquals(array(
'file' => '',
'token' => '12345',
'original_name' => '',
'file' => $file,
'token' => '',
'name' => '',
), $this->field->getDisplayedData());
$this->assertEquals($oldPath, $this->field->getData());
}
public function testSubmitHandlesUploadErrIniSize()
{
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
$file->expects($this->any())
->method('getError')
->will($this->returnValue(UPLOAD_ERR_INI_SIZE));
$this->field->submit(array(
'file' => $file,
'token' => '12345',
'original_name' => ''
));
$this->assertTrue($this->field->isIniSizeExceeded());
}
public function testSubmitHandlesUploadErrFormSize()
{
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
$file->expects($this->any())
->method('getError')
->will($this->returnValue(UPLOAD_ERR_FORM_SIZE));
$this->field->submit(array(
'file' => $file,
'token' => '12345',
'original_name' => ''
));
$this->assertTrue($this->field->isFormSizeExceeded());
}
public function testSubmitHandlesUploadErrPartial()
{
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
$file->expects($this->any())
->method('getError')
->will($this->returnValue(UPLOAD_ERR_PARTIAL));
$this->field->submit(array(
'file' => $file,
'token' => '12345',
'original_name' => ''
));
$this->assertFalse($this->field->isUploadComplete());
}
public function testSubmitThrowsExceptionOnUploadErrNoTmpDir()
{
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
$file->expects($this->any())
->method('getError')
->will($this->returnValue(UPLOAD_ERR_NO_TMP_DIR));
$this->setExpectedException('Symfony\Component\Form\Exception\FormException');
$this->field->submit(array(
'file' => $file,
'token' => '12345',
'original_name' => ''
));
}
public function testSubmitThrowsExceptionOnUploadErrCantWrite()
{
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
$file->expects($this->any())
->method('getError')
->will($this->returnValue(UPLOAD_ERR_CANT_WRITE));
$this->setExpectedException('Symfony\Component\Form\Exception\FormException');
$this->field->submit(array(
'file' => $file,
'token' => '12345',
'original_name' => ''
));
}
public function testSubmitThrowsExceptionOnUploadErrExtension()
{
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
$file->expects($this->any())
->method('getError')
->will($this->returnValue(UPLOAD_ERR_EXTENSION));
$this->setExpectedException('Symfony\Component\Form\Exception\FormException');
$this->field->submit(array(
'file' => $file,
'token' => '12345',
'original_name' => ''
));
$this->assertEquals($tmpPath, $this->field->getData());
}
}

View File

@ -23,6 +23,8 @@ class TestCase extends \PHPUnit_Framework_TestCase
protected $fieldFactory;
protected $storage;
protected $factory;
protected function setUp()
@ -31,6 +33,10 @@ class TestCase extends \PHPUnit_Framework_TestCase
$this->csrfProvider = $this->getMock('Symfony\Component\Form\CsrfProvider\CsrfProviderInterface');
$this->validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
$this->fieldFactory = $this->getMock('Symfony\Component\Form\FieldFactory\FieldFactoryInterface');
$this->factory = new FormFactory($this->theme, $this->csrfProvider, $this->validator, $this->fieldFactory);
$this->storage = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\TemporaryStorage')
->disableOriginalConstructor()
->getMock();
$this->factory = new FormFactory($this->theme, $this->csrfProvider,
$this->validator, $this->fieldFactory, $this->storage);
}
}