【PHPフレームワークFlow】レスポンス項目を指定する方法

# 初めに
Flowを用いてAPIを作成している際、レスポンスで返却する項目を簡単に絞る方法を知りました。
忘れないように覚書きします。

# レスポンスとして返す項目を絞りたい

FlowではModelクラス（DBのTBLと1体1になっているクラス）をレスポンスとして設定することが可能です。
しかし、テーブル情報を持つModelクラスをそのままレスポンスに設定してしまうと、返したくない項目もレスポンスに設定されてしまいます。
返却する項目を指定する場合、レスポンスを整形する処理を入れるかレスポンス用のデータクラスを別で作成する必要があり、どちらにせよFlowの恩恵がなくなってしまいます。

そういう場合に、```setConfiguration()```メソッドを用いることでFlowの利点を消さずに返却する項目を簡単に指定できるようになります。


## setConfiguration()
```setConfiguration()```はFlowのJsonViewクラスで定義されているメソッドです。
以下のように項目を連想配列で指定し、その子項目に対してレスポンスの絞り込みを行います。

```php:setConfiguration()の例
    public function getItemAction()
    {
        $item = $this->itemRepository->findAll();
        $this->view->assign('value', array(
            "item" => $item,
        ));
        $this->view->setConfiguration(array(
            'value' => array(
                'item' => array(
                    "_descendAll" => array(
                        '_only' => array('name')
                    )
                )
            )
        ));
    }
```
:::note info
```_descendAll```は子項目のすべてに対して同様の指定をする場合に記載します。個別に指定する場合は```_descend```を指定します。
:::

```setConfigration()```では、返却する項目以外にもいくつか設定可能な項目があります。設定できる項目は以下です。

| プロパティ                  | 説明                                                         |
|-----------------------------|--------------------------------------------------------------|
| _only                       | レスポンスに含める項目を指定           |
| _exclude                    | レスポンスに含めない項目を指定       |
| _exposeObjectIdentifier    | DB上のデータの識別子をレスポンスに含めるかどうかを指定|
| _exposedObjectIdentifierKey | データ識別子を返す場合のキー名を指定  |
| _exposeClassName            | レスポンスに設定したオブジェクトのクラスのパスを返す|

# 試してみた
それでは、```setConfiguration()```を試してみましょう。
今回用いたControllerとModelクラスは以下になります。

<details><summary>ControllerとModelの実装</summary>

```php:Controller
<?php
namespace Neos\Welcome\Controller;


use Neos\Flow\Annotations as Flow;
use Neos\Flow\Mvc\Controller\ActionController;
use Neos\Flow\Mvc\View\JsonView;

class ItemController extends ActionController
{

    /**
     * @Flow\Inject
     * @var \Neos\Flow\Mvc\View\JsonView
     */
    protected $view;

    /**
     * @Flow\Inject
     * @var \Neos\Welcome\Domain\Repository\ItemRepository
     */
    protected $itemRepository;

    public function getItemAction()
    {
        $item = $this->itemRepository->findAll();
        $this->view->assign('value', array(
            "item" => $item,
        ));
    }
}

```

```php:Model
<?php
namespace Neos\Welcome\Domain\Model;


use Neos\Flow\Annotations as Flow;
use Doctrine\ORM\Mapping as ORM;

/**
 * @Flow\Entity
 * @ORM\Table(name="item")
 */
class Item
{

    /**
     * @ORM\Column(type="string", name="item_name", length=20, nullable=false, unique=true)
     * @var string
     */
    protected $name;

    /**
     * @ORM\Column(type="string", length=100)
     * @var string
     */
    protected $description;

    /**
     * @ORM\Column(type="integer", nullable=false)
     * @var int
     */
    protected $price;

    // コンストラクタ
    public function __construct(string $name, string $description, int $price)
    {
        $this->name = $name;
        $this->description = $description;
        $this->price = $price; // Remember to hash the password before setting it
    }

    // getters and setters...
    public function getName(): string
    {
        return $this->name;
    }

    public function getDescription(): string
    {
        return $this->description;
    }

    public function getPrice(): int
    {
        return $this->price;
    }
}

```

</details>

```setConfigration()```特に何も指定しない場合は以下のようなレスポンスになります。

```sh
curl http://localhost:8081/Neos.Welcome/Item/getItem | jq

{
  "item": [
    {
      "description": "Item Description",
      "name": "Item Name",
      "price": 100
    }
  ]
}
```

## _only
以下のように```_only```を指定することで、返却する項目を指定することができます。


```php
    public function getItemAction()
    {
        $item = $this->itemRepository->findAll();
        $this->view->assign('value', array(
            "item" => $item,
        ));
        $this->view->setConfiguration(array(
            'value' => array(
                'item' => array(
                    "_descendAll" => array(
                        '_only' => array('name')
                    )
                )
            )
        ));
    }
```

実際のレスポンスは以下です。指定したnameだけが返却されています。
```sh
$ curl http://localhost:8081/Neos.Welcome/Item/getItem | jq
{
  "item": [
    {
      "name": "Item Name"
    }
  ]
}
```

## _exclude
以下のように```_exclude```を指定することで、返却しない項目を指定することができます。


```php
    public function getItemAction()
    {
        $item = $this->itemRepository->findAll();
        $this->view->assign('value', array(
            "item" => $item,
        ));
        $this->view->setConfiguration(array(
            'value' => array(
                'item' => array(
                    "_descendAll" => array(
                        '_only' => array('name')
                    )
                )
            )
        ));
    }
```

実際のレスポンスは以下です。指定したname以外が返却されます。
```sh
$ curl http://localhost:8081/Neos.Welcome/Item/getItem | jq
{
  "item": [
    {
      "description": "Item Description",
      "price": 100
    }
  ]
}
```
## _exposeObjectIdentifier, _exposedObjectIdentifierKey
以下のように```_exposeObjectIdentifier```を指定することで、返却するデータに紐づく```persistence_object_identifier```を返却することができます。

:::note info

```persistence_object_identifier```とは、doctrine（Flowで使用されてるORM）がテーブル管理に用いている主キーです。
:::
```_exposedObjectIdentifierKey```を用いると```persistence_object_identifier```を返す際にキーを設定することができます。
未設定の場合キーは```__identity```になります。


```php
    public function getItemAction()
    {
        $item = $this->itemRepository->findAll();
        $this->view->assign('value', array(
            "item" => $item,
        ));
        $this->view->setConfiguration(array(
            'value' => array(
                'item' => array(
                    "_descendAll" => array(
                        '_exposeObjectIdentifier' => true,
                        '_exposedObjectIdentifierKey' => 'testKey!!',
                    )
                )
            )
        ));
    }
```

実際のレスポンスは以下です。
```sh
$ curl http://localhost:8081/Neos.Welcome/Item/getItem | jq
{
  "item": [
    {
      "description": "Item Description",
      "name": "Item Name",
      "price": 100,
      "testKey!!": "f29af2ba-4394-444d-a780-beeb7f25cc46"
    }
  ]
}
```

## _exposeClassName
以下のように```_exposeClassName```を指定することで、返却するデータがどのModelを使用しているかを一緒に返却することができます。
（用途がぱっと思いつかないですが、同リポジトリに別APIを呼ぶ場合などに使用する感じ？）


```php
    public function getItemAction()
    {
        $item = $this->itemRepository->findAll();
        $this->view->assign('value', array(
            "item" => $item,
        ));
        $this->view->setConfiguration(array(
            'value' => array(
                'item' => array(
                    "_descendAll" => array(
                        '_exposeClassName' => JsonView::EXPOSE_CLASSNAME_FULLY_QUALIFIED
                    )
                )
            )
        ));
    }
```

実際のレスポンスは以下です。
```sh
$ curl http://localhost:8081/Neos.Welcome/Item/getItem | jq
{
  "item": [
    {
      "description": "Item Description",
      "name": "Item Name",
      "price": 100,
      "__class": "Neos\\Welcome\\Domain\\Model\\Item"
    }
  ]
}
```


# 終わりに
今回は、Flowの```setConfiguration()```メソッドについてまとめました。
使いどころありそうな気がしますがどうでしょう。
またFlowについて分かったことがあればアウトプットします。

# 参考

https://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/ModelViewController.html#json-view