【Craft CMS】配列から任意の値をキーにした連想配列を生成したりグループ化したりできる便利なArrayHelper::index

同人誌、同人ゲーム、同人ソフトのダウンロードショップ - DLsite

Laravelのpluck()のように、DBから取得する際にforeachなどで処理しやすいようにデータを整形したく、探してみたのだがCraft CMS 3系には同じようなものはないらしい。

代わりになりそうなのが、ArrayHelperという配列操作のクラスにあるindex()メソッドで同じことができるので使ってみた。

頻繁に使う場合はファイルの先頭に”craft\helpers\ArrayHelper”のエイリアスを設定しておくか、下記のようにインポートしておくことでコードが少し短くできる。

// ファイル冒頭で定義しておく
use craft\helpers\ArrayHelper;
$arr = ArrayHelper::index($arr, 'id');

1,任意の値をキーにした配列を生成する

例えば”User::find()->asArray()->all()”などで下記のようなユーザー配列を取得したとする。

$arr = [
    ['id' => '10001', 'class' => '一組', 'name' => '阿部'],
    ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    ['id' => '10003', 'class' => '二組', 'name' => '内田'],
    ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    ['id' => '10005', 'class' => '三組', 'name' => '太田'],
];

この配列だと、特定の’id’に対して処理をしようとすると全ての要素を見ないといけなくなるが、次のように ArrayHelper::index() を通して「’id’をキーにした配列」に整形しておくことで処理が少し簡単に書きやすくなる。

$arr1 = craft\helpers\ArrayHelper::index($arr, 'id');
// $arr1の中身
[
    '10001' => ['id' => '10001', 'class' => '一組', 'name' => '阿部'],
    '10002' => ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    '10003' => ['id' => '10003', 'class' => '二組', 'name' => '内田'],
    '10004' => ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    '10005' => ['id' => '10005', 'class' => '三組', 'name' => '太田'],
];
if(isset($arr1['10003'])) {
    // 処理
}

ちなみに、上記までであればArrayHelper::index()を使わなくても、PHPが用意している標準の配列関数array_column()で同じことができる。

$arr1 = array_column($arr, null, 'id');

array_column()で書くサンプル → https://paiza.io/projects/zZGZFY2WFqYGo20hPGBZsQ

注意点として、第二引数で指定したキーの値が、複数の配列で重複していた場合、後の配列で上書きされてしまう。

例えば次の配列は「’id’ => ‘10001’」が二つあるが、これを第二引数に’id’を指定したindex()メソッドを通してしまうと

$arr2 = [
    ['id' => '10001', 'class' => '一組', 'name' => '阿部'],
    ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    ['id' => '10003', 'class' => '二組', 'name' => '内田'],
    ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    ['id' => '10005', 'class' => '三組', 'name' => '太田'],
    ['id' => '10001', 'class' => '特別進学', 'name' => '阿部寛'],
];
$arr2 = craft\helpers\ArrayHelper::index($arr2, 'id');
// $arr2の中身
[
    '10001' => ['id' => '10001', 'class' => '特別進学', 'name' => '阿部寛'],
    '10002' => ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    '10003' => ['id' => '10003', 'class' => '二組', 'name' => '内田'],
    '10004' => ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    '10005' => ['id' => '10005', 'class' => '三組', 'name' => '太田'],
];

このように「class’一組’の阿部」が「class’特別進学’の阿部寛」に上書きされてしまうので、使用する際は値が重複していないか注意する必要がある。

また、ネストした配列の値をキーにすることもできる。

次のように’test’の値に配列がセットされている二次元配列があったとして

$arr3 = [
    ['id' => '10001', 'class' => '一組', 'name' => '阿部', 'test' => ['testId' => '111', 'score' => '10']],
    ['id' => '10002', 'class' => '一組', 'name' => '伊藤', 'test' => ['testId' => '111', 'score' => '20']],
    ['id' => '10003', 'class' => '二組', 'name' => '内田', 'test' => ['testId' => '111', 'score' => '30']],
    ['id' => '10004', 'class' => '二組', 'name' => '遠藤', 'test' => ['testId' => '222', 'score' => '40']],
    ['id' => '10005', 'class' => '三組', 'name' => '太田', 'test' => ['testId' => '222', 'score' => '50']],
];

その中の’score’の値をキーにした配列を生成したい場合は’test.score’というような感じでカンマ区切りで指定する。

$arr3 = craft\helpers\ArrayHelper::index($arr3, 'test.score');
// $arr3の中身
[
    '10' => ['id' => '10001', 'class' => '一組', 'name' => '阿部', 'test' => ['testId' => '111', 'score' => '10']],
    '20' => ['id' => '10002', 'class' => '一組', 'name' => '伊藤', 'test' => ['testId' => '111', 'score' => '20']],
    '30' => ['id' => '10003', 'class' => '二組', 'name' => '内田', 'test' => ['testId' => '111', 'score' => '30']],
    '40' => ['id' => '10004', 'class' => '二組', 'name' => '遠藤', 'test' => ['testId' => '222', 'score' => '40']],
    '50' => ['id' => '10005', 'class' => '三組', 'name' => '太田', 'test' => ['testId' => '222', 'score' => '50']],
];

2,任意の値でグループ化する

第三引数にキー名を指定すると、その値でグループ化した配列を生成することができる。

$arr4 = [
    ['id' => '10001', 'class' => '一組', 'name' => '阿部'],
    ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    ['id' => '10003', 'class' => '二組', 'name' => '内田'],
    ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    ['id' => '10005', 'class' => '三組', 'name' => '太田'],
];
$arr4 = craft\helpers\ArrayHelper::index($arr4, 'id', 'class');
// $arr4の中身
[
    '一組' => [
        '10001' => ['id' => '10001', 'class' => '一組', 'name' => '阿部'],
        '10002' => ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    ],
    '二組' => [
        '10003' => ['id' => '10003', 'class' => '二組', 'name' => '内田'],
        '10004' => ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    ],
    '三組' => [
        '10005' => ['id' => '10005', 'class' => '三組', 'name' => '太田']
    ],
];

このとき、第二引数にnullを指定すると、グループ化された中の配列のキーは、通常の配列と同じように0から採番されたものが設定される。

$arr5 = [
    ['id' => '10001', 'class' => '一組', 'name' => '阿部'],
    ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    ['id' => '10003', 'class' => '二組', 'name' => '内田'],
    ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    ['id' => '10005', 'class' => '三組', 'name' => '太田'],
];
$arr5 = craft\helpers\ArrayHelper::index($arr5, null, 'class');
// $arr5の中身
[
    '一組' => [
        0 => ['id' => '10001', 'class' => '一組', 'name' => '阿部'],
        1 => ['id' => '10002', 'class' => '一組', 'name' => '伊藤'],
    ],
    '二組' => [
        0 => ['id' => '10003', 'class' => '二組', 'name' => '内田'],
        1 => ['id' => '10004', 'class' => '二組', 'name' => '遠藤'],
    ],
    '三組' => [
        0 => ['id' => '10005', 'class' => '三組', 'name' => '太田']
    ],
];

また、第三引数の指定は配列を使って複数指定することができる他、第二引数と同様にネストした配列の値を指定することもできる。

$arr6 = [
    ['id' => '10001', 'class' => '一組', 'name' => '阿部', 'test' => ['testId' => '111', 'score' => '10']],
    ['id' => '10002', 'class' => '一組', 'name' => '伊藤', 'test' => ['testId' => '111', 'score' => '20']],
    ['id' => '10003', 'class' => '二組', 'name' => '内田', 'test' => ['testId' => '111', 'score' => '30']],
    ['id' => '10004', 'class' => '二組', 'name' => '遠藤', 'test' => ['testId' => '222', 'score' => '40']],
    ['id' => '10005', 'class' => '三組', 'name' => '太田', 'test' => ['testId' => '222', 'score' => '50']],
];
$arr6 = craft\helpers\ArrayHelper::index($arr6, 'id', ['class', 'test.testId']);
// $arr6の中身
[
    '一組' => [
        '111' => [
            '10001' => ['id' => '10001', 'class' => '一組', 'name' => '阿部', 'test' => ['testId' => '111', 'score' => '10']],
            '10002' => ['id' => '10002', 'class' => '一組', 'name' => '伊藤', 'test' => ['testId' => '111', 'score' => '20']],
        ],
    ],
    '二組' => [
        '111' => [
            '10003' => ['id' => '10003', 'class' => '二組', 'name' => '内田', 'test' => ['testId' => '111', 'score' => '30']],
        ],
        '222' => [
            '10004' => ['id' => '10004', 'class' => '二組', 'name' => '遠藤', 'test' => ['testId' => '222', 'score' => '40']],
        ],
    ],
    '三組' => [
        '222' => [
            '10005' => ['id' => '10005', 'class' => '三組', 'name' => '太田', 'test' => ['testId' => '222', 'score' => '50']],
        ],
    ],
];

3,配列内の全ての要素がオブジェクトの場合でも使用できる

ArrayHelper::index()は第一引数に渡す変数が配列であれば、配列の要素が全てオブジェクトであっても上記と同じ処理が可能らしい。

例えば”User::findAll()”などで下記のようなユーザーオブジェクトの配列を取得したとすると

^ array:5 [▼
    0 => {#4122 ▼
        +"id": 10001
        +"class": "一組"
        +"name": "阿部"
        +"test": {#4121 ▼
            +"testId": "111"
            +"score": "10"
        }
    }
    1 => {#4124 ▼
        +"id": 10002
        +"class": "一組"
        +"name": "伊藤"
        +"test": {#4125 ▼
            +"testId": "111"
            +"score": "20"
        }
    }
    2 => {#4126 ▼
        +"id": 10003
        +"class": "二組"
        +"name": "内田"
        +"test": {#4127 ▼
            +"testId": "111"
            +"score": "30"
        }
    }
    3 => {#4128 ▼
        +"id": 10004
        +"class": "二組"
        +"name": "遠藤"
        +"test": {#4129 ▼
            +"testId": "222"
            +"score": "40"
        }
    }
    4 => {#4130 ▼
        +"id": 10005
        +"class": "三組"
        +"name": "太田"
        +"test": {#4131 ▼
            +"testId": "222"
            +"score": "50"
        }
    }
]

配列の時と同じように指定すれば整形してくれる。

dd($objArr, craft\helpers\ArrayHelper::index($objArr, 'id', 'test.testId'));
^ array:2 [▼
    111 => array:3 [▼
        10001 => {#4122 ▼
            +"id": 10001
            +"class": "一組"
            +"name": "阿部"
            +"test": {#4121 ▼
                +"testId": "111"
                +"score": "10"
            }
        }
        10002 => {#4124 ▼
            +"id": 10002
            +"class": "一組"
            +"name": "伊藤"
            +"test": {#4125 ▼
                +"testId": "111"
                +"score": "20"
            }
        }
        10003 => {#4126 ▼
            +"id": 10003
            +"class": "二組"
            +"name": "内田"
            +"test": {#4127 ▼
                +"testId": "111"
                +"score": "30"
            }
        }
    ]
    222 => array:2 [▼
        10004 => {#4128 ▼
            +"id": 10004
            +"class": "二組"
            +"name": "遠藤"
            +"test": {#4129 ▼
                +"testId": "222"
                +"score": "40"
            }
        }
        10005 => {#4130 ▼
            +"id": 10005
            +"class": "三組"
            +"name": "太田"
            +"test": {#4131 ▼
                +"testId": "222"
                +"score": "50"
            }
        }
    ]
]

他に第二引数、第三引数にキーではなく無名関数を定義して複雑な処理をすることも可能なので、詳しくはYiiのリファレンスを確認してみてください。

同人誌、同人ゲーム、同人ソフトのダウンロードショップ - DLsite

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です