Skip to content
This repository has been archived by the owner on Aug 8, 2021. It is now read-only.

Multiple primitive types are now supported #1

Merged
merged 1 commit into from Sep 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
205 changes: 118 additions & 87 deletions src/ObjectMapper.php
Expand Up @@ -129,100 +129,131 @@ public function mapDataToObject($data, $targetClass)
if (isset($data[$field->name])) {
$val = null;

// Check the type of the field and set the val
switch (strtolower($field->type)) {
case 'int':
case 'integer':
if (!is_int($data[$field->name])) {
throw new TypeMismatchException($field->type, gettype($data[$field->name]));
}
$val = (int)$data[$field->name];
break;
case 'float':
case 'double':
case 'real':
if (!is_float($data[$field->name])) {
throw new TypeMismatchException($field->type, gettype($data[$field->name]));
}
$val = (double)$data[$field->name];
break;
case 'bool':
case 'boolean':
if (!is_bool($data[$field->name])) {
throw new TypeMismatchException($field->type, gettype($data[$field->name]));
}
$val = (bool)$data[$field->name];
break;
case 'array':
if (!is_array($data[$field->name])) {
throw new TypeMismatchException($field->type, gettype($data[$field->name]));
}
$val = (array)$data[$field->name];
break;
case 'string':
if (!is_string($data[$field->name])) {
throw new TypeMismatchException($field->type, gettype($data[$field->name]));
}
$val = (string)$data[$field->name];
break;
case 'object':
$tmpVal = $data[$field->name];
if (is_array($tmpVal) && array_keys($tmpVal) != range(0, count($tmpVal))) {
$data[$field->name] = (object)$tmpVal;
}
if (!is_object($data[$field->name])) {
throw new TypeMismatchException($field->type, gettype($data[$field->name]));
}
$val = (object)$data[$field->name];
break;
case 'date':
case 'datetime':
// Accepts the following formats:
// 2017-09-09
// 2017-09-09 13:20:59
// 2017-09-09T13:20:59
// 2017-09-09T13:20:59.511
// 2017-09-09T13:20:59.511Z
// 2017-09-09T13:20:59-02:00
$validPattern = '~^\d{4}-\d{2}-\d{2}((T|\s{1})\d{2}:\d{2}:\d{2}(\.\d{1,3}(Z|)|(\+|\-)\d{2}:\d{2}|)|)$~';

$tmpVal = $data[$field->name];
if (preg_match($validPattern, $tmpVal)) {
$data[$field->name] = new \DateTime($tmpVal);
} else {
$casted = intval($tmpVal);
if (is_numeric($tmpVal) || ($casted == $tmpVal && strlen($casted) == strlen($tmpVal))) {
$data[$field->name] = new \DateTime();
$data[$field->name]->setTimestamp($tmpVal);
$types = explode('|', $field->type);
$typeKeys = array_keys($types);
$lastTypeKey = end($typeKeys);

foreach ($types as $typeKey => $type) {
$isLastElement = ($typeKey == $lastTypeKey);
// Check the type of the field and set the val
switch (strtolower($type)) {
case 'int':
case 'integer':
if (!is_int($data[$field->name])) {
if ($isLastElement) {
throw new TypeMismatchException($type, gettype($data[$field->name]));
}
break;
}
}
$val = (int)$data[$field->name];
break;
case 'float':
case 'double':
case 'real':
if (!is_float($data[$field->name])) {
if ($isLastElement) {
throw new TypeMismatchException($type, gettype($data[$field->name]));
}
break;
}
$val = (double)$data[$field->name];
break;
case 'bool':
case 'boolean':
if (!is_bool($data[$field->name])) {
if ($isLastElement) {
throw new TypeMismatchException($type, gettype($data[$field->name]));
}
break;
}
$val = (bool)$data[$field->name];
break;
case 'array':
if (!is_array($data[$field->name])) {
if ($isLastElement) {
throw new TypeMismatchException($type, gettype($data[$field->name]));
}
break;
}
$val = (array)$data[$field->name];
break;
case 'string':
if (!is_string($data[$field->name])) {
if ($isLastElement) {
throw new TypeMismatchException($type, gettype($data[$field->name]));
}
break;
}
$val = (string)$data[$field->name];
break;
case 'object':
$tmpVal = $data[$field->name];
if (is_array($tmpVal) && array_keys($tmpVal) != range(0, count($tmpVal))) {
$data[$field->name] = (object)$tmpVal;
}
if (!is_object($data[$field->name])) {
if ($isLastElement) {
throw new TypeMismatchException($type, gettype($data[$field->name]));
}
break;
}
$val = (object)$data[$field->name];
break;
case 'date':
case 'datetime':
// Accepts the following formats:
// 2017-09-09
// 2017-09-09 13:20:59
// 2017-09-09T13:20:59
// 2017-09-09T13:20:59.511
// 2017-09-09T13:20:59.511Z
// 2017-09-09T13:20:59-02:00
$validPattern = '~^\d{4}-\d{2}-\d{2}((T|\s{1})\d{2}:\d{2}:\d{2}(\.\d{1,3}(Z|)|(\+|\-)\d{2}:\d{2}|)|)$~';

if ($data[$field->name] instanceof \DateTime === false) {
throw new TypeMismatchException($field->type, gettype($data[$field->name]));
}
$tmpVal = $data[$field->name];
if (preg_match($validPattern, $tmpVal)) {
$data[$field->name] = new \DateTime($tmpVal);
} else {
$casted = intval($tmpVal);
if (is_numeric($tmpVal) || ($casted == $tmpVal && strlen($casted) == strlen($tmpVal))) {
$data[$field->name] = new \DateTime();
$data[$field->name]->setTimestamp($tmpVal);
}
}

if (strtolower($field->type) == 'date') {
$data[$field->name]->setTime(0, 0, 0);
}
if ($data[$field->name] instanceof \DateTime === false) {
if ($isLastElement) {
throw new TypeMismatchException($type, gettype($data[$field->name]));
}
break;
}

$val = $data[$field->name];
break;
default:
// If none of the primitives above match it is an custom object

// Check if it's an array of X
if (substr($field->type, -2) == '[]') {
$t = substr($field->type, 0, -2);
$val = [];
foreach ($data[$field->name] as $entry) {
if (strtolower($type) == 'date') {
$data[$field->name]->setTime(0, 0, 0);
}

$val = $data[$field->name];
break;
default:
// If none of the primitives above match it is an custom object

// Check if it's an array of X
if (substr($type, -2) == '[]' && is_array($data[$field->name])) {
$t = substr($type, 0, -2);
$val = [];
foreach ($data[$field->name] as $entry) {
// Map the data recursive
$val[] = (object)$this->mapDataToObject($entry, $t);
}
} elseif (substr($type, -2) != '[]') {
// Map the data recursive
$val[] = (object)$this->mapDataToObject($entry, $t);
$val = (object)$this->mapDataToObject($data[$field->name], $type);
}
} else {
// Map the data recursive
$val = (object)$this->mapDataToObject($data[$field->name], $field->type);
}
break;
}
if ($val !== null) {
break;
}
}

// Assign the JSON data to the object property
Expand Down
20 changes: 20 additions & 0 deletions tests/ObjectMapperTest.php
Expand Up @@ -134,6 +134,26 @@ public function testMapDataToObject()
$this->assertEquals($address, $person->address);
}

public function testMapDataToObjectMultipleTypes()
{
$mapper = new ObjectMapper();
$data = json_decode(file_get_contents(__DIR__ . '/res/person_string_address.json'), true);

/** @var Person $person */
$person = $mapper->mapDataToObject($data, Person::class);
$this->assertSame('Pete', $person->name);
$this->assertSame('Peterson', $person->surname);
$this->assertSame(28, $person->age);
$this->assertSame(1.72, $person->height);
$this->assertTrue($person->isCool);
$this->assertSame(['Pepe', 'Pete'], $person->nicknames);
$this->assertEquals((object)['hello' => 'Hi', 'bye' => 'Ciao!'], $person->dictionary);
$this->assertEquals(strtotime('2017-03-08T09:41:00'), $person->created->getTimestamp());
$this->assertEquals(strtotime('9.9.2017 00:00:00'), $person->updated->getTimestamp());
$this->assertEquals(strtotime('10.9.2017 00:00:00'), $person->deleted->getTimestamp());
$this->assertSame("Mainstreet 22a, A-12345, Best Town, Germany", $person->address);
}

public function testMapDataToObjectMultiple()
{
$mapper = new ObjectMapper();
Expand Down
2 changes: 1 addition & 1 deletion tests/Objects/Person.php
Expand Up @@ -38,7 +38,7 @@ class Person
/** @MintWare\JOM\JsonField(name="dictionary", type="object") */
public $dictionary;

/** @MintWare\JOM\JsonField(name="address", type="MintWare\Tests\JOM\Objects\Address") */
/** @MintWare\JOM\JsonField(name="address", type="string|MintWare\Tests\JOM\Objects\Address") */
public $address;

/**
Expand Down
19 changes: 19 additions & 0 deletions tests/res/person_string_address.json
@@ -0,0 +1,19 @@
{
"firstname": "Pete",
"surname": "Peterson",
"age": 28,
"height": 1.72,
"is_cool": true,
"nicknames": [
"Pepe",
"Pete"
],
"dictionary": {
"hello": "Hi",
"bye": "Ciao!"
},
"address": "Mainstreet 22a, A-12345, Best Town, Germany",
"created": "2017-03-08T09:41:00",
"updated": "1504915250",
"deleted": 1505001600
}