mirror of
https://github.com/danog/Valinor.git
synced 2024-12-02 17:48:14 +01:00
122 lines
2.7 KiB
Markdown
122 lines
2.7 KiB
Markdown
# Getting started
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
composer require cuyz/valinor
|
|
```
|
|
|
|
## Example
|
|
|
|
An application must handle the data coming from an external API; the response
|
|
has a JSON format and describes a thread and its answers. The validity of this
|
|
input is unsure, besides manipulating a raw JSON string is laborious and
|
|
inefficient.
|
|
|
|
```json
|
|
{
|
|
"id": 1337,
|
|
"content": "Do you like potatoes?",
|
|
"date": "1957-07-23 13:37:42",
|
|
"answers": [
|
|
{
|
|
"user": "Ella F.",
|
|
"message": "I like potatoes",
|
|
"date": "1957-07-31 15:28:12"
|
|
},
|
|
{
|
|
"user": "Louis A.",
|
|
"message": "And I like tomatoes",
|
|
"date": "1957-08-13 09:05:24"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
The application must be certain that it can handle this data correctly; wrapping
|
|
the input in a value object will help.
|
|
|
|
---
|
|
|
|
A schema representing the needed structure must be provided, using classes.
|
|
|
|
```php
|
|
final class Thread
|
|
{
|
|
public function __construct(
|
|
public readonly int $id,
|
|
public readonly string $content,
|
|
public readonly DateTimeInterface $date,
|
|
/** @var Answer[] */
|
|
public readonly array $answers,
|
|
) {}
|
|
}
|
|
|
|
final class Answer
|
|
{
|
|
public function __construct(
|
|
public readonly string $user,
|
|
public readonly string $message,
|
|
public readonly DateTimeInterface $date,
|
|
) {}
|
|
}
|
|
```
|
|
|
|
Then a mapper is used to hydrate a source into these objects.
|
|
|
|
```php
|
|
public function getThread(int $id): Thread
|
|
{
|
|
$rawJson = $this->client->request("https://example.com/thread/$id");
|
|
|
|
try {
|
|
return (new \CuyZ\Valinor\MapperBuilder())
|
|
->mapper()
|
|
->map(
|
|
Thread::class,
|
|
new \CuyZ\Valinor\Mapper\Source\JsonSource($rawJson)
|
|
);
|
|
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
|
|
// Do something…
|
|
}
|
|
}
|
|
```
|
|
|
|
## Mapping advanced types
|
|
|
|
Although it is recommended to map an input to a value object, in some cases
|
|
mapping to another type can be easier/more flexible.
|
|
|
|
It is for instance possible to map to an array of objects:
|
|
|
|
```php
|
|
try {
|
|
$objects = (new \CuyZ\Valinor\MapperBuilder())
|
|
->mapper()
|
|
->map(
|
|
'array<' . SomeClass::class . '>',
|
|
[/* … */]
|
|
);
|
|
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
|
|
// Do something…
|
|
}
|
|
```
|
|
|
|
For simple use-cases, an array shape can be used:
|
|
|
|
```php
|
|
try {
|
|
$array = (new \CuyZ\Valinor\MapperBuilder())
|
|
->mapper()
|
|
->map(
|
|
'array{foo: string, bar: int}',
|
|
[/* … */]
|
|
);
|
|
|
|
echo $array['foo'];
|
|
echo $array['bar'] * 2;
|
|
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
|
|
// Do something…
|
|
}
|
|
```
|