Skip to content

Commit 788faa4

Browse files
committed
Add DateTimeBinding
fixes #30
1 parent 0103c45 commit 788faa4

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [3.1.0] - 2020-04-10
8+
### Added
9+
- `DateTimeBinding` for parsing date string
10+
711
## [3.0.0] - 2020-03-25
812
### Changed
913
- Update dependencies to be compatible with PHP 7.4

readme.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ The following `Binding` implementations are available
103103
* [FieldBinding](#fieldbinding)
104104
* [ArrayBinding](#arraybinding)
105105
* [AliasBinding](#aliasbinding)
106+
* [DateTimeBinding](#datetimebinding)
106107
* [CallbackBinding](#callbackbinding)
107108

108109
#### FieldBinding
@@ -131,6 +132,14 @@ Defines a JSON field to property binding.
131132
new AliasBinding($property, $jsonField);
132133
```
133134

135+
#### DateTimeBinding
136+
Defines a JSON field to property binding and converts the given string to a `DateTime` instance.
137+
138+
**Signature:**
139+
```php
140+
new new DateTimeBinding($property, $jsonField, $isRequired = false, $dateTimeFormat = DateTime::ATOM);
141+
```
142+
134143
#### CallbackBinding
135144
Defines a property binding that gets the callback result set as its value.
136145

src/Bindings/DateTimeBinding.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace Karriere\JsonDecoder\Bindings;
4+
5+
use DateTime;
6+
use Karriere\JsonDecoder\Binding;
7+
8+
class DateTimeBinding extends Binding
9+
{
10+
/**
11+
* @var string
12+
*/
13+
private $format;
14+
15+
/**
16+
* DateTimeBinding constructor.
17+
*
18+
* @param string $property the property to bind to
19+
* @param string $jsonField the json field
20+
* @param bool $isRequired defines if the field value is required during decoding
21+
* @param string $dateTimeFormat defines the date format used for parsing, defaults to DateTime::ATOM
22+
*/
23+
public function __construct($property, $jsonField, $isRequired = false, $dateTimeFormat = DateTime::ATOM)
24+
{
25+
parent::__construct($property, $jsonField, null, $isRequired);
26+
27+
$this->format = $dateTimeFormat;
28+
}
29+
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
public function validate($jsonData): bool
34+
{
35+
if (array_key_exists($this->jsonField, $jsonData)) {
36+
return DateTime::createFromFormat($this->format, $jsonData[$this->jsonField]) !== false;
37+
}
38+
39+
return !$this->isRequired;
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function bind($jsonDecoder, $jsonData, $propertyAccessor)
46+
{
47+
if (array_key_exists($this->jsonField, $jsonData)) {
48+
$dateTimeObject = DateTime::createFromFormat($this->format, $jsonData[$this->jsonField]);
49+
50+
if ($dateTimeObject !== false) {
51+
$propertyAccessor->set($dateTimeObject);
52+
}
53+
}
54+
}
55+
}

src/ClassBindings.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function decode($data, $instance)
6464

6565
if (!$binding->validate($data)) {
6666
throw new JsonValueException(
67-
sprintf('Unable to bind required property "%s" because JSON data is missing', $propertyName)
67+
sprintf('Unable to bind required property "%s" because JSON data is missing or invalid', $propertyName)
6868
);
6969
}
7070

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace tests\specs\Karriere\JsonDecoder\Bindings;
4+
5+
use DateTime;
6+
use Karriere\JsonDecoder\Bindings\DateTimeBinding;
7+
use Karriere\JsonDecoder\JsonDecoder;
8+
use Karriere\JsonDecoder\PropertyAccessor;
9+
use PhpSpec\ObjectBehavior;
10+
use Prophecy\Argument;
11+
12+
class DateTimeBindingSpec extends ObjectBehavior
13+
{
14+
public function let()
15+
{
16+
$this->beConstructedWith('property', 'field');
17+
}
18+
19+
public function it_is_initializable()
20+
{
21+
$this->shouldHaveType(DateTimeBinding::class);
22+
}
23+
24+
public function it_should_return_the_property_name()
25+
{
26+
$this->property()->shouldReturn('property');
27+
}
28+
29+
public function it_should_succeed_on_binding_validation()
30+
{
31+
$this->validate(['field' => '2018-02-01T12:00:00+00:00'])->shouldReturn(true);
32+
}
33+
34+
public function it_should_fail_on_binding_validation_for_a_required_property_with_invalid_format()
35+
{
36+
$this->beConstructedWith('property', 'field', true);
37+
$this->validate(['field' => 'value'])->shouldReturn(false);
38+
}
39+
40+
public function it_should_fail_on_binding_validation_for_a_not_required_property_with_invalid_format()
41+
{
42+
$this->validate(['field' => 'value'])->shouldReturn(false);
43+
}
44+
45+
public function it_should_be_able_to_parse_an_atom_datetime(JsonDecoder $jsonDecoder, PropertyAccessor $propertyAccessor)
46+
{
47+
$expectedDateTime = DateTime::createFromFormat(DateTime::ATOM, '2020-01-01T12:00:00+00:00');
48+
$propertyAccessor->set($expectedDateTime)->shouldBeCalled();
49+
50+
$this->bind($jsonDecoder, ['field' => '2020-01-01T12:00:00+00:00'], $propertyAccessor);
51+
}
52+
53+
public function it_should_not_set_a_value_for_an_empty_datetime_string(JsonDecoder $jsonDecoder, PropertyAccessor $propertyAccessor)
54+
{
55+
$propertyAccessor->set(Argument::any())->shouldNotBeCalled();
56+
57+
$this->bind($jsonDecoder, ['field' => ''], $propertyAccessor);
58+
}
59+
60+
public function it_should_not_set_a_value_for_an_invalid_formatted_datetime_string(JsonDecoder $jsonDecoder, PropertyAccessor $propertyAccessor)
61+
{
62+
$propertyAccessor->set(Argument::any())->shouldNotBeCalled();
63+
64+
$this->bind($jsonDecoder, ['field' => 'invalid'], $propertyAccessor);
65+
}
66+
}

0 commit comments

Comments
 (0)