GinqでCSVを出力できるginq-csvを作ってみた

Ginq便利ですよね!

GinqはPHPLINQです。

LINQMicrosoftが開発したコレクションを操作する方法です。

本質的に、LINQ to Objects は、コレクションを扱うための新しい方法です。 従来の方法では、複雑な foreach ループを記述して、コレクションからどのようにデータを取得するかを指定する必要がありました。 LINQ を使用する場合は、何を取得するかを表す宣言コードを記述します。 また、LINQ クエリには、従来の foreach ループと比べて次の 3 つの重要な利点があります。

  • 簡潔で読みやすい (特に複数の条件をフィルター処理する場合)。
  • 強力なフィルター処理、並べ替え、およびグループ化機能を最小限のアプリケーション コードで実現できる。
  • ほとんど変更せずに、他のデータ ソースに移植できる。 一般に、データに対して実行する操作が複雑なほど、従来の反復処理の代わりに LINQ を使用することの意義が高まります。 (http://msdn.microsoft.com/ja-jp/library/bb397919(v=vs.100).aspx より引用)

自分が書くPHPはだいたいforeachなので、ちょっと複雑な処理が必要なforeachになったらGinqで書くことにしています。

<?php
use Ginq\Ginq;

$result = Ginq::from([
    ['iojs', 'iojs/io.js', 'JavaScript', 'shama', 'Evented IO for V8 JavaScript'],
    ['inconshreveable', 'inconshreveable/ngrok', 'Go', 'k1LoW', 'Introspected tunnels to localhost'],
    ['robweber', 'robweber/xbmcbackup', 'Python', 'kvz', 'Backup your xbmc profile'],
    ['ronnywang', 'ronnywang/PHPMemcacheSASL', 'PHP', 'shin1x1', 'PHP Memcache class with SASL support, heroku test ok'],
    ['DefactoSoftware', 'DefactoSoftware/Hours', 'Ruby', 'kawahiro311', "Time registration that doesn't suck"],
    ['azu', 'azu/en-ja-ruby-translator', 'JavaScript', 'tricknotes', 'ずるっこ!ライクな英和辞書 Greasemonkey.'],
    ['Carthage', 'Carthage/Carthage', 'Objective->C', 'dragon3', 'A simple, decentralized dependency manager for Cocoa'],
])->where(function($v) {
    return ($v[2]  ==  'JavaScript');
})->select(function($v) {
    return array($v[0], $v[1], $v[4]);
})->toList(); 
// [['iojs', 'iojs/io.js', 'Evented IO for V8 JavaScript'],  ['azu', 'azu/en-ja-ruby-translator', 'ずるっこ!ライクな英和辞書 Greasemonkey.']]

そんなGinqは標準で返り値を配列にすることはできたのですが、 CSVにする機能 が欲しかったので作ってみました。

GinqCsv

インストール

composer.jsonに以下を追記してください

{
    "require": {
        "k1low/ginq-csv": "~0.9.3"
    }
}

使い方

Ginq\GinqCsvGinq::register() で登録して、toList()toCsv() に変えるだけです。

<?php
use Ginq\Ginq;
use Ginq\GinqCsv;

Ginq::register('Ginq\GinqCsv');

$result = Ginq::from([
    ['iojs', 'iojs/io.js', 'JavaScript', 'shama', 'Evented IO for V8 JavaScript'],
    ['inconshreveable', 'inconshreveable/ngrok', 'Go', 'k1LoW', 'Introspected tunnels to localhost'],
    ['robweber', 'robweber/xbmcbackup', 'Python', 'kvz', 'Backup your xbmc profile'],
    ['ronnywang', 'ronnywang/PHPMemcacheSASL', 'PHP', 'shin1x1', 'PHP Memcache class with SASL support, heroku test ok'],
    ['DefactoSoftware', 'DefactoSoftware/Hours', 'Ruby', 'kawahiro311', "Time registration that doesn't suck"],
    ['azu', 'azu/en-ja-ruby-translator', 'JavaScript', 'tricknotes', 'ずるっこ!ライクな英和辞書 Greasemonkey.'],
    ['Carthage', 'Carthage/Carthage', 'Objective->C', 'dragon3', 'A simple, decentralized dependency manager for Cocoa'],
])->where(function($v) {
    return ($v[2]  ==  'JavaScript');
})->select(function($v) {
    return array($v[0], $v[1], $v[4]);
})->toCsv();
// "iojs","iojs/io.js","Evented IO for V8 JavaScript"
// "azu","azu/en-ja-ruby-translator","ずるっこ!ライクな英和辞書 Greasemonkey."

オプション

toCSV()にオプションを渡すことで、出力するCSVフォーマットや出力方法を変更できます。

オプション 概要 デフォルト値
csvEncoding 出力CSVエンコーディング UTF-8
delimiter 区切り文字 ,
enclosure 囲み文字 "
newlineChar 改行文字 \n
forceEnclose 囲み文字を常につけるか true
forceOutput 文字列として返り値を返さず1行ごとに直接出力するか false

例えば、「Windows Excelで読めるCSV」を出力するしたら、たぶんこんな感じでしょうか?

<?php
use Ginq\Ginq;
use Ginq\GinqCsv;
Ginq::register('Ginq\GinqCsv');

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=data.csv');

Ginq::from(
 // CSV出力したい配列
)->toCsv([
  'csvEncoding' => 'SJIS-win',
  'delimiter' => ',',
  'enclosure' => '"',
  'newlineChar' => "\r\n",
  'forceEnclose' => false,
  'forceOutput' => true,
]);

というわけで

これで気軽にCSV出力!!