[Form] Catch exceptions in DataTransformers

This commit is contained in:
Victor Berchet 2011-05-10 12:27:15 +02:00
parent 9cc7aacf76
commit dac798c791
11 changed files with 212 additions and 60 deletions

View File

@ -25,17 +25,19 @@ class ArrayToBooleanChoicesTransformer implements DataTransformerInterface
}
/**
* Transforms a single choice or an array of choices to a format appropriate
* for the nested checkboxes/radio buttons.
* Transforms an array of choices to a format appropriate for the nested
* checkboxes/radio buttons.
*
* The result is an array with the options as keys and true/false as values,
* depending on whether a given option is selected. If this field is rendered
* as select tag, the value is not modified.
*
* @param mixed $array An array if "multiple" is set to true, a scalar
* value otherwise.
* @return mixed An array if "expanded" or "multiple" is set to true,
* a scalar value otherwise.
* @param mixed $array An array
*
* @return mixed An array
*
* @throws UnexpectedTypeException if the given value is not an array
* @throws TransformationFailedException if the choices can not be retrieved
*/
public function transform($array)
{
@ -47,27 +49,31 @@ class ArrayToBooleanChoicesTransformer implements DataTransformerInterface
throw new UnexpectedTypeException($array, 'array');
}
$choices = $this->choiceList->getChoices();
try {
$choices = $this->choiceList->getChoices();
} catch (\Exception $e) {
throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
}
foreach ($choices as $choice => $_) {
$choices[$choice] = in_array($choice, $array, true);
foreach (array_keys($choices) as $key) {
$choices[$key] = in_array($key, $array, true);
}
return $choices;
}
/**
* Transforms a checkbox/radio button array to a single choice or an array
* of choices.
* Transforms a checkbox/radio button array to an array of choices.
*
* The input value is an array with the choices as keys and true/false as
* values, depending on whether a given choice is selected. The output
* is an array with the selected choices or a single selected choice.
* is an array with the selected choices.
*
* @param mixed $value An array if "expanded" or "multiple" is set to true,
* a scalar value otherwise.
* @return mixed $value An array if "multiple" is set to true, a scalar
* value otherwise.
* @param mixed $value An array
*
* @return mixed $value An array
*
* @throws UnexpectedTypeException if the given value is not an array
*/
public function reverseTransform($value)
{

View File

@ -45,7 +45,11 @@ class DataTransformerChain implements DataTransformerInterface
* by this method.
*
* @param mixed $value The original value
*
* @return mixed The transformed value
*
* @throws Symfony\Component\Form\Exception\TransformationFailedException
* @throws Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function transform($value)
{
@ -66,7 +70,11 @@ class DataTransformerChain implements DataTransformerInterface
* by this method.
*
* @param mixed $value The transformed value
*
* @return mixed The reverse-transformed value
*
* @throws Symfony\Component\Form\Exception\TransformationFailedException
* @throws Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function reverseTransform($value)
{

View File

@ -56,6 +56,7 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
* @return array Localized date.
*
* @throws UnexpectedTypeException if the given value is not an instance of \DateTime
* @throws TransformationFailedException if the output timezone is not supported
*/
public function transform($dateTime)
{
@ -74,8 +75,13 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
throw new UnexpectedTypeException($dateTime, '\DateTime');
}
if ($this->inputTimezone !== $this->outputTimezone) {
$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
try {
$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
}
$result = array_intersect_key(array(
@ -106,6 +112,7 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
*
* @throws UnexpectedTypeException if the given value is not an array
* @throws TransformationFailedException if the value could not bet transformed
* @throws TransformationFailedException if the input timezone is not supported
*/
public function reverseTransform($value)
{
@ -146,14 +153,14 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
empty($value['second']) ? '0' : $value['second'],
$this->outputTimezone
));
if ($this->inputTimezone !== $this->outputTimezone) {
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
}
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
if ($this->inputTimezone !== $this->outputTimezone) {
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
}
return $dateTime;
}
}

View File

@ -52,11 +52,11 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
}
if (!in_array($dateFormat, self::$formats, true)) {
throw new \InvalidArgumentException(sprintf('The value $dateFormat is expected to be one of "%s". Is "%s"', implode('", "', self::$formats), $dateFormat));
throw new UnexpectedTypeException($dateFormat, implode('", "', self::$formats));
}
if (!in_array($timeFormat, self::$formats, true)) {
throw new \InvalidArgumentException(sprintf('The value $timeFormat is expected to be one of "%s". Is "%s"', implode('", "', self::$formats), $timeFormat));
throw new UnexpectedTypeException($timeFormat, implode('", "', self::$formats));
}
$this->dateFormat = $dateFormat;
@ -106,6 +106,7 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
*
* @throws UnexpectedTypeException if the given value is not a string
* @throws TransformationFailedException if the date could not be parsed
* @throws TransformationFailedException if the input timezone is not supported
*/
public function reverseTransform($value)
{
@ -127,7 +128,11 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
$dateTime = new \DateTime(sprintf('@%s UTC', $timestamp));
if ('UTC' !== $this->inputTimezone) {
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
try {
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
}
return $dateTime;

View File

@ -51,6 +51,7 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
* @return string A value as produced by PHP's date() function
*
* @throws UnexpectedTypeException if the given value is not a \DateTime instance
* @throws TransformationFailedException if the output timezone is not supported
*/
public function transform($value)
{
@ -62,7 +63,11 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
throw new UnexpectedTypeException($value, '\DateTime');
}
$value->setTimezone(new \DateTimeZone($this->outputTimezone));
try {
$value->setTimezone(new \DateTimeZone($this->outputTimezone));
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
return $value->format($this->format);
}
@ -76,6 +81,7 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
*
* @throws UnexpectedTypeException if the given value is not a string
* @throws TransformationFailedException if the date could not be parsed
* @throws TransformationFailedException if the input timezone is not supported
*/
public function reverseTransform($value)
{
@ -93,10 +99,10 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
if ($this->inputTimezone !== $this->outputTimezone) {
$dateTime->setTimeZone(new \DateTimeZone($this->inputTimezone));
}
return $dateTime;
} catch (\Exception $e) {
throw new TransformationFailedException('Invalid date format.', $e->getCode(), $e);
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
return $dateTime;
}
}

View File

@ -30,6 +30,7 @@ class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
* @return integer A timestamp
*
* @throws UnexpectedTypeException if the given value is not an instance of \DateTime
* @throws TransformationFailedException if the output timezone is not supported
*/
public function transform($value)
{
@ -41,7 +42,11 @@ class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
throw new UnexpectedTypeException($value, '\DateTime');
}
$value->setTimezone(new \DateTimeZone($this->outputTimezone));
try {
$value->setTimezone(new \DateTimeZone($this->outputTimezone));
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
return (int) $value->format('U');
}
@ -72,10 +77,10 @@ class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
if ($this->inputTimezone !== $this->outputTimezone) {
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
}
return $dateTime;
} catch (\Exception $e) {
throw new TransformationFailedException('Invalid timestamp format.', $e->getCode(), $e);
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
return $dateTime;
}
}

View File

@ -13,6 +13,8 @@ namespace Symfony\Component\Form\Extension\Core\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\HttpFoundation\File\File;
/**
@ -20,6 +22,15 @@ use Symfony\Component\HttpFoundation\File\File;
*/
class FileToStringTransformer implements DataTransformerInterface
{
/**
* Transforms a File instance to a path
*
* @param File $file The file
*
* @return string The path to the file
*
* @throws UnexpectedTypeException if the given file is not an instance of File
*/
public function transform($file)
{
if (null === $file || '' === $file) {
@ -33,6 +44,17 @@ class FileToStringTransformer implements DataTransformerInterface
return $file->getPath();
}
/**
* Transforms a path to a File instance
*
* @param string $path The path to the file
*
* @return File The File
*
* @throws UnexpectedTypeException if the given path is not a string
* @throws TransformationFailedException if the File instance could not be created
*/
public function reverseTransform($path)
{
if (null === $path || '' === $path) {
@ -43,6 +65,16 @@ class FileToStringTransformer implements DataTransformerInterface
throw new UnexpectedTypeException($path, 'string');
}
return new File($path);
try {
$file = new File($path);
} catch (FileNotFoundException $e) {
throw new TransformationFailedException(
sprintf('The file "%s" does not exist', $path),
$e->getCode(),
$e
);
}
return $file;
}
}

View File

@ -19,14 +19,19 @@ class ScalarToBooleanChoicesTransformer implements DataTransformerInterface
{
private $choiceList;
/**
* Constructor.
*
* @param ChoiceListInterface $choiceList
*/
public function __construct(ChoiceListInterface $choiceList)
{
$this->choiceList = $choiceList;
}
/**
* Transforms a single choice or an array of choices to a format appropriate
* for the nested checkboxes/radio buttons.
* Transforms a single choice to a format appropriate for the nested
* checkboxes/radio buttons.
*
* The result is an array with the options as keys and true/false as values,
* depending on whether a given option is selected. If this field is rendered
@ -34,32 +39,43 @@ class ScalarToBooleanChoicesTransformer implements DataTransformerInterface
*
* @param mixed $value An array if "multiple" is set to true, a scalar
* value otherwise.
* @return mixed An array if "expanded" or "multiple" is set to true,
* a scalar value otherwise.
*
* @return mixed An array
*
* @throws UnexpectedTypeException if the given value is not scalar
* @throws TransformationFailedException if the choices can not be retrieved
*/
public function transform($value)
{
$choices = $this->choiceList->getChoices();
if (!is_scalar($value) && !is_null($value)) {
throw new UnexpectedTypeException($value, 'scalar');
}
foreach ($choices as $choice => $_) {
$choices[$choice] = $choice === $value;
try {
$choices = $this->choiceList->getChoices();
} catch (\Exception $e) {
throw new TransformationFailedException('Can not get the choice list', $e->getCode(), $e);
}
foreach (array_keys($choices) as $key) {
$choices[$key] = $key === $value;
}
return $choices;
}
/**
* Transforms a checkbox/radio button array to a single choice or an array
* of choices.
* Transforms a checkbox/radio button array to a single choice.
*
* The input value is an array with the choices as keys and true/false as
* values, depending on whether a given choice is selected. The output
* is an array with the selected choices or a single selected choice.
* is the selected choice.
*
* @param mixed $value An array if "expanded" or "multiple" is set to true,
* a scalar value otherwise.
* @return mixed $value An array if "multiple" is set to true, a scalar
* value otherwise.
* @param array $value An array of values
*
* @return mixed $value A scalar value
*
* @throws new UnexpectedTypeException if the given value is not an array
*/
public function reverseTransform($value)
{

View File

@ -123,12 +123,12 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase
$this->assertEquals($dateTime->format('d.m.Y H:i'), $transformer->transform($input));
}
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testTransformRequiresValidDateTime()
{
$transformer = new DateTimeToLocalizedStringTransformer();
$this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
$transformer->transform('2010-01-01');
}
@ -225,35 +225,37 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase
$this->assertSame(null, $transformer->reverseTransform('', null));
}
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testReverseTransformRequiresString()
{
$transformer = new DateTimeToLocalizedStringTransformer();
$this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
$transformer->reverseTransform(12345, null);
}
/**
* @expectedException Symfony\Component\Form\Exception\TransformationFailedException
*/
public function testReverseTransformWrapsIntlErrors()
{
$transformer = new DateTimeToLocalizedStringTransformer();
$this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
$transformer->reverseTransform('12345', null);
}
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testValidateDateFormatOption()
{
$this->setExpectedException('\InvalidArgumentException');
new DateTimeToLocalizedStringTransformer(null, null, 'foobar');
}
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testValidateTimeFormatOption()
{
$this->setExpectedException('\InvalidArgumentException');
new DateTimeToLocalizedStringTransformer(null, null, null, 'foobar');
}
}

View File

@ -0,0 +1,65 @@
<?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\Tests\Component\Form\Extension\Core\DataTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\FileToStringTransformer;
use Symfony\Component\HttpFoundation\File\File;
class FileToStringTransformerTest extends \PHPUnit_Framework_TestCase
{
private $transformer;
protected function setUp()
{
$this->transformer = new FileToStringTransformer();
}
public function testTransform()
{
$path = realpath(__DIR__.'/../../../Fixtures/foo');
$file = new File($path);
$t = $this->transformer->transform($file);
$this->assertTrue(file_exists($path));
$this->assertInternalType('string', $t);
$this->assertEquals($path, realpath($t));
}
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testTransformRequiresAFile()
{
$this->transformer->transform(array());
}
public function testReverseTransform()
{
$path = realpath(__DIR__.'/../../../Fixtures/foo');
$file = new File($path);
$r = $this->transformer->reverseTransform($path);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $file);
$this->assertEquals($path, realpath($r->getPath()));
}
/**
* @expectedException Symfony\Component\Form\Exception\TransformationFailedException
*/
public function testReverseTransformRequiresArray()
{
$t = $this->transformer->reverseTransform(__DIR__.'/../../../Fixtures/no-foo');
}
}