CakePHP 4.x: FriendsOfCake/crud の Config の api.success.data キー

api.success.data.row を指定する場合の例

下記のような感じで

// \Crud\Action\BaseAction を継承したカスタムアクション
class HogeAction extends BaseAction
{
    protected $_defaultConfig = [
        // ...
        'api' => [
            'methods' => ['get'],
            'success' => [
                'code' => 200,
            ],
           // ...
        ],
    ];

    protected function _get()
    {
        //...

        /** @var HogesTable $HogesTable */
        $HogesTable = $this->_table();

        /** @var \Cake\Database\Query $hoges */
        $hoges = $HogesTable()->find()->where(...);

        $fuga = ['a', 'b', 'c'];

        $row = [
          'hoges' => $hoges,
          'fuga' => $fuga,
        ];

        $this->setConfig('api.success.data.raw', $row);

        $subject = $this->_subject();
        $subject->set([
            'success' => true,
        ]);

        $this->_trigger('beforeRender', $subject);
    }

こんな感じのレスポンスを返せる

string(xxx) "{
    "success": true,
    "data": {
        "hoges": [ // HogeEntity の配列
            // ...
        ],
        "fuga": [
            "a",
            "b",
            "c"
        ]
    }
}"

備考: api.success.data.raw に 「文字列の数字をキーにした配列」 を設定する事は出来ない

こんな感じにしてしまうと、

        $row = [
          '1' => $hoges,
          '2' => $fuga,
        ];

        $this->setConfig('api.success.data.raw', $row);

Crud\Listener\ApiListener::_expandPath の第二引数に int が渡り、TypeError になる。

[TypeError] Crud\Listener\ApiListener::_expandPath(): Argument #2 ($path) must be of type string, int given, called in /srv/app/vendor/friendsofcake/crud/src/Listener/ApiListener.php

これはPHPの配列の仕様によるものなので、 api.success.data.raw には「文字列(文字列の数字以外)をキーにした配列」を設定する必要がある

https://www.php.net/manual/ja/language.types.array.php より抜粋

> key は、整数 または 文字列です。 value には任意の型を指定できます。
>
> さらに、次のような key のキャストが発生します。
> 
> 10 進数の int として妥当な形式の String は、 数値の前に + 記号がついていない限り、 int 型にキャストされます。
> つまり、キーに "8" を指定すると、実際には 8 として格納されるということです。

2023/05/30 追記: data に 「文字列の数字をキーにした配列」を設定したい場合 を参照

api.success.data.subject を指定する場合の例

    protected function _get()
    {
        //...

        /** @var \Cake\Database\Query $hoges */
        $hoges = $HogesTable()->find()->where(...);

        $fuga = ['a', 'b', 'c'];

        $this->setConfig('api.success.data.subject', 'hoges');

        $subject = $this->_subject();
        $subject->set([
            'hoges' => $hoges,
            'success' => true,
        ]);

        $this->_trigger('beforeRender', $subject);
    }
string(xxx) "{
    "success": true,
    "data": {
        "hoges": [ // HogeEntity の配列
          // ...
        ]
    }
}"
    protected function _get()
    {
        //...

        /** @var \Cake\Database\Query $hoges */
        $hoges = $HogesTable()->find()->where(...);

        $this->setConfig('api.success.data.subject', ['hoges', 'fuga']);

        $subject = $this->_subject();
        $subject->set([
            'hoges' => $hoges,
            'huga' => $huga,
            'success' => true,
        ]);

        $this->_trigger('beforeRender', $subject);
    }
string(xxx) "{
    "success": true,
    "data": {
        "hoges": [ // HogeEntity の配列
          // ...
        ],
        "fuga": [
            "a",
            "b",
            "c"
        ]
    }
}"

api.success.data.entity を指定する場合の例

    protected function _get()
    {
        //...

        /** @var HogeEntity $hogeEntity */
        $hogeEntity = $HogesTable->get(1);

        // property名を指定
        $this->setConfig('api.success.data.entity', ['id', 'name', 'email']);

        $subject = $this->_subject();
        $subject->set([
            'entity' => $hogeEntity,
            'success' => true,
        ]);

        $this->_trigger('beforeRender', $subject);
    }
string(xxx) "{
    "success": true,
    "data": {
        "id": xxx,
        "name": xxx,
        "email": xxx
    }
}"
    protected function _get()
    {
        //...

        /** @var HogeEntity $hogeEntity */
        $hogeEntity = $HogesTable->get(1);

        // HogeEntity のメソッド名を指定
        $this->setConfig('api.success.data.entity', ['toArray', 'isNew']);

        $subject = $this->_subject();
        $subject->set([
            'entity' => $hogeEntity,
            'success' => true,
        ]);

        $this->_trigger('beforeRender', $subject);
    }
string(xxx) "{
    "success": true,
    "data": {
        "toArray": {
            "id": xxx,
            "name": xxx,
            "email": xxx,
            // ...
        },
        "isNew": false
    }
}"

2023/05/30 追記: data に 「文字列の数字をキーにした配列」を設定したい場合

use ViewVarTrait;$_defaultConfig'scope' => 'table' を忘れない事

class HogeAction extends BaseAction
{
    use ViewVarTrait;

    protected $_defaultConfig = [
        'scope' => 'table',
        'api' => [
            'methods' => ['get'],
            'success' => [
                'code' => 200,
            ],
        ],
    ];

    protected function _get(): void
    {
        //...

        $array = //「文字列の数字をキーにした配列」

        $subject = $this->_subject();
        $subject->set([
            'success' => true,
            'entities' => $array,
        ]);

        $this->_trigger('beforeRender', $subject);
    }
}