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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,6 +13,8 @@ namespace Symfony\Component\Form\Extension\Core\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException; 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; use Symfony\Component\HttpFoundation\File\File;
/** /**
@ -20,6 +22,15 @@ use Symfony\Component\HttpFoundation\File\File;
*/ */
class FileToStringTransformer implements DataTransformerInterface 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) public function transform($file)
{ {
if (null === $file || '' === $file) { if (null === $file || '' === $file) {
@ -33,6 +44,17 @@ class FileToStringTransformer implements DataTransformerInterface
return $file->getPath(); 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) public function reverseTransform($path)
{ {
if (null === $path || '' === $path) { if (null === $path || '' === $path) {
@ -43,6 +65,16 @@ class FileToStringTransformer implements DataTransformerInterface
throw new UnexpectedTypeException($path, 'string'); 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; private $choiceList;
/**
* Constructor.
*
* @param ChoiceListInterface $choiceList
*/
public function __construct(ChoiceListInterface $choiceList) public function __construct(ChoiceListInterface $choiceList)
{ {
$this->choiceList = $choiceList; $this->choiceList = $choiceList;
} }
/** /**
* Transforms a single choice or an array of choices to a format appropriate * Transforms a single choice to a format appropriate for the nested
* for the nested checkboxes/radio buttons. * checkboxes/radio buttons.
* *
* The result is an array with the options as keys and true/false as values, * 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 * 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 * @param mixed $value An array if "multiple" is set to true, a scalar
* value otherwise. * 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) public function transform($value)
{ {
$choices = $this->choiceList->getChoices(); if (!is_scalar($value) && !is_null($value)) {
throw new UnexpectedTypeException($value, 'scalar');
}
foreach ($choices as $choice => $_) { try {
$choices[$choice] = $choice === $value; $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; return $choices;
} }
/** /**
* Transforms a checkbox/radio button array to a single choice or an array * Transforms a checkbox/radio button array to a single choice.
* of choices.
* *
* The input value is an array with the choices as keys and true/false as * 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 * 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, * @param array $value An array of values
* a scalar value otherwise. *
* @return mixed $value An array if "multiple" is set to true, a scalar * @return mixed $value A scalar value
* value otherwise. *
* @throws new UnexpectedTypeException if the given value is not an array
*/ */
public function reverseTransform($value) 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)); $this->assertEquals($dateTime->format('d.m.Y H:i'), $transformer->transform($input));
} }
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testTransformRequiresValidDateTime() public function testTransformRequiresValidDateTime()
{ {
$transformer = new DateTimeToLocalizedStringTransformer(); $transformer = new DateTimeToLocalizedStringTransformer();
$this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
$transformer->transform('2010-01-01'); $transformer->transform('2010-01-01');
} }
@ -225,35 +225,37 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase
$this->assertSame(null, $transformer->reverseTransform('', null)); $this->assertSame(null, $transformer->reverseTransform('', null));
} }
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testReverseTransformRequiresString() public function testReverseTransformRequiresString()
{ {
$transformer = new DateTimeToLocalizedStringTransformer(); $transformer = new DateTimeToLocalizedStringTransformer();
$this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
$transformer->reverseTransform(12345, null); $transformer->reverseTransform(12345, null);
} }
/**
* @expectedException Symfony\Component\Form\Exception\TransformationFailedException
*/
public function testReverseTransformWrapsIntlErrors() public function testReverseTransformWrapsIntlErrors()
{ {
$transformer = new DateTimeToLocalizedStringTransformer(); $transformer = new DateTimeToLocalizedStringTransformer();
$this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
$transformer->reverseTransform('12345', null); $transformer->reverseTransform('12345', null);
} }
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testValidateDateFormatOption() public function testValidateDateFormatOption()
{ {
$this->setExpectedException('\InvalidArgumentException');
new DateTimeToLocalizedStringTransformer(null, null, 'foobar'); new DateTimeToLocalizedStringTransformer(null, null, 'foobar');
} }
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testValidateTimeFormatOption() public function testValidateTimeFormatOption()
{ {
$this->setExpectedException('\InvalidArgumentException');
new DateTimeToLocalizedStringTransformer(null, null, null, 'foobar'); 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');
}
}