Mapping Json to PHP object using JsonMapper
Tags: php, json, mapping, laravel
Published: 2021-04-05 19:46:32

# Introduction of a strongly types in PHP
Since PHP 7.0 started with the introduction of typehints the language has evolved and enabled developers to use build strictly typed code. This has lead to tools such as PHPStan and Rector that can benefit these type hints.

JsonMapper is a PHP library that lets developers use that type information. As it allows you to map JSON to your PHP objects using an extendable middleware based architecture.

Let's see how this can easily be used to map a JSON API response to a PHP object within minutes. Without having to write any mapping rules. As an alternative to the `php artisan inspire` command we shall introduce an alternative to tell us a joke. The API we are using is available at https://official-joke-api.appspot.com/random_joke

# Let's get mapping
## Starting a new Laravel project
```bash
# Create the project from the laravel/laravel template
composer create-project --prefer-dist laravel/laravel joke
cd joke

# Require the JsonMapper laravel package and publish the config
composer require json-mapper/laravel-package
php artisan vendor:publish --provider="JsonMapper\LaravelPackage\ServiceProvider"
```

## Configuration
In order to benefit the typed properties middleware from JsonMapper we need to change the configuration from `default` to `best-fit`. This will include the [TypedProperties middleware](https://jsonmapper.net/docs/middleware/typed-properties/) if running PHP 7.4

```php
<?php
# ./config/json-mapper.php

return [
    'type' => 'best-fit'
];
```

## The object
The structure of the response is a single object containing the properties: `id`, `type`, `setup` and `punchline`.
In order to map this a PHP object we need to create one that fits the API definition, a simple DTO will do.

```php
<?php
# ./app/Dto/JokeData.php

namespace App\Dto;

class JokeData 
{
    public int $id;
    public string $type;
    public string $setup;
    public string $punchline;
}
```

## The console command
You can easily bootstrap a new command using the artisan tool that comes with Laravel:
```bash
php artisan make:command JokeCommand
```

The JsonMapper Laravel package we installed earlier makes the `JsonMapperInterface` available from the service container.
Al we need to do is set the command signature (1), fetch the JSON data (2), map it using JsonMapper to our PHP object (3) and tell the joke (4).

```php
<?php
#app/Console/Commands/JokeCommand.php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use JsonMapper\LaravelPackage\JsonMapperInterface;
use App\Dto\JokeData;

class Joke extends Command
{
    protected $signature = 'joke'; # (1)
    protected $description = 'Tell a joke';
    private JsonMapperInterface $mapper;

    public function __construct(JsonMapperInterface $mapper)
    {
        parent::__construct();
        $this->mapper = $mapper;
    }

    public function handle()
    {
        # Fetch the data (2)
        $url = 'https://official-joke-api.appspot.com/random_joke';
        $data = Http::get($url);

        # Map the data (3)
        $joke = new JokeData();
        $this->mapper->mapObjectFromString($data, $joke);

        # Tell the joke (4)
        $this->output->writeln($joke->setup . ' ' . $joke->punchline);

        return 0;
    }
}
```

# Wrap up
And that is all there is to it. We've started a new project, added the [JsonMapper Laravel package](https://jsonmapper.net/docs/guides/laravel-usage/), created a DTO and mapped the fetched data onto out DTO.

```bash
$ php artisan joke
Did you hear the one about the guy with the broken hearing aid? Neither did he.
```

If you want to read more about JsonMapper please checkout the documentation website [https://jsonmapper.net](https://jsonmapper.net)