やりたいこと
コレクションの要素をキーにする。ただし要素からは消したい。
例えば、id, name, email
みたいな構造のデータベースのテーブルがあるとします。
ここから複数行のレコードを取得し、下記のような感じで整形したいとします。
id1 => [name1, email1],
id2 => [name2, email2],
id3 => [name3, email3],
やり方
mapWithKeys()
で。
※Laravel 5.4以降のCollectionで使用可能なメソッドです。
テスト実装
例えば下記のように実装してみましょう。
$users_raw->mapWithKeys(function ($item)
{
return [
$item['id'] => [
'name' => $item['name'],
'email' => $item['email'],
]
];
})->toArray();
テストコード全体
/tests/Unit/MapWithKeysTest.php
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Collection as Collection;
use App\User as User;
class ExampleTest extends TestCase
{
public function testMapWithKeys()
{
echo "\n",'=== ',__FUNCTION__,' ===',"\n";
// モデルファクトリーで定義したテストユーザーを作成
$users_raw = factory(User::class, 3)->make();
// DBにINSERTしていないため、手動でIDを追加
foreach ($users_raw as $key => &$user) {
$user->id = $key + 1;
}
// テストデータ表示
echo "\n",'=== TEST_D\ATA ===',"\n";
var_dump($users_raw);
// テストの実装
$users_result = $users_raw->mapWithKeys(function ($item)
{
return [
$item['id'] => [
'name' => $item['name'],
'email' => $item['email'],
]
];
})->toArray();
// テスト結果
echo "\n",'=== TEST_RESULT ===',"\n";
var_dump($users_result);
$this->assertTrue(true);
}
}
テスト結果
array(3) {
[1] => array(2) {
["name"] => string(20) "Prof. Wiley Yundt MD"
["email"] => string(30) "mosciski.esperanza@example.net"
}
[2] => array(2) {
["name"] => string(12) "Easter Fahey"
["email"] => string(29) "donnell.bahringer@example.org"
}
[3] => array(2) {
["name"] => string(20) "Camille Cummings PhD"
["email"] => string(19) "bobby76@example.org"
}
}
補足1
keyBy()
でもいいのでは?
$queryBuilder = self::select(id, name, email);
return $queryBuilder->get()->keyBy('id');
結果
$idが要素側にも入ったままになるため、少し冗長に。
id1 => [id1, name1, email1],
id2 => [id2, name2, email2],
id3 => [id3, name3, email3],
※keyBy()
は各要素のキーを指定するメソッドであり、要素の内容には触れないためのようです。
補足2
$queryBuilder = self::select(id, name, email);
return $queryBuilder->get()->keyBy('id')->only(['name', 'email']);
結果
[]
ええ……どうしてこうなった……
※ こちらは配列変換が再帰的に行われるからのようです。