Skip to content

Commit

Permalink
Support "?type" syntax for nullable types
Browse files Browse the repository at this point in the history
In addition to "int|null", JsonMapper now also supports "?int"
- a syntax that was added to PHP in versino 7.1.0
("Nullable type syntactic sugar").

Resolves: #235
  • Loading branch information
RobinvanderVliet authored and cweiske committed May 17, 2024
1 parent d879831 commit 99fea88
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 16 deletions.
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ Supported type names
- ``Suit:string|Suit:int`` - exception will be thrown if the JSON value is not present in the enum
- Nullable types:

- ``int|null`` - will be ``null`` if the value in JSON is
- ``int|null`` or ``?int`` - will be ``null`` if the value in JSON is
``null``, otherwise it will be an integer
- ``Contact|null`` - will be ``null`` if the value in JSON is
- ``Contact|null`` or ``?Contact`` - will be ``null`` if the value in JSON is
``null``, otherwise it will be an object of type ``Contact``

ArrayObjects and extending classes are treated as arrays.
Expand Down Expand Up @@ -327,7 +327,7 @@ parameters into the call.
Nullables
---------
JsonMapper throws an exception when a JSON property is ``null``,
unless the PHP class property has a nullable type - e.g. ``Contact|null``.
unless the PHP class property has a nullable type - e.g. ``Contact|null`` or ``?Contact``.

If your API contains many fields that may be ``null`` and you do not want
to make all your type definitions nullable, set:
Expand Down
5 changes: 3 additions & 2 deletions src/JsonMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,8 @@ protected function hasVariadicArrayType($accessor)
*/
protected function isNullable($type)
{
return stripos('|' . $type . '|', '|null|') !== false;
return stripos('|' . $type . '|', '|null|') !== false
|| strpos('|' . $type, '|?') !== false;
}

/**
Expand All @@ -873,7 +874,7 @@ protected function removeNullable($type)
return null;
}
return substr(
str_ireplace('|null|', '|', '|' . $type . '|'),
str_ireplace(['|null|', '|?'], '|', '|' . $type . '|'),
1, -1
);
}
Expand Down
60 changes: 50 additions & 10 deletions tests/SimpleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,40 +122,80 @@ public function testMapSimpleMixed()
/**
* Test for "@var int|null" with int value
*/
public function testMapSimpleNullableInt()
public function testMapSimpleNullableIntWithInt()
{
$jm = new JsonMapper();
$sn = $jm->map(
json_decode('{"pnullable":0}'),
json_decode('{"pnullableInt":0}'),
new JsonMapperTest_Simple()
);
$this->assertSame(0, $sn->pnullable);
$this->assertSame(0, $sn->pnullableInt);
}

/**
* Test for "@var int|null" with null value
*/
public function testMapSimpleNullableNull()
public function testMapSimpleNullableIntWithNull()
{
$jm = new JsonMapper();
$sn = $jm->map(
json_decode('{"pnullable":null}'),
json_decode('{"pnullableInt":null}'),
new JsonMapperTest_Simple()
);
$this->assertNull($sn->pnullable);
$this->assertNull($sn->pnullableInt);
}

/**
* Test for "@var int|null" with string value
* Test for "@var int|null" with string value (force cast)
*/
public function testMapSimpleNullableWrong()
public function testMapSimpleNullableIntWithWrongType()
{
$jm = new JsonMapper();
$sn = $jm->map(
json_decode('{"pnullable":"12345"}'),
json_decode('{"pnullableInt":"12345"}'),
new JsonMapperTest_Simple()
);
$this->assertSame(12345, $sn->pnullable);
$this->assertSame(12345, $sn->pnullableInt);
}

/**
* Test for "@var ?string" with string value
*/
public function testMapSimpleNullableStringWithString()
{
$jm = new JsonMapper();
$sn = $jm->map(
json_decode('{"pnullableString":"test"}'),
new JsonMapperTest_Simple()
);
$this->assertSame('test', $sn->pnullableString);
}

/**
* Test for "@var ?string" with null value
*/
public function testMapSimpleNullableStringWithNull()
{
$jm = new JsonMapper();
$sn = $jm->map(
json_decode('{"pnullableString":null}'),
new JsonMapperTest_Simple()
);
$this->assertNull($sn->pnullableString);
$this->assertEquals(null, $sn->pnullableString);
}

/**
* Test for "@var ?string" with int value (force cast)
*/
public function testMapSimpleNullableStringWithWrongType()
{
$jm = new JsonMapper();
$sn = $jm->map(
json_decode('{"pnullableString":0}'),
new JsonMapperTest_Simple()
);
$this->assertSame('0', $sn->pnullableString);
}

/**
Expand Down
7 changes: 6 additions & 1 deletion tests/support/JsonMapperTest/Simple.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ class JsonMapperTest_Simple
/**
* @var int|null
*/
public $pnullable;
public $pnullableInt;

/**
* @var ?string
*/
public $pnullableString;

/**
* @var float
Expand Down

0 comments on commit 99fea88

Please sign in to comment.