diff --git a/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php b/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php index ed46134c52..f90217be2d 100644 --- a/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php +++ b/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php @@ -357,7 +357,7 @@ class ModelChoiceList extends ObjectChoiceList } // readonly="true" models do not implement Persistent. - if ($model instanceof BaseObject and method_exists($model, 'getPrimaryKey')) { + if ($model instanceof BaseObject && method_exists($model, 'getPrimaryKey')) { return array($model->getPrimaryKey()); } diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index cc3f9272eb..673fd5fde2 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -32,12 +32,12 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer * * @see BaseDateTimeTransformer::formats for available format options * - * @param string $inputTimezone The name of the input timezone - * @param string $outputTimezone The name of the output timezone - * @param integer $dateFormat The date format - * @param integer $timeFormat The time format - * @param \IntlDateFormatter $calendar An \IntlDateFormatter instance - * @param string $pattern A pattern to pass to \IntlDateFormatter + * @param string $inputTimezone The name of the input timezone + * @param string $outputTimezone The name of the output timezone + * @param integer $dateFormat The date format + * @param integer $timeFormat The time format + * @param integer $calendar One of the \IntlDateFormatter calendar constants + * @param string $pattern A pattern to pass to \IntlDateFormatter * * @throws UnexpectedTypeException If a format is not supported * @throws UnexpectedTypeException if a timezone is not a string diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php index a257fd3ce8..cbaac96859 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php @@ -22,31 +22,73 @@ use Symfony\Component\Form\Exception\UnexpectedTypeException; */ class DateTimeToStringTransformer extends BaseDateTimeTransformer { - private $format; + /** + * Format used for generating strings + * @var string + */ + private $generateFormat; + + /** + * Format used for parsing strings + * + * Different than the {@link $generateFormat} because formats for parsing + * support additional characters in PHP that are not supported for + * generating strings. + * + * @var string + */ + private $parseFormat; + + /** + * Whether to parse by appending a pipe "|" to the parse format. + * + * This only works as of PHP 5.3.8. + * + * @var Boolean + */ + private $parseUsingPipe; /** * Transforms a \DateTime instance to a string * * @see \DateTime::format() for supported formats * - * @param string $inputTimezone The name of the input timezone - * @param string $outputTimezone The name of the output timezone - * @param string $format The date format + * @param string $inputTimezone The name of the input timezone + * @param string $outputTimezone The name of the output timezone + * @param string $format The date format + * @param Boolean $parseUsingPipe Whether to parse by appending a pipe "|" to the parse format * * @throws UnexpectedTypeException if a timezone is not a string */ - public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s') + public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = null) { parent::__construct($inputTimezone, $outputTimezone); - $this->format = $format; + $this->generateFormat = $this->parseFormat = $format; + + // The pipe in the parser pattern only works as of PHP 5.3.8 + $this->parseUsingPipe = null === $parseUsingPipe + ? version_compare(phpversion(), '5.3.8', '>=') + : $parseUsingPipe; + + // See http://php.net/manual/en/datetime.createfromformat.php + // The character "|" in the format makes sure that the parts of a date + // that are *not* specified in the format are reset to the corresponding + // values from 1970-01-01 00:00:00 instead of the current time. + // Without "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 12:32:47", + // where the time corresponds to the current server time. + // With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00", + // which is at least deterministic and thus used here. + if ($this->parseUsingPipe && false === strpos($this->parseFormat, '|')) { + $this->parseFormat .= '|'; + } } /** * Transforms a DateTime object into a date string with the configured format * and timezone * - * @param DateTime $value A DateTime object + * @param \DateTime $value A DateTime object * * @return string A value as produced by PHP's date() function * @@ -70,7 +112,7 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } - return $value->format($this->format); + return $value->format($this->generateFormat); } /** @@ -78,7 +120,7 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer * * @param string $value A value as produced by PHP's date() function * - * @return \DateTime An instance of \DateTime + * @return \DateTime An instance of \DateTime * * @throws UnexpectedTypeException if the given value is not a string * @throws TransformationFailedException if the date could not be parsed @@ -95,20 +137,89 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer } try { - $dateTime = new \DateTime($value, new \DateTimeZone($this->outputTimezone)); - $lastErrors = \DateTime::getLastErrors(); - if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) { - throw new \UnexpectedValueException(implode(', ', array_merge(array_values($lastErrors['warnings']), array_values($lastErrors['errors'])))); + $outputTz = new \DateTimeZone($this->outputTimezone); + $dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz); + + // On PHP versions < 5.3.8 we need to emulate the pipe operator + // and reset parts not given in the format to their equivalent + // of the UNIX base timestamp. + if (!$this->parseUsingPipe) { + list($year, $month, $day, $hour, $minute, $second) = explode('-', $dateTime->format('Y-m-d-H-i-s')); + + // Check which of the date parts are present in the pattern + preg_match( + '/(' . + '(?[djDl])|' . + '(?[FMmn])|' . + '(?[Yy])|' . + '(?[ghGH])|' . + '(?i)|' . + '(?s)|' . + '(?z)|' . + '(?U)|' . + '[^djDlFMmnYyghGHiszU]' . + ')*/', + $this->parseFormat, + $matches + ); + + // preg_match() does not guarantee to set all indices, so + // set them unless given + $matches = array_merge(array( + 'day' => false, + 'month' => false, + 'year' => false, + 'hour' => false, + 'minute' => false, + 'second' => false, + 'dayofyear' => false, + 'timestamp' => false, + ), $matches); + + // Reset all parts that don't exist in the format to the + // corresponding part of the UNIX base timestamp + if (!$matches['timestamp']) { + if (!$matches['dayofyear']) { + if (!$matches['day']) { + $day = 1; + } + if (!$matches['month']) { + $month = 1; + } + } + if (!$matches['year']) { + $year = 1970; + } + if (!$matches['hour']) { + $hour = 0; + } + if (!$matches['minute']) { + $minute = 0; + } + if (!$matches['second']) { + $second = 0; + } + $dateTime->setDate($year, $month, $day); + $dateTime->setTime($hour, $minute, $second); + } } - // Force value to be in same format as given to transform - if ($value !== $dateTime->format($this->format)) { - $dateTime = new \DateTime($dateTime->format($this->format), new \DateTimeZone($this->outputTimezone)); + $lastErrors = \DateTime::getLastErrors(); + + if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) { + throw new TransformationFailedException( + implode(', ', array_merge( + array_values($lastErrors['warnings']), + array_values($lastErrors['errors']) + )) + ); } if ($this->inputTimezone !== $this->outputTimezone) { $dateTime->setTimeZone(new \DateTimeZone($this->inputTimezone)); } + } catch (TransformationFailedException $e) { + throw $e; } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index ab0bf2f2d5..f776f5e12d 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -34,7 +34,7 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase $this->dateTimeWithoutSeconds = null; } - public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) + public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false) { if ($expected instanceof \DateTime && $actual instanceof \DateTime) { $expected = $expected->format('c'); @@ -44,54 +44,59 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase parent::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); } - public function testTransformShortDate() + public function dataProvider() { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::SHORT); - $this->assertEquals('03.02.10 04:05', $transformer->transform($this->dateTime)); + return array( + array(\IntlDateFormatter::SHORT, null, null, '03.02.10 04:05', '2010-02-03 04:05:00 UTC'), + array(\IntlDateFormatter::MEDIUM, null, null, '03.02.2010 04:05', '2010-02-03 04:05:00 UTC'), + array(\IntlDateFormatter::LONG, null, null, '03. Februar 2010 04:05', '2010-02-03 04:05:00 UTC'), + array(\IntlDateFormatter::FULL, null, null, 'Mittwoch, 03. Februar 2010 04:05', '2010-02-03 04:05:00 UTC'), + array(\IntlDateFormatter::SHORT, \IntlDateFormatter::NONE, null, '03.02.10', '2010-02-03 00:00:00 UTC'), + array(\IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE, null, '03.02.2010', '2010-02-03 00:00:00 UTC'), + array(\IntlDateFormatter::LONG, \IntlDateFormatter::NONE, null, '03. Februar 2010', '2010-02-03 00:00:00 UTC'), + array(\IntlDateFormatter::FULL, \IntlDateFormatter::NONE, null, 'Mittwoch, 03. Februar 2010', '2010-02-03 00:00:00 UTC'), + array(null, \IntlDateFormatter::SHORT, null, '03.02.2010 04:05', '2010-02-03 04:05:00 UTC'), + array(null, \IntlDateFormatter::MEDIUM, null, '03.02.2010 04:05:06', '2010-02-03 04:05:06 UTC'), + array(null, \IntlDateFormatter::LONG, null, + '03.02.2010 04:05:06 GMT' . ($this->isLowerThanIcuVersion('4.8') ? '+00:00' : ''), + '2010-02-03 04:05:06 UTC'), + // see below for extra test case for time format FULL + array(\IntlDateFormatter::NONE, \IntlDateFormatter::SHORT, null, '04:05', '1970-01-01 04:05:00 UTC'), + array(\IntlDateFormatter::NONE, \IntlDateFormatter::MEDIUM, null, '04:05:06', '1970-01-01 04:05:06 UTC'), + array(\IntlDateFormatter::NONE, \IntlDateFormatter::LONG, null, + '04:05:06 GMT' . ($this->isLowerThanIcuVersion('4.8') ? '+00:00' : ''), + '1970-01-01 04:05:06 UTC'), + array(null, null, 'yyyy-MM-dd HH:mm:00', '2010-02-03 04:05:00', '2010-02-03 04:05:00 UTC'), + array(null, null, 'yyyy-MM-dd HH:mm', '2010-02-03 04:05', '2010-02-03 04:05:00 UTC'), + array(null, null, 'yyyy-MM-dd HH', '2010-02-03 04', '2010-02-03 04:00:00 UTC'), + array(null, null, 'yyyy-MM-dd', '2010-02-03', '2010-02-03 00:00:00 UTC'), + array(null, null, 'yyyy-MM', '2010-02', '2010-02-01 00:00:00 UTC'), + array(null, null, 'yyyy', '2010', '2010-01-01 00:00:00 UTC'), + array(null, null, 'dd-MM-yyyy', '03-02-2010', '2010-02-03 00:00:00 UTC'), + array(null, null, 'HH:mm:ss', '04:05:06', '1970-01-01 04:05:06 UTC'), + array(null, null, 'HH:mm:00', '04:05:00', '1970-01-01 04:05:00 UTC'), + array(null, null, 'HH:mm', '04:05', '1970-01-01 04:05:00 UTC'), + array(null, null, 'HH', '04', '1970-01-01 04:00:00 UTC'), + ); } - public function testTransformMediumDate() + /** + * @dataProvider dataProvider + */ + public function testTransform($dateFormat, $timeFormat, $pattern, $output, $input) { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::MEDIUM); + $transformer = new DateTimeToLocalizedStringTransformer( + 'UTC', + 'UTC', + $dateFormat, + $timeFormat, + \IntlDateFormatter::GREGORIAN, + $pattern + ); - $this->assertEquals('03.02.2010 04:05', $transformer->transform($this->dateTime)); - } + $input = new \DateTime($input); - public function testTransformLongDate() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::LONG); - - $this->assertEquals('03. Februar 2010 04:05', $transformer->transform($this->dateTime)); - } - - public function testTransformFullDate() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL); - - $this->assertEquals('Mittwoch, 03. Februar 2010 04:05', $transformer->transform($this->dateTime)); - } - - public function testTransformShortTime() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::SHORT); - - $this->assertEquals('03.02.2010 04:05', $transformer->transform($this->dateTime)); - } - - public function testTransformMediumTime() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::MEDIUM); - - $this->assertEquals('03.02.2010 04:05:06', $transformer->transform($this->dateTime)); - } - - public function testTransformLongTime() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::LONG); - - $expected = $this->isLowerThanIcuVersion('4.8') ? '03.02.2010 04:05:06 GMT+00:00' : '03.02.2010 04:05:06 GMT'; - - $this->assertEquals($expected, $transformer->transform($this->dateTime)); + $this->assertEquals($output, $transformer->transform($input)); } public function testTransformFullTime() @@ -143,7 +148,7 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase } /** - * @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException */ public function testTransformRequiresValidDateTime() { @@ -162,53 +167,23 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase //$transformer->transform(1.5); } - public function testReverseTransformShortDate() + /** + * @dataProvider dataProvider + */ + public function testReverseTransform($dateFormat, $timeFormat, $pattern, $input, $output) { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::SHORT); + $transformer = new DateTimeToLocalizedStringTransformer( + 'UTC', + 'UTC', + $dateFormat, + $timeFormat, + \IntlDateFormatter::GREGORIAN, + $pattern + ); - $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('03.02.10 04:05')); - } + $output = new \DateTime($output); - public function testReverseTransformMediumDate() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::MEDIUM); - - $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('03.02.2010 04:05')); - } - - public function testReverseTransformLongDate() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::LONG); - - $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('03. Februar 2010 04:05')); - } - - public function testReverseTransformFullDate() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', \IntlDateFormatter::FULL); - - $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('Mittwoch, 03. Februar 2010 04:05')); - } - - public function testReverseTransformShortTime() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::SHORT); - - $this->assertDateTimeEquals($this->dateTimeWithoutSeconds, $transformer->reverseTransform('03.02.2010 04:05')); - } - - public function testReverseTransformMediumTime() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::MEDIUM); - - $this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('03.02.2010 04:05:06')); - } - - public function testReverseTransformLongTime() - { - $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC', null, \IntlDateFormatter::LONG); - - $this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('03.02.2010 04:05:06 GMT+00:00')); + $this->assertEquals($output, $transformer->reverseTransform($input)); } public function testReverseTransformFullTime() @@ -256,7 +231,7 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase } /** - * @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException */ public function testReverseTransformRequiresString() { @@ -265,7 +240,7 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase } /** - * @expectedException Symfony\Component\Form\Exception\TransformationFailedException + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException */ public function testReverseTransformWrapsIntlErrors() { @@ -274,7 +249,7 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase } /** - * @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException */ public function testValidateDateFormatOption() { @@ -282,7 +257,7 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase } /** - * @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException */ public function testValidateTimeFormatOption() { @@ -290,7 +265,7 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase } /** - * @expectedException Symfony\Component\Form\Exception\TransformationFailedException + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException */ public function testReverseTransformWithNonExistingDate() { diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php index 16fe2b29ed..804549fd80 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php @@ -15,30 +15,59 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransf class DateTimeToStringTransformerTest extends DateTimeTestCase { - public function testTransform() + public function dataProvider() { - $transformer = new DateTimeToStringTransformer('UTC', 'UTC', 'Y-m-d H:i:s'); + return array( + array('Y-m-d H:i:s', '2010-02-03 16:05:06', '2010-02-03 16:05:06 UTC'), + array('Y-m-d H:i:00', '2010-02-03 16:05:00', '2010-02-03 16:05:00 UTC'), + array('Y-m-d H:i', '2010-02-03 16:05', '2010-02-03 16:05:00 UTC'), + array('Y-m-d H', '2010-02-03 16', '2010-02-03 16:00:00 UTC'), + array('Y-m-d', '2010-02-03', '2010-02-03 00:00:00 UTC'), + array('Y-m', '2010-02', '2010-02-01 00:00:00 UTC'), + array('Y', '2010', '2010-01-01 00:00:00 UTC'), + array('d-m-Y', '03-02-2010', '2010-02-03 00:00:00 UTC'), + array('H:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'), + array('H:i:00', '16:05:00', '1970-01-01 16:05:00 UTC'), + array('H:i', '16:05', '1970-01-01 16:05:00 UTC'), + array('H', '16', '1970-01-01 16:00:00 UTC'), - $input = new \DateTime('2010-02-03 04:05:06 UTC'); - $output = clone $input; - $output->setTimezone(new \DateTimeZone('UTC')); - $output = $output->format('Y-m-d H:i:s'); + // different day representations + array('Y-m-j', '2010-02-3', '2010-02-03 00:00:00 UTC'), + array('Y-z', '2010-33', '2010-02-03 00:00:00 UTC'), + array('z', '33', '1970-02-03 00:00:00 UTC'), - $this->assertEquals($output, $transformer->transform($input)); + // not bijective + //array('Y-m-D', '2010-02-Wed', '2010-02-03 00:00:00 UTC'), + //array('Y-m-l', '2010-02-Wednesday', '2010-02-03 00:00:00 UTC'), + + // different month representations + array('Y-n-d', '2010-2-03', '2010-02-03 00:00:00 UTC'), + array('Y-M-d', '2010-Feb-03', '2010-02-03 00:00:00 UTC'), + array('Y-F-d', '2010-February-03', '2010-02-03 00:00:00 UTC'), + + // different year representations + array('y-m-d', '10-02-03', '2010-02-03 00:00:00 UTC'), + + // different time representations + array('G:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'), + array('g:i:s a', '4:05:06 pm', '1970-01-01 16:05:06 UTC'), + array('h:i:s a', '04:05:06 pm', '1970-01-01 16:05:06 UTC'), + + // seconds since unix + array('U', '1265213106', '2010-02-03 16:05:06 UTC'), + ); } /** - * @dataProvider getFormatAndDateTime + * @dataProvider dataProvider */ - public function testTransformRandomFormat($format, $datetime) + public function testTransform($format, $output, $input) { $transformer = new DateTimeToStringTransformer('UTC', 'UTC', $format); - $input = new \DateTime($datetime); - $output = clone $input; - $output->setTimezone(new \DateTimeZone('UTC')); + $input = new \DateTime($input); - $this->assertEquals($output->format($format), $transformer->transform($input)); + $this->assertEquals($output, $transformer->transform($input)); } public function testTransform_empty() @@ -68,39 +97,32 @@ class DateTimeToStringTransformerTest extends DateTimeTestCase $transformer->transform('1234'); } - public function testReverseTransform() + /** + * @dataProvider dataProvider + */ + public function testReverseTransformBeforePhp538($format, $input, $output) { - $reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', 'Y-m-d H:i:s'); + $reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format, false); - $output = new \DateTime('2010-02-03 04:05:06 UTC'); - $input = $output->format('Y-m-d H:i:s'); + $output = new \DateTime($output); $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input)); } /** - * @dataProvider getFormatAndDateTime + * @dataProvider dataProvider */ - public function testReverseTransformRandomFormat($format, $datetime) + public function testReverseTransformAsOfPhp538($format, $input, $output) { + if (version_compare(phpversion(), '5.3.8', '<')) { + $this->markTestSkipped('Requires PHP 5.3.8 or newer'); + } + $reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format); - $dateTime = new \DateTime($datetime); - $input = $dateTime->format($format); + $output = new \DateTime($output); - $this->assertDateTimeEquals($dateTime, $reverseTransformer->reverseTransform($input)); - } - - public function getFormatAndDateTime() - { - return array( - array('Y-m-d H:i:s', '2010-02-03 04:05:06 UTC'), - array('Y-m-d H:i:00', '2010-02-03 04:05:00 UTC'), - array('Y-m-d', '2010-02-03 UTC'), - array('d-m-Y', '03-02-2010 UTC'), - array('H:i:s', '04:05:06 UTC'), - array('H:i:00', '04:05:00 UTC'), - ); + $this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input)); } public function testReverseTransform_empty() @@ -114,7 +136,7 @@ class DateTimeToStringTransformerTest extends DateTimeTestCase { $reverseTransformer = new DateTimeToStringTransformer('America/New_York', 'Asia/Hong_Kong', 'Y-m-d H:i:s'); - $output = new \DateTime('2010-02-03 04:05:06 Asia/Hong_Kong'); + $output = new \DateTime('2010-02-03 16:05:06 Asia/Hong_Kong'); $input = $output->format('Y-m-d H:i:s'); $output->setTimeZone(new \DateTimeZone('America/New_York')); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php index 5c0d960870..1f51a9dc35 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php @@ -105,9 +105,9 @@ class TimeTypeTest extends LocalizedTestCase 'widget' => 'single_text', )); - $form->bind('03:04:05'); + $form->bind('03:04'); - $this->assertEquals(new \DateTime('03:04:00 UTC'), $form->getData()); + $this->assertEquals(new \DateTime('1970-01-01 03:04:00 UTC'), $form->getData()); $this->assertEquals('03:04', $form->getViewData()); } @@ -162,7 +162,7 @@ class TimeTypeTest extends LocalizedTestCase 'widget' => 'single_text', )); - $form->bind('03:04:05'); + $form->bind('03:04'); $this->assertEquals('03:04:00', $form->getData()); $this->assertEquals('03:04', $form->getViewData()); diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php index 4a262aade3..69ebae9542 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php @@ -43,13 +43,18 @@ class MongoDbSessionHandler implements \SessionHandlerInterface * * data_field: The field name for storing the session data [default: data] * * time_field: The field name for storing the timestamp [default: time] * - * @param \Mongo $mongo A "Mongo" instance - * @param array $options An associative array of field options + * @param \Mongo|\MongoClient $mongo A MongoClient or Mongo instance + * @param array $options An associative array of field options * + * @throws \InvalidArgumentException When MongoClient or Mongo instance not provided * @throws \InvalidArgumentException When "database" or "collection" not provided */ - public function __construct(\Mongo $mongo, array $options) + public function __construct($mongo, array $options) { + if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { + throw new \InvalidArgumentException('MongoClient or Mongo instance required'); + } + if (!isset($options['database']) || !isset($options['collection'])) { throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler'); } @@ -150,7 +155,7 @@ class MongoDbSessionHandler implements \SessionHandlerInterface private function getCollection() { if (null === $this->collection) { - $this->collection = $this->mongo->selectDB($this->options['database'])->selectCollection($this->options['collection']); + $this->collection = $this->mongo->selectCollection($this->options['database'], $this->options['collection']); } return $this->collection; diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php index 474fc3b029..1cfd1175cb 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php @@ -27,11 +27,13 @@ class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - if (!class_exists('\Mongo')) { - $this->markTestSkipped('MongoDbSessionHandler requires the mongo extension.'); + if (!extension_loaded('mongo')) { + $this->markTestSkipped('MongoDbSessionHandler requires the PHP "mongo" extension.'); } - $this->mongo = $this->getMockBuilder('Mongo') + $mongoClass = (version_compare(phpversion('mongo'), '1.3.0', '<')) ? 'Mongo' : 'MongoClient'; + + $this->mongo = $this->getMockBuilder($mongoClass) ->disableOriginalConstructor() ->getMock(); @@ -46,6 +48,22 @@ class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase $this->storage = new MongoDbSessionHandler($this->mongo, $this->options); } + /** + * @expectedException InvalidArgumentException + */ + public function testConstructorShouldThrowExceptionForInvalidMongo() + { + new MongoDbSessionHandler(new \stdClass(), $this->options); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testConstructorShouldThrowExceptionForMissingOptions() + { + new MongoDbSessionHandler($this->mongo, array()); + } + public function testOpenMethodAlwaysReturnTrue() { $this->assertTrue($this->storage->open('test', 'test'), 'The "open" method should always return true'); @@ -58,22 +76,13 @@ class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase public function testWrite() { - $database = $this->getMockBuilder('MongoDB') - ->disableOriginalConstructor() - ->getMock(); - $collection = $this->getMockBuilder('MongoCollection') ->disableOriginalConstructor() ->getMock(); $this->mongo->expects($this->once()) - ->method('selectDB') - ->with($this->options['database']) - ->will($this->returnValue($database)); - - $database->expects($this->once()) ->method('selectCollection') - ->with($this->options['collection']) + ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); $that = $this; @@ -96,22 +105,13 @@ class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase public function testReplaceSessionData() { - $database = $this->getMockBuilder('MongoDB') - ->disableOriginalConstructor() - ->getMock(); - $collection = $this->getMockBuilder('MongoCollection') ->disableOriginalConstructor() ->getMock(); $this->mongo->expects($this->once()) - ->method('selectDB') - ->with($this->options['database']) - ->will($this->returnValue($database)); - - $database->expects($this->once()) ->method('selectCollection') - ->with($this->options['collection']) + ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); $data = array(); @@ -130,22 +130,13 @@ class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase public function testDestroy() { - $database = $this->getMockBuilder('MongoDB') - ->disableOriginalConstructor() - ->getMock(); - $collection = $this->getMockBuilder('MongoCollection') ->disableOriginalConstructor() ->getMock(); $this->mongo->expects($this->once()) - ->method('selectDB') - ->with($this->options['database']) - ->will($this->returnValue($database)); - - $database->expects($this->once()) ->method('selectCollection') - ->with($this->options['collection']) + ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); $collection->expects($this->once()) @@ -157,22 +148,13 @@ class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase public function testGc() { - $database = $this->getMockBuilder('MongoDB') - ->disableOriginalConstructor() - ->getMock(); - $collection = $this->getMockBuilder('MongoCollection') ->disableOriginalConstructor() ->getMock(); $this->mongo->expects($this->once()) - ->method('selectDB') - ->with($this->options['database']) - ->will($this->returnValue($database)); - - $database->expects($this->once()) ->method('selectCollection') - ->with($this->options['collection']) + ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); $that = $this; diff --git a/src/Symfony/Component/HttpKernel/Profiler/MongoDbProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/MongoDbProfilerStorage.php index 7e4553c3e4..9ca529e910 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/MongoDbProfilerStorage.php +++ b/src/Symfony/Component/HttpKernel/Profiler/MongoDbProfilerStorage.php @@ -85,7 +85,9 @@ class MongoDbProfilerStorage implements ProfilerStorageInterface 'time' => $profile->getTime() ); - return $this->getMongo()->update(array('_id' => $profile->getToken()), array_filter($record, function ($v) { return !empty($v); }), array('upsert' => true)); + $result = $this->getMongo()->update(array('_id' => $profile->getToken()), array_filter($record, function ($v) { return !empty($v); }), array('upsert' => true)); + + return (boolean) (isset($result['ok']) ? $result['ok'] : $result); } /** @@ -97,12 +99,15 @@ class MongoDbProfilerStorage implements ProfilerStorageInterface { if ($this->mongo === null) { if (preg_match('#^(mongodb://.*)/(.*)/(.*)$#', $this->dsn, $matches)) { - $mongo = new \Mongo($matches[1] . (!empty($matches[2]) ? '/' . $matches[2] : '')); + $server = $matches[1] . (!empty($matches[2]) ? '/' . $matches[2] : ''); $database = $matches[2]; $collection = $matches[3]; + + $mongoClass = (version_compare(phpversion('mongo'), '1.3.0', '<')) ? '\Mongo' : '\MongoClient'; + $mongo = new $mongoClass($server); $this->mongo = $mongo->selectCollection($database, $collection); } else { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use MongoDB with an invalid dsn "%s". The expected format is "mongodb://user:pass@location/database/collection"', $this->dsn)); + throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use MongoDB with an invalid dsn "%s". The expected format is "mongodb://[user:pass@]host/database/collection"', $this->dsn)); } }