2017-08-01 16:22:43 +01:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Serializer\Normalizer ;
use Symfony\Component\Serializer\Exception\InvalidArgumentException ;
use Symfony\Component\Serializer\Exception\UnexpectedValueException ;
/**
* Normalizes an instance of { @ see \DateInterval } to an interval string .
* Denormalizes an interval string to an instance of { @ see \DateInterval } .
*
* @ author Jérôme Parmentier < jerome @ prmntr . me >
*/
2018-04-27 13:29:13 +01:00
class DateIntervalNormalizer implements NormalizerInterface , DenormalizerInterface , CacheableSupportsMethodInterface
2017-08-01 16:22:43 +01:00
{
2020-12-08 16:59:59 +00:00
public const FORMAT_KEY = 'dateinterval_format' ;
2017-08-01 16:22:43 +01:00
2019-01-16 20:35:37 +00:00
private $defaultContext = [
2019-08-09 12:45:54 +01:00
self :: FORMAT_KEY => '%rP%yY%mM%dDT%hH%iM%sS' ,
2019-01-16 20:35:37 +00:00
];
2017-08-01 16:22:43 +01:00
2018-10-03 16:09:15 +01:00
/**
* @ param array $defaultContext
*/
2019-01-16 20:35:37 +00:00
public function __construct ( $defaultContext = [])
2017-08-01 16:22:43 +01:00
{
2018-10-03 16:09:15 +01:00
if ( ! \is_array ( $defaultContext )) {
2020-09-02 17:08:58 +01:00
@ trigger_error ( sprintf ( 'The "format" parameter is deprecated since Symfony 4.2, use the "%s" key of the context instead.' , self :: FORMAT_KEY ), \E_USER_DEPRECATED );
2018-10-03 16:09:15 +01:00
2019-01-16 20:35:37 +00:00
$defaultContext = [ self :: FORMAT_KEY => ( string ) $defaultContext ];
2018-10-03 16:09:15 +01:00
}
$this -> defaultContext = array_merge ( $this -> defaultContext , $defaultContext );
2017-08-01 16:22:43 +01:00
}
/**
* { @ inheritdoc }
*
* @ throws InvalidArgumentException
2020-11-25 11:55:08 +00:00
*
* @ return string
2017-08-01 16:22:43 +01:00
*/
2019-01-16 09:39:14 +00:00
public function normalize ( $object , $format = null , array $context = [])
2017-08-01 16:22:43 +01:00
{
if ( ! $object instanceof \DateInterval ) {
throw new InvalidArgumentException ( 'The object must be an instance of "\DateInterval".' );
}
2018-10-03 16:09:15 +01:00
return $object -> format ( $context [ self :: FORMAT_KEY ] ? ? $this -> defaultContext [ self :: FORMAT_KEY ]);
2017-08-01 16:22:43 +01:00
}
/**
* { @ inheritdoc }
*/
public function supportsNormalization ( $data , $format = null )
{
return $data instanceof \DateInterval ;
}
2018-04-30 22:41:10 +01:00
/**
* { @ inheritdoc }
*/
public function hasCacheableSupportsMethod () : bool
{
2020-02-04 09:29:10 +00:00
return __CLASS__ === static :: class ;
2018-04-30 22:41:10 +01:00
}
2017-08-01 16:22:43 +01:00
/**
* { @ inheritdoc }
*
* @ throws InvalidArgumentException
* @ throws UnexpectedValueException
2020-11-25 11:55:08 +00:00
*
* @ return \DateInterval
2017-08-01 16:22:43 +01:00
*/
2019-08-15 12:16:03 +01:00
public function denormalize ( $data , $type , $format = null , array $context = [])
2017-08-01 16:22:43 +01:00
{
2018-07-26 09:45:46 +01:00
if ( ! \is_string ( $data )) {
2020-03-16 07:32:23 +00:00
throw new InvalidArgumentException ( sprintf ( 'Data expected to be a string, "%s" given.' , \gettype ( $data )));
2017-08-01 16:22:43 +01:00
}
if ( ! $this -> isISO8601 ( $data )) {
throw new UnexpectedValueException ( 'Expected a valid ISO 8601 interval string.' );
}
2018-10-03 16:09:15 +01:00
$dateIntervalFormat = $context [ self :: FORMAT_KEY ] ? ? $this -> defaultContext [ self :: FORMAT_KEY ];
2017-08-01 16:22:43 +01:00
2019-08-08 18:35:41 +01:00
$signPattern = '' ;
switch ( substr ( $dateIntervalFormat , 0 , 2 )) {
case '%R' :
$signPattern = '[-+]' ;
$dateIntervalFormat = substr ( $dateIntervalFormat , 2 );
break ;
case '%r' :
$signPattern = '-?' ;
$dateIntervalFormat = substr ( $dateIntervalFormat , 2 );
break ;
}
$valuePattern = '/^' . $signPattern . preg_replace ( '/%([yYmMdDhHiIsSwW])(\w)/' , '(?P<$1>\d+)$2' , $dateIntervalFormat ) . '$/' ;
2017-08-01 16:22:43 +01:00
if ( ! preg_match ( $valuePattern , $data )) {
throw new UnexpectedValueException ( sprintf ( 'Value "%s" contains intervals not accepted by format "%s".' , $data , $dateIntervalFormat ));
}
try {
2019-08-08 18:35:41 +01:00
if ( '-' === $data [ 0 ]) {
$interval = new \DateInterval ( substr ( $data , 1 ));
$interval -> invert = 1 ;
return $interval ;
}
if ( '+' === $data [ 0 ]) {
return new \DateInterval ( substr ( $data , 1 ));
}
2017-08-01 16:22:43 +01:00
return new \DateInterval ( $data );
} catch ( \Exception $e ) {
throw new UnexpectedValueException ( $e -> getMessage (), $e -> getCode (), $e );
}
}
/**
* { @ inheritdoc }
*/
public function supportsDenormalization ( $data , $type , $format = null )
{
return \DateInterval :: class === $type ;
}
2019-09-25 11:08:54 +01:00
private function isISO8601 ( string $string ) : bool
2017-08-01 16:22:43 +01:00
{
2019-08-08 18:35:41 +01:00
return preg_match ( '/^[\-+]?P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:(?:\d+D|%[dD]D)|(?:\d+W|%[wW]W))?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/' , $string );
2017-08-01 16:22:43 +01:00
}
}