Skip to content

Commit

Permalink
amending type hinting, fleshing out examples
Browse files Browse the repository at this point in the history
  • Loading branch information
SignpostMarv committed Aug 4, 2019
1 parent edfd7a0 commit 3c01fed
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 25 deletions.
119 changes: 117 additions & 2 deletions README.md
Expand Up @@ -12,8 +12,12 @@ Typed Object, a simplified version of [signpostmarv/daft-object](https://github.
```php
use SignpostMarv\DaftTypedObject\Immutable as Base;

use SignpostMarv\DaftTypedObject\Immutable as Base;

/**
* @template-extends Base<array{id:int, name:string}>
* @psalm-type DATA = array{id:int, name:string}
*
* @template-extends Base<DATA, DATA>
*
* @property-read int $id
* @property-read string $name
Expand All @@ -39,7 +43,9 @@ class Immutable extends Base
use SignpostMarv\DaftTypedObject\DaftTypedObject as Base;

/**
* @template-extends Base<array{id:int, name:string}>
* @psalm-type DATA = array{id:int, name:string}
*
* @template-extends Base<DATA, DATA>
*
* @property int $id
* @property string $name
Expand All @@ -58,4 +64,113 @@ class Mutable extends Base
*/
protected $name;
}

```

### Mutable with `DateTimeImmutable` & nullables
```php
use DateTimeImmutable;
use SignpostMarv\DaftTypedObject\DaftTypedObject as Base;

/**
* @template T as array{id:int, name:string, date:DateTimeImmutable|null}
* @template S as array{id:int, name:string, date:string|null}
*
* @template-extends Base<T, S>
*
* @property-read int $id
* @property-read string $name
* @property-read DateTimeImmutable $date
*/
class MutableWithNullables extends Base
{
const TYPED_PROPERTIES = ['id', 'name', 'date'];

const TYPED_NULLABLE_PROPERTIES = ['date'];

/**
* @var int
*/
protected $id;

/**
* @var string|null
*/
protected $name;

/**
* @var DateTimeImmutable|null
*/
protected $date;

/**
* @template K as key-of<T>
*
* @param K $property
* @param T[K] $value
*
* @return S[K]
*/
public static function PropertyValueToScalarOrNull(
string $property,
$value
) {
/**
* @var T[K]|DateTimeImmutable
*/
$value = $value;

if ($value instanceof DateTimeImmutable) {
/**
* @var S[K]
*/
return (string) $value->format('Y-m-d');
}

/**
* @var S[K]
*/
return parent::PropertyValueToScalarOrNull((string) $property, $value);
}

/**
* @template K as key-of<S>
*
* @param K|'date' $property
* @param S[K] $value
*
* @return T[K]
*/
public static function PropertyScalarOrNullToValue(
string $property,
$value
) {
/**
* @var S[K]|string
*/
$value = $value;

if ('date' === $property && is_string($value)) {
$out = new DateTimeImmutable($value);
} else {
/**
* @var S[K]
*/
$value = $value;

/**
* @var T[K]
*/
$out = parent::PropertyScalarOrNullToValue(
(string) $property,
$value
);
}

/**
* @var T[K]
*/
return $out;
}
}
```
40 changes: 28 additions & 12 deletions Tests/DaftTypedObjectTest.php
Expand Up @@ -52,12 +52,16 @@ public function dataProviderPackedImplementations() : array
],
Fixtures\MutableWithNullables::class => [
[
['id' => 1, 'name' => 'foo'],
['id' => 1, 'name' => 'foo'],
[
'id' => 1,
'name' => 'foo',
'date' => new DateTimeImmutable('1970-01-01'),
],
['id' => 1, 'name' => 'foo', 'date' => '1970-01-01'],
],
[
['id' => 1, 'name' => null],
['id' => 1, 'name' => null],
['id' => 1, 'name' => 'foo', 'date' => null],
['id' => 1, 'name' => 'foo', 'date' => null],
],
],
];
Expand All @@ -82,40 +86,50 @@ public function dataProviderImplementations() : Generator
/**
* @dataProvider dataProviderImplementations
*
* @template T as array<string, scalar|array|object|null>
* @template K as key-of<T>
* @template S as array<K, scalar|null>
*
* @param class-string<DaftTypedObject> $type
* @param array<string, scalar|array|object|null> $args
* @param array<string, scalar|null> $expected
* @param T $args
* @param S $expected
*/
public function testJsonSerialize(
string $type,
array $args,
array $expected
) : void {
/**
* @var array<string, scalar|null>
* @var S
*/
$jsonified = (new $type($args))->jsonSerialize();

static::assertSame($expected, $jsonified);

/**
* @var array<int, K>
*/
$properties = array_keys($jsonified);

static::assertSame(
$expected,
(new $type(array_combine(array_keys($jsonified), array_map(
/**
* @param scalar|null $value
* @param K $property
* @param S[K] $value
*
* @return scalar|array|object|null
* @return T[K]
*/
function (string $property, $value) use ($type) {
/**
* @var scalar|array|object|null
* @var T[K]
*/
return $type::PropertyScalarOrNullToValue(
$property,
(string) $property,
$value
);
},
array_keys($jsonified),
$properties,
$jsonified
))))->jsonSerialize()
);
Expand Down Expand Up @@ -341,6 +355,8 @@ public function testMutableSetSucceeds(
++$value;
} elseif (is_string($value)) {
$value = strrev($value);
} elseif ($value instanceof DateTimeImmutable) {
$value = $value->modify('+1 second');
}

$object->$property = $value;
Expand Down
4 changes: 3 additions & 1 deletion Tests/Fixtures/Immutable.php
Expand Up @@ -9,7 +9,9 @@
use SignpostMarv\DaftTypedObject\Immutable as Base;

/**
* @template-extends Base<array{id:int, name:string}>
* @psalm-type DATA = array{id:int, name:string}
*
* @template-extends Base<DATA, DATA>
*
* @property-read int $id
* @property-read string $name
Expand Down
4 changes: 3 additions & 1 deletion Tests/Fixtures/Mutable.php
Expand Up @@ -9,7 +9,9 @@
use SignpostMarv\DaftTypedObject\DaftTypedObject as Base;

/**
* @template-extends Base<array{id:int, name:string}>
* @psalm-type DATA = array{id:int, name:string}
*
* @template-extends Base<DATA, DATA>
*
* @property int $id
* @property string $name
Expand Down
88 changes: 84 additions & 4 deletions Tests/Fixtures/MutableWithNullables.php
Expand Up @@ -6,19 +6,24 @@

namespace SignpostMarv\DaftTypedObject\Fixtures;

use DateTimeImmutable;
use SignpostMarv\DaftTypedObject\DaftTypedObject as Base;

/**
* @template-extends Base<array{id:int, name:string|null}>
* @template T as array{id:int, name:string, date:DateTimeImmutable|null}
* @template S as array{id:int, name:string, date:string|null}
*
* @template-extends Base<T, S>
*
* @property-read int $id
* @property-read string|null $name
* @property-read string $name
* @property-read DateTimeImmutable $date
*/
class MutableWithNullables extends Base
{
const TYPED_PROPERTIES = ['id', 'name'];
const TYPED_PROPERTIES = ['id', 'name', 'date'];

const TYPED_NULLABLE_PROPERTIES = ['name'];
const TYPED_NULLABLE_PROPERTIES = ['date'];

/**
* @var int
Expand All @@ -29,4 +34,79 @@ class MutableWithNullables extends Base
* @var string|null
*/
protected $name;

/**
* @var DateTimeImmutable|null
*/
protected $date;

/**
* @template K as key-of<T>
*
* @param K $property
* @param T[K] $value
*
* @return S[K]
*/
public static function PropertyValueToScalarOrNull(
string $property,
$value
) {
/**
* @var T[K]|DateTimeImmutable
*/
$value = $value;

if ($value instanceof DateTimeImmutable) {
/**
* @var S[K]
*/
return (string) $value->format('Y-m-d');
}

/**
* @var S[K]
*/
return parent::PropertyValueToScalarOrNull((string) $property, $value);
}

/**
* @template K as key-of<S>
*
* @param K|'date' $property
* @param S[K] $value
*
* @return T[K]
*/
public static function PropertyScalarOrNullToValue(
string $property,
$value
) {
/**
* @var S[K]|string
*/
$value = $value;

if ('date' === $property && is_string($value)) {
$out = new DateTimeImmutable($value);
} else {
/**
* @var S[K]
*/
$value = $value;

/**
* @var T[K]
*/
$out = parent::PropertyScalarOrNullToValue(
(string) $property,
$value
);
}

/**
* @var T[K]
*/
return $out;
}
}
3 changes: 2 additions & 1 deletion psalm.baseline.xml
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="3.4.10@c283f0877d543e7ab738d231ba6a3cdce5e1039a">
<file src="Tests/DaftTypedObjectTest.php">
<InvalidArgument occurrences="1">
<InvalidArgument occurrences="2">
<code>new DateTimeImmutable()</code>
<code>testJsonSerialize</code>
</InvalidArgument>
</file>
</files>

0 comments on commit 3c01fed

Please sign in to comment.