Eloquent ORMでDBから値を取得すると、Collectionオブジェクトで返ってきます。
取得後のデータを色々と加工できてとても便利です。
しかし、どうしても欲しい形式のデータに変換できなかったので、変換して返すメソッドを追加してみます。
この拡張は、サービスプロバイダーに登録する必要が無いので、とても簡単に出来ます。
対象のバージョン(動作確認済み)は5.1です。
DBは、Postgresql9.4.4を使用しています。
#追加メソッドを記述するクラスを用意
Illuminate\Database\Eloquent\Collectionを継承したクラスを用意します。
追加メソッドについては後ほど説明します。
こんな感じで用意してみました。
<?php namespace App\KantaiCollection;
use Illuminate\Database\Eloquent\Collection;
class KantaiCollection extends Collection
{
}
正直これがやりたかっただけです。寒いと思った方は、ブラウザバックして下さい!
...ですが、実は全く無関係な話ではなく、艦これで使用されているかは不明ですが、DMMが運営しているゲームにはLaravel5を導入しているものもあるようです。
DMMゲームのログ解析~ログ収集と解析の概要~
http://labotech.dmm.com/entry/2015/08/20/184051
#追加メソッドの記述
少し脱線してしまいましたが、説明に戻ります。
私が欲しかったデータ形式というのは、指定したカラムをキーにした連想配列です。
理由としては、ループ処理の時にissetで存在確認ができ、パフォーマンス向上(脱in_array)が見込めたからです。
また、連想配列の性質を利用して、SQLでdistinctを使用しなくても、重複を省いた一覧を取得できます。
(どちらのパフォーマンスが上かは調べてないですが)
ということで、こんな感じに実装してみました。
<?php namespace App\KantaiCollection;
use Illuminate\Database\Eloquent\Collection;
class KantaiCollection extends Collection
{
/**
* 指定したカラムをキーにHash化
*
* @param string $column
* @return array
*/
public function toHash($column)
{
$result = [];
foreach ($this->items as $item)
{
$result[$item[$column]] = $item;
}
return $result;
}
}
簡単に処理を説明すると、
$this->itemsには、取得時の配列とオブジェクトが入っています。
なので、これをループさせ、指定したカラムをキーにした配列に入れなおしています。
#Eloquent ModelのnewCollectionをオーバーライドする
Eloquent Modelを用意し、newCollection()というメソッドをオーバーライドします。
<?php namespace App\Kantai;
use Illuminate\Database\Eloquent\Model;
use App\KantaiCollection;
class Kantai extends Model
{
/**
* コレクションの拡張
*
* @param array $models
* @return \App\KantaiCollection
*/
public function newCollection(array $models = [])
{
return new KantaiCollection($models);
}
}
これで、先ほどのメソッドが使えるようになりました!
ちなみに、ドキュメントにも記載されているので、ご存知の方が多いかもですが、
artisanコマンドでモデル作成時に-mオプションを付けると、マイグレーションも同時に作成されるので便利です。
(seederも一緒に作成出来るオプションがあれば、さらに便利なんだけど)
#データを用意して確認してみる
「Kantais」テーブルのデータを用意します。
艦種と名前だけのシンプルなデータですが、中身はこんな感じです。
id | type | name | created_at | updated_at
----+----------+------+---------------------+---------------------
1 | 駆逐艦 | 吹雪 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
2 | 駆逐艦 | 睦月 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
3 | 軽巡洋艦 | 川内 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
4 | 軽巡洋艦 | 神通 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
5 | 重巡洋艦 | 愛宕 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
6 | 重巡洋艦 | 利根 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
7 | 戦艦 | 長門 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
8 | 戦艦 | 金剛 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
9 | 空母 | 赤城 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
10 | 空母 | 加賀 | 2015-12-24 00:00:00 | 2015-12-24 00:00:00
では、レコード全てを取得して、nameをキーにした連想配列を取得してみます。
メソッドの使い方はこんな感じです。
<?php
namespace App\Http\Controllers\KanColle;
use App\Http\Controllers\Controller;
class KanColleController extends Controller
{
public function index()
{
$kantai = app('App\Kantai');
dd($kantai->all()->toHash('name'));
}
}
ちなみに、さっきのメソッドをall()だけにして、コレクションで返すと...
当たり前ですが、Collectionオブジェクトの名前が「KantaiCollection」になります。
ということで、2回目ですが、これがやりたかっただけなんです
以上、お付き合いありがとうございました。
#まとめ
- Illuminate\Database\Eloquent\Collectionを継承したクラスを用意
- そこに、追加したい処理を記述
- Eloquent ModelのnewCollection()をオーバーライドする
ご指摘や、もっと良いやり方があるという方は、ぜひコメント下さい。