Valinor/docs/pages/getting-started.md

122 lines
2.7 KiB
Markdown
Raw Normal View History

# 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…
}
```